GSSCredential
Douglas Surber
douglas.surber at oracle.com
Tue Jun 11 15:40:13 UTC 2019
Another approach is the one in ADBA. This requires building a bigger mechanism but it is much more capable as well.
public interface ConnectionProperty extends Serializable {
public String name();
public Class<?> range();
public default boolean validate(Object value) {
return (value == null && this.range() == Void.class) || this.range().isInstance(value);
}
public default Object defaultValue() { return null; }
public boolean isSensitive(); // things like passwords
public default boolean configure(Connection conn, Object value) {
// returns true if it changes the state of the Connection
if (validate(value)) {
return false;
}
else {
throw new IllegalArgumentException(value.toString() + " is invalid");
}
}
}
Then we can use ConnectionProperty where needed
public void setConnectionProperty(ConnectionProperty prop, Object value) throws SQLException;
public Connection getConnection(Map<ConnectionProperty, Object value> props) throws SQLException;
To solve the GSSCredential problem all that is needed is a GSSCredentialProperty.
public enum JdbcConnectionProperty implements ConnectionProperty {
GSSCONNECTION() {
public Class<?> range() { return Class.forName("org.ietf.jgss.GSSCredential"); }
public boolean isSensitive() { return true; }
},
USER() {
public Class<?> range() { return String.class; }
public boolean isSensitive() { return false; }
},
PASSWORD() {
public Class<?> range() { return String.class; }
public boolean isSensitive() { return true; }
}
}
Use code can define its own ConnectionProperties and use them by implementing the configure method. Drivers can define their own properties and either implement the configure method or do whatever is necessary internally.
This is a bigger change than just adding setGSSCredential but it avoids the dependency issue and it is extensible. I won't go so far as to say I'm proposing it, but if the consensus is that it is a good thing I'm happy to move forward with it.
Douglas
> On Jun 11, 2019, at 7:54 AM, Mark Rotteveel <mark at lawinegevaar.nl> wrote:
>
> On 2019-06-10 17:06, Douglas Surber wrote:
>>> Given using proxies and reflection is very common in JDBC drivers
>>> and related tools and libraries (especially with `DataSource`
>>> related things), declaring as `requires static` is not an acceptable
>>> solution. Declaring with `requires` will be the minimum necessary to
>>> ensure proper functionality and the least amount of surprise.
>>> Probably `requires transitive` is better as JDBC drivers will need
>>> to actually implement this method as well. Otherwise, the driver
>>> will need to use `requires static`, `requires` or `requires
>>> transitive` themselves; although I have actually not seen
>>> modularized JDBC drivers yet so maybe that is of lesser importance.
>> As a driver implementer I have no problem with the driver
>> module-info.java including 'requires static java.security.jgss'. The
>> driver would use 'requires static' so that driver users would not have
>> to include java.security.jgss unless they actually used it.
>
> My point was more that the java.sql module at minimum will need to declare `requires java.security.jgss` to avoid nasty surprises with proxies and reflection. The `requires` dependency isn't inherited, but it will at least prevent NoClassDefFoundErrors at runtime as the module will be loaded and present.
>
>> Proxying requiring java.security.jgss is a bigger concern. As you say,
>> proxying a very common in stacks that use JDBC. I doubt any of our
>> customers would care. I have no idea if there are any JDBC users that
>> require an absolutely minimal module set and that also use proxying.
>
> I doubt users of JDBC will look to minimize dependencies, but that it is all too easy to use that as an excuse not to consider the impact of these types of changes.
>
>> Sure this can be just a proprietary extension; there no real necessity
>> that it be part of the standard. But from that perspective there isn't
>> much need for a JDBC standard at all.In spite of all the
>> standardization around SQL, the various databases are all quite
>> different. It is hard to write a vendor independent JDBC app of much
>> sophistication.
>
> I'd beg to differ, there are a lot of tools that build on the foundations of JDBC, and those tools only exists because JDBC offers a common API. And JDBC - with all its problems - is one of the better database APIs compared with other languages.
>
>> But since we have a JDBC standard. since GSS is itself
>> a standard, and since using GSS to authenticate to a database is
>> common enough, it seemed reasonable to add GSS support to JDBC. Oracle
>> is not the only vendor to want to support GSS. I know SqlServer does
>> also. I can't say about other vendors.
>
> I accept that, but then, shouldn't we go all out and also add it to DriverManager (DriverManager.getConnection(String url, GSSCredential credential)) and to CommonDataSource (CommonDataSource.setGSSCredential(GSSCredential) or DataSource (DataSource.getConnection(GSSCredential))? Why only to ConnectionBuilder? Would repeatedly using it in a data source even work (or would that require a different approach)?
>
> If there is such a need, wouldn't ConnectionBuilder be the least relevant API to add it?
>
>> Mostly I am disappointed that Jigsaw has such a profound effect on API
>> design. Without Jigsaw this question would never have arisen.
>
> Yes, I agree. But I'm also surprised there isn't anything in the java.security package (part of java.base) that could serve as a parent-interface for GSSCredential or as an alternative way to get credentials.
>
> In any case, I don't mind adding this to JDBC, but we will need to carefully consider if the module dependency should be `requires` or `requires transitive`. I don't think using only `requires static` is a good idea.
>
> If we do want to minimize the module dependency to only when it is really necessary, then we'll need to look for a more convoluted solutions.
>
> Example of such a convoluted approach:
>
> public interface WithGSSCredential {
> void setGSSCredential(GSSCredential gssCredential);
> }
>
> Then if implementations want to use it, they would need to implement it as an extra interface, and users would need to explicitly unwrap to that interface to set it. As implementations that make this explicit choice will depend on the module anyway, the reflection or proxy headache will go away. Although workable, it wouldn't win a beauty contest.
>
> Or maybe
>
> public interface CredentialSource<T> {
> T getCredential();
> }
>
> and in ConnectionBuilder:
>
> ConnectionBuilder setCredentialSource(CredentialSource<?> credentialSource)
>
> and maybe add a simple wrapper around GSSCredential in JDBC, eg
>
> public GSSCredentialSource implements CredentialSource<GSSCredential> {
> private final GSSCredential credential;
>
> public GSSCredentialSource(GSSCredential credential) {
> this.credential = credential;
> }
>
> public GSSCredential getCredential() {
> return credential;
> }
> }
>
> Alternatively, in ConnectionBuilder, just use
>
> <T> ConnectionBuilder setCredential(T credential);
>
> This would allow more flexibility (other credential types could be used), but these last two solutions lead to an unclear API (or at least: unclear expectations).
>
> There are probably better solutions though, but right now, none come to mind.
>
> It all comes down to the question: do we care about extending the module dependencies of JDBC or not?
>
> Mark
More information about the jdbc-spec-discuss
mailing list