From 38e0513545b6e5a5127e233ae414f247d68749be Mon Sep 17 00:00:00 2001 From: Jithin Roy <51138777+royjit@users.noreply.github.com> Date: Tue, 19 May 2020 11:59:59 -0700 Subject: [PATCH] feat(Auth): Hub events for signedIn signedOut and sessionExpire (#457) --- Amplify.xcodeproj/project.pbxproj | 4 + .../Auth/Models/AuthEventName.swift | 17 ++++ .../AWSAuthPlugin.xcodeproj/project.pbxproj | 16 +++ .../AWSAuthPlugin+Configure.swift | 6 +- .../AWSAuthPlugin/AWSAuthPlugin+Reset.swift | 1 + .../Auth/AWSAuthPlugin/AWSAuthPlugin.swift | 3 + .../HubEvents/AuthHubEventBehavior.swift | 17 ++++ .../HubEvents/AuthHubEventHandler.swift | 98 +++++++++++++++++++ 8 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 Amplify/Categories/Auth/Models/AuthEventName.swift create mode 100644 AmplifyPlugins/Auth/AWSAuthPlugin/HubEvents/AuthHubEventBehavior.swift create mode 100644 AmplifyPlugins/Auth/AWSAuthPlugin/HubEvents/AuthHubEventHandler.swift diff --git a/Amplify.xcodeproj/project.pbxproj b/Amplify.xcodeproj/project.pbxproj index 32d21339c6..e75cdb3061 100644 --- a/Amplify.xcodeproj/project.pbxproj +++ b/Amplify.xcodeproj/project.pbxproj @@ -216,6 +216,7 @@ B4A19DAB24101EEB00DE2E55 /* AuthCategoryBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4A19DAA24101EEB00DE2E55 /* AuthCategoryBehavior.swift */; }; B4A19DAD24101F7100DE2E55 /* AuthSignUpOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4A19DAC24101F7100DE2E55 /* AuthSignUpOperation.swift */; }; B4ADE8F4241063820007E86C /* AuthCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4ADE8F3241063820007E86C /* AuthCategory.swift */; }; + B4B1E0E524733687007F3261 /* AuthEventName.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B1E0E424733687007F3261 /* AuthEventName.swift */; }; B4B5CC812457B0690019C783 /* AuthFetchUserAttributesRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B5CC802457B0690019C783 /* AuthFetchUserAttributesRequest.swift */; }; B4B5CC872457B2470019C783 /* AuthUpdateUserAttributeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B5CC862457B2470019C783 /* AuthUpdateUserAttributeRequest.swift */; }; B4B5CC8B2457B32D0019C783 /* AuthConfirmUserAttributeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B5CC8A2457B32D0019C783 /* AuthConfirmUserAttributeRequest.swift */; }; @@ -919,6 +920,7 @@ B4A19DAA24101EEB00DE2E55 /* AuthCategoryBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthCategoryBehavior.swift; sourceTree = ""; }; B4A19DAC24101F7100DE2E55 /* AuthSignUpOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthSignUpOperation.swift; sourceTree = ""; }; B4ADE8F3241063820007E86C /* AuthCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthCategory.swift; sourceTree = ""; }; + B4B1E0E424733687007F3261 /* AuthEventName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthEventName.swift; sourceTree = ""; }; B4B5CC802457B0690019C783 /* AuthFetchUserAttributesRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFetchUserAttributesRequest.swift; sourceTree = ""; }; B4B5CC862457B2470019C783 /* AuthUpdateUserAttributeRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthUpdateUserAttributeRequest.swift; sourceTree = ""; }; B4B5CC8A2457B32D0019C783 /* AuthConfirmUserAttributeRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthConfirmUserAttributeRequest.swift; sourceTree = ""; }; @@ -1950,6 +1952,7 @@ B43CD857241147F900BF5A60 /* AuthUser.swift */, B493E69224524E8C00D9E521 /* AuthUserAttribute.swift */, B493E69024524D3200D9E521 /* DeliveryDestination.swift */, + B4B1E0E424733687007F3261 /* AuthEventName.swift */, ); path = Models; sourceTree = ""; @@ -3971,6 +3974,7 @@ 95DAAB84237F13940028544F /* VoiceType.swift in Sources */, FAA2E8C223A00D5800E420EA /* APICategory+Resettable.swift in Sources */, B4FA336324105D1800E1C659 /* AuthCategoryPlugin.swift in Sources */, + B4B1E0E524733687007F3261 /* AuthEventName.swift in Sources */, 6B33896823AAACC900561E5B /* ReachabilityUpdate.swift in Sources */, FAA2E8CC23A02A5400E420EA /* HubCategory+Resettable.swift in Sources */, 2142099823721F4400FA140C /* RESTOperationRequest.swift in Sources */, diff --git a/Amplify/Categories/Auth/Models/AuthEventName.swift b/Amplify/Categories/Auth/Models/AuthEventName.swift new file mode 100644 index 0000000000..401fb3ed96 --- /dev/null +++ b/Amplify/Categories/Auth/Models/AuthEventName.swift @@ -0,0 +1,17 @@ +// +// Copyright 2018-2020 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation + +public extension HubPayload.EventName.Auth { + + static let signedIn = "Auth.signedIn" + + static let signedOut = "Auth.signedOut" + + static let sessionExpired = "Auth.sessionExpired" +} diff --git a/AmplifyPlugins/Auth/AWSAuthPlugin.xcodeproj/project.pbxproj b/AmplifyPlugins/Auth/AWSAuthPlugin.xcodeproj/project.pbxproj index 0433c906e4..2b36e8eea5 100644 --- a/AmplifyPlugins/Auth/AWSAuthPlugin.xcodeproj/project.pbxproj +++ b/AmplifyPlugins/Auth/AWSAuthPlugin.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ AACCE0421C5E26DF52717461 /* Pods_HostApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 234C2AFA9205B1766FB8E090 /* Pods_HostApp.framework */; }; B40208E224627290009CF25A /* AuthResetPasswordRequest+Validate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40208E124627290009CF25A /* AuthResetPasswordRequest+Validate.swift */; }; B40208E42462729F009CF25A /* AuthConfirmResetPasswordRequest+Validate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40208E32462729F009CF25A /* AuthConfirmResetPasswordRequest+Validate.swift */; }; + B402F77724734142006C8A1C /* AuthHubEventBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = B402F77624734142006C8A1C /* AuthHubEventBehavior.swift */; }; B416E2A3244EA3F500E8E96D /* AWSAuthFetchSessionOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B416E2A2244EA3F500E8E96D /* AWSAuthFetchSessionOperation.swift */; }; B416E2AF244EAE6800E8E96D /* AWSAuthCognitoSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = B416E2AE244EAE6800E8E96D /* AWSAuthCognitoSession.swift */; }; B416E2B3244F8E8700E8E96D /* AWSCognitoUserPoolTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = B416E2B2244F8E8700E8E96D /* AWSCognitoUserPoolTokens.swift */; }; @@ -80,6 +81,7 @@ B49FAA5124478775001868ED /* AuthenticationProviderAdapter+SignIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49FAA5024478775001868ED /* AuthenticationProviderAdapter+SignIn.swift */; }; B4A65ADB244E4C0E003A8F57 /* AuthErrorHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4A65ADA244E4C0E003A8F57 /* AuthErrorHelper.swift */; }; B4A65ADF244E4D2D003A8F57 /* AWSCognitoAuthError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4A65ADE244E4D2D003A8F57 /* AWSCognitoAuthError.swift */; }; + B4B1E0E824733907007F3261 /* AuthHubEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B1E0E724733907007F3261 /* AuthHubEventHandler.swift */; }; B4B5CC9C2457B9820019C783 /* AWSAuthUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B5CC9B2457B9820019C783 /* AWSAuthUser.swift */; }; B4B5CC9E24586C9E0019C783 /* AuthUserServiceBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B5CC9D24586C9E0019C783 /* AuthUserServiceBehavior.swift */; }; B4B5CCAB2458AE2B0019C783 /* AuthUserServiceAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B5CCAA2458AE2B0019C783 /* AuthUserServiceAdapter.swift */; }; @@ -140,6 +142,7 @@ 94AE978618BF1C30FD808FB6 /* Pods-HostApp-AWSAuthPluginIntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HostApp-AWSAuthPluginIntegrationTests.debug.xcconfig"; path = "Target Support Files/Pods-HostApp-AWSAuthPluginIntegrationTests/Pods-HostApp-AWSAuthPluginIntegrationTests.debug.xcconfig"; sourceTree = ""; }; B40208E124627290009CF25A /* AuthResetPasswordRequest+Validate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AuthResetPasswordRequest+Validate.swift"; sourceTree = ""; }; B40208E32462729F009CF25A /* AuthConfirmResetPasswordRequest+Validate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AuthConfirmResetPasswordRequest+Validate.swift"; sourceTree = ""; }; + B402F77624734142006C8A1C /* AuthHubEventBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthHubEventBehavior.swift; sourceTree = ""; }; B416E2A2244EA3F500E8E96D /* AWSAuthFetchSessionOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSAuthFetchSessionOperation.swift; sourceTree = ""; }; B416E2AE244EAE6800E8E96D /* AWSAuthCognitoSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSAuthCognitoSession.swift; sourceTree = ""; }; B416E2B2244F8E8700E8E96D /* AWSCognitoUserPoolTokens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSCognitoUserPoolTokens.swift; sourceTree = ""; }; @@ -211,6 +214,7 @@ B49FAA5024478775001868ED /* AuthenticationProviderAdapter+SignIn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AuthenticationProviderAdapter+SignIn.swift"; sourceTree = ""; }; B4A65ADA244E4C0E003A8F57 /* AuthErrorHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthErrorHelper.swift; sourceTree = ""; }; B4A65ADE244E4D2D003A8F57 /* AWSCognitoAuthError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AWSCognitoAuthError.swift; sourceTree = ""; }; + B4B1E0E724733907007F3261 /* AuthHubEventHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthHubEventHandler.swift; sourceTree = ""; }; B4B5CC9B2457B9820019C783 /* AWSAuthUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSAuthUser.swift; sourceTree = ""; }; B4B5CC9D24586C9E0019C783 /* AuthUserServiceBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthUserServiceBehavior.swift; sourceTree = ""; }; B4B5CCAA2458AE2B0019C783 /* AuthUserServiceAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthUserServiceAdapter.swift; sourceTree = ""; }; @@ -382,6 +386,7 @@ B49FAA2324451A22001868ED /* AWSAuthPlugin+Reset.swift */, B41B895F24672AB40092F96D /* ClientBehavior */, B49FAA3E24457039001868ED /* Dependency */, + B4B1E0E6247338BF007F3261 /* HubEvents */, B439F2AC24488CFD00C30CBB /* Models */, B49FAA4724458011001868ED /* Operations */, B439F2A92448835700C30CBB /* Request */, @@ -523,6 +528,15 @@ path = Error; sourceTree = ""; }; + B4B1E0E6247338BF007F3261 /* HubEvents */ = { + isa = PBXGroup; + children = ( + B4B1E0E724733907007F3261 /* AuthHubEventHandler.swift */, + B402F77624734142006C8A1C /* AuthHubEventBehavior.swift */, + ); + path = HubEvents; + sourceTree = ""; + }; B4B5CCAC2458AF390019C783 /* UserOperations */ = { isa = PBXGroup; children = ( @@ -1164,10 +1178,12 @@ B493E6A82454CF6A00D9E521 /* AWSAuthSocialWebUISignInOperation.swift in Sources */, B493E6A62454CEC700D9E521 /* AWSAuthWebUISignInOperation.swift in Sources */, B41B896324672AB40092F96D /* AWSAuthPlugin+DeviceBehavior.swift in Sources */, + B402F77724734142006C8A1C /* AuthHubEventBehavior.swift in Sources */, B49FAA2424451A22001868ED /* AWSAuthPlugin+Reset.swift in Sources */, B4B5CC9C2457B9820019C783 /* AWSAuthUser.swift in Sources */, B46884222460AB1600221268 /* AWSAuthRememberDeviceOperation.swift in Sources */, B4A65ADF244E4D2D003A8F57 /* AWSCognitoAuthError.swift in Sources */, + B4B1E0E824733907007F3261 /* AuthHubEventHandler.swift in Sources */, B49FAA302445275F001868ED /* AuthPluginErrorConstants.swift in Sources */, B452F1E72450F9160069F7FA /* AWSAuthConfirmSignUpOptions.swift in Sources */, ); diff --git a/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin+Configure.swift b/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin+Configure.swift index 9cc5aba082..5a07f923f6 100644 --- a/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin+Configure.swift +++ b/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin+Configure.swift @@ -34,10 +34,12 @@ extension AWSAuthPlugin { let authorizationProvider = AuthorizationProviderAdapter(awsMobileClient: awsMobileClient) let userService = AuthUserServiceAdapter(awsMobileClient: awsMobileClient) let deviceService = AuthDeviceServiceAdapter(awsMobileClient: awsMobileClient) + let hubEventHandler = AuthHubEventHandler() configure(authenticationProvider: authenticationProvider, authorizationProvider: authorizationProvider, userService: userService, - deviceService: deviceService) + deviceService: deviceService, + hubEventHandler: hubEventHandler) } catch let authError as AuthError { throw authError } catch { @@ -65,11 +67,13 @@ extension AWSAuthPlugin { authorizationProvider: AuthorizationProviderBehavior, userService: AuthUserServiceBehavior, deviceService: AuthDeviceServiceBehavior, + hubEventHandler: AuthHubEventBehavior, queue: OperationQueue = OperationQueue()) { self.authenticationProvider = authenticationProvider self.authorizationProvider = authorizationProvider self.userService = userService self.deviceService = deviceService + self.hubEventHandler = hubEventHandler self.queue = queue } } diff --git a/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin+Reset.swift b/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin+Reset.swift index dacaa796cd..bbac8dfb73 100644 --- a/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin+Reset.swift +++ b/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin+Reset.swift @@ -25,6 +25,7 @@ extension AWSAuthPlugin { authenticationProvider = nil userService = nil deviceService = nil + hubEventHandler = nil onComplete() } } diff --git a/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin.swift b/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin.swift index dc1b41888d..96b5b787b3 100644 --- a/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin.swift +++ b/AmplifyPlugins/Auth/AWSAuthPlugin/AWSAuthPlugin.swift @@ -29,6 +29,9 @@ final public class AWSAuthPlugin: AuthCategoryPlugin { /// Operations related to the auth device var deviceService: AuthDeviceServiceBehavior! + /// Handles different auth event send through hub + var hubEventHandler: AuthHubEventBehavior! + /// The unique key of the plugin within the auth category. public var key: PluginKey { return "awsCognitoAuthPlugin" diff --git a/AmplifyPlugins/Auth/AWSAuthPlugin/HubEvents/AuthHubEventBehavior.swift b/AmplifyPlugins/Auth/AWSAuthPlugin/HubEvents/AuthHubEventBehavior.swift new file mode 100644 index 0000000000..1d5204a746 --- /dev/null +++ b/AmplifyPlugins/Auth/AWSAuthPlugin/HubEvents/AuthHubEventBehavior.swift @@ -0,0 +1,17 @@ +// +// Copyright 2018-2020 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation + +protocol AuthHubEventBehavior { + + func sendUserSignedInEvent() + + func sendUserSignedOutEvent() + + func sendSessionExpiredEvent() +} diff --git a/AmplifyPlugins/Auth/AWSAuthPlugin/HubEvents/AuthHubEventHandler.swift b/AmplifyPlugins/Auth/AWSAuthPlugin/HubEvents/AuthHubEventHandler.swift new file mode 100644 index 0000000000..5b780ac473 --- /dev/null +++ b/AmplifyPlugins/Auth/AWSAuthPlugin/HubEvents/AuthHubEventHandler.swift @@ -0,0 +1,98 @@ +// +// Copyright 2018-2020 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Amplify +import AWSPluginsCore + +class AuthHubEventHandler: AuthHubEventBehavior { + + var lastSendEventName: HubPayloadEventName? + + init() { + setupHubEvents() + } + + func sendUserSignedInEvent() { + dispatchAuthEvent(HubPayload.EventName.Auth.signedIn) + } + + func sendUserSignedOutEvent() { + dispatchAuthEvent(HubPayload.EventName.Auth.signedOut) + } + + func sendSessionExpiredEvent() { + dispatchAuthEvent(HubPayload.EventName.Auth.sessionExpired) + } + + private func setupHubEvents() { + + _ = Amplify.Hub.listen(to: .auth) {[weak self] payload in + switch payload.eventName { + + case HubPayload.EventName.Auth.signIn: + guard let event = payload.data as? AWSAuthSignInOperation.OperationResult, + case let .success(result) = event else { + return + } + self?.handleSignInEvent(result) + + case HubPayload.EventName.Auth.confirmSignIn: + guard let event = payload.data as? AWSAuthConfirmSignInOperation.OperationResult, + case let .success(result) = event else { + return + } + self?.handleSignInEvent(result) + + case HubPayload.EventName.Auth.signOut: + guard let event = payload.data as? AWSAuthSignOutOperation.OperationResult, + case .success(_) = event else { + return + } + self?.sendUserSignedOutEvent() + + case HubPayload.EventName.Auth.fetchSession: + guard let event = payload.data as? AWSAuthFetchSessionOperation.OperationResult, + case let .success(result) = event else { + return + } + self?.handleSessionEvent(result) + + default: + break + } + } + } + + private func handleSignInEvent(_ signInResult: AuthSignInResult) { + guard signInResult.isSignedIn else { + return + } + sendUserSignedInEvent() + } + + private func handleSessionEvent(_ sessionResult: AuthSession) { + guard let tokensProvider = sessionResult as? AuthCognitoTokensProvider, + case let .failure(authError) = tokensProvider.getCognitoTokens() else { + return + } + + guard case let .service(_, _, cognitoError as AWSCognitoAuthError) = authError, + cognitoError == .sessionExpired else { + return + } + + sendSessionExpiredEvent() + } + + private func dispatchAuthEvent(_ eventName: String) { + if eventName != lastSendEventName { + lastSendEventName = eventName + Amplify.Hub.dispatch(to: .auth, payload: HubPayload(eventName: eventName)) + } + } + +}