Skip to content

Commit

Permalink
feat(Auth): provide AuthConfiguration from plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
lawmicha committed Mar 13, 2024
1 parent 7d9640a commit 44ad12b
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public final class AWSCognitoAuthPlugin: AWSCognitoAuthPluginBehavior {
var queue: OperationQueue!

/// Configuration for the auth plugin
var authConfiguration: AuthConfiguration!
@_spi(InternalAmplifyConfiguration)
internal(set) public var authConfiguration: AuthConfiguration!

/// Handles different auth event send through hub
var hubEventHandler: AuthHubEventBehavior!
Expand All @@ -35,6 +36,7 @@ public final class AWSCognitoAuthPlugin: AWSCognitoAuthPluginBehavior {
/// The user network preferences for timeout and retry
let networkPreferences: AWSCognitoNetworkPreferences?

@available(*, deprecated, message: "Use `authConfiguration`")
@_spi(InternalAmplifyConfiguration)
internal(set) public var jsonConfiguration: JSONValue?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

enum AuthConfiguration {
public enum AuthConfiguration {
case userPools(UserPoolConfigurationData)
case identityPools(IdentityPoolConfigurationData)
case userPoolsAndIdentityPools(UserPoolConfigurationData, IdentityPoolConfigurationData)
Expand All @@ -21,7 +21,7 @@ extension AuthConfiguration: Codable {
case identityPools
}

func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

switch self {
Expand All @@ -35,7 +35,7 @@ extension AuthConfiguration: Codable {
}
}

init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)

let userConfigData = try? values.decode(UserPoolConfigurationData.self, forKey: .userPools)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

struct IdentityPoolConfigurationData: Equatable {
public struct IdentityPoolConfigurationData: Equatable {
let poolId: String
let region: String

Expand All @@ -25,7 +25,7 @@ extension IdentityPoolConfigurationData: CustomDebugDictionaryConvertible {
}

extension IdentityPoolConfigurationData: CustomDebugStringConvertible {
var debugDescription: String {
public var debugDescription: String {
debugDictionary.debugDescription
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import Amplify

@_spi(InternalAmplifyConfiguration)
public struct PasswordProtectionSettings: Equatable, Codable {
public var minLength: Int?
public var characterPolicy: [PasswordCharacterPolicy]

public init(minLength: Int?,
characterPolicy: [PasswordCharacterPolicy]) {
self.minLength = minLength
self.characterPolicy = characterPolicy
}
}

@_spi(InternalAmplifyConfiguration)
public enum PasswordCharacterPolicy: String, Codable {
case lowercase = "REQUIRES_LOWERCASE"
case uppercase = "REQUIRES_UPPERCASE"
case numbers = "REQUIRES_NUMBERS"
case symbols = "REQUIRES_SYMBOLS"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

@_spi(InternalAmplifyConfiguration)
public enum SignUpAttributeType: String, Codable {
case address = "ADDRESS"
case birthDate = "BIRTHDATE"
case email = "EMAIL"
case familyName = "FAMILY_NAME"
case gender = "GENDER"
case givenName = "GIVEN_NAME"
case middleName = "MIDDLE_NAME"
case name = "NAME"
case nickname = "NICKNAME"
case phoneNumber = "PHONE_NUMBER"
case preferredUsername = "PREFERRED_USERNAME"
case profile = "PROFILE"
case website = "WEBSITE"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import Amplify

@_spi(InternalAmplifyConfiguration)
public enum UsernameAttribute: String, Codable {
case username = "USERNAME"
case email = "EMAIL"
case phoneNumber = "PHONE_NUMBER"

public init?(from authUserAttributeKey: AuthUserAttributeKey) {
switch authUserAttributeKey {
case .email:
self = .email
case .phoneNumber:
self = .phoneNumber
default:
return nil
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import ClientRuntime

struct UserPoolConfigurationData: Equatable {
public struct UserPoolConfigurationData: Equatable {

let poolId: String
let clientId: String
Expand All @@ -17,6 +17,14 @@ struct UserPoolConfigurationData: Equatable {
let pinpointAppId: String?
let hostedUIConfig: HostedUIConfigurationData?
let authFlowType: AuthFlowType
@_spi(InternalAmplifyConfiguration)
public let passwordProtectionSettings: PasswordProtectionSettings?
@_spi(InternalAmplifyConfiguration)
public let usernameAttributes: [UsernameAttribute]
@_spi(InternalAmplifyConfiguration)
public let signUpAttributes: [SignUpAttributeType]
@_spi(InternalAmplifyConfiguration)
public let verificationMechanisms: [VerificationMechanism]

init(
poolId: String,
Expand All @@ -26,7 +34,11 @@ struct UserPoolConfigurationData: Equatable {
clientSecret: String? = nil,
pinpointAppId: String? = nil,
authFlowType: AuthFlowType = .userSRP,
hostedUIConfig: HostedUIConfigurationData? = nil
hostedUIConfig: HostedUIConfigurationData? = nil,
passwordProtectionSettings: PasswordProtectionSettings? = nil,
usernameAttributes: [UsernameAttribute] = [],
signUpAttributes: [SignUpAttributeType] = [],
verificationMechanisms: [VerificationMechanism] = []
) {
self.poolId = poolId
self.clientId = clientId
Expand All @@ -36,6 +48,10 @@ struct UserPoolConfigurationData: Equatable {
self.pinpointAppId = pinpointAppId
self.hostedUIConfig = hostedUIConfig
self.authFlowType = authFlowType
self.passwordProtectionSettings = passwordProtectionSettings
self.usernameAttributes = usernameAttributes
self.signUpAttributes = signUpAttributes
self.verificationMechanisms = verificationMechanisms
}

/// Amazon Cognito user pool: cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>,
Expand All @@ -62,7 +78,7 @@ extension UserPoolConfigurationData: CustomDebugDictionaryConvertible {
}

extension UserPoolConfigurationData: CustomDebugStringConvertible {
var debugDescription: String {
public var debugDescription: String {
debugDictionary.debugDescription
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

@_spi(InternalAmplifyConfiguration)
public enum VerificationMechanism: String, Codable {
case email = "EMAIL"
case phoneNumber = "PHONE_NUMBER"
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct ConfigurationHelper {
return nil
}

// parse `pinpointId`
var pinpointId: String?
if case .string(let pinpointIdFromConfig) = cognitoUserPoolJSON.value(at: "PinpointAppId") {
pinpointId = pinpointIdFromConfig
Expand All @@ -44,6 +45,7 @@ struct ConfigurationHelper {
return nil
}()

// parse `authFlowType`
var authFlowType: AuthFlowType
if case .boolean(let isMigrationEnabled) = cognitoUserPoolJSON.value(at: "MigrationEnabled"),
isMigrationEnabled == true {
Expand All @@ -56,22 +58,96 @@ struct ConfigurationHelper {
authFlowType = .userSRP
}

// parse `clientSecret`
var clientSecret: String?
if case .string(let clientSecretFromConfig) = cognitoUserPoolJSON.value(at: "AppClientSecret") {
clientSecret = clientSecretFromConfig
}

// parse `hostedUIConfig`
let hostedUIConfig = parseHostedConfiguration(
configuration: config.value(at: "Auth.Default.OAuth"))

// parse `passwordProtectionSettings`
let cognitoConfiguration = config.value(at: "Auth.Default")
var passwordProtectionSettings: PasswordProtectionSettings?
if case .object(let passwordSettings) = cognitoConfiguration?.value(at: "passwordProtectionSettings") {

// parse `minLength`
var minLength: Int?
if case .number(let value) = passwordSettings["passwordPolicyMinLength"] {
minLength = Int(value)
} else if case .string(let value) = passwordSettings["passwordPolicyMinLength"],
let intValue = Int(value) {
minLength = intValue
}

// parse `characterPolicy`
var characterPolicy: [PasswordCharacterPolicy] = []
if case .array(let characters) = passwordSettings["passwordPolicyCharacters"] {
characterPolicy = characters.compactMap { value in
guard case .string(let string) = value else {
return nil
}

return .init(rawValue: string)
}
}

passwordProtectionSettings = PasswordProtectionSettings(
minLength: minLength,
characterPolicy: characterPolicy
)
}

// parse `usernameAttributes`
var usernameAttributes: [UsernameAttribute] = []
if case .array(let attributes) = cognitoConfiguration?["usernameAttributes"] {
usernameAttributes = attributes.compactMap { value in
guard case .string(let string) = value else {
return nil
}

return .init(rawValue: string)
}
}

// parse `signUpAttributes`
var signUpAttributes: [SignUpAttributeType] = []
if case .array(let attributes) = cognitoConfiguration?["signupAttributes"] {
signUpAttributes = attributes.compactMap { value in
guard case .string(let string) = value else {
return nil
}

return .init(rawValue: string)
}
}

var verificationMechanisms: [VerificationMechanism] = []
if case .array(let attributes) = cognitoConfiguration?["verificationMechanisms"] {
verificationMechanisms = attributes.compactMap { value in
guard case .string(let string) = value else {
return nil
}

return .init(rawValue: string)
}
}

return UserPoolConfigurationData(poolId: poolId,
clientId: appClientId,
region: region,
endpoint: endpoint,
clientSecret: clientSecret,
pinpointAppId: pinpointId,
authFlowType: authFlowType,
hostedUIConfig: hostedUIConfig)
hostedUIConfig: hostedUIConfig,
passwordProtectionSettings: passwordProtectionSettings,
usernameAttributes: usernameAttributes,
signUpAttributes: signUpAttributes,
verificationMechanisms: verificationMechanisms)

}

static func parseHostedConfiguration(configuration: JSONValue?) -> HostedUIConfigurationData? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import XCTest
import AWSCognitoIdentity
@testable import Amplify
@testable import AWSCognitoAuthPlugin
@_spi(InternalAmplifyConfiguration) @testable import AWSCognitoAuthPlugin
import AWSCognitoIdentityProvider
import ClientRuntime

Expand Down

0 comments on commit 44ad12b

Please sign in to comment.