diff --git a/aws-android-sdk-cognitoauth/src/main/java/com/amazonaws/mobileconnectors/cognitoauth/AuthClient.java b/aws-android-sdk-cognitoauth/src/main/java/com/amazonaws/mobileconnectors/cognitoauth/AuthClient.java index 171be894bd..072fc33258 100644 --- a/aws-android-sdk-cognitoauth/src/main/java/com/amazonaws/mobileconnectors/cognitoauth/AuthClient.java +++ b/aws-android-sdk-cognitoauth/src/main/java/com/amazonaws/mobileconnectors/cognitoauth/AuthClient.java @@ -21,6 +21,9 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Handler; import androidx.browser.customtabs.CustomTabsClient; @@ -28,9 +31,11 @@ import androidx.browser.customtabs.CustomTabsServiceConnection; import androidx.browser.customtabs.CustomTabsSession; import android.text.TextUtils; +import android.util.Log; import com.amazonaws.cognito.clientcontext.data.UserContextDataProvider; import com.amazonaws.mobileconnectors.cognitoauth.activities.CustomTabsManagerActivity; +import com.amazonaws.mobileconnectors.cognitoauth.exceptions.AuthClientException; import com.amazonaws.mobileconnectors.cognitoauth.exceptions.AuthInvalidGrantException; import com.amazonaws.mobileconnectors.cognitoauth.exceptions.AuthNavigationException; import com.amazonaws.mobileconnectors.cognitoauth.exceptions.AuthServiceException; @@ -44,8 +49,11 @@ import java.net.URL; import java.security.InvalidParameterException; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * Local client for {@link Auth}. @@ -64,6 +72,21 @@ public class AuthClient { */ public static final int CUSTOM_TABS_ACTIVITY_CODE = 49281; + /** + * Namespace for logging client activities + */ + private static final String TAG = AuthClient.class.getSimpleName(); + + /** + * Name of redirect activity in charge of handling auth responses. + */ + private static final String REDIRECT_ACTIVITY_NAME = "HostedUIRedirectActivity"; + + /** + * Default timeout duration for auth redirects. + */ + private static final long REDIRECT_TIMEOUT_SECONDS = 10; + /** * Specifies what browser package to default to if one isn't specified. */ @@ -104,12 +127,20 @@ public class AuthClient { */ private AuthHandler userHandler; + /** + * Remembers whether redirect activity was found in manifest or not. + */ + private boolean isRedirectActivityDeclared; + + // - Chrome Custom Tabs Controls private CustomTabsClient mCustomTabsClient; private CustomTabsSession mCustomTabsSession; private CustomTabsIntent mCustomTabsIntent; private CustomTabsServiceConnection mCustomTabsServiceConnection; + private CountDownLatch cookiesCleared; + /** * Constructs {@link AuthClient} with no user name. * @param context Required: The android application {@link Context}. @@ -129,6 +160,7 @@ protected AuthClient(final Context context, final Auth pool, final String userna this.context = context; this.pool = pool; this.userId = username; + this.isRedirectActivityDeclared = false; preWarmChrome(); } @@ -250,8 +282,7 @@ public void signOut() { * @param browserPackage String specifying the browser package to launch the specified url. */ public void signOut(String browserPackage) { - LocalDataManager.clearCache(pool.awsKeyValueStore, context, pool.getAppId(), userId); - launchSignOut(pool.getSignOutRedirectUri(), browserPackage); + signOut(false, browserPackage); } /** @@ -271,8 +302,8 @@ public void signOut(final boolean clearLocalTokensOnly) { /** * Signs-out a user. *
- * Clears cached tokens for the user. Launches the sign-out Cognito web end-point to - * clear all Cognito Auth cookies stored by Chrome. + * Launches the sign-out Cognito web end-point to clear all Cognito Auth cookies stored + * by Chrome. Cached tokens will be deleted if sign-out redirect is completed. *
* * @param clearLocalTokensOnly true if signs out the user from the client, @@ -280,9 +311,33 @@ public void signOut(final boolean clearLocalTokensOnly) { * @param browserPackage String specifying the browser package to launch the specified url. */ public void signOut(final boolean clearLocalTokensOnly, final String browserPackage) { - LocalDataManager.clearCache(pool.awsKeyValueStore, context, pool.getAppId(), userId); if (!clearLocalTokensOnly) { + endSession(browserPackage); + } + + // Delete local cache + LocalDataManager.clearCache(pool.awsKeyValueStore, context, pool.getAppId(), userId); + } + + /** + * Ends current browser session. + * @param browserPackage browser package to launch sign-out endpoint from. + * @throws AuthClientException if sign-out redirect fails to resolve. + */ + private void endSession(final String browserPackage) throws AuthClientException { + boolean redirectReceived; + try { + cookiesCleared = new CountDownLatch(1); launchSignOut(pool.getSignOutRedirectUri(), browserPackage); + if (!isRedirectActivityDeclared()) { + cookiesCleared.countDown(); + } + redirectReceived = cookiesCleared.await(REDIRECT_TIMEOUT_SECONDS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new AuthNavigationException("User cancelled sign-out."); + } + if (!redirectReceived) { + throw new AuthServiceException("Timed out while waiting for sign-out redirect response."); } } @@ -415,6 +470,11 @@ public void run() { } } } else { + if (cookiesCleared != null) { + cookiesCleared.countDown(); + Log.d(TAG, "Sign-out was successful."); + } + // User sign-out. returnCallback = new Runnable() { @Override @@ -572,7 +632,7 @@ private Map