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));
}
}
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);
}
}
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;
}
}
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);
}
}
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."));
}
}
Aggregations