/* * Copyright 2013-2016 Amazon.com, * Inc. or its affiliates. All Rights Reserved. * * Licensed under the Amazon Software License (the "License"). * You may not use this file except in compliance with the * License. A copy of the License is located at * * http://aws.amazon.com/asl/ * * or in the "license" file accompanying this file. This file is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, express or implied. See the License * for the specific language governing permissions and * limitations under the License. */ package com.amazonaws.mobileconnectors.cognitoidentityprovider; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AnonymousAWSCredentials; import com.amazonaws.mobileconnectors.cognitoidentityprovider.handlers.AuthenticationHandler; import com.amazonaws.mobileconnectors.cognitoidentityprovider.handlers.SignUpHandler; import com.amazonaws.mobileconnectors.cognitoidentityprovider.util.CognitoSecretHash; import com.amazonaws.regions.Regions; import com.amazonaws.services.cognitoidentityprovider.AmazonCognitoIdentityProvider; import com.amazonaws.services.cognitoidentityprovider.AmazonCognitoIdentityProviderClient; import com.amazonaws.services.cognitoidentityprovider.model.AttributeType; import com.amazonaws.services.cognitoidentityprovider.model.SignUpRequest; import com.amazonaws.services.cognitoidentityprovider.model.SignUpResult; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * This represents a user-pool in a Cognito identity provider account. The user-pools are called as * <b>Cognito User Identity Pool</b> or <b>User Identity Pool</b> or <b>User Pool</b>. All of these * terms represent the same entity, which is a pool of users in your account. * <p> * A user-pool can have these: * * 1) User pool ID, {@code userPoolId}. This is an unique identifier for your user pool. This is * a required parameter to use the SDK. * * 2) Client identifier, {@code clientId}. This is generated for a user pool and each user pool * can have several of these. A client identifier will associated with one, and only one, user * pool. This is required to use the SDK. A client identifier can have one or no client secrets. * * 3) Client secret, {@code clientSecret}. This is generated for a Client identified. A client * identifier may have a client secret, it is not necessary to generate a client secret for all * client identifiers. However if a client identifier has a client secret then this client secret * has to be used, along with the client identifier, in the SDK. * </p> * * On a user-pool new user's can sign-up and create new {@link CognitoUser}. */ public class CognitoUserPool { /** * Cognito Your Identity Pool ID */ private final String userPoolId; /** * Client ID created for your pool {@code userPoolId}. */ private final String clientId; /** * Client secret generated for this {@code clientId}, this may be {@code null} if a secret is not * generated for the {@code clientId}. */ private String clientSecret; /** * Application context. */ private final Context context; /** * CIP low-level client. */ private final AmazonCognitoIdentityProvider client; /** * Calculated with {@code userId}, {@code clientId} and {@code clientSecret} */ private String secretHash; /** * Constructs a user-pool with a developer specified {@link ClientConfiguration} and default AWS region {@link Regions}. * Region defaults to US-EAST-1. * * @param context REQUIRED: Android application context * @param userPoolId REQUIRED: User-pool-Id of the user-pool * @param clientId REQUIRED: Client-Id generated for this app and user-pool at the * Cognito Identity Provider developer console * @param clientSecret REQUIRED: Client Secret generated for this app and user-pool at * the Cognito Identity Provider developer console * @param clientConfiguration REQUIRED: The client configuration options controlling how this * client connects to Cognito Identity Provider Service (e.g. proxy settings, * retry counts, etc.). */ public CognitoUserPool(Context context, String userPoolId, String clientId, String clientSecret, ClientConfiguration clientConfiguration) { this(context, userPoolId, clientId, clientSecret, clientConfiguration, Regions.US_EAST_1); } /** * Constructs a user-pool with default {@link ClientConfiguration} and default AWS region {@link Regions}. * Region defaults to US-EAST-1. * * @param context REQUIRED: Android application context. * @param userPoolId REQUIRED: User-pool-Id of the user-pool. * @param clientId REQUIRED: Client-Id generated for this app and user-pool at the * Cognito Identity Provider developer console. * @param clientSecret REQUIRED: Client Secret generated for this app and user-pool at * the Cognito Identity Provider developer console. */ public CognitoUserPool(Context context, String userPoolId, String clientId, String clientSecret) { this(context, userPoolId, clientId, clientSecret, new ClientConfiguration(), Regions.US_EAST_1); } /** * Constructs a user-pool with default {@link ClientConfiguration}. * * @param context REQUIRED: Android application context. * @param userPoolId REQUIRED: User-pool-Id of the user-pool. * @param clientId REQUIRED: Client-Id generated for this app and user-pool at the * Cognito Identity Provider developer console. * @param clientSecret REQUIRED: Client Secret generated for this app and user-pool at * the Cognito Identity Provider developer console. * @param region REQUIRED: AWS region {@link Regions}. */ public CognitoUserPool(Context context, String userPoolId, String clientId, String clientSecret, Regions region) { this(context, userPoolId, clientId, clientSecret, new ClientConfiguration(), region); } /** * Constructs a user-pool. * * @param context REQUIRED: Android application context. * @param userPoolId REQUIRED: User-pool-Id of the user-pool. * @param clientId REQUIRED: Client-Id generated for this app and user-pool at the * Cognito Identity Provider developer console. * @param clientSecret REQUIRED: Client Secret generated for this app and user-pool at * the Cognito Identity Provider developer console. * @param clientConfiguration REQUIRED: The client configuration options controlling how this * client connects to Cognito Identity Provider Service (e.g. proxy settings, * retry counts, etc.). * @param region REQUIRED: AWS region {@link Regions}. */ public CognitoUserPool(Context context, String userPoolId, String clientId, String clientSecret, ClientConfiguration clientConfiguration, Regions region) { this.context = context; this.userPoolId = userPoolId; this.clientId = clientId; this.clientSecret = clientSecret; this.client = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), clientConfiguration); this.client.setRegion(com.amazonaws.regions.Region.getRegion(region)); } /** * Constructs a user-pool with default {@link ClientConfiguration}. * * @param context REQUIRED: Android application context. * @param userPoolId REQUIRED: User-pool-Id of the user-pool. * @param clientId REQUIRED: Client-Id generated for this app and user-pool at the * Cognito Identity Provider developer console. * @param clientSecret REQUIRED: Client Secret generated for this app and user-pool at * the Cognito Identity Provider developer console. * @param client REQUIRED: AWS low-level Cognito Identity Provider Client. */ public CognitoUserPool(Context context, String userPoolId, String clientId, String clientSecret, AmazonCognitoIdentityProvider client) { this.context = context; this.userPoolId = userPoolId; this.clientId = clientId; this.clientSecret = clientSecret; this.client = client; } /** * Returns Client ID set for this pool. * * @return Client ID. */ public String getClientId() { return clientId; } /** * Returns Pool ID of this pool. * * @return Your User Pool ID. */ public String getUserPoolId() { return userPoolId; } /** * Runs user registration in background. * * @param userId REQUIRED: userId for this user * @param password REQUIRED: Password for this user * @param userAttributes REQUIRED: Contains all attributes for this user * @param validationData REQUIRED: Parameters for lambda function for user registration * @param callback REQUIRED: callback, must not be null */ public void signUpInBackground(final String userId, final String password, final CognitoUserAttributes userAttributes, final Map<String, String> validationData, final SignUpHandler callback) { new Thread(new Runnable() { @Override public void run() { Handler handler = new Handler(context.getMainLooper()); Runnable returnCallback; try { final SignUpResult signUpResult = signUpInternal(userId, password, userAttributes, validationData); final CognitoUser user = getUser(userId); returnCallback = new Runnable() { @Override public void run() { callback.onSuccess(user, signUpResult.getUserConfirmed(), new CognitoUserCodeDeliveryDetails(signUpResult.getCodeDeliveryDetails())); } }; } catch(final Exception e) { returnCallback = new Runnable() { @Override public void run() { callback.onFailure(e); } }; } handler.post(returnCallback); } }).start(); } /** * Runs user registration in current thread. * <p> * <b>Note:</b> This method will perform network operations. Calling this method in * applications' main thread will cause Android to throw NetworkOnMainThreadException. * </p> * * @param userId REQUIRED: userId for this user * @param password REQUIRED: Password for this user * @param userAttributes REQUIRED: Contains all attributes for this user * @param validationData REQUIRED: Parameters for lambda function for user registration * @param callback REQUIRED: callback, must not be null */ public void signUp(final String userId, final String password, final CognitoUserAttributes userAttributes, final Map<String, String> validationData, final SignUpHandler callback) { try { SignUpResult signUpResult = signUpInternal(userId, password, userAttributes, validationData); CognitoUser user = getUser(userId); callback.onSuccess(user, signUpResult.getUserConfirmed(), new CognitoUserCodeDeliveryDetails(signUpResult.getCodeDeliveryDetails())); } catch(final Exception e) { callback.onFailure(e); } } /** * Internal method to sign-up a new user in Cognito Identity Provider user pool. * * @param userId REQUIRED: The new user userId. * @param password REQUIRED: Password you want to associate to this use. * @param userAttributes REQUIRED: User attributes. * @param validationData REQUIRED: Validation key value pairs, these will be passed to pre * and post registration lambda functions. * * @return CognitoUser */ private SignUpResult signUpInternal(String userId, String password, CognitoUserAttributes userAttributes, Map<String, String> validationData) { // Create a list of {@link AttributeType} from {@code userAttributes} List<AttributeType> validationDataList = null; if(validationData != null) { validationDataList = new ArrayList<AttributeType>(); for (Map.Entry<String, String> data : validationData.entrySet()) { AttributeType validation = new AttributeType(); validation.setName(data.getKey()); validation.setValue(data.getValue()); validationDataList.add(validation); } } // Generate Client secret hash secretHash = CognitoSecretHash.getSecretHash(userId, clientId, clientSecret); // Create User registration request SignUpRequest signUpUserRequest = new SignUpRequest(); signUpUserRequest.setUsername(userId); signUpUserRequest.setPassword(password); signUpUserRequest.setClientId(clientId); signUpUserRequest.setSecretHash(secretHash); signUpUserRequest.setUserAttributes(userAttributes.getAttributesList()); signUpUserRequest.setValidationData(validationDataList); return client.signUp(signUpUserRequest); } /** * Returns last authenticated user on this device in this user pool. * * @return An instance of the {@link CognitoUser} for last authenticated, cached on this device */ public CognitoUser getCurrentUser() { SharedPreferences csiCachedTokens = context.getSharedPreferences("CognitoIdentityProviderCache", 0); String csiLastUserKey = "CognitoIdentityProvider." + clientId + ".LastAuthUser"; if(csiCachedTokens.contains(csiLastUserKey)){ return getUser(csiCachedTokens.getString(csiLastUserKey, null)); } else { return getUser(); } } /** * Returns a {@link CognitoUser} with no username set. * * @return {@link CognitoUser}. */ public CognitoUser getUser() { return new CognitoUser(this, null, clientId, clientSecret, null, client, context); } /** * Returns a CognitoUser with userId {@code userId} * <p> * This CognitoUser is not authenticated. Call {@link CognitoUser#getSession(AuthenticationHandler)} * to get valid tokens {@link CognitoUserSession} * </p> * * @param userId Can be null * @return a new CognitoUser instance with userId {@code userId} */ public CognitoUser getUser(String userId) { if (userId == null) { return getUser(); } if(userId.isEmpty()) { return getUser(); } return new CognitoUser(this, userId, clientId, clientSecret, CognitoSecretHash.getSecretHash(userId, clientId, clientSecret), client, context); } }