Search in sources :

Example 1 with ApiAuthException

use of com.amplifyframework.api.ApiException.ApiAuthException in project amplify-android by aws-amplify.

the class MutiAuthSubscriptionOperation method dispatchRequest.

private void dispatchRequest() {
    LOG.debug("Processing subscription request: " + getRequest().getContent());
    // If the auth types iterator still has items to return;
    if (authTypes.hasNext()) {
        // Advance the iterator, and get the next auth type to try.
        AuthorizationType authorizationType = authTypes.next();
        LOG.debug("Attempting to subscribe with " + authorizationType.name());
        GraphQLRequest<T> request = getRequest();
        // added to the request.
        if (authTypes.isOwnerBasedRule()) {
            try {
                request = requestDecorator.decorate(request, authorizationType);
            } catch (ApiAuthException apiAuthException) {
                // For ApiAuthExceptions, just queue up a dispatchRequest call. If there are no
                // other auth types left, it will emit the error to the client's callback
                // because authTypes.hasNext() will be false.
                subscriptionFuture = executorService.submit(this::dispatchRequest);
                return;
            } catch (ApiException apiException) {
                LOG.warn("Unable to automatically add an owner to the request.", apiException);
                emitErrorAndCancelSubscription(apiException);
                return;
            }
        }
        subscriptionEndpoint.requestSubscription(request, authorizationType, subscriptionId -> {
            MutiAuthSubscriptionOperation.this.subscriptionId = subscriptionId;
            onSubscriptionStart.accept(subscriptionId);
        }, response -> {
            if (response.hasErrors() && hasAuthRelatedErrors(response) && authTypes.hasNext()) {
                // If there are auth-related errors, dispatch an ApiAuthException
                executorService.submit(this::dispatchRequest);
            } else {
                // Otherwise, we just want to dispatch it as a next item and
                // let callers deal with the errors.
                onNextItem.accept(response);
            }
        }, apiException -> {
            LOG.warn("A subscription error occurred.", apiException);
            if (apiException instanceof ApiAuthException && authTypes.hasNext()) {
                executorService.submit(this::dispatchRequest);
            } else {
                emitErrorAndCancelSubscription(apiException);
            }
        }, onSubscriptionComplete);
    } else {
        emitErrorAndCancelSubscription(new ApiException("Unable to establish subscription connection.", AmplifyException.TODO_RECOVERY_SUGGESTION));
    }
}
Also used : ApiAuthException(com.amplifyframework.api.ApiException.ApiAuthException) ApiException(com.amplifyframework.api.ApiException)

Example 2 with ApiAuthException

use of com.amplifyframework.api.ApiException.ApiAuthException in project amplify-android by aws-amplify.

the class SubscriptionEndpoint method requestSubscription.

