Skip to content

Commit ecca2da

Browse files
committed
support of STS throttling instructions + caching of InteractionRequiredException… (#201)
support of server side throttling instructions + caching of InteractionRequiredException responses
1 parent 1d44f0c commit ecca2da

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
}

0 commit comments

Comments
 (0)