Skip to content

Commit 2c33841

Browse files
committed
use modular approach for AAD Password with ADAL4J
1 parent 1a80f96 commit 2c33841

File tree

3 files changed

+95
-74
lines changed

3 files changed

+95
-74
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.microsoft.sqlserver.jdbc;
2+
3+
import java.net.MalformedURLException;
4+
import java.text.MessageFormat;
5+
import java.util.concurrent.ExecutionException;
6+
import java.util.concurrent.ExecutorService;
7+
import java.util.concurrent.Executors;
8+
import java.util.concurrent.Future;
9+
10+
import com.microsoft.aad.adal4j.AuthenticationContext;
11+
import com.microsoft.aad.adal4j.AuthenticationException;
12+
import com.microsoft.aad.adal4j.AuthenticationResult;
13+
import com.microsoft.sqlserver.jdbc.SQLServerConnection.ActiveDirectoryAuthentication;
14+
import com.microsoft.sqlserver.jdbc.SQLServerConnection.SqlFedAuthInfo;
15+
16+
class SQLServerADAL4JUtils {
17+
18+
static SqlFedAuthToken getSqlFedAuthToken(SqlFedAuthInfo fedAuthInfo,
19+
String user,
20+
String password,
21+
String authenticationString) throws SQLServerException {
22+
ExecutorService executorService = Executors.newFixedThreadPool(1);
23+
try {
24+
AuthenticationContext context = new AuthenticationContext(fedAuthInfo.stsurl, false, executorService);
25+
Future<AuthenticationResult> future = context.acquireToken(fedAuthInfo.spn, ActiveDirectoryAuthentication.jdbcFedauthClientId, user,
26+
password, null);
27+
28+
AuthenticationResult authenticationResult = future.get();
29+
SqlFedAuthToken fedAuthToken = new SqlFedAuthToken(authenticationResult.getAccessToken(), authenticationResult.getExpiresOnDate());
30+
31+
return fedAuthToken;
32+
}
33+
catch (MalformedURLException | InterruptedException e) {
34+
throw new SQLServerException(e.getMessage(), null);
35+
}
36+
catch (ExecutionException e) {
37+
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ADALExecution"));
38+
Object[] msgArgs = {user, authenticationString};
39+
40+
// the cause error message uses \\n\\r which does not give correct format
41+
// change it to \r\n to provide correct format
42+
String correctedErrorMessage = e.getCause().getMessage().replaceAll("\\\\r\\\\n", "\r\n");
43+
AuthenticationException correctedAuthenticationException = new AuthenticationException(correctedErrorMessage);
44+
45+
// SQLServerException is caused by ExecutionException, which is caused by AuthenticationException
46+
// to match the exception tree before error message correction
47+
ExecutionException correctedExecutionException = new ExecutionException(correctedAuthenticationException);
48+
49+
throw new SQLServerException(form.format(msgArgs), null, 0, correctedExecutionException);
50+
}
51+
finally {
52+
executorService.shutdown();
53+
}
54+
}
55+
}

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

+13-74
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import java.net.DatagramSocket;
1717
import java.net.IDN;
1818
import java.net.InetAddress;
19-
import java.net.MalformedURLException;
2019
import java.net.SocketException;
2120
import java.net.UnknownHostException;
2221
import java.sql.Blob;
@@ -38,30 +37,21 @@
3837
import java.sql.Struct;
3938
import java.text.MessageFormat;
4039
import java.util.Arrays;
41-
import java.util.Date;
4240
import java.util.Enumeration;
4341
import java.util.HashMap;
4442
import java.util.List;
4543
import java.util.Locale;
4644
import java.util.Map;
4745
import java.util.Properties;
4846
import java.util.UUID;
49-
import java.util.concurrent.ExecutionException;
5047
import java.util.concurrent.Executor;
51-
import java.util.concurrent.ExecutorService;
52-
import java.util.concurrent.Executors;
53-
import java.util.concurrent.Future;
5448
import java.util.concurrent.TimeUnit;
5549
import java.util.concurrent.atomic.AtomicInteger;
5650
import java.util.logging.Level;
5751

5852
import javax.sql.XAConnection;
5953
import javax.xml.bind.DatatypeConverter;
6054

