Skip to content

Commit 8a79bc8

Browse files
authored
support of STS throttling instructions + caching of InteractionRequiredException… (#201)
support of server side throttling instructions + caching of InteractionRequiredException responses
1 parent 5b86ce3 commit 8a79bc8

File tree

54 files changed

+951
-143
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+951
-143
lines changed

src/integrationtest/java/com.microsoft.aad.msal4j/ApacheHttpClientAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private IHttpResponse buildMsalResponseFromApacheResponse(CloseableHttpResponse
8484
for(Header header: apacheResponse.getAllHeaders()){
8585
headers.put(header.getName(), Collections.singletonList(header.getValue()));
8686
}
87-
((HttpResponse) httpResponse).headers(headers);
87+
((HttpResponse) httpResponse).addHeaders(headers);
8888

8989
String responseBody = EntityUtils.toString(apacheResponse.getEntity(), "UTF-8");
9090
((HttpResponse) httpResponse).body(responseBody);

src/integrationtest/java/com.microsoft.aad.msal4j/AuthorizationCodeIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ private IAuthenticationResult acquireTokenInteractiveB2C(ConfidentialClientAppli
218218

219219
private String acquireAuthorizationCodeAutomated(
220220
User user,
221-
ClientApplicationBase app){
221+
AbstractClientApplicationBase app){
222222

223223
BlockingQueue<AuthorizationResult> authorizationCodeQueue = new LinkedBlockingQueue<>();
224224

@@ -256,7 +256,7 @@ private String acquireAuthorizationCodeAutomated(
256256
}
257257
return result.code();
258258
}
259-
private String buildAuthenticationCodeURL(ClientApplicationBase app) {
259+
private String buildAuthenticationCodeURL(AbstractClientApplicationBase app) {
260260
String scope;
261261

262262
AuthorityType authorityType= app.authenticationAuthority.authorityType;

src/integrationtest/java/com.microsoft.aad.msal4j/OkHttpClientAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ private IHttpResponse buildMsalResponseFromOkResponse(Response okHttpResponse) t
7676

7777
Headers headers = okHttpResponse.headers();
7878
if(headers != null){
79-
((HttpResponse) httpResponse).headers(headers.toMultimap());
79+
((HttpResponse) httpResponse).addHeaders(headers.toMultimap());
8080
}
8181
return httpResponse;
8282
}

src/integrationtest/java/com.microsoft.aad.msal4j/SeleniumTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public void startUpBrowser(){
3636
seleniumDriver = SeleniumExtensions.createDefaultWebDriver();
3737
}
3838

39-
void runSeleniumAutomatedLogin(User user, ClientApplicationBase app) {
39+
void runSeleniumAutomatedLogin(User user, AbstractClientApplicationBase app) {
4040
AuthorityType authorityType = app.authenticationAuthority.authorityType;
4141
if(authorityType == AuthorityType.B2C){
4242
switch(user.getB2cProvider().toLowerCase()){

src/main/java/com/microsoft/aad/msal4j/ClientApplicationBase.java renamed to src/main/java/com/microsoft/aad/msal4j/AbstractClientApplicationBase.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* Abstract class containing common methods and properties to both {@link PublicClientApplication}
2929
* and {@link ConfidentialClientApplication}.
3030
*/
31-
abstract class ClientApplicationBase implements IClientApplicationBase {
31+
abstract class AbstractClientApplicationBase implements IClientApplicationBase {
3232

3333
protected Logger log;
3434
protected Authority authenticationAuthority;
@@ -92,7 +92,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(AuthorizationCodePa
9292
AuthorizationCodeRequest authorizationCodeRequest = new AuthorizationCodeRequest(
9393
parameters,
9494
this,
95-
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE));
95+
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE, parameters));
9696

9797
return this.executeRequest(authorizationCodeRequest);
9898
}
@@ -105,7 +105,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(RefreshTokenParamet
105105
RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(
106106
parameters,
107107
this,
108-
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_REFRESH_TOKEN));
108+
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_REFRESH_TOKEN, parameters));
109109

110110
return executeRequest(refreshTokenRequest);
111111
}
@@ -132,7 +132,7 @@ public CompletableFuture<IAuthenticationResult> acquireTokenSilently(SilentParam
132132
SilentRequest silentRequest = new SilentRequest(
133133
parameters,
134134
this,
135-
createRequestContext(PublicApi.ACQUIRE_TOKEN_SILENTLY));
135+
createRequestContext(PublicApi.ACQUIRE_TOKEN_SILENTLY, parameters));
136136

137137
return executeRequest(silentRequest);
138138
}
@@ -141,7 +141,7 @@ public CompletableFuture<IAuthenticationResult> acquireTokenSilently(SilentParam
141141
public CompletableFuture<Set<IAccount>> getAccounts() {
142142
MsalRequest msalRequest =
143143
new MsalRequest(this, null,
144-
createRequestContext(PublicApi.GET_ACCOUNTS)){};
144+
createRequestContext(PublicApi.GET_ACCOUNTS, null)){};
145145

146146
AccountsSupplier supplier = new AccountsSupplier(this, msalRequest);
147147

@@ -154,7 +154,7 @@ public CompletableFuture<Set<IAccount>> getAccounts() {
154154
@Override
155155
public CompletableFuture removeAccount(IAccount account) {
156156
MsalRequest msalRequest = new MsalRequest(this, null,
157-
createRequestContext(PublicApi.REMOVE_ACCOUNTS)){};
157+
createRequestContext(PublicApi.REMOVE_ACCOUNTS, null)){};
158158

159159
RemoveAccountRunnable runnable = new RemoveAccountRunnable(msalRequest, account);
160160

@@ -231,8 +231,8 @@ private AuthenticationResultSupplier getAuthenticationResultSupplier(MsalRequest
231231
return supplier;
232232
}
233233

234-
RequestContext createRequestContext(PublicApi publicApi) {
235-
return new RequestContext(this, publicApi);
234+
RequestContext createRequestContext(PublicApi publicApi, IApiParameters apiParameters) {
235+
return new RequestContext(this, publicApi, apiParameters);
236236
}
237237

238238
ServiceBundle getServiceBundle() {
@@ -285,7 +285,7 @@ public Builder(String clientId) {
285285
/**
286286
* Set URL of the authenticating authority or security token service (STS) from which MSAL
287287
* will acquire security tokens.
288-
* The default value is {@link ClientApplicationBase#DEFAULT_AUTHORITY}
288+
* The default value is {@link AbstractClientApplicationBase#DEFAULT_AUTHORITY}
289289
*
290290
* @param val a string value of authority
291291
* @return instance of the Builder on which method was called
@@ -330,7 +330,7 @@ public T b2cAuthority(String val) throws MalformedURLException{
330330
* Set a boolean value telling the application if the authority needs to be verified
331331
* against a list of known authorities. Authority is only validated when:
332332
* 1 - It is an Azure Active Directory authority (not B2C or ADFS)
333-
* 2 - Instance discovery metadata is not set via {@link ClientApplicationBase#aadAadInstanceDiscoveryResponse}
333+
* 2 - Instance discovery metadata is not set via {@link AbstractClientApplicationBase#aadAadInstanceDiscoveryResponse}
334334
*
335335
* The default value is true.
336336
*
@@ -486,7 +486,7 @@ public T setTokenCacheAccessAspect(ITokenCacheAccessAspect val) {
486486
* Sets instance discovery response data which will be used for determining tenant discovery
487487
* endpoint and authority aliases.
488488
*
489-
* Note that authority validation is not done even if {@link ClientApplicationBase#validateAuthority}
489+
* Note that authority validation is not done even if {@link AbstractClientApplicationBase#validateAuthority}
490490
* is set to true.
491491
*
492492
* For more information, see
@@ -513,10 +513,10 @@ private static Authority createDefaultAADAuthority() {
513513
return authority;
514514
}
515515

516-
abstract ClientApplicationBase build();
516+
abstract AbstractClientApplicationBase build();
517517
}
518518

519-
ClientApplicationBase(Builder<?> builder) {
519+
AbstractClientApplicationBase(Builder<?> builder) {
520520
clientId = builder.clientId;
521521
authority = builder.authority;
522522
validateAuthority = builder.validateAuthority;

src/main/java/com/microsoft/aad/msal4j/AccountsSupplier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111
class AccountsSupplier implements Supplier<Set<IAccount>> {
1212

13-
ClientApplicationBase clientApplication;
13+
AbstractClientApplicationBase clientApplication;
1414
MsalRequest msalRequest;
1515

16-
AccountsSupplier(ClientApplicationBase clientApplication, MsalRequest msalRequest) {
16+
AccountsSupplier(AbstractClientApplicationBase clientApplication, MsalRequest msalRequest) {
1717

1818
this.clientApplication = clientApplication;
1919
this.msalRequest = msalRequest;

src/main/java/com/microsoft/aad/msal4j/AcquireTokenByAuthorizationGrantSupplier.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class AcquireTokenByAuthorizationGrantSupplier extends AuthenticationResultSuppl
1818
private Authority requestAuthority;
1919
private MsalRequest msalRequest;
2020

21-
AcquireTokenByAuthorizationGrantSupplier(ClientApplicationBase clientApplication,
21+
AcquireTokenByAuthorizationGrantSupplier(AbstractClientApplicationBase clientApplication,
2222
MsalRequest msalRequest,
2323
Authority authority) {
2424
super(clientApplication, msalRequest);
@@ -28,6 +28,16 @@ class AcquireTokenByAuthorizationGrantSupplier extends AuthenticationResultSuppl
2828

2929
AuthenticationResult execute() throws Exception {
3030
AbstractMsalAuthorizationGrant authGrant = msalRequest.msalAuthorizationGrant();
31+
32+
if (IsUiRequiredCacheSupported()) {
33+
MsalInteractionRequiredException cachedEx =
34+
InteractionRequiredCache.getCachedInteractionRequiredException(
35+
((RefreshTokenRequest) msalRequest).getFullThumbprint());
36+
if (cachedEx != null) {
37+
throw cachedEx;
38+
}
39+
}
40+
3141
if (authGrant instanceof OAuthAuthorizationGrant) {
3242
msalRequest.msalAuthorizationGrant =
3343
processPasswordGrant((OAuthAuthorizationGrant) authGrant);
@@ -41,15 +51,27 @@ AuthenticationResult execute() throws Exception {
4151
integratedAuthGrant.getUserName()), integratedAuthGrant.getScopes());
4252
}
4353

44-
if(requestAuthority == null){
54+
if (requestAuthority == null) {
4555
requestAuthority = clientApplication.authenticationAuthority;
4656
}
4757

48-
if(requestAuthority.authorityType == AuthorityType.AAD){
58+
if (requestAuthority.authorityType == AuthorityType.AAD) {
4959
requestAuthority = getAuthorityWithPrefNetworkHost(requestAuthority.authority());
5060
}
5161

52-
return clientApplication.acquireTokenCommon(msalRequest, requestAuthority);
62+
try {
63+
return clientApplication.acquireTokenCommon(msalRequest, requestAuthority);
64+
} catch (MsalInteractionRequiredException ex) {
65+
if (IsUiRequiredCacheSupported()) {
66+
InteractionRequiredCache.set(((RefreshTokenRequest) msalRequest).getFullThumbprint(), ex);
67+
}
68+
throw ex;
69+
}
70+
}
71+
72+
private boolean IsUiRequiredCacheSupported() {
73+
return msalRequest instanceof RefreshTokenRequest &&
74+
clientApplication instanceof PublicClientApplication;
5375
}
5476

5577
private OAuthAuthorizationGrant processPasswordGrant(
@@ -59,7 +81,7 @@ private OAuthAuthorizationGrant processPasswordGrant(
5981
return authGrant;
6082
}
6183

62-
if(msalRequest.application().authenticationAuthority.authorityType != AuthorityType.AAD){
84+
if (msalRequest.application().authenticationAuthority.authorityType != AuthorityType.AAD) {
6385
return authGrant;
6486
}
6587

@@ -131,13 +153,11 @@ private AuthorizationGrant getAuthorizationGrantIntegrated(String userName) thro
131153
this.clientApplication.logPii());
132154

133155
updatedGrant = getSAMLAuthorizationGrant(wsTrustResponse);
134-
}
135-
else if (userRealmResponse.isAccountManaged()) {
156+
} else if (userRealmResponse.isAccountManaged()) {
136157
throw new MsalClientException(
137158
"Password is required for managed user",
138159
AuthenticationErrorCode.PASSWORD_REQUIRED_FOR_MANAGED_USER);
139-
}
140-
else{
160+
} else {
141161
throw new MsalClientException(
142162
"User Realm request failed",
143163
AuthenticationErrorCode.USER_REALM_DISCOVERY_FAILED);

src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ private AuthenticationResult acquireTokenWithAuthorizationCode(AuthorizationResu
154154
AuthorizationCodeRequest authCodeRequest = new AuthorizationCodeRequest(
155155
parameters,
156156
clientApplication,
157-
clientApplication.createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE));
157+
clientApplication.createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE, parameters));
158158

159159
AcquireTokenByAuthorizationGrantSupplier acquireTokenByAuthorizationGrantSupplier =
160160
new AcquireTokenByAuthorizationGrantSupplier(

src/main/java/com/microsoft/aad/msal4j/AcquireTokenSilentSupplier.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class AcquireTokenSilentSupplier extends AuthenticationResultSupplier {
77

88
private SilentRequest silentRequest;
99

10-
AcquireTokenSilentSupplier(ClientApplicationBase clientApplication, SilentRequest silentRequest) {
10+
AcquireTokenSilentSupplier(AbstractClientApplicationBase clientApplication, SilentRequest silentRequest) {
1111
super(clientApplication, silentRequest);
1212

1313
this.silentRequest = silentRequest;
@@ -40,12 +40,12 @@ AuthenticationResult execute() throws Exception {
4040
}
4141

4242
if (silentRequest.parameters().forceRefresh() || StringHelper.isBlank(res.accessToken())) {
43-
4443
if (!StringHelper.isBlank(res.refreshToken())) {
4544
RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(
4645
RefreshTokenParameters.builder(silentRequest.parameters().scopes(), res.refreshToken()).build(),
4746
silentRequest.application(),
48-
silentRequest.requestContext());
47+
silentRequest.requestContext(),
48+
silentRequest);
4949

5050
AcquireTokenByAuthorizationGrantSupplier acquireTokenByAuthorisationGrantSupplier =
5151
new AcquireTokenByAuthorizationGrantSupplier(clientApplication, refreshTokenRequest, requestAuthority);

src/main/java/com/microsoft/aad/msal4j/AuthenticationErrorCode.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,9 @@ public class AuthenticationErrorCode {
9090
* https://aka.ms/msal4j-interactive-request
9191
*/
9292
public final static String DESKTOP_BROWSER_NOT_SUPPORTED = "desktop_browser_not_supported";
93+
94+
/**
95+
* Request was throttled according to instructions from STS.
96+
*/
97+
public final static String THROTTLED_REQUEST = "throttled_request";
9398
}

src/main/java/com/microsoft/aad/msal4j/AuthenticationResultSupplier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616

1717
abstract class AuthenticationResultSupplier implements Supplier<IAuthenticationResult> {
1818

19-
ClientApplicationBase clientApplication;
19+
AbstractClientApplicationBase clientApplication;
2020
MsalRequest msalRequest;
2121

22-
AuthenticationResultSupplier(ClientApplicationBase clientApplication, MsalRequest msalRequest) {
22+
AuthenticationResultSupplier(AbstractClientApplicationBase clientApplication, MsalRequest msalRequest) {
2323
this.clientApplication = clientApplication;
2424
this.msalRequest = msalRequest;
2525
}

src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeParameters.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
@Accessors(fluent = true)
2121
@Getter
2222
@AllArgsConstructor(access = AccessLevel.PRIVATE)
23-
public class AuthorizationCodeParameters {
23+
public class AuthorizationCodeParameters implements IApiParameters {
2424

2525
/**
2626
* Authorization code acquired in the first step of OAuth2.0 authorization code flow. For more

src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeRequest.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,12 @@
66
import com.nimbusds.oauth2.sdk.AuthorizationCode;
77
import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
88
import com.nimbusds.oauth2.sdk.AuthorizationGrant;
9-
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
109
import com.nimbusds.oauth2.sdk.pkce.CodeVerifier;
11-
import lombok.Builder;
12-
13-
import java.net.URI;
14-
import java.util.Set;
1510

1611
class AuthorizationCodeRequest extends MsalRequest {
1712

1813
AuthorizationCodeRequest(AuthorizationCodeParameters parameters,
19-
ClientApplicationBase application,
14+
AbstractClientApplicationBase application,
2015
RequestContext requestContext){
2116
super(application, createMsalGrant(parameters), requestContext);
2217
}

src/main/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParameters.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import java.util.TreeSet;
2020

2121
/**
22-
* Parameters for {@link ClientApplicationBase#getAuthorizationRequestUrl(AuthorizationRequestUrlParameters)}
22+
* Parameters for {@link AbstractClientApplicationBase#getAuthorizationRequestUrl(AuthorizationRequestUrlParameters)}
2323
*/
2424
@Accessors(fluent = true)
2525
@Getter

src/main/java/com/microsoft/aad/msal4j/ClientCredentialParameters.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
@Accessors(fluent = true)
1919
@Getter
2020
@AllArgsConstructor(access = AccessLevel.PRIVATE)
21-
public class ClientCredentialParameters {
21+
public class ClientCredentialParameters implements IApiParameters {
2222

2323
/**
2424
* Scopes for which the application is requesting access to.

src/main/java/com/microsoft/aad/msal4j/ClientInfo.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import java.util.Base64;
1212

13+
import static com.microsoft.aad.msal4j.Constants.POINT_DELIMITER;
14+
1315
@Getter(AccessLevel.PACKAGE)
1416
class ClientInfo {
1517

@@ -29,6 +31,6 @@ public static ClientInfo createFromJson(String clientInfoJsonBase64Encoded){
2931
}
3032

3133
String toAccountIdentifier(){
32-
return uniqueIdentifier + "." + unqiueTenantIdentifier;
34+
return uniqueIdentifier + POINT_DELIMITER + unqiueTenantIdentifier;
3335
}
3436
}

src/main/java/com/microsoft/aad/msal4j/ConfidentialClientApplication.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
* <p>
2828
* Conditionally thread-safe
2929
*/
30-
public class ConfidentialClientApplication extends ClientApplicationBase implements IConfidentialClientApplication {
30+
public class ConfidentialClientApplication extends AbstractClientApplicationBase implements IConfidentialClientApplication {
3131

3232
private ClientAuthentication clientAuthentication;
3333
private boolean clientCertAuthentication = false;
@@ -42,7 +42,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(ClientCredentialPar
4242
new ClientCredentialRequest(
4343
parameters,
4444
this,
45-
createRequestContext(PublicApi.ACQUIRE_TOKEN_FOR_CLIENT));
45+
createRequestContext(PublicApi.ACQUIRE_TOKEN_FOR_CLIENT, parameters));
4646

4747
return this.executeRequest(clientCredentialRequest);
4848
}
@@ -55,7 +55,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(OnBehalfOfParameter
5555
OnBehalfOfRequest oboRequest = new OnBehalfOfRequest(
5656
parameters,
5757
this,
58-
createRequestContext(PublicApi.ACQUIRE_TOKEN_ON_BEHALF_OF));
58+
createRequestContext(PublicApi.ACQUIRE_TOKEN_ON_BEHALF_OF, parameters));
5959

6060
return this.executeRequest(oboRequest);
6161
}
@@ -132,7 +132,7 @@ public static Builder builder(String clientId, IClientCredential clientCredentia
132132
return new Builder(clientId, clientCredential);
133133
}
134134

135-
public static class Builder extends ClientApplicationBase.Builder<Builder> {
135+
public static class Builder extends AbstractClientApplicationBase.Builder<Builder> {
136136

137137
private IClientCredential clientCredential;
138138

0 commit comments

Comments
 (0)