Search in sources :

Example 1 with SilentTokenCommandParameters

use of com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters in project microsoft-authentication-library-common-for-android by AzureAD.

the class CommandDispatcher method submitSilentReturningFuture.

/**
 * submitSilent - Run a command using the silent thread pool, and return the future governing it.
 *
 * @param command
 */
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public static FinalizableResultFuture<CommandResult> submitSilentReturningFuture(@SuppressWarnings(WarningType.rawtype_warning) @NonNull final BaseCommand command) {
    final String methodName = ":submitSilent";
    final CommandParameters commandParameters = command.getParameters();
    final String correlationId = initializeDiagnosticContext(commandParameters.getCorrelationId(), commandParameters.getSdkType() == null ? SdkType.UNKNOWN.getProductName() : commandParameters.getSdkType().getProductName(), commandParameters.getSdkVersion());
    // set correlation id on parameters as it may not already be set
    commandParameters.setCorrelationId(correlationId);
    logParameters(TAG + methodName, correlationId, commandParameters, command.getPublicApiId());
    final Handler handler = new Handler(Looper.getMainLooper());
    synchronized (mapAccessLock) {
        final FinalizableResultFuture<CommandResult> finalFuture;
        if (command.isEligibleForCaching()) {
            FinalizableResultFuture<CommandResult> future = sExecutingCommandMap.get(command);
            if (null == future) {
                future = new FinalizableResultFuture<>();
                final FinalizableResultFuture<CommandResult> putValue = sExecutingCommandMap.putIfAbsent(command, future);
                if (null == putValue) {
                    // our value was inserted.
                    future.whenComplete(getCommandResultConsumer(command, handler));
                } else {
                    // Our value was not inserted, grab the one that was and hang a new listener off it
                    putValue.whenComplete(getCommandResultConsumer(command, handler));
                    return putValue;
                }
            } else {
                future.whenComplete(getCommandResultConsumer(command, handler));
                return future;
            }
            finalFuture = future;
        } else {
            finalFuture = new FinalizableResultFuture<>();
            finalFuture.whenComplete(getCommandResultConsumer(command, handler));
        }
        sSilentExecutor.execute(new Runnable() {

            @Override
            public void run() {
                try {
                    // initializing again since the request is transferred to a different thread pool
                    initializeDiagnosticContext(correlationId, commandParameters.getSdkType() == null ? SdkType.UNKNOWN.getProductName() : commandParameters.getSdkType().getProductName(), commandParameters.getSdkVersion());
                    EstsTelemetry.getInstance().initTelemetryForCommand(command);
                    EstsTelemetry.getInstance().emitApiId(command.getPublicApiId());
                    CommandResult commandResult = null;
                    // Log operation parameters
                    if (command.getParameters() instanceof SilentTokenCommandParameters) {
                        EstsTelemetry.getInstance().emitForceRefresh(((SilentTokenCommandParameters) command.getParameters()).isForceRefresh());
                    }
                    // If nothing in cache, execute the command and cache the result
                    if (commandResult == null) {
                        commandResult = executeCommand(command);
                        // Disabling throttling ADO:1383033
                        // cacheCommandResult(command, commandResult);
                        Logger.info(TAG + methodName, "Completed silent request as owner for correlation id : **" + correlationId + ", with the status : " + commandResult.getStatus().getLogStatus() + " is cacheable : " + command.isEligibleForCaching());
                    } else {
                        Logger.info(TAG + methodName, "Silent command result returned from cache for correlation id : " + correlationId + " having status : " + commandResult.getStatus().getLogStatus());
                        // Added to keep the original correlation id intact, and to not let it mutate with the cascading requests hitting the cache.
                        commandResult = new CommandResult(commandResult.getStatus(), commandResult.getResult(), commandResult.getCorrelationId());
                    }
                    // TODO 1309671 : change required to stop the LocalAuthenticationResult object from mutating in cases of cached command.
                    // set correlation id on Local Authentication Result
                    setCorrelationIdOnResult(commandResult, correlationId);
                    Telemetry.getInstance().flush(correlationId);
                    EstsTelemetry.getInstance().flush(command, commandResult);
                    finalFuture.setResult(commandResult);
                } catch (final Throwable t) {
                    Logger.info(TAG + methodName, "Request encountered an exception with correlation id : **" + correlationId);
                    finalFuture.setException(new ExecutionException(t));
                } finally {
                    synchronized (mapAccessLock) {
                        if (command.isEligibleForCaching()) {
                            final FinalizableResultFuture mapFuture = sExecutingCommandMap.remove(command);
                            if (mapFuture == null) {
                                // If this has happened, the command that we started with has mutated.  We will
                                // examine every entry in the map, find the one with the same object identity
                                // and remove it.
                                // ADO:TODO:1153495 - Rekey this map with stable string keys.
                                Logger.error(TAG, "The command in the map has mutated " + command.getClass().getCanonicalName() + " the calling application was " + command.getParameters().getApplicationName(), null);
                                cleanMap(command);
                            }
                        }
                        finalFuture.setCleanedUp();
                    }
                    DiagnosticContext.clear();
                }
            }
        });
        return finalFuture;
    }
}
Also used : SilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters) Handler(android.os.Handler) FinalizableResultFuture(com.microsoft.identity.common.internal.result.FinalizableResultFuture) CommandParameters(com.microsoft.identity.common.internal.commands.parameters.CommandParameters) BrokerInteractiveTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.BrokerInteractiveTokenCommandParameters) SilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters) ExecutionException(java.util.concurrent.ExecutionException) VisibleForTesting(androidx.annotation.VisibleForTesting)