synchronized <T> void requestSubscription(@NonNull GraphQLRequest<T> request, @NonNull AuthorizationType authType, @NonNull Consumer<String> onSubscriptionStarted, @NonNull Consumer<GraphQLResponse<T>> onNextItem, @NonNull Consumer<ApiException> onSubscriptionError, @NonNull Action onSubscriptionComplete) {
    Objects.requireNonNull(request);
    Objects.requireNonNull(onSubscriptionStarted);
    Objects.requireNonNull(onNextItem);
    Objects.requireNonNull(onSubscriptionError);
    Objects.requireNonNull(onSubscriptionComplete);
    // force a new connection to be created.
    if (webSocketListener == null || webSocketListener.isDisconnectedState()) {
        webSocketListener = new AmplifyWebSocketListener();
        try {
            webSocket = okHttpClient.newWebSocket(new Request.Builder().url(buildConnectionRequestUrl(authType)).addHeader("Sec-WebSocket-Protocol", "graphql-ws").build(), webSocketListener);
        } catch (ApiException apiException) {
            onSubscriptionError.accept(apiException);
            return;
        }
    }
    final String subscriptionId = UUID.randomUUID().toString();
    pendingSubscriptionIds.add(subscriptionId);
    // Every request waits here for the connection to be ready.
    Connection connection = webSocketListener.waitForConnectionReady();
    if (connection.hasFailure()) {
        // If the latch didn't count all the way down
        if (pendingSubscriptionIds.remove(subscriptionId)) {
            // The subscription was pending, so we need to emit an error.
            onSubscriptionError.accept(new ApiException(connection.getFailureReason(), AmplifyException.TODO_RECOVERY_SUGGESTION));
            return;
        }
    }
    try {
        webSocket.send(new JSONObject().put("id", subscriptionId).put("type", "start").put("payload", new JSONObject().put("data", request.getContent()).put("extensions", new JSONObject().put("authorization", authorizer.createHeadersForSubscription(request, authType)))).toString());
    } catch (JSONException | ApiException exception) {
        // If the subscriptionId was still pending, then we can call the onSubscriptionError
        if (pendingSubscriptionIds.remove(subscriptionId)) {
            if (exception instanceof ApiAuthException) {
                // Don't wrap it if it's an ApiAuthException.
                onSubscriptionError.accept((ApiAuthException) exception);
            } else {
                onSubscriptionError.accept(new ApiException("Failed to construct subscription registration message.", exception, AmplifyException.TODO_RECOVERY_SUGGESTION));
            }
        }
        return;
    }
    Subscription<T> subscription = new Subscription<>(onNextItem, onSubscriptionError, onSubscriptionComplete, responseFactory, request.getResponseType(), request);
    subscriptions.put(subscriptionId, subscription);
    if (subscription.awaitSubscriptionReady()) {
        pendingSubscriptionIds.remove(subscriptionId);
        onSubscriptionStarted.accept(subscriptionId);
    }
}
Also used : ApiAuthException(com.amplifyframework.api.ApiException.ApiAuthException) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) Request(okhttp3.Request) JSONException(org.json.JSONException) JSONObject(org.json.JSONObject) ApiException(com.amplifyframework.api.ApiException)

Example 3 with ApiAuthException

use of com.amplifyframework.api.ApiException.ApiAuthException in project amplify-android by aws-amplify.

the class ApiRequestDecoratorFactory method forAuthType.

/**
 * Given a authorization type, it returns the appropriate request decorator.
 * @param authorizationType the authorization type to be used for the request.
 * @return the appropriate request decorator for the given authorization type.
 * @throws ApiAuthException if unable to get a request decorator.
 */
