Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional realm connection string property for Kerberos authentication #1581

Merged
merged 5 commits into from Jun 4, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -505,6 +505,21 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
*/
String getAuthentication();

/**
* Sets the realm for Kerberos authentication.
VeryVerySpicy marked this conversation as resolved.
Show resolved Hide resolved
*
* @param realm
* A String that contains the realm
*/
void setRealm(String realm);

/**
* Returns the realm for Kerberos authentication.
VeryVerySpicy marked this conversation as resolved.
Show resolved Hide resolved
*
* @return A String that contains the realm
*/
String getRealm();

/**
* Sets the server spn.
*
Expand Down
Expand Up @@ -581,6 +581,22 @@ public String getServerName() {
return getStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_NAME.toString(), null);
}

/**
* Sets the realm for Kerberos authentication.
*
* @param realm
* realm
*/
@Override
public void setRealm(String realm) {
setStringProperty(connectionProps, SQLServerDriverStringProperty.REALM.toString(), realm);
}

@Override
public String getRealm() {
return getStringProperty(connectionProps, SQLServerDriverStringProperty.REALM.toString(), null);
}

/**
* Sets the Service Principal Name (SPN) of the target SQL Server.
* https://msdn.microsoft.com/en-us/library/cc280459.aspx
Expand Down
Expand Up @@ -349,6 +349,7 @@ enum SQLServerDriverStringProperty {
DOMAIN("domain", ""),
SERVER_NAME("serverName", ""),
SERVER_SPN("serverSpn", ""),
REALM("realm", ""),
SOCKET_FACTORY_CLASS("socketFactoryClass", ""),
SOCKET_FACTORY_CONSTRUCTOR_ARG("socketFactoryConstructorArg", ""),
TRUST_STORE_TYPE("trustStoreType", "JKS"),
Expand Down Expand Up @@ -569,6 +570,8 @@ public final class SQLServerDriver implements java.sql.Driver {
SQLServerDriverStringProperty.SERVER_NAME.getDefaultValue(), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SERVER_SPN.toString(),
SQLServerDriverStringProperty.SERVER_SPN.getDefaultValue(), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.REALM.toString(),
SQLServerDriverStringProperty.REALM.getDefaultValue(), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SOCKET_FACTORY_CLASS.toString(),
SQLServerDriverStringProperty.SOCKET_FACTORY_CLASS.getDefaultValue(), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SOCKET_FACTORY_CONSTRUCTOR_ARG.toString(),
Expand Down
Expand Up @@ -187,6 +187,7 @@ protected Object[][] getContents() {
{"R_domainPropertyDescription", "The Windows domain to authenticate in using NTLM."},
{"R_serverNamePropertyDescription", "The computer running SQL Server."},
{"R_portNumberPropertyDescription", "The TCP port where an instance of SQL Server is listening."},
{"R_realmPropertyDescription", "The realm for Kerberos authentication."},
{"R_serverSpnPropertyDescription", "SQL Server SPN."},
{"R_columnEncryptionSettingPropertyDescription", "The column encryption setting."},
{"R_enclaveAttestationUrlPropertyDescription", "The enclave attestation URL."},
Expand Down
32 changes: 18 additions & 14 deletions src/main/java/com/microsoft/sqlserver/jdbc/SSPIAuthentication.java
Expand Up @@ -124,31 +124,35 @@ private String findRealmFromHostname(RealmValidator realmValidator, String hostn
* flag to indicate of hostname canonicalization is allowed
* @return SPN enriched with realm
*/
String enrichSpnWithRealm(String spn, boolean allowHostnameCanonicalization) {
String enrichSpnWithRealm(SQLServerConnection con, String spn, boolean allowHostnameCanonicalization) {
if (spn == null) {
return spn;
}
Matcher m = SPN_PATTERN.matcher(spn);
if (!m.matches()) {
return spn;
}
if (m.group(3) != null) {
String realm = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.REALM.toString());
if (m.group(3) != null && (null == realm || realm.trim().isEmpty())) {
// Realm is already present, no need to enrich, the job has already been done
return spn;
}
String dnsName = m.group(1);
String portOrInstance = m.group(2);
RealmValidator realmValidator = getRealmValidator();
String realm = findRealmFromHostname(realmValidator, dnsName);
if (realm == null && allowHostnameCanonicalization) {
// We failed, try with canonical host name to find a better match
try {
String canonicalHostName = InetAddress.getByName(dnsName).getCanonicalHostName();
realm = findRealmFromHostname(realmValidator, canonicalHostName);
// match means hostname is correct (for instance if server name was an IP) so override dnsName as well
dnsName = canonicalHostName;
} catch (UnknownHostException e) {
// ignored, cannot canonicalize
// If realm is not specified in the connection, try to derive it.
if (null == realm || realm.trim().isEmpty()) {
RealmValidator realmValidator = getRealmValidator();
realm = findRealmFromHostname(realmValidator, dnsName);
if (realm == null && allowHostnameCanonicalization) {
VeryVerySpicy marked this conversation as resolved.
Show resolved Hide resolved
// We failed, try with canonical host name to find a better match
try {
String canonicalHostName = InetAddress.getByName(dnsName).getCanonicalHostName();
realm = findRealmFromHostname(realmValidator, canonicalHostName);
// match means hostname is correct (for instance if server name was an IP) so override dnsName as well
dnsName = canonicalHostName;
} catch (UnknownHostException e) {
// ignored, cannot canonicalize
VeryVerySpicy marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
if (realm == null) {
VeryVerySpicy marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -188,6 +192,6 @@ String getSpn(SQLServerConnection con) {
spn = makeSpn(con, con.currentConnectPlaceHolder.getServerName(),
con.currentConnectPlaceHolder.getPortNumber());
}
return enrichSpnWithRealm(spn, null == userSuppliedServerSpn);
return enrichSpnWithRealm(con, spn, null == userSuppliedServerSpn);
}
}
Expand Up @@ -189,6 +189,9 @@ public void testDataSource() {
ds.setServerName(stringPropValue);
assertEquals(stringPropValue, ds.getServerName(), TestResource.getResource("R_valuesAreDifferent"));

ds.setRealm(stringPropValue);
assertEquals(stringPropValue, ds.getRealm(), TestResource.getResource("R_valuesAreDifferent"));

ds.setServerSpn(stringPropValue);
assertEquals(stringPropValue, ds.getServerSpn(), TestResource.getResource("R_valuesAreDifferent"));

Expand Down