Skip to content

Commit 49cc04e

Browse files
committed
Managed Identity dev experience improvements #1936
Signed-off-by: Jeff Wasty <[email protected]>
1 parent d7b11dd commit 49cc04e

16 files changed

+404
-323
lines changed

src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,9 @@ final class TDS {
198198
static final int TDS_FEDAUTH_LIBRARY_RESERVED = 0x7F;
199199
static final byte ADALWORKFLOW_ACTIVEDIRECTORYPASSWORD = 0x01;
200200
static final byte ADALWORKFLOW_ACTIVEDIRECTORYINTEGRATED = 0x02;
201-
static final byte ADALWORKFLOW_ACTIVEDIRECTORYMSI = 0x03;
201+
static final byte ADALWORKFLOW_ACTIVEDIRECTORYMANAGEDIDENTITY = 0x03;
202202
static final byte ADALWORKFLOW_ACTIVEDIRECTORYINTERACTIVE = 0x03;
203+
static final byte ADALWORKFLOW_DEFAULTAZURECREDENTIAL = 0x03;
203204
static final byte ADALWORKFLOW_ACTIVEDIRECTORYSERVICEPRINCIPAL = 0x01; // Using the Password byte as that is the
204205
// closest we have.
205206
static final byte FEDAUTH_INFO_ID_STSURL = 0x01; // FedAuthInfoData is token endpoint URL from which to acquire fed

src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -391,35 +391,34 @@ CallableStatement prepareCall(String sql, int nType, int nConcur, int nHold,
391391
* boolean value for 'delayLoadingLobs'.
392392
*/
393393
void setDelayLoadingLobs(boolean delayLoadingLobs);
394-
394+
395395
/**
396396
* Sets the name of the preferred type of IP Address.
397397
*
398398
* @param iPAddressPreference
399399
* A String that contains the preferred type of IP Address.
400400
*/
401401
void setIPAddressPreference(String iPAddressPreference);
402-
402+
403403
/**
404404
* Gets the name of the preferred type of IP Address.
405405
*
406406
* @return IPAddressPreference
407-
* A String that contains the preferred type of IP Address.
407+
* A String that contains the preferred type of IP Address.
408408
*/
409409
String getIPAddressPreference();
410410

411411
/**
412-
* Gets the time-to-live for the the cached MSI token
413-
*
414-
* @return time-to-live for the cached MSI token
412+
* Deprecated. Time-to-live is no longer supported for the cached Managed Identity tokens.
413+
* This method will always return 0 and is for backwards compatibility only.
415414
*/
415+
@Deprecated
416416
int getMsiTokenCacheTtl();
417417

418418
/**
419-
* Sets time-to-live for the the cached MSI token
420-
*
421-
* @param timeToLive
422-
* Changes the setting as per description
419+
* Deprecated. Time-to-live is no longer supported for the cached Managed Identity tokens.
420+
* This method is a no-op for backwards compatibility only.
423421
*/
422+
@Deprecated
424423
void setMsiTokenCacheTtl(int timeToLive);
425424
}

src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -932,18 +932,24 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
932932
void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert);
933933

934934
/**
935-
* Sets the client id to be used to retrieve access token from MSI EndPoint.
935+
* This method is deprecated. Use {@link ISQLServerDataSource#setUser(String user)} instead.
936+
*
937+
* Sets the client id to be used to retrieve the access token for a user-assigned Managed Identity.
936938
*
937-
* @param msiClientId
938-
* Client ID of User Assigned Managed Identity
939+
* @param managedIdentityClientId
940+
* Client ID of the user-assigned Managed Identity.
939941
*/
940-
void setMSIClientId(String msiClientId);
942+
@Deprecated
943+
void setMSIClientId(String managedIdentityClientId);
941944

942945
/**
946+
* This method is deprecated. Use {@link ISQLServerDataSource#getUser()} instead.
947+
*
943948
* Returns the value for the connection property 'msiClientId'.
944949
*
945950
* @return msiClientId property value
946951
*/
952+
@Deprecated
947953
String getMSIClientId();
948954

949955
/**
@@ -1129,7 +1135,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
11291135
/**
11301136
* Sets the 'AADSecurePrincipalId' connection property used for Active Directory Service Principal authentication.
11311137
*
1132-
* @deprecated Use {@link ISQLServerDataSource#setUser(String password)} instead
1138+
* @deprecated Use {@link ISQLServerDataSource#setUser(String user)} instead
11331139
* @param AADSecurePrincipalId
11341140
* Active Directory Service Principal Id.
11351141
*/
@@ -1208,17 +1214,16 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
12081214
String getPrepareMethod();
12091215