public RequestDecorator forAuthType(@NonNull AuthorizationType authorizationType) throws ApiAuthException {
    switch(authorizationType) {
        case AMAZON_COGNITO_USER_POOLS:
            // Note that if there was no user-provided cognito provider passed in to initialize
            // the API plugin, we will try to default to using the DefaultCognitoUserPoolsAuthProvider.
            // If that fails, we then have no choice but to bubble up the error.
            CognitoUserPoolsAuthProvider cognitoUserPoolsAuthProvider = apiAuthProviders.getCognitoUserPoolsAuthProvider() != null ? apiAuthProviders.getCognitoUserPoolsAuthProvider() : new DefaultCognitoUserPoolsAuthProvider();
            // By calling getLatestAuthToken() here instead of inside the lambda block, makes the exception
            // handling a little bit cleaner. If getLatestAuthToken() is called from inside the lambda expression
            // below, we'd have to surround it with a try catch. By doing it this way, if there's a problem,
            // the ApiException will just be bubbled up. Same for OPENID_CONNECT.
            final String token;
            try {
                token = cognitoUserPoolsAuthProvider.getLatestAuthToken();
            } catch (ApiException exception) {
                throw new ApiAuthException("Failed to retrieve auth token from Cognito provider.", exception, "Check the application logs for details.");
            }
            return new TokenRequestDecorator(() -> token);
        case OPENID_CONNECT:
            if (apiAuthProviders.getOidcAuthProvider() == null) {
                throw new ApiAuthException("Attempting to use OPENID_CONNECT authorization " + "without an OIDC provider.", "Configure an OidcAuthProvider when initializing " + "the API plugin.");
            }
            final String oidcToken;
            try {
                oidcToken = apiAuthProviders.getOidcAuthProvider().getLatestAuthToken();
            } catch (ApiException exception) {
                throw new ApiAuthException("Failed to retrieve auth token from OIDC provider.", exception, "Check the application logs for details.");
            }
            return new TokenRequestDecorator(() -> oidcToken);
        case AWS_LAMBDA:
            if (apiAuthProviders.getFunctionAuthProvider() == null) {
                throw new ApiAuthException("Attempting to use AWS_LAMBDA authorization " + "without a provider implemented.", "Configure a FunctionAuthProvider when initializing the API plugin.");
            }
            final String functionToken;
            try {
                functionToken = apiAuthProviders.getFunctionAuthProvider().getLatestAuthToken();
            } catch (ApiException exception) {
                throw new ApiAuthException("Failed to retrieve auth token from function auth provider.", exception, "Check the application logs for details.");
            }
            return new TokenRequestDecorator(() -> functionToken);
        case API_KEY:
            if (apiAuthProviders.getApiKeyAuthProvider() != null) {
                return new ApiKeyRequestDecorator(apiAuthProviders.getApiKeyAuthProvider());
            } else if (apiKey != null) {
                return new ApiKeyRequestDecorator(() -> apiKey);
            } else {
                throw new ApiAuthException("Attempting to use API_KEY authorization without " + "an API key provider or an API key in the config file", "Verify that an API key is in the config file or an " + "ApiKeyAuthProvider is setup during the API " + "plugin initialization.");
            }
        case AWS_IAM:
            AWSCredentialsProvider credentialsProvider = apiAuthProviders.getAWSCredentialsProvider() != null ? apiAuthProviders.getAWSCredentialsProvider() : getDefaultCredentialsProvider();
            final AWS4Signer signer;
            final String serviceName;
            if (endpointType == EndpointType.GRAPHQL) {
                signer = new AppSyncV4Signer(region);
                serviceName = APP_SYNC_SERVICE_NAME;
            } else {
                signer = new ApiGatewayIamSigner(region);
                serviceName = API_GATEWAY_SERVICE_NAME;
            }
            return new IamRequestDecorator(signer, credentialsProvider, serviceName);
        case NONE:
        default:
            return NO_OP_REQUEST_DECORATOR;
    }
}
Also used : ApiAuthException(com.amplifyframework.api.ApiException.ApiAuthException) DefaultCognitoUserPoolsAuthProvider(com.amplifyframework.api.aws.sigv4.DefaultCognitoUserPoolsAuthProvider) AWS4Signer(com.amazonaws.auth.AWS4Signer) ApiGatewayIamSigner(com.amplifyframework.api.aws.sigv4.ApiGatewayIamSigner) DefaultCognitoUserPoolsAuthProvider(com.amplifyframework.api.aws.sigv4.DefaultCognitoUserPoolsAuthProvider) CognitoUserPoolsAuthProvider(com.amplifyframework.api.aws.sigv4.CognitoUserPoolsAuthProvider) AWSCredentialsProvider(com.amazonaws.auth.AWSCredentialsProvider) ApiException(com.amplifyframework.api.ApiException) AppSyncV4Signer(com.amplifyframework.api.aws.sigv4.AppSyncV4Signer)

Example 4 with ApiAuthException

use of com.amplifyframework.api.ApiException.ApiAuthException in project amplify-android by aws-amplify.

the class DefaultCognitoUserPoolsAuthProvider method fetchToken.