61-
import com.microsoft.aad.adal4j.AuthenticationContext;
62-
import com.microsoft.aad.adal4j.AuthenticationException;
63-
import com.microsoft.aad.adal4j.AuthenticationResult;
64-
6555
/**
6656
* SQLServerConnection implements a JDBC connection to SQL Server. SQLServerConnections support JDBC connection pooling and may be either physical
6757
* JDBC connections or logical JDBC connections.
@@ -146,46 +136,24 @@ class FederatedAuthenticationFeatureExtensionData {
146136
}
147137

148138
class SqlFedAuthInfo {
149-
private String spn;
150-
private String stsurl;
139+
String spn;
140+
String stsurl;
151141

152142
@Override
153143
public String toString() {
154144
return "STSURL: " + stsurl + ", SPN: " + spn;
155145
}
156146
}
157147

158-
final class SqlFedAuthToken {
159-
private final Date expiresOn;
160-
private final String accessToken;
161-
162-
SqlFedAuthToken(final String accessToken,
163-
final long expiresIn) {
164-
this.accessToken = accessToken;
165-
166-
Date now = new Date();
167-
now.setTime(now.getTime() + (expiresIn * 1000));
168-
this.expiresOn = now;
169-
}
170-
171-
SqlFedAuthToken(final String accessToken,
172-
final Date expiresOn) {
173-
this.accessToken = accessToken;
174-
this.expiresOn = expiresOn;
175-
}
176-
177-
Date getExpiresOnDate() {
178-
return expiresOn;
179-
}
180-
}
148+
181149

182-
private class ActiveDirectoryAuthentication {
183-
private static final String jdbcFedauthClientId = "7f98cb04-cd1e-40df-9140-3bf7e2cea4db";
184-
private static final String AdalGetAccessTokenFunctionName = "ADALGetAccessToken";
185-
private static final int GetAccessTokenSuccess = 0;
186-
private static final int GetAccessTokenInvalidGrant = 1;
187-
private static final int GetAccessTokenTansisentError = 2;
188-
private static final int GetAccessTokenOtherError = 3;
150+
class ActiveDirectoryAuthentication {
151+
static final String jdbcFedauthClientId = "7f98cb04-cd1e-40df-9140-3bf7e2cea4db";
152+
static final String AdalGetAccessTokenFunctionName = "ADALGetAccessToken";
153+
static final int GetAccessTokenSuccess = 0;
154+
static final int GetAccessTokenInvalidGrant = 1;
155+
static final int GetAccessTokenTansisentError = 2;
156+
static final int GetAccessTokenOtherError = 3;
189157
}
190158

191159
/**
@@ -3474,39 +3442,10 @@ private SqlFedAuthToken getFedAuthToken(SqlFedAuthInfo fedAuthInfo) throws SQLSe
34743442
numberOfAttempts++;
34753443

34763444
if (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDirectoryPassword.toString())) {
3477-
ExecutorService executorService = Executors.newFixedThreadPool(1);
3478-
try {
3479-
AuthenticationContext context = new AuthenticationContext(fedAuthInfo.stsurl, false, executorService);
3480-
Future<AuthenticationResult> future = context.acquireToken(fedAuthInfo.spn, ActiveDirectoryAuthentication.jdbcFedauthClientId,
3481-
user, password, null);
3482-
3483-
AuthenticationResult authenticationResult = future.get();
3484-
fedAuthToken = new SqlFedAuthToken(authenticationResult.getAccessToken(), authenticationResult.getExpiresOnDate());
3445+
fedAuthToken = SQLServerADAL4JUtils.getSqlFedAuthToken(fedAuthInfo, user, password, authenticationString);
34853446

3486-
// Break out of the retry loop in successful case.
3487-
break;
3488-
}
3489-
catch (MalformedURLException | InterruptedException e) {
3490-
throw new SQLServerException(e.getMessage(), null);
3491-
}
3492-
catch (ExecutionException e) {
3493-
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ADALExecution"));
3494-
Object[] msgArgs = {user, authenticationString};
3495-
3496-
// the cause error message uses \\n\\r which does not give correct format
3497-
// change it to \r\n to provide correct format
3498-
String correctedErrorMessage = e.getCause().getMessage().replaceAll("\\\\r\\\\n", "\r\n");
3499-
AuthenticationException correctedAuthenticationException = new AuthenticationException(correctedErrorMessage);
3500-
3501-
// SQLServerException is caused by ExecutionException, which is caused by AuthenticationException
3502-
// to match the exception tree before error message correction
3503-
ExecutionException correctedExecutionException = new ExecutionException(correctedAuthenticationException);
3504-
3505-
throw new SQLServerException(form.format(msgArgs), null, 0, correctedExecutionException);
3506-
}
3507-
finally {
3508-
executorService.shutdown();
3509-
}
3447+
// Break out of the retry loop in successful case.
3448+
break;
35103449
}
35113450
else if (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString())) {
35123451
try {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.microsoft.sqlserver.jdbc;
2+
3+
import java.util.Date;
4+
5+
class SqlFedAuthToken {
6+
final Date expiresOn;
7+
final String accessToken;
8+
9+
SqlFedAuthToken(final String accessToken,
10+
final long expiresIn) {
11+
this.accessToken = accessToken;
12+
13+
Date now = new Date();
14+
now.setTime(now.getTime() + (expiresIn * 1000));
15+
this.expiresOn = now;
16+
}
17+
18+
SqlFedAuthToken(final String accessToken,
19+
final Date expiresOn) {
20+
this.accessToken = accessToken;
21+
this.expiresOn = expiresOn;
22+
}
23+
24+
Date getExpiresOnDate() {
25+
return expiresOn;
26+
}
27+
}

0 commit comments

Comments
 (0)