12101216
/**
1211-
* Sets time-to-live for the the cached MSI token
1212-
*
1213-
* @param timeToLive
1214-
* Changes the setting as per description
1217+
* Deprecated. Time-to-live is no longer supported for the cached Managed Identity tokens.
1218+
* This method is a no-op for backwards compatibility only.
12151219
*/
1220+
@Deprecated
12161221
void setMsiTokenCacheTtl(int timeToLive);
12171222

12181223
/**
1219-
* Gets the time-to-live for the the cached MSI token
1220-
*
1221-
* @return time-to-live for the cached MSI token
1224+
* Deprecated. Time-to-live is no longer supported for the cached Managed Identity tokens.
1225+
* This method will always return 0 and is for backwards compatibility only.
12221226
*/
1227+
@Deprecated
12231228
int getMsiTokenCacheTtl();
12241229
}

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ public SQLServerColumnEncryptionAzureKeyVaultProvider(TokenCredential tokenCrede
274274
* @throws SQLServerException
275275
* when an error occurs
276276
*/
277+
@Deprecated
277278
public SQLServerColumnEncryptionAzureKeyVaultProvider(
278279
SQLServerKeyVaultAuthenticationCallback authenticationCallback) throws SQLServerException {
279280
if (null == authenticationCallback) {

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,6 @@ public class SQLServerConnection implements ISQLServerConnection, java.io.Serial
221221
/** encrypted truststore password */
222222
byte[] encryptedTrustStorePassword = null;
223223

224-
/** cached MSI token time-to-live */
225-
private int cachedMsiTokenTtl = 0;
226-
227224
/**
228225
* Return an existing cached SharedTimer associated with this Connection or create a new one.
229226
*
@@ -515,8 +512,11 @@ class FederatedAuthenticationFeatureExtensionData implements Serializable {
515512
case "ACTIVEDIRECTORYINTEGRATED":
516513
this.authentication = SqlAuthentication.ActiveDirectoryIntegrated;
517514
break;
518-
case "ACTIVEDIRECTORYMSI":
519-
this.authentication = SqlAuthentication.ActiveDirectoryMSI;
515+
case "ACTIVEDIRECTORYMANAGEDIDENTITY":
516+
this.authentication = SqlAuthentication.ActiveDirectoryManagedIdentity;
517+
break;
518+
case "DEFAULTAZURECREDENTIAL":
519+
this.authentication = SqlAuthentication.DefaultAzureCredential;
520520
break;
521521
case "ACTIVEDIRECTORYSERVICEPRINCIPAL":
522522
this.authentication = SqlAuthentication.ActiveDirectoryServicePrincipal;
@@ -2324,6 +2324,14 @@ Connection connectInternal(Properties propsIn,
23242324
}
23252325
authenticationString = SqlAuthentication.valueOfString(sPropValue).toString().trim();
23262326

2327+
if (authenticationString.equalsIgnoreCase(SqlAuthentication.DefaultAzureCredential.toString())
2328+
&& (!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString())
2329+
.isEmpty())) {
2330+
MessageFormat form = new MessageFormat(
2331+
SQLServerException.getErrString("R_MSIAuthenticationWithPassword"));
2332+
throw new SQLServerException(form.format(new Object[] {authenticationString}), null);
2333+
}
2334+
23272335
if (integratedSecurity
23282336
&& !authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) {
23292337
throw new SQLServerException(
@@ -2348,13 +2356,12 @@ Connection connectInternal(Properties propsIn,
23482356
null);
23492357
}
23502358

2351-
if (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryMSI.toString())
2352-
&& ((!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString())
2353-
.isEmpty())
2354-
|| (!activeConnectionProperties
2355-
.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()).isEmpty()))) {
2356-
throw new SQLServerException(SQLServerException.getErrString("R_MSIAuthenticationWithUserPassword"),
2357-
null);
2359+
if (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryManagedIdentity.toString())
2360+
&& (!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString())
2361+
.isEmpty())) {
2362+
MessageFormat form = new MessageFormat(
2363+
SQLServerException.getErrString("R_MSIAuthenticationWithPassword"));
2364+
throw new SQLServerException(form.format(new Object[] {authenticationString}), null);
23582365
}
23592366

23602367
if (authenticationString
@@ -2641,26 +2648,6 @@ else if (0 == requestedPacketSize)
26412648
activeConnectionProperties.setProperty(sPropKey, sPropValue);
26422649
}
26432650

2644-
cachedMsiTokenTtl = SQLServerDriverIntProperty.MSI_TOKEN_CACHE_TTL.getDefaultValue();
2645-
sPropValue = activeConnectionProperties
2646-
.getProperty(SQLServerDriverIntProperty.MSI_TOKEN_CACHE_TTL.toString());
2647-
if (null != sPropValue && sPropValue.length() > 0) {
2648-
try {
2649-
cachedMsiTokenTtl = Integer.parseInt(sPropValue);
2650-
} catch (NumberFormatException e) {
2651-
MessageFormat form = new MessageFormat(
2652-
SQLServerException.getErrString("R_invalidMsiTokenCacheTtl"));
2653-
Object[] msgArgs = {sPropValue};
2654-
SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false);
2655-
}
2656-
if (cachedMsiTokenTtl < 0) {
2657-
MessageFormat form = new MessageFormat(
2658-
SQLServerException.getErrString("R_invalidMsiTokenCacheTtl"));
2659-
Object[] msgArgs = {sPropValue};
2660-
SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false);
2661-
}
2662-
}
2663-
26642651
sPropKey = SQLServerDriverStringProperty.CLIENT_CERTIFICATE.toString();
26652652
sPropValue = activeConnectionProperties.getProperty(sPropKey);
26662653
if (null != sPropValue) {
@@ -4669,8 +4656,11 @@ int writeFedAuthFeatureRequest(boolean write, /* if false just calculates the le
46694656
case ActiveDirectoryIntegrated:
46704657
workflow = TDS.ADALWORKFLOW_ACTIVEDIRECTORYINTEGRATED;
46714658
break;
4672-
case ActiveDirectoryMSI:
4673-
workflow = TDS.ADALWORKFLOW_ACTIVEDIRECTORYMSI;
4659+
case ActiveDirectoryManagedIdentity:
4660+
workflow = TDS.ADALWORKFLOW_ACTIVEDIRECTORYMANAGEDIDENTITY;
4661+
break;
4662+
case DefaultAzureCredential:
4663+
workflow = TDS.ADALWORKFLOW_DEFAULTAZURECREDENTIAL;
46744664
break;
46754665
case ActiveDirectoryInteractive:
46764666
workflow = TDS.ADALWORKFLOW_ACTIVEDIRECTORYINTERACTIVE;
@@ -4887,7 +4877,9 @@ private void logon(LogonCommand command) throws SQLServerException {
48874877
*/
48884878
if (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryPassword.toString())
48894879
|| ((authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString())
4890-
|| authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryMSI.toString())
4880+
|| authenticationString
4881+
.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryManagedIdentity.toString())
4882+
|| authenticationString.equalsIgnoreCase(SqlAuthentication.DefaultAzureCredential.toString())
48914883
|| authenticationString
48924884
.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryServicePrincipal.toString())
48934885
|| authenticationString
@@ -5408,7 +5400,8 @@ void onFedAuthInfo(SqlFedAuthInfo fedAuthInfo, TDSTokenHandler tdsTokenHandler)
54085400
assert (null != activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString())
54095401
&& null != activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()))
54105402
|| (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString())
5411-
|| authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryMSI.toString())
5403+
|| authenticationString
5404+
.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryManagedIdentity.toString())
54125405
|| authenticationString
54135406
.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryInteractive.toString())
54145407
&& fedAuthRequiredPreLoginResponse);
@@ -5437,31 +5430,39 @@ private SqlFedAuthToken getFedAuthToken(SqlFedAuthInfo fedAuthInfo) throws SQLSe
54375430
// No:of milliseconds to sleep for the initial back off.
54385431
int sleepInterval = 100;
54395432