// Fetches token from the mobile client.
private synchronized void fetchToken() throws ApiException {
    final Semaphore semaphore = new Semaphore(0);
    lastTokenRetrievalFailureMessage = null;
    awsMobileClient.getTokens(new Callback<Tokens>() {

        @Override
        public void onResult(Tokens result) {
            token = result.getAccessToken().getTokenString();
            semaphore.release();
        }

        @Override
        public void onError(Exception error) {
            lastTokenRetrievalFailureMessage = error.getLocalizedMessage();
            semaphore.release();
        }
    });
    try {
        semaphore.acquire();
    } catch (InterruptedException exception) {
        throw new ApiException("Interrupted waiting for Cognito Userpools token.", exception, AmplifyException.TODO_RECOVERY_SUGGESTION);
    }
    if (lastTokenRetrievalFailureMessage != null) {
        throw new ApiAuthException(lastTokenRetrievalFailureMessage, AmplifyException.TODO_RECOVERY_SUGGESTION);
    }
}
Also used : ApiAuthException(com.amplifyframework.api.ApiException.ApiAuthException) Semaphore(java.util.concurrent.Semaphore) AmplifyException(com.amplifyframework.AmplifyException) ApiException(com.amplifyframework.api.ApiException) ApiAuthException(com.amplifyframework.api.ApiException.ApiAuthException) Tokens(com.amazonaws.mobile.client.results.Tokens) ApiException(com.amplifyframework.api.ApiException)

Example 5 with ApiAuthException

use of com.amplifyframework.api.ApiException.ApiAuthException in project amplify-android by aws-amplify.

the class MultiAuthAppSyncGraphQLOperation method dispatchRequest.

private void dispatchRequest() {
    if (authTypes.hasNext()) {
        AuthorizationType authType = authTypes.next();
        Request okHttpRequest = new Request.Builder().url(endpoint).addHeader("accept", CONTENT_TYPE).addHeader("content-type", CONTENT_TYPE).post(RequestBody.create(getRequest().getContent(), MediaType.parse(CONTENT_TYPE))).build();
        Request decoratedOkHttpRequest;
        try {
            RequestDecorator requestDecorator = apiRequestDecoratorFactory.forAuthType(authType);
            decoratedOkHttpRequest = requestDecorator.decorate(okHttpRequest);
        } catch (ApiException apiException) {
            LOG.warn("Failed to make a successful request with " + authType, apiException);
            // Only queue up a retry if it's an auth-related exception.
            if (apiException instanceof ApiAuthException && authTypes.hasNext()) {
                executorService.submit(this::dispatchRequest);
            } else {
                onFailure.accept(apiException);
            }
            return;
        }
        LOG.debug("Request: " + getRequest().getContent());
        ongoingCall = client.newCall(decoratedOkHttpRequest);
        ongoingCall.enqueue(new OkHttpCallback());
    } else {
        onFailure.accept(new ApiAuthException("Unable to successfully complete request with any of the compatible auth types.", "Check your application logs for detail."));
    }
}
Also used : ApiAuthException(com.amplifyframework.api.ApiException.ApiAuthException) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) Request(okhttp3.Request) RequestDecorator(com.amplifyframework.api.aws.auth.RequestDecorator) ApiException(com.amplifyframework.api.ApiException)

Aggregations

ApiAuthException (com.amplifyframework.api.ApiException.ApiAuthException)7 ApiException (com.amplifyframework.api.ApiException)5 AmplifyException (com.amplifyframework.AmplifyException)2 GraphQLRequest (com.amplifyframework.api.graphql.GraphQLRequest)2 Request (okhttp3.Request)2 DefaultRequest (com.amazonaws.DefaultRequest)1 AWS4Signer (com.amazonaws.auth.AWS4Signer)1 AWSCredentialsProvider (com.amazonaws.auth.AWSCredentialsProvider)1 Tokens (com.amazonaws.mobile.client.results.Tokens)1 AppSyncGraphQLRequest (com.amplifyframework.api.aws.AppSyncGraphQLRequest)1 RequestDecorator (com.amplifyframework.api.aws.auth.RequestDecorator)1 ApiGatewayIamSigner (com.amplifyframework.api.aws.sigv4.ApiGatewayIamSigner)1 AppSyncV4Signer (com.amplifyframework.api.aws.sigv4.AppSyncV4Signer)1 CognitoUserPoolsAuthProvider (com.amplifyframework.api.aws.sigv4.CognitoUserPoolsAuthProvider)1 DefaultCognitoUserPoolsAuthProvider (com.amplifyframework.api.aws.sigv4.DefaultCognitoUserPoolsAuthProvider)1 AuthRule (com.amplifyframework.core.model.AuthRule)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1