// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. package com.microsoft.aad.msal4j; import org.slf4j.LoggerFactory; import java.util.concurrent.CompletableFuture; import java.util.function.Function; import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotNull; /** * Class to be used to acquire tokens for confidential client applications (Web Apps, Web APIs, * and daemon applications). * For details see {@link IConfidentialClientApplication} *

* Conditionally thread-safe */ public class ConfidentialClientApplication extends AbstractClientApplicationBase implements IConfidentialClientApplication { private ClientCertificate clientCertificate; String assertion; String secret; /** AppTokenProvider creates a Credential from a function that provides access tokens. The function must be concurrency safe. This is intended only to allow the Azure SDK to cache MSI tokens. It isn't useful to applications in general because the token provider must implement all authentication logic. */ public Function> appTokenProvider; private boolean sendX5c; @Override public CompletableFuture acquireToken(ClientCredentialParameters parameters) { validateNotNull("parameters", parameters); RequestContext context = new RequestContext( this, PublicApi.ACQUIRE_TOKEN_FOR_CLIENT, parameters); ClientCredentialRequest clientCredentialRequest = new ClientCredentialRequest( parameters, this, context, appTokenProvider); return this.executeRequest(clientCredentialRequest); } @Override public CompletableFuture acquireToken(OnBehalfOfParameters parameters) { validateNotNull("parameters", parameters); RequestContext context = new RequestContext( this, PublicApi.ACQUIRE_TOKEN_ON_BEHALF_OF, parameters); OnBehalfOfRequest oboRequest = new OnBehalfOfRequest( parameters, this, context); return this.executeRequest(oboRequest); } private ConfidentialClientApplication(Builder builder) { super(builder); sendX5c = builder.sendX5c; appTokenProvider = builder.appTokenProvider; log = LoggerFactory.getLogger(ConfidentialClientApplication.class); initClientAuthentication(builder.clientCredential); this.tenant = this.authenticationAuthority.tenant; } private void initClientAuthentication(IClientCredential clientCredential) { validateNotNull("clientCredential", clientCredential); if (clientCredential instanceof ClientSecret) { this.secret = ((ClientSecret) clientCredential).clientSecret(); } else if (clientCredential instanceof ClientCertificate) { this.clientCertificate = (ClientCertificate) clientCredential; this.assertion = getAssertionString(clientCredential); } else if (clientCredential instanceof ClientAssertion) { this.assertion = getAssertionString(clientCredential); } else { throw new IllegalArgumentException("Unsupported client credential"); } } String getAssertionString(IClientCredential clientCredential) { if (clientCredential instanceof ClientCertificate) { boolean useSha1 = Authority.detectAuthorityType(this.authenticationAuthority.canonicalAuthorityUrl()) == AuthorityType.ADFS; return JwtHelper.buildJwt( clientId(), clientCertificate, this.authenticationAuthority.selfSignedJwtAudience(), sendX5c, useSha1).assertion(); } else if (clientCredential instanceof ClientAssertion) { return ((ClientAssertion) clientCredential).assertion(); } else { throw new IllegalArgumentException("Unsupported client credential"); } } /** * Creates instance of Builder of ConfidentialClientApplication * * @param clientId Client ID (Application ID) of the application as registered * in the application registration portal (portal.azure.com) * @param clientCredential The client credential to use for token acquisition. * @return instance of Builder of ConfidentialClientApplication */ public static Builder builder(String clientId, IClientCredential clientCredential) { return new Builder(clientId, clientCredential); } public boolean sendX5c() { return this.sendX5c; } public static class Builder extends AbstractClientApplicationBase.Builder { private IClientCredential clientCredential; private boolean sendX5c = true; private Function> appTokenProvider; private Builder(String clientId, IClientCredential clientCredential) { super(clientId); this.clientCredential = clientCredential; } /** * Specifies if the x5c claim (public key of the certificate) should be sent to the STS. * Default value is true * * @param val true if the x5c should be sent. Otherwise false * @return instance of the Builder on which method was called */ public ConfidentialClientApplication.Builder sendX5c(boolean val) { this.sendX5c = val; return self(); } ///

/// Allows setting a callback which returns an access token, based on the passed-in parameters. /// MSAL will pass in its authentication parameters to the callback and it is expected that the callback /// will construct a and return it to MSAL. /// MSAL will cache the token response the same way it does for other authentication results. /// Note: This is only for client credential flows. /// /// Authentication callback which returns an access token. /// The builder to chain the .With methods public ConfidentialClientApplication.Builder appTokenProvider(Function> appTokenProvider){ if(appTokenProvider!=null){ this.appTokenProvider = appTokenProvider; return self(); } throw new NullPointerException("appTokenProvider is null") ; } @Override public ConfidentialClientApplication build() { return new ConfidentialClientApplication(this); } @Override protected ConfidentialClientApplication.Builder self() { return this; } } }