com.microsoft.aad.msal4j.AbstractClientApplicationBase Maven / Gradle / Ivy
Show all versions of com.liferay.mail.outlook.auth.connector.provider
// Generated by delombok at Mon Apr 17 18:26:07 UTC 2023
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.aad.msal4j;
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
import org.slf4j.Logger;
import javax.net.ssl.SSLSocketFactory;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotBlank;
import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotNull;
/**
* Abstract class containing common methods and properties to both {@link PublicClientApplication}
* and {@link ConfidentialClientApplication}.
*/
public abstract class AbstractClientApplicationBase implements IClientApplicationBase {
protected Logger log;
protected Authority authenticationAuthority;
private ServiceBundle serviceBundle;
private String clientId;
private String authority;
private boolean validateAuthority;
private String correlationId;
private boolean logPii;
private Consumer>> telemetryConsumer;
private Proxy proxy;
private SSLSocketFactory sslSocketFactory;
private Integer connectTimeoutForDefaultHttpClient;
private Integer readTimeoutForDefaultHttpClient;
protected TokenCache tokenCache;
private String applicationName;
private String applicationVersion;
private AadInstanceDiscoveryResponse aadAadInstanceDiscoveryResponse;
protected abstract ClientAuthentication clientAuthentication();
private String clientCapabilities;
private boolean autoDetectRegion;
protected String azureRegion;
private boolean instanceDiscovery;
@Override
public CompletableFuture acquireToken(AuthorizationCodeParameters parameters) {
validateNotNull("parameters", parameters);
RequestContext context = new RequestContext(this, PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE, parameters);
AuthorizationCodeRequest authorizationCodeRequest = new AuthorizationCodeRequest(parameters, this, context);
return this.executeRequest(authorizationCodeRequest);
}
@Override
public CompletableFuture acquireToken(RefreshTokenParameters parameters) {
validateNotNull("parameters", parameters);
RequestContext context = new RequestContext(this, PublicApi.ACQUIRE_TOKEN_BY_REFRESH_TOKEN, parameters);
RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(parameters, this, context);
return executeRequest(refreshTokenRequest);
}
@Override
public CompletableFuture acquireTokenSilently(SilentParameters parameters) throws MalformedURLException {
validateNotNull("parameters", parameters);
RequestContext context;
if (parameters.account() != null) {
context = new RequestContext(this, PublicApi.ACQUIRE_TOKEN_SILENTLY, parameters, UserIdentifier.fromHomeAccountId(parameters.account().homeAccountId()));
} else {
context = new RequestContext(this, PublicApi.ACQUIRE_TOKEN_SILENTLY, parameters);
}
SilentRequest silentRequest = new SilentRequest(parameters, this, context, null);
return executeRequest(silentRequest);
}
@Override
public CompletableFuture> getAccounts() {
RequestContext context = new RequestContext(this, PublicApi.GET_ACCOUNTS, null);
MsalRequest msalRequest = new MsalRequest(this, null, context) {
};
AccountsSupplier supplier = new AccountsSupplier(this, msalRequest);
return serviceBundle.getExecutorService() != null ? CompletableFuture.supplyAsync(supplier, serviceBundle.getExecutorService()) : CompletableFuture.supplyAsync(supplier);
}
@Override
public CompletableFuture removeAccount(IAccount account) {
RequestContext context = new RequestContext(this, PublicApi.REMOVE_ACCOUNTS, null);
MsalRequest msalRequest = new MsalRequest(this, null, context) {
};
RemoveAccountRunnable runnable = new RemoveAccountRunnable(msalRequest, account);
return serviceBundle.getExecutorService() != null ? CompletableFuture.runAsync(runnable, serviceBundle.getExecutorService()) : CompletableFuture.runAsync(runnable);
}
@Override
public URL getAuthorizationRequestUrl(AuthorizationRequestUrlParameters parameters) {
validateNotNull("parameters", parameters);
parameters.requestParameters.put("client_id", Collections.singletonList(this.clientId));
//If the client application has any client capabilities set, they must be merged into the claims parameter
if (this.clientCapabilities != null) {
if (parameters.requestParameters.containsKey("claims")) {
String claims = String.valueOf(parameters.requestParameters.get("claims").get(0));
String mergedClaimsCapabilities = JsonHelper.mergeJSONString(claims, this.clientCapabilities);
parameters.requestParameters.put("claims", Collections.singletonList(mergedClaimsCapabilities));
} else {
parameters.requestParameters.put("claims", Collections.singletonList(this.clientCapabilities));
}
}
return parameters.createAuthorizationURL(this.authenticationAuthority, parameters.requestParameters());
}
CompletableFuture executeRequest(MsalRequest msalRequest) {
AuthenticationResultSupplier supplier = getAuthenticationResultSupplier(msalRequest);
ExecutorService executorService = serviceBundle.getExecutorService();
return executorService != null ? CompletableFuture.supplyAsync(supplier, executorService) : CompletableFuture.supplyAsync(supplier);
}
AuthenticationResult acquireTokenCommon(MsalRequest msalRequest, Authority requestAuthority) throws Exception {
HttpHeaders headers = msalRequest.headers();
if (logPii) {
log.debug(LogHelper.createMessage(String.format("Using Client Http Headers: %s", headers), headers.getHeaderCorrelationIdValue()));
}
TokenRequestExecutor requestExecutor = new TokenRequestExecutor(requestAuthority, msalRequest, serviceBundle);
AuthenticationResult result = requestExecutor.executeTokenRequest();
if (authenticationAuthority.authorityType.equals(AuthorityType.AAD)) {
InstanceDiscoveryMetadataEntry instanceDiscoveryMetadata = AadInstanceDiscoveryProvider.getMetadataEntry(requestAuthority.canonicalAuthorityUrl(), validateAuthority, msalRequest, serviceBundle);
tokenCache.saveTokens(requestExecutor, result, instanceDiscoveryMetadata.preferredCache);
} else {
tokenCache.saveTokens(requestExecutor, result, authenticationAuthority.host);
}
return result;
}
private AuthenticationResultSupplier getAuthenticationResultSupplier(MsalRequest msalRequest) {
AuthenticationResultSupplier supplier;
if (msalRequest instanceof DeviceCodeFlowRequest) {
supplier = new AcquireTokenByDeviceCodeFlowSupplier((PublicClientApplication) this, (DeviceCodeFlowRequest) msalRequest);
} else if (msalRequest instanceof SilentRequest) {
supplier = new AcquireTokenSilentSupplier(this, (SilentRequest) msalRequest);
} else if (msalRequest instanceof InteractiveRequest) {
supplier = new AcquireTokenByInteractiveFlowSupplier((PublicClientApplication) this, (InteractiveRequest) msalRequest);
} else if (msalRequest instanceof ClientCredentialRequest) {
supplier = new AcquireTokenByClientCredentialSupplier((ConfidentialClientApplication) this, (ClientCredentialRequest) msalRequest);
} else if (msalRequest instanceof OnBehalfOfRequest) {
supplier = new AcquireTokenByOnBehalfOfSupplier((ConfidentialClientApplication) this, (OnBehalfOfRequest) msalRequest);
} else {
supplier = new AcquireTokenByAuthorizationGrantSupplier(this, msalRequest, null);
}
return supplier;
}
ServiceBundle getServiceBundle() {
return serviceBundle;
}
public static abstract class Builder> {
// Required parameters
private String clientId;
// Optional parameters - initialized to default values
private String authority = DEFAULT_AUTHORITY;
private Authority authenticationAuthority = createDefaultAADAuthority();
private boolean validateAuthority = true;
private String correlationId;
private boolean logPii = false;
private ExecutorService executorService;
private Proxy proxy;
private SSLSocketFactory sslSocketFactory;
private IHttpClient httpClient;
private Consumer>> telemetryConsumer;
private Boolean onlySendFailureTelemetry = false;
private String applicationName;
private String applicationVersion;
private ITokenCacheAccessAspect tokenCacheAccessAspect;
private AadInstanceDiscoveryResponse aadInstanceDiscoveryResponse;
private String clientCapabilities;
private boolean autoDetectRegion;
private String azureRegion;
private Integer connectTimeoutForDefaultHttpClient;
private Integer readTimeoutForDefaultHttpClient;
private boolean instanceDiscovery = true;
/**
* Constructor to create instance of Builder of client application
*
* @param clientId Client ID (Application ID) of the application as registered
* in the application registration portal (portal.azure.com)
*/
public Builder(String clientId) {
validateNotBlank("clientId", clientId);
this.clientId = clientId;
}
abstract T self();
/**
* Set URL of the authenticating authority or security token service (STS) from which MSAL
* will acquire security tokens.
* 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
* @throws MalformedURLException if val is malformed URL
*/
public T authority(String val) throws MalformedURLException {
authority = Authority.enforceTrailingSlash(val);
URL authorityURL = new URL(authority);
switch (Authority.detectAuthorityType(authorityURL)) {
case AAD:
authenticationAuthority = new AADAuthority(authorityURL);
break;
case ADFS:
authenticationAuthority = new ADFSAuthority(authorityURL);
break;
case CIAM:
authenticationAuthority = new CIAMAuthority(authorityURL);
break;
default:
throw new IllegalArgumentException("Unsupported authority type.");
}
Authority.validateAuthority(authenticationAuthority.canonicalAuthorityUrl());
return self();
}
/**
* Set URL of the authenticating B2C authority from which MSAL will acquire tokens
*
* Valid B2C authorities should look like: https://<something.b2clogin.com/<tenant>/<policy>
*
* MSAL Java also supports a legacy B2C authority format, which looks like: https://<host>/tfp/<tenant>/<policy>
*
* However, MSAL Java will eventually stop supporting the legacy format. See here for information on how to migrate to the new format: https://aka.ms/msal4j-b2c
*
* @param val a boolean value for validateAuthority
* @return instance of the Builder on which method was called
*/
public T b2cAuthority(String val) throws MalformedURLException {
authority = Authority.enforceTrailingSlash(val);
URL authorityURL = new URL(authority);
Authority.validateAuthority(authorityURL);
if (Authority.detectAuthorityType(authorityURL) != AuthorityType.B2C) {
throw new IllegalArgumentException("Unsupported authority type. Please use B2C authority");
}
authenticationAuthority = new B2CAuthority(authorityURL);
validateAuthority = false;
return self();
}
/**
* 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 AbstractClientApplicationBase#aadAadInstanceDiscoveryResponse}
*
* The default value is true.
*
* @param val a boolean value for validateAuthority
* @return instance of the Builder on which method was called
*/
public T validateAuthority(boolean val) {
validateAuthority = val;
return self();
}
/**
* Set optional correlation id to be used by the API.
* If not provided, the API generates a random UUID.
*
* @param val a string value of correlation id
* @return instance of the Builder on which method was called
*/
public T correlationId(String val) {
validateNotBlank("correlationId", val);
correlationId = val;
return self();
}
/**
* Set logPii - boolean value, which determines
* whether Pii (personally identifiable information) will be logged in.
* The default value is false.
*
* @param val a boolean value for logPii
* @return instance of the Builder on which method was called
*/
public T logPii(boolean val) {
logPii = val;
return self();
}
/**
* Sets ExecutorService to be used to execute the requests.
* Developer is responsible for maintaining the lifecycle of the ExecutorService.
*
* @param val an instance of ExecutorService
* @return instance of the Builder on which method was called
*/
public T executorService(ExecutorService val) {
validateNotNull("executorService", val);
executorService = val;
return self();
}
/**
* Sets Proxy configuration to be used by the client application (MSAL4J by default uses
* {@link javax.net.ssl.HttpsURLConnection}) for all network communication.
* If no proxy value is passed in, system defined properties are used. If HTTP client is set on
* the client application (via ClientApplication.builder().httpClient()),
* proxy configuration should be done on the HTTP client object being passed in,
* and not through this method.
*
* @param val an instance of Proxy
* @return instance of the Builder on which method was called
*/
public T proxy(Proxy val) {
validateNotNull("proxy", val);
proxy = val;
return self();
}
/**
* Sets HTTP client to be used by the client application for all HTTP requests. Allows for fine
* grained configuration of HTTP client.
*
* @param val Implementation of {@link IHttpClient}
* @return instance of the Builder on which method was called
*/
public T httpClient(IHttpClient val) {
validateNotNull("httpClient", val);
httpClient = val;
return self();
}
/**
* Sets SSLSocketFactory to be used by the client application for all network communication.
* If HTTP client is set on the client application (via ClientApplication.builder().httpClient()),
* any configuration of SSL should be done on the HTTP client and not through this method.
*
* @param val an instance of SSLSocketFactory
* @return instance of the Builder on which method was called
*/
public T sslSocketFactory(SSLSocketFactory val) {
validateNotNull("sslSocketFactory", val);
sslSocketFactory = val;
return self();
}
/**
* Sets the connect timeout value used in HttpsURLConnection connections made by {@link DefaultHttpClient},
* and is not needed if using a custom HTTP client
*
* @param val timeout value in milliseconds
* @return instance of the Builder on which method was called
*/
public T connectTimeoutForDefaultHttpClient(Integer val) {
validateNotNull("connectTimeoutForDefaultHttpClient", val);
connectTimeoutForDefaultHttpClient = val;
return self();
}
/**
* Sets the read timeout value used in HttpsURLConnection connections made by {@link DefaultHttpClient},
* and is not needed if using a custom HTTP client
*
* @param val timeout value in milliseconds
* @return instance of the Builder on which method was called
*/
public T readTimeoutForDefaultHttpClient(Integer val) {
validateNotNull("readTimeoutForDefaultHttpClient", val);
readTimeoutForDefaultHttpClient = val;
return self();
}
T telemetryConsumer(Consumer>> val) {
validateNotNull("telemetryConsumer", val);
telemetryConsumer = val;
return self();
}
T onlySendFailureTelemetry(Boolean val) {
onlySendFailureTelemetry = val;
return self();
}
/**
* Sets application name for telemetry purposes
*
* @param val application name
* @return instance of the Builder on which method was called
*/
public T applicationName(String val) {
validateNotNull("applicationName", val);
applicationName = val;
return self();
}
/**
* Sets application version for telemetry purposes
*
* @param val application version
* @return instance of the Builder on which method was called
*/
public T applicationVersion(String val) {
validateNotNull("applicationVersion", val);
applicationVersion = val;
return self();
}
/**
* Sets ITokenCacheAccessAspect to be used for cache_data persistence.
*
* @param val an instance of ITokenCacheAccessAspect
* @return instance of the Builder on which method was called
*/
public T setTokenCacheAccessAspect(ITokenCacheAccessAspect val) {
validateNotNull("tokenCacheAccessAspect", val);
tokenCacheAccessAspect = val;
return self();
}
/**
* 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 AbstractClientApplicationBase#validateAuthority}
* is set to true.
*
* For more information, see
* https://aka.ms/msal4j-instance-discovery
*
* @param val JSON formatted value of response from AAD instance discovery endpoint
* @return instance of the Builder on which method was called
*/
public T aadInstanceDiscoveryResponse(String val) {
validateNotNull("aadInstanceDiscoveryResponse", val);
aadInstanceDiscoveryResponse = AadInstanceDiscoveryProvider.parseInstanceDiscoveryMetadata(val);
return self();
}
private static Authority createDefaultAADAuthority() {
Authority authority;
try {
authority = new AADAuthority(new URL(DEFAULT_AUTHORITY));
} catch (Exception e) {
throw new MsalClientException(e);
}
return authority;
}
public T clientCapabilities(Set capabilities) {
clientCapabilities = JsonHelper.formCapabilitiesJson(capabilities);
return self();
}
/**
* Indicates that the library should attempt to discover the Azure region the application is running in when
* fetching the instance discovery metadata. Regions can only be detected when running in an Azure environment,
* such as an Azure VM or other service, or if the environment has environment variable named REGION_NAME configured.
*
* Although you can enable both autodetection here and a specific region with {@link AbstractClientApplicationBase#azureRegion} at the same time,
* the region set with {@link AbstractClientApplicationBase#azureRegion} will take priority if there is a mismatch.
*
* See here for more information about supported scenarios: https://aka.ms/msal4j-azure-regions
*
* @param val boolean (default is false)
* @return instance of the Builder on which method was called
*/
public T autoDetectRegion(boolean val) {
autoDetectRegion = val;
return self();
}
/**
* Set the region that the library will use to format authorities in token requests. If given a valid Azure region,
* the library will attempt to make token requests at a regional ESTS-R endpoint rather than the global ESTS endpoint.
*
* Regions must be valid Azure regions and their short names should be used, such as 'westus' for the West US Azure region,
* 'centralus' for the Central US Azure region, etc.
*
* Although you can set a specific region here and enable autodetection with {@link AbstractClientApplicationBase#autoDetectRegion} at the same time
* the specific region set here will take priority over the autodetected region if there is a mismatch.
*
* See here for more information about supported scenarios: https://aka.ms/msal4j-azure-regions
*
* @param val String region name
* @return instance of the Builder on which method was called
*/
public T azureRegion(String val) {
azureRegion = val;
return self();
}
/**
* Historically, MSAL would connect to a central endpoint located at
* ``https://login.microsoftonline.com`` to acquire some metadata, especially when using an unfamiliar authority.
* This behavior is known as Instance Discovery.
* This parameter defaults to true, which enables the Instance Discovery.
* If you do not know some authorities beforehand,
* yet still want MSAL to accept any authority that you will provide,
* you can use a ``False`` to unconditionally disable Instance Discovery.
*/
public T instanceDiscovery(boolean val) {
instanceDiscovery = val;
return self();
}
abstract AbstractClientApplicationBase build();
}
AbstractClientApplicationBase(Builder> builder) {
clientId = builder.clientId;
authority = builder.authority;
validateAuthority = builder.validateAuthority;
correlationId = builder.correlationId;
logPii = builder.logPii;
applicationName = builder.applicationName;
applicationVersion = builder.applicationVersion;
telemetryConsumer = builder.telemetryConsumer;
proxy = builder.proxy;
sslSocketFactory = builder.sslSocketFactory;
connectTimeoutForDefaultHttpClient = builder.connectTimeoutForDefaultHttpClient;
readTimeoutForDefaultHttpClient = builder.readTimeoutForDefaultHttpClient;
serviceBundle = new ServiceBundle(builder.executorService, builder.httpClient == null ? new DefaultHttpClient(builder.proxy, builder.sslSocketFactory, builder.connectTimeoutForDefaultHttpClient, builder.readTimeoutForDefaultHttpClient) : builder.httpClient, new TelemetryManager(telemetryConsumer, builder.onlySendFailureTelemetry));
authenticationAuthority = builder.authenticationAuthority;
tokenCache = new TokenCache(builder.tokenCacheAccessAspect);
aadAadInstanceDiscoveryResponse = builder.aadInstanceDiscoveryResponse;
clientCapabilities = builder.clientCapabilities;
autoDetectRegion = builder.autoDetectRegion;
azureRegion = builder.azureRegion;
instanceDiscovery = builder.instanceDiscovery;
if (aadAadInstanceDiscoveryResponse != null) {
AadInstanceDiscoveryProvider.cacheInstanceDiscoveryMetadata(authenticationAuthority.host, aadAadInstanceDiscoveryResponse);
}
}
@java.lang.SuppressWarnings("all")
public String clientId() {
return this.clientId;
}
@java.lang.SuppressWarnings("all")
public String authority() {
return this.authority;
}
@java.lang.SuppressWarnings("all")
public boolean validateAuthority() {
return this.validateAuthority;
}
@java.lang.SuppressWarnings("all")
public String correlationId() {
return this.correlationId;
}
@java.lang.SuppressWarnings("all")
public boolean logPii() {
return this.logPii;
}
@java.lang.SuppressWarnings("all")
Consumer>> telemetryConsumer() {
return this.telemetryConsumer;
}
@java.lang.SuppressWarnings("all")
public Proxy proxy() {
return this.proxy;
}
@java.lang.SuppressWarnings("all")
public SSLSocketFactory sslSocketFactory() {
return this.sslSocketFactory;
}
@java.lang.SuppressWarnings("all")
public Integer connectTimeoutForDefaultHttpClient() {
return this.connectTimeoutForDefaultHttpClient;
}
@java.lang.SuppressWarnings("all")
public Integer readTimeoutForDefaultHttpClient() {
return this.readTimeoutForDefaultHttpClient;
}
@java.lang.SuppressWarnings("all")
public TokenCache tokenCache() {
return this.tokenCache;
}
@java.lang.SuppressWarnings("all")
public String applicationName() {
return this.applicationName;
}
@java.lang.SuppressWarnings("all")
public String applicationVersion() {
return this.applicationVersion;
}
@java.lang.SuppressWarnings("all")
public AadInstanceDiscoveryResponse aadAadInstanceDiscoveryResponse() {
return this.aadAadInstanceDiscoveryResponse;
}
@java.lang.SuppressWarnings("all")
public String clientCapabilities() {
return this.clientCapabilities;
}
@java.lang.SuppressWarnings("all")
public boolean autoDetectRegion() {
return this.autoDetectRegion;
}
@java.lang.SuppressWarnings("all")
public String azureRegion() {
return this.azureRegion;
}
@java.lang.SuppressWarnings("all")
public boolean instanceDiscovery() {
return this.instanceDiscovery;
}
}