5433+
if (!msalContextExists()
5434+
&& !authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryInteractive.toString())) {
5435+
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_MSALMissing"));
5436+
throw new SQLServerException(form.format(new Object[] {authenticationString}), null, 0, null);
5437+
}
5438+
54405439
while (true) {
54415440
if (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryPassword.toString())) {
5442-
if (!msalContextExists()) {
5443-
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_MSALMissing"));
5444-
throw new SQLServerException(form.format(new Object[] {authenticationString}), null, 0, null);
5445-
}
54465441
fedAuthToken = SQLServerMSAL4JUtils.getSqlFedAuthToken(fedAuthInfo, user,
54475442
activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()),
54485443
authenticationString);
54495444

54505445
// Break out of the retry loop in successful case.
54515446
break;
5452-
} else if (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryMSI.toString())) {
5453-
fedAuthToken = SQLServerSecurityUtility.getMSIAuthToken(fedAuthInfo.spn,
5454-
activeConnectionProperties.getProperty(SQLServerDriverStringProperty.MSI_CLIENT_ID.toString()),
5455-
cachedMsiTokenTtl);
5447+
} else if (authenticationString
5448+
.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryManagedIdentity.toString())) {
5449+
5450+
String managedIdentityClientId = activeConnectionProperties
5451+
.getProperty(SQLServerDriverStringProperty.USER.toString());
5452+
5453+
if (null != managedIdentityClientId && !managedIdentityClientId.isEmpty()) {
5454+
fedAuthToken = SQLServerSecurityUtility.getManagedIdentityCredAuthToken(fedAuthInfo.spn,
5455+
managedIdentityClientId);
5456+
break;
5457+
}
5458+
5459+
fedAuthToken = SQLServerSecurityUtility.getManagedIdentityCredAuthToken(fedAuthInfo.spn,
5460+
activeConnectionProperties.getProperty(SQLServerDriverStringProperty.MSI_CLIENT_ID.toString()));
54565461

54575462
// Break out of the retry loop in successful case.
54585463
break;
54595464
} else if (authenticationString
54605465
.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryServicePrincipal.toString())) {
5461-
if (!msalContextExists()) {
5462-
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_MSALMissing"));
5463-
throw new SQLServerException(form.format(new Object[] {authenticationString}), null, 0, null);
5464-
}
54655466

54665467
// aadPrincipalID and aadPrincipalSecret is deprecated replaced by username and password
54675468
if (aadPrincipalID != null && !aadPrincipalID.isEmpty() && aadPrincipalSecret != null
@@ -5561,16 +5562,26 @@ private SqlFedAuthToken getFedAuthToken(SqlFedAuthInfo fedAuthInfo) throws SQLSe
55615562
// Break out of the retry loop in successful case.
55625563
break;
55635564
} else if (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryInteractive.toString())) {
5564-
if (!msalContextExists()) {
5565-
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_MSALMissing"));
5566-
throw new SQLServerException(form.format(new Object[] {authenticationString}), null, 0, null);
5567-
}
55685565
// interactive flow
55695566
fedAuthToken = SQLServerMSAL4JUtils.getSqlFedAuthTokenInteractive(fedAuthInfo, user,
55705567
authenticationString);
55715568

55725569
// Break out of the retry loop in successful case.
55735570
break;
5571+
} else if (authenticationString.equalsIgnoreCase(SqlAuthentication.DefaultAzureCredential.toString())) {
5572+
String managedIdentityClientId = activeConnectionProperties
5573+
.getProperty(SQLServerDriverStringProperty.USER.toString());
5574+
5575+
if (null != managedIdentityClientId && !managedIdentityClientId.isEmpty()) {
5576+
fedAuthToken = SQLServerSecurityUtility.getDefaultAzureCredAuthToken(fedAuthInfo.spn,
5577+
managedIdentityClientId);
5578+
break;
5579+
}
5580+
5581+
fedAuthToken = SQLServerSecurityUtility.getDefaultAzureCredAuthToken(fedAuthInfo.spn,
5582+
activeConnectionProperties.getProperty(SQLServerDriverStringProperty.MSI_CLIENT_ID.toString()));
5583+
5584+
break;
55745585
}
55755586
}
55765587

@@ -7491,15 +7502,23 @@ public void setStatementPoolingCacheSize(int value) {
74917502
parameterMetadataCache.setCapacity(value);
74927503
}
74937504

7505+
/**
7506+
* Deprecated. Time-to-live is no longer supported for the cached Managed Identity tokens.
7507+
* This method will always return 0 and is for backwards compatibility only.
7508+
*/
7509+
@Deprecated
74947510
@Override
74957511
public int getMsiTokenCacheTtl() {
7496-
return cachedMsiTokenTtl;
7512+
return 0;
74977513
}
74987514

7515+
/**
7516+
* Deprecated. Time-to-live is no longer supported for the cached Managed Identity tokens.
7517+
* This method is a no-op for backwards compatibility only.
7518+
*/
7519+
@Deprecated
74997520
@Override
7500-
public void setMsiTokenCacheTtl(int timeToLive) {
7501-
this.cachedMsiTokenTtl = timeToLive;
7502-
}
7521+
public void setMsiTokenCacheTtl(int timeToLive) {}
75037522

75047523
/**
75057524
* Prepares the cache handle.

0 commit comments

Comments
 (0)