Example 2 with SilentTokenCommandParameters

use of com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters in project microsoft-authentication-library-common-for-android by AzureAD.

the class LocalMSALController method acquireTokenSilent.

@Override
public AcquireTokenResult acquireTokenSilent(@NonNull final SilentTokenCommandParameters parameters) throws IOException, ClientException, ArgumentException, ServiceException {
    final String methodName = ":acquireTokenSilent";
    Logger.verbose(TAG + methodName, "Acquiring token silently...");
    Telemetry.emit(new ApiStartEvent().putProperties(parameters).putApiId(TelemetryEventStrings.Api.LOCAL_ACQUIRE_TOKEN_SILENT));
    final AcquireTokenResult acquireTokenSilentResult = new AcquireTokenResult();
    // Validate MSAL Parameters
    parameters.validate();
    // Add default scopes
    final Set<String> mergedScopes = addDefaultScopes(parameters);
    final SilentTokenCommandParameters parametersWithScopes = parameters.toBuilder().scopes(mergedScopes).build();
    @SuppressWarnings(WarningType.rawtype_warning) final OAuth2TokenCache tokenCache = parametersWithScopes.getOAuth2TokenCache();
    final AccountRecord targetAccount = getCachedAccountRecord(parametersWithScopes);
    // Build up params for Strategy construction
    final AbstractAuthenticationScheme authScheme = parametersWithScopes.getAuthenticationScheme();
    final OAuth2StrategyParameters strategyParameters = new OAuth2StrategyParameters();
    strategyParameters.setContext(parametersWithScopes.getAndroidApplicationContext());
    @SuppressWarnings(WarningType.rawtype_warning) final OAuth2Strategy strategy = parametersWithScopes.getAuthority().createOAuth2Strategy(strategyParameters);
    // Suppressing unchecked warning of converting List<ICacheRecord> to List due to generic type not provided for tokenCache
    @SuppressWarnings(WarningType.unchecked_warning) final List<ICacheRecord> cacheRecords = tokenCache.loadWithAggregatedAccountData(parametersWithScopes.getClientId(), TextUtils.join(" ", parametersWithScopes.getScopes()), targetAccount, authScheme);
    // The first element is the 'fully-loaded' CacheRecord which may contain the AccountRecord,
    // AccessTokenRecord, RefreshTokenRecord, and IdTokenRecord... (if all of those artifacts exist)
    // subsequent CacheRecords represent other profiles (projections) of this principal in
    // other tenants. Those tokens will be 'sparse', meaning that their AT/RT will not be loaded
    final ICacheRecord fullCacheRecord = cacheRecords.get(0);
    if (accessTokenIsNull(fullCacheRecord) || refreshTokenIsNull(fullCacheRecord) || parametersWithScopes.isForceRefresh() || !isRequestAuthorityRealmSameAsATRealm(parametersWithScopes.getAuthority(), fullCacheRecord.getAccessToken()) || !strategy.validateCachedResult(authScheme, fullCacheRecord)) {
        if (!refreshTokenIsNull(fullCacheRecord)) {
            // No AT found, but the RT checks out, so we'll use it
            Logger.verbose(TAG + methodName, "No access token found, but RT is available.");
            renewAccessToken(parametersWithScopes, acquireTokenSilentResult, tokenCache, strategy, fullCacheRecord);
        } else {
            // TODO need the refactor, should just throw the ui required exception, rather than
            // wrap the exception later in the exception wrapper.
            final ClientException exception = new ClientException(ErrorStrings.NO_TOKENS_FOUND, "No refresh token was found. ");
            Telemetry.emit(new ApiEndEvent().putException(exception).putApiId(TelemetryEventStrings.Api.LOCAL_ACQUIRE_TOKEN_SILENT));
            throw exception;
        }
    } else if (fullCacheRecord.getAccessToken().isExpired()) {
        Logger.warn(TAG + methodName, "Access token is expired. Removing from cache...");
        // Remove the expired token
        tokenCache.removeCredential(fullCacheRecord.getAccessToken());
        Logger.verbose(TAG + methodName, "Renewing access token...");
        // Request a new AT
        renewAccessToken(parametersWithScopes, acquireTokenSilentResult, tokenCache, strategy, fullCacheRecord);
    } else {
        Logger.verbose(TAG + methodName, "Returning silent result");
        // the result checks out, return that....
        acquireTokenSilentResult.setLocalAuthenticationResult(new LocalAuthenticationResult(finalizeCacheRecordForResult(fullCacheRecord, parametersWithScopes.getAuthenticationScheme()), cacheRecords, SdkType.MSAL, true));
    }
    Telemetry.emit(new ApiEndEvent().putResult(acquireTokenSilentResult).putApiId(TelemetryEventStrings.Api.LOCAL_ACQUIRE_TOKEN_SILENT));
    return acquireTokenSilentResult;
}
Also used : AcquireTokenResult(com.microsoft.identity.common.internal.result.AcquireTokenResult) SilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters) ICacheRecord(com.microsoft.identity.common.internal.cache.ICacheRecord) OAuth2StrategyParameters(com.microsoft.identity.common.internal.providers.oauth2.OAuth2StrategyParameters) OAuth2Strategy(com.microsoft.identity.common.internal.providers.oauth2.OAuth2Strategy) AbstractAuthenticationScheme(com.microsoft.identity.common.internal.authscheme.AbstractAuthenticationScheme) OAuth2TokenCache(com.microsoft.identity.common.internal.providers.oauth2.OAuth2TokenCache) ApiEndEvent(com.microsoft.identity.common.internal.telemetry.events.ApiEndEvent) ApiStartEvent(com.microsoft.identity.common.internal.telemetry.events.ApiStartEvent) AccountRecord(com.microsoft.identity.common.internal.dto.AccountRecord) ClientException(com.microsoft.identity.common.exception.ClientException) LocalAuthenticationResult(com.microsoft.identity.common.internal.result.LocalAuthenticationResult)

