Skip to content

support of STS throttling instructions + caching of InteractionRequiredException… #201

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

Merged
merged 5 commits into from
May 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private IHttpResponse buildMsalResponseFromApacheResponse(CloseableHttpResponse
for(Header header: apacheResponse.getAllHeaders()){
headers.put(header.getName(), Collections.singletonList(header.getValue()));
}
((HttpResponse) httpResponse).headers(headers);
((HttpResponse) httpResponse).addHeaders(headers);

String responseBody = EntityUtils.toString(apacheResponse.getEntity(), "UTF-8");
((HttpResponse) httpResponse).body(responseBody);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ private IAuthenticationResult acquireTokenInteractiveB2C(ConfidentialClientAppli

private String acquireAuthorizationCodeAutomated(
User user,
ClientApplicationBase app){
AbstractClientApplicationBase app){

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

Expand Down Expand Up @@ -256,7 +256,7 @@ private String acquireAuthorizationCodeAutomated(
}
return result.code();
}
private String buildAuthenticationCodeURL(ClientApplicationBase app) {
private String buildAuthenticationCodeURL(AbstractClientApplicationBase app) {
String scope;

AuthorityType authorityType= app.authenticationAuthority.authorityType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ private IHttpResponse buildMsalResponseFromOkResponse(Response okHttpResponse) t

Headers headers = okHttpResponse.headers();
if(headers != null){
((HttpResponse) httpResponse).headers(headers.toMultimap());
((HttpResponse) httpResponse).addHeaders(headers.toMultimap());
}
return httpResponse;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void startUpBrowser(){
seleniumDriver = SeleniumExtensions.createDefaultWebDriver();
}

void runSeleniumAutomatedLogin(User user, ClientApplicationBase app) {
void runSeleniumAutomatedLogin(User user, AbstractClientApplicationBase app) {
AuthorityType authorityType = app.authenticationAuthority.authorityType;
if(authorityType == AuthorityType.B2C){
switch(user.getB2cProvider().toLowerCase()){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* Abstract class containing common methods and properties to both {@link PublicClientApplication}
* and {@link ConfidentialClientApplication}.
*/
abstract class ClientApplicationBase implements IClientApplicationBase {
abstract class AbstractClientApplicationBase implements IClientApplicationBase {

protected Logger log;
protected Authority authenticationAuthority;
Expand Down Expand Up @@ -92,7 +92,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(AuthorizationCodePa
AuthorizationCodeRequest authorizationCodeRequest = new AuthorizationCodeRequest(
parameters,
this,
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE));
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE, parameters));

return this.executeRequest(authorizationCodeRequest);
}
Expand All @@ -105,7 +105,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(RefreshTokenParamet
RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(
parameters,
this,
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_REFRESH_TOKEN));
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_REFRESH_TOKEN, parameters));

return executeRequest(refreshTokenRequest);
}
Expand All @@ -132,7 +132,7 @@ public CompletableFuture<IAuthenticationResult> acquireTokenSilently(SilentParam
SilentRequest silentRequest = new SilentRequest(
parameters,
this,
createRequestContext(PublicApi.ACQUIRE_TOKEN_SILENTLY));
createRequestContext(PublicApi.ACQUIRE_TOKEN_SILENTLY, parameters));

return executeRequest(silentRequest);
}
Expand All @@ -141,7 +141,7 @@ public CompletableFuture<IAuthenticationResult> acquireTokenSilently(SilentParam
public CompletableFuture<Set<IAccount>> getAccounts() {
MsalRequest msalRequest =
new MsalRequest(this, null,
createRequestContext(PublicApi.GET_ACCOUNTS)){};
createRequestContext(PublicApi.GET_ACCOUNTS, null)){};

AccountsSupplier supplier = new AccountsSupplier(this, msalRequest);

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

RemoveAccountRunnable runnable = new RemoveAccountRunnable(msalRequest, account);

Expand Down Expand Up @@ -231,8 +231,8 @@ private AuthenticationResultSupplier getAuthenticationResultSupplier(MsalRequest
return supplier;
}

RequestContext createRequestContext(PublicApi publicApi) {
return new RequestContext(this, publicApi);
RequestContext createRequestContext(PublicApi publicApi, IApiParameters apiParameters) {
return new RequestContext(this, publicApi, apiParameters);
}

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

abstract ClientApplicationBase build();
abstract AbstractClientApplicationBase build();
}

ClientApplicationBase(Builder<?> builder) {
AbstractClientApplicationBase(Builder<?> builder) {
clientId = builder.clientId;
authority = builder.authority;
validateAuthority = builder.validateAuthority;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@

class AccountsSupplier implements Supplier<Set<IAccount>> {

ClientApplicationBase clientApplication;
AbstractClientApplicationBase clientApplication;
MsalRequest msalRequest;

AccountsSupplier(ClientApplicationBase clientApplication, MsalRequest msalRequest) {
AccountsSupplier(AbstractClientApplicationBase clientApplication, MsalRequest msalRequest) {

this.clientApplication = clientApplication;
this.msalRequest = msalRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AcquireTokenByAuthorizationGrantSupplier extends AuthenticationResultSuppl
private Authority requestAuthority;
private MsalRequest msalRequest;

AcquireTokenByAuthorizationGrantSupplier(ClientApplicationBase clientApplication,
AcquireTokenByAuthorizationGrantSupplier(AbstractClientApplicationBase clientApplication,
MsalRequest msalRequest,
Authority authority) {
super(clientApplication, msalRequest);
Expand All @@ -28,6 +28,16 @@ class AcquireTokenByAuthorizationGrantSupplier extends AuthenticationResultSuppl

AuthenticationResult execute() throws Exception {
AbstractMsalAuthorizationGrant authGrant = msalRequest.msalAuthorizationGrant();

if (IsUiRequiredCacheSupported()) {
MsalInteractionRequiredException cachedEx =
InteractionRequiredCache.getCachedInteractionRequiredException(
((RefreshTokenRequest) msalRequest).getFullThumbprint());
if (cachedEx != null) {
throw cachedEx;
}
}

if (authGrant instanceof OAuthAuthorizationGrant) {
msalRequest.msalAuthorizationGrant =
processPasswordGrant((OAuthAuthorizationGrant) authGrant);
Expand All @@ -41,15 +51,27 @@ AuthenticationResult execute() throws Exception {
integratedAuthGrant.getUserName()), integratedAuthGrant.getScopes());
}

if(requestAuthority == null){
if (requestAuthority == null) {
requestAuthority = clientApplication.authenticationAuthority;
}

if(requestAuthority.authorityType == AuthorityType.AAD){
if (requestAuthority.authorityType == AuthorityType.AAD) {
requestAuthority = getAuthorityWithPrefNetworkHost(requestAuthority.authority());
}

return clientApplication.acquireTokenCommon(msalRequest, requestAuthority);
try {
return clientApplication.acquireTokenCommon(msalRequest, requestAuthority);
} catch (MsalInteractionRequiredException ex) {
if (IsUiRequiredCacheSupported()) {
InteractionRequiredCache.set(((RefreshTokenRequest) msalRequest).getFullThumbprint(), ex);
}
throw ex;
}
}

private boolean IsUiRequiredCacheSupported() {
return msalRequest instanceof RefreshTokenRequest &&
clientApplication instanceof PublicClientApplication;
}

private OAuthAuthorizationGrant processPasswordGrant(
Expand All @@ -59,7 +81,7 @@ private OAuthAuthorizationGrant processPasswordGrant(
return authGrant;
}

if(msalRequest.application().authenticationAuthority.authorityType != AuthorityType.AAD){
if (msalRequest.application().authenticationAuthority.authorityType != AuthorityType.AAD) {
return authGrant;
}

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

updatedGrant = getSAMLAuthorizationGrant(wsTrustResponse);
}
else if (userRealmResponse.isAccountManaged()) {
} else if (userRealmResponse.isAccountManaged()) {
throw new MsalClientException(
"Password is required for managed user",
AuthenticationErrorCode.PASSWORD_REQUIRED_FOR_MANAGED_USER);
}
else{
} else {
throw new MsalClientException(
"User Realm request failed",
AuthenticationErrorCode.USER_REALM_DISCOVERY_FAILED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ private AuthenticationResult acquireTokenWithAuthorizationCode(AuthorizationResu
AuthorizationCodeRequest authCodeRequest = new AuthorizationCodeRequest(
parameters,
clientApplication,
clientApplication.createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE));
clientApplication.createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE, parameters));

AcquireTokenByAuthorizationGrantSupplier acquireTokenByAuthorizationGrantSupplier =
new AcquireTokenByAuthorizationGrantSupplier(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class AcquireTokenSilentSupplier extends AuthenticationResultSupplier {

private SilentRequest silentRequest;

AcquireTokenSilentSupplier(ClientApplicationBase clientApplication, SilentRequest silentRequest) {
AcquireTokenSilentSupplier(AbstractClientApplicationBase clientApplication, SilentRequest silentRequest) {
super(clientApplication, silentRequest);

this.silentRequest = silentRequest;
Expand Down Expand Up @@ -40,12 +40,12 @@ AuthenticationResult execute() throws Exception {
}

if (silentRequest.parameters().forceRefresh() || StringHelper.isBlank(res.accessToken())) {

if (!StringHelper.isBlank(res.refreshToken())) {
RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(
RefreshTokenParameters.builder(silentRequest.parameters().scopes(), res.refreshToken()).build(),
silentRequest.application(),
silentRequest.requestContext());
silentRequest.requestContext(),
silentRequest);

AcquireTokenByAuthorizationGrantSupplier acquireTokenByAuthorisationGrantSupplier =
new AcquireTokenByAuthorizationGrantSupplier(clientApplication, refreshTokenRequest, requestAuthority);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,9 @@ public class AuthenticationErrorCode {
* https://aka.ms/msal4j-interactive-request
*/
public final static String DESKTOP_BROWSER_NOT_SUPPORTED = "desktop_browser_not_supported";

/**
* Request was throttled according to instructions from STS.
*/
public final static String THROTTLED_REQUEST = "throttled_request";
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

abstract class AuthenticationResultSupplier implements Supplier<IAuthenticationResult> {

ClientApplicationBase clientApplication;
AbstractClientApplicationBase clientApplication;
MsalRequest msalRequest;

AuthenticationResultSupplier(ClientApplicationBase clientApplication, MsalRequest msalRequest) {
AuthenticationResultSupplier(AbstractClientApplicationBase clientApplication, MsalRequest msalRequest) {
this.clientApplication = clientApplication;
this.msalRequest = msalRequest;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
@Accessors(fluent = true)
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AuthorizationCodeParameters {
public class AuthorizationCodeParameters implements IApiParameters {

/**
* Authorization code acquired in the first step of OAuth2.0 authorization code flow. For more
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,12 @@
import com.nimbusds.oauth2.sdk.AuthorizationCode;
import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
import com.nimbusds.oauth2.sdk.AuthorizationGrant;
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
import com.nimbusds.oauth2.sdk.pkce.CodeVerifier;
import lombok.Builder;

import java.net.URI;
import java.util.Set;

class AuthorizationCodeRequest extends MsalRequest {

AuthorizationCodeRequest(AuthorizationCodeParameters parameters,
ClientApplicationBase application,
AbstractClientApplicationBase application,
RequestContext requestContext){
super(application, createMsalGrant(parameters), requestContext);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import java.util.TreeSet;

/**
* Parameters for {@link ClientApplicationBase#getAuthorizationRequestUrl(AuthorizationRequestUrlParameters)}
* Parameters for {@link AbstractClientApplicationBase#getAuthorizationRequestUrl(AuthorizationRequestUrlParameters)}
*/
@Accessors(fluent = true)
@Getter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
@Accessors(fluent = true)
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ClientCredentialParameters {
public class ClientCredentialParameters implements IApiParameters {

/**
* Scopes for which the application is requesting access to.
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/microsoft/aad/msal4j/ClientInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import java.util.Base64;

import static com.microsoft.aad.msal4j.Constants.POINT_DELIMITER;

@Getter(AccessLevel.PACKAGE)
class ClientInfo {

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

String toAccountIdentifier(){
return uniqueIdentifier + "." + unqiueTenantIdentifier;
return uniqueIdentifier + POINT_DELIMITER + unqiueTenantIdentifier;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* <p>
* Conditionally thread-safe
*/
public class ConfidentialClientApplication extends ClientApplicationBase implements IConfidentialClientApplication {
public class ConfidentialClientApplication extends AbstractClientApplicationBase implements IConfidentialClientApplication {

private ClientAuthentication clientAuthentication;
private boolean clientCertAuthentication = false;
Expand All @@ -42,7 +42,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(ClientCredentialPar
new ClientCredentialRequest(
parameters,
this,
createRequestContext(PublicApi.ACQUIRE_TOKEN_FOR_CLIENT));
createRequestContext(PublicApi.ACQUIRE_TOKEN_FOR_CLIENT, parameters));

return this.executeRequest(clientCredentialRequest);
}
Expand All @@ -55,7 +55,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(OnBehalfOfParameter
OnBehalfOfRequest oboRequest = new OnBehalfOfRequest(
parameters,
this,
createRequestContext(PublicApi.ACQUIRE_TOKEN_ON_BEHALF_OF));
createRequestContext(PublicApi.ACQUIRE_TOKEN_ON_BEHALF_OF, parameters));

return this.executeRequest(oboRequest);
}
Expand Down Expand Up @@ -132,7 +132,7 @@ public static Builder builder(String clientId, IClientCredential clientCredentia
return new Builder(clientId, clientCredential);
}

public static class Builder extends ClientApplicationBase.Builder<Builder> {
public static class Builder extends AbstractClientApplicationBase.Builder<Builder> {

private IClientCredential clientCredential;

Expand Down
Loading