Example 3 with SilentTokenCommandParameters

use of com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters in project microsoft-authentication-library-common-for-android by AzureAD.

the class SilentTokenCommand method execute.

@Override
public AcquireTokenResult execute() throws Exception {
    AcquireTokenResult result = null;
    final String methodName = ":execute";
    for (int ii = 0; ii < this.getControllers().size(); ii++) {
        final BaseController controller = this.getControllers().get(ii);
        try {
            com.microsoft.identity.common.internal.logging.Logger.verbose(TAG + methodName, "Executing with controller: " + controller.getClass().getSimpleName());
            result = controller.acquireTokenSilent((SilentTokenCommandParameters) getParameters());
            if (result.getSucceeded()) {
                com.microsoft.identity.common.internal.logging.Logger.verbose(TAG + methodName, "Executing with controller: " + controller.getClass().getSimpleName() + ": Succeeded");
                return result;
            }
        } catch (UiRequiredException | ClientException e) {
            if (// was invalid_grant
            e.getErrorCode().equals(AuthenticationConstants.OAuth2ErrorCode.INVALID_GRANT) && this.getControllers().size() > ii + 1) {
                // isn't the last controller we can try
                continue;
            } else if ((e.getErrorCode().equals(ErrorStrings.NO_TOKENS_FOUND) || e.getErrorCode().equals(ErrorStrings.NO_ACCOUNT_FOUND)) && this.getControllers().size() > ii + 1) {
                // if no token or account for this silent call, we should continue to the next silent call.
                continue;
            } else {
                throw e;
            }
        }
    }
    return result;
}
Also used : AcquireTokenResult(com.microsoft.identity.common.internal.result.AcquireTokenResult) SilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters) BaseController(com.microsoft.identity.common.internal.controllers.BaseController) UiRequiredException(com.microsoft.identity.common.exception.UiRequiredException) ClientException(com.microsoft.identity.common.exception.ClientException)

Example 4 with SilentTokenCommandParameters

use of com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters in project microsoft-authentication-library-common-for-android by AzureAD.

the class ApiStartEvent method putProperties.

public ApiStartEvent putProperties(@Nullable final CommandParameters parameters) {
    if (parameters == null) {
        return this;
    }
    if (parameters.getSdkType() != null) {
        put(Key.SDK_NAME, parameters.getSdkType().name());
    }
    put(Key.SDK_VERSION, parameters.getSdkVersion());
    // Pii
    put(Key.REDIRECT_URI, parameters.getRedirectUri());
    // Pii
    put(Key.CLIENT_ID, parameters.getClientId());
    put(Key.BROKER_PROTOCOL_VERSION, String.valueOf(parameters.getRequiredBrokerProtocolVersion()));
    if (parameters instanceof TokenCommandParameters) {
        final TokenCommandParameters tokenCommandParameters = (TokenCommandParameters) parameters;
        final Authority authority = tokenCommandParameters.getAuthority();
        if (authority != null) {
            if (authority.getAuthorityURL() != null) {
                // Pii
                put(Key.AUTHORITY, authority.getAuthorityURL().getAuthority());
            }
            put(Key.AUTHORITY_TYPE, authority.getAuthorityTypeString());
        }
        put(Key.CLAIM_REQUEST, StringUtil.isEmpty(tokenCommandParameters.getClaimsRequestJson()) ? Value.FALSE : Value.TRUE);
        if (tokenCommandParameters.getScopes() != null) {
            put(Key.SCOPE_SIZE, String.valueOf(tokenCommandParameters.getScopes().size()));
            // Pii
            put(Key.SCOPE, tokenCommandParameters.getScopes().toString());
        }
        final AbstractAuthenticationScheme authScheme = tokenCommandParameters.getAuthenticationScheme();
        if (null != authScheme) {
            put(Key.AUTHENTICATION_SCHEME, authScheme.getName());
        }
    }
    if (parameters instanceof InteractiveTokenCommandParameters) {
        final InteractiveTokenCommandParameters atOperationParameters = (InteractiveTokenCommandParameters) parameters;
        if (atOperationParameters.getAuthorizationAgent() != null) {
            put(Key.USER_AGENT, atOperationParameters.getAuthorizationAgent().name());
        }
        put(// Pii
        Key.LOGIN_HINT, atOperationParameters.getLoginHint());
        if (atOperationParameters.getExtraQueryStringParameters() != null) {
            put(// Pii
            Key.REQUEST_QUERY_PARAMS, String.valueOf(atOperationParameters.getExtraQueryStringParameters().size()));
        }
        if (atOperationParameters.getPrompt() != null) {
            put(Key.PROMPT_BEHAVIOR, atOperationParameters.getPrompt().toString());
        }
    }
    if (parameters instanceof SilentTokenCommandParameters) {
        final SilentTokenCommandParameters silentParameters = (SilentTokenCommandParameters) parameters;
        if (silentParameters.getAccount() != null) {
            // Pii
            put(Key.USER_ID, silentParameters.getAccount().getHomeAccountId());
        }
        put(Key.IS_FORCE_REFRESH, String.valueOf(silentParameters.isForceRefresh()));
    }
    if (parameters instanceof BrokerInteractiveTokenCommandParameters) {
    // TODO when integrate the telemetry with broker.
    }
    if (parameters instanceof BrokerSilentTokenCommandParameters) {
    // TODO when integrate the telemetry with broker.
    }
    return this;
}
Also used : AbstractAuthenticationScheme(com.microsoft.identity.common.internal.authscheme.AbstractAuthenticationScheme) SilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters) BrokerSilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.BrokerSilentTokenCommandParameters) BrokerSilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.BrokerSilentTokenCommandParameters) InteractiveTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.InteractiveTokenCommandParameters) BrokerInteractiveTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.BrokerInteractiveTokenCommandParameters) SilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters) TokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.TokenCommandParameters) BrokerSilentTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.BrokerSilentTokenCommandParameters) Authority(com.microsoft.identity.common.internal.authorities.Authority) InteractiveTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.InteractiveTokenCommandParameters) BrokerInteractiveTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.BrokerInteractiveTokenCommandParameters) BrokerInteractiveTokenCommandParameters(com.microsoft.identity.common.internal.commands.parameters.BrokerInteractiveTokenCommandParameters)

Aggregations

SilentTokenCommandParameters (com.microsoft.identity.common.internal.commands.parameters.SilentTokenCommandParameters)4 ClientException (com.microsoft.identity.common.exception.ClientException)2 AbstractAuthenticationScheme (com.microsoft.identity.common.internal.authscheme.AbstractAuthenticationScheme)2 BrokerInteractiveTokenCommandParameters (com.microsoft.identity.common.internal.commands.parameters.BrokerInteractiveTokenCommandParameters)2 AcquireTokenResult (com.microsoft.identity.common.internal.result.AcquireTokenResult)2 Handler (android.os.Handler)1 VisibleForTesting (androidx.annotation.VisibleForTesting)1 UiRequiredException (com.microsoft.identity.common.exception.UiRequiredException)1 Authority (com.microsoft.identity.common.internal.authorities.Authority)1 ICacheRecord (com.microsoft.identity.common.internal.cache.ICacheRecord)1 BrokerSilentTokenCommandParameters (com.microsoft.identity.common.internal.commands.parameters.BrokerSilentTokenCommandParameters)1 CommandParameters (com.microsoft.identity.common.internal.commands.parameters.CommandParameters)1 InteractiveTokenCommandParameters (com.microsoft.identity.common.internal.commands.parameters.InteractiveTokenCommandParameters)1 TokenCommandParameters (com.microsoft.identity.common.internal.commands.parameters.TokenCommandParameters)1 BaseController (com.microsoft.identity.common.internal.controllers.BaseController)1 AccountRecord (com.microsoft.identity.common.internal.dto.AccountRecord)1 OAuth2Strategy (com.microsoft.identity.common.internal.providers.oauth2.OAuth2Strategy)1 OAuth2StrategyParameters (com.microsoft.identity.common.internal.providers.oauth2.OAuth2StrategyParameters)1 OAuth2TokenCache (com.microsoft.identity.common.internal.providers.oauth2.OAuth2TokenCache)1 FinalizableResultFuture (com.microsoft.identity.common.internal.result.FinalizableResultFuture)1