diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.pbxproj b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.pbxproj new file mode 100644 index 00000000..be73f571 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.pbxproj @@ -0,0 +1,436 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + EC0BA22A282AA69E00F8326E /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = EC0BA229282AA69E00F8326E /* JGProgressHUD */; }; + EC1A825A2822D0D1008D81BA /* FRAuth in Frameworks */ = {isa = PBXBuildFile; productRef = EC1A82592822D0D1008D81BA /* FRAuth */; }; + EC1A825C2822D0D1008D81BA /* FRCore in Frameworks */ = {isa = PBXBuildFile; productRef = EC1A825B2822D0D1008D81BA /* FRCore */; }; + EC1A825E2822D0D1008D81BA /* FRFacebookSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = EC1A825D2822D0D1008D81BA /* FRFacebookSignIn */; }; + EC1A82602822D0D1008D81BA /* FRGoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = EC1A825F2822D0D1008D81BA /* FRGoogleSignIn */; }; + EC4F96C12695E82400B3C9B8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC4F96C02695E82400B3C9B8 /* AppDelegate.swift */; }; + EC4F96C52695E82400B3C9B8 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC4F96C42695E82400B3C9B8 /* LoginViewController.swift */; }; + EC4F96C82695E82400B3C9B8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC4F96C62695E82400B3C9B8 /* Main.storyboard */; }; + EC4F96CA2695E82500B3C9B8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC4F96C92695E82500B3C9B8 /* Assets.xcassets */; }; + EC4F96CD2695E82500B3C9B8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC4F96CB2695E82500B3C9B8 /* LaunchScreen.storyboard */; }; + ECA14863282A6F7900D52E7D /* AuthenticatedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA14862282A6F7900D52E7D /* AuthenticatedViewController.swift */; }; + ECD8E04E2A6E811C009C421C /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD8E04D2A6E811C009C421C /* SettingsViewController.swift */; }; + ECD8E0502A6E8AAF009C421C /* PebbleBankUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD8E04F2A6E8AAF009C421C /* PebbleBankUtilities.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + EC3A95FF27C8E9150094C650 /* FRCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FRCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EC4F96BD2695E82400B3C9B8 /* UnsummitAuthentication.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UnsummitAuthentication.app; sourceTree = BUILT_PRODUCTS_DIR; }; + EC4F96C02695E82400B3C9B8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + EC4F96C42695E82400B3C9B8 /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; + EC4F96C72695E82400B3C9B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + EC4F96C92695E82500B3C9B8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + EC4F96CC2695E82500B3C9B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + EC4F96CE2695E82500B3C9B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + ECA14862282A6F7900D52E7D /* AuthenticatedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticatedViewController.swift; sourceTree = ""; }; + ECD8E04D2A6E811C009C421C /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; + ECD8E04F2A6E8AAF009C421C /* PebbleBankUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PebbleBankUtilities.swift; sourceTree = ""; }; + ECEAA19E2A375443004F5823 /* UnsummitAuthentication.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = UnsummitAuthentication.entitlements; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + EC4F96BA2695E82400B3C9B8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EC1A825E2822D0D1008D81BA /* FRFacebookSignIn in Frameworks */, + EC1A825A2822D0D1008D81BA /* FRAuth in Frameworks */, + EC1A825C2822D0D1008D81BA /* FRCore in Frameworks */, + EC1A82602822D0D1008D81BA /* FRGoogleSignIn in Frameworks */, + EC0BA22A282AA69E00F8326E /* JGProgressHUD in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + EC4F96B42695E82400B3C9B8 = { + isa = PBXGroup; + children = ( + EC4F96BF2695E82400B3C9B8 /* UnsummitAuthentication */, + EC4F96BE2695E82400B3C9B8 /* Products */, + F84DC7CFEA86E95FDAA1F6EB /* Frameworks */, + ); + sourceTree = ""; + }; + EC4F96BE2695E82400B3C9B8 /* Products */ = { + isa = PBXGroup; + children = ( + EC4F96BD2695E82400B3C9B8 /* UnsummitAuthentication.app */, + ); + name = Products; + sourceTree = ""; + }; + EC4F96BF2695E82400B3C9B8 /* UnsummitAuthentication */ = { + isa = PBXGroup; + children = ( + ECEAA19E2A375443004F5823 /* UnsummitAuthentication.entitlements */, + EC4F96C02695E82400B3C9B8 /* AppDelegate.swift */, + EC4F96C42695E82400B3C9B8 /* LoginViewController.swift */, + ECA14862282A6F7900D52E7D /* AuthenticatedViewController.swift */, + ECD8E04D2A6E811C009C421C /* SettingsViewController.swift */, + EC4F96C62695E82400B3C9B8 /* Main.storyboard */, + EC4F96C92695E82500B3C9B8 /* Assets.xcassets */, + EC4F96CB2695E82500B3C9B8 /* LaunchScreen.storyboard */, + EC4F96CE2695E82500B3C9B8 /* Info.plist */, + ECD8E04F2A6E8AAF009C421C /* PebbleBankUtilities.swift */, + ); + path = UnsummitAuthentication; + sourceTree = ""; + }; + F84DC7CFEA86E95FDAA1F6EB /* Frameworks */ = { + isa = PBXGroup; + children = ( + EC3A95FF27C8E9150094C650 /* FRCore.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + EC4F96BC2695E82400B3C9B8 /* UnsummitAuthentication */ = { + isa = PBXNativeTarget; + buildConfigurationList = EC4F96D12695E82500B3C9B8 /* Build configuration list for PBXNativeTarget "UnsummitAuthentication" */; + buildPhases = ( + EC4F96B92695E82400B3C9B8 /* Sources */, + EC4F96BA2695E82400B3C9B8 /* Frameworks */, + EC4F96BB2695E82400B3C9B8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = UnsummitAuthentication; + packageProductDependencies = ( + EC1A82592822D0D1008D81BA /* FRAuth */, + EC1A825B2822D0D1008D81BA /* FRCore */, + EC1A825D2822D0D1008D81BA /* FRFacebookSignIn */, + EC1A825F2822D0D1008D81BA /* FRGoogleSignIn */, + EC0BA229282AA69E00F8326E /* JGProgressHUD */, + ); + productName = BioExample; + productReference = EC4F96BD2695E82400B3C9B8 /* UnsummitAuthentication.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + EC4F96B52695E82400B3C9B8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1240; + LastUpgradeCheck = 1240; + TargetAttributes = { + EC4F96BC2695E82400B3C9B8 = { + CreatedOnToolsVersion = 12.4; + }; + }; + }; + buildConfigurationList = EC4F96B82695E82400B3C9B8 /* Build configuration list for PBXProject "UnsummitAuthentication" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = EC4F96B42695E82400B3C9B8; + packageReferences = ( + EC1A82582822D0D1008D81BA /* XCRemoteSwiftPackageReference "forgerock-ios-sdk" */, + EC0BA228282AA69E00F8326E /* XCRemoteSwiftPackageReference "JGProgressHUD" */, + ); + productRefGroup = EC4F96BE2695E82400B3C9B8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + EC4F96BC2695E82400B3C9B8 /* UnsummitAuthentication */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + EC4F96BB2695E82400B3C9B8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EC4F96CD2695E82500B3C9B8 /* LaunchScreen.storyboard in Resources */, + EC4F96CA2695E82500B3C9B8 /* Assets.xcassets in Resources */, + EC4F96C82695E82400B3C9B8 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + EC4F96B92695E82400B3C9B8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EC4F96C52695E82400B3C9B8 /* LoginViewController.swift in Sources */, + ECD8E0502A6E8AAF009C421C /* PebbleBankUtilities.swift in Sources */, + ECA14863282A6F7900D52E7D /* AuthenticatedViewController.swift in Sources */, + EC4F96C12695E82400B3C9B8 /* AppDelegate.swift in Sources */, + ECD8E04E2A6E811C009C421C /* SettingsViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + EC4F96C62695E82400B3C9B8 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + EC4F96C72695E82400B3C9B8 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + EC4F96CB2695E82500B3C9B8 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + EC4F96CC2695E82500B3C9B8 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + EC4F96CF2695E82500B3C9B8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + EC4F96D02695E82500B3C9B8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + EC4F96D22695E82500B3C9B8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = UnsummitAuthentication/UnsummitAuthentication.entitlements; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 9QSE66762D; + INFOPLIST_FILE = UnsummitAuthentication/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.unsummit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + EC4F96D32695E82500B3C9B8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = UnsummitAuthentication/UnsummitAuthentication.entitlements; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 9QSE66762D; + INFOPLIST_FILE = UnsummitAuthentication/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.unsummit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + EC4F96B82695E82400B3C9B8 /* Build configuration list for PBXProject "UnsummitAuthentication" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EC4F96CF2695E82500B3C9B8 /* Debug */, + EC4F96D02695E82500B3C9B8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EC4F96D12695E82500B3C9B8 /* Build configuration list for PBXNativeTarget "UnsummitAuthentication" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EC4F96D22695E82500B3C9B8 /* Debug */, + EC4F96D32695E82500B3C9B8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + EC0BA228282AA69E00F8326E /* XCRemoteSwiftPackageReference "JGProgressHUD" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/JonasGessner/JGProgressHUD.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.0.0; + }; + }; + EC1A82582822D0D1008D81BA /* XCRemoteSwiftPackageReference "forgerock-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/ForgeRock/forgerock-ios-sdk.git"; + requirement = { + kind = exactVersion; + version = 4.0.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + EC0BA229282AA69E00F8326E /* JGProgressHUD */ = { + isa = XCSwiftPackageProductDependency; + package = EC0BA228282AA69E00F8326E /* XCRemoteSwiftPackageReference "JGProgressHUD" */; + productName = JGProgressHUD; + }; + EC1A82592822D0D1008D81BA /* FRAuth */ = { + isa = XCSwiftPackageProductDependency; + package = EC1A82582822D0D1008D81BA /* XCRemoteSwiftPackageReference "forgerock-ios-sdk" */; + productName = FRAuth; + }; + EC1A825B2822D0D1008D81BA /* FRCore */ = { + isa = XCSwiftPackageProductDependency; + package = EC1A82582822D0D1008D81BA /* XCRemoteSwiftPackageReference "forgerock-ios-sdk" */; + productName = FRCore; + }; + EC1A825D2822D0D1008D81BA /* FRFacebookSignIn */ = { + isa = XCSwiftPackageProductDependency; + package = EC1A82582822D0D1008D81BA /* XCRemoteSwiftPackageReference "forgerock-ios-sdk" */; + productName = FRFacebookSignIn; + }; + EC1A825F2822D0D1008D81BA /* FRGoogleSignIn */ = { + isa = XCSwiftPackageProductDependency; + package = EC1A82582822D0D1008D81BA /* XCRemoteSwiftPackageReference "forgerock-ios-sdk" */; + productName = FRGoogleSignIn; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = EC4F96B52695E82400B3C9B8 /* Project object */; +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..ca863a55 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,77 @@ +{ + "pins" : [ + { + "identity" : "appauth-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/openid/AppAuth-iOS.git", + "state" : { + "revision" : "33660c271c961f8ce1084cc13f2ea8195e864f7d", + "version" : "1.5.0" + } + }, + { + "identity" : "facebook-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/facebook/facebook-ios-sdk.git", + "state" : { + "revision" : "5c7367dadcbe504702c041621dc09752bf2cd747", + "version" : "16.0.1" + } + }, + { + "identity" : "forgerock-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ForgeRock/forgerock-ios-sdk.git", + "state" : { + "revision" : "d78e9f26be17df12476198a4fae1ef532432ab8b", + "version" : "4.0.0" + } + }, + { + "identity" : "googlesignin-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleSignIn-iOS.git", + "state" : { + "revision" : "7932d33686c1dc4d7df7a919aae47361d1cdfda4", + "version" : "7.0.0" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "4e9bbf2808b8fee444e84a48f5f3c12641987d3e", + "version" : "1.7.2" + } + }, + { + "identity" : "gtmappauth", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GTMAppAuth.git", + "state" : { + "revision" : "b9d1683be336ba8c8d1c6867bafeb056a5399700", + "version" : "1.3.0" + } + }, + { + "identity" : "jgprogresshud", + "kind" : "remoteSourceControl", + "location" : "https://github.com/JonasGessner/JGProgressHUD.git", + "state" : { + "revision" : "78d7cd35f1d90ff74fd82e486f2cbe4b24be8cf9", + "version" : "2.2.0" + } + }, + { + "identity" : "joseswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/airsidemobile/JOSESwift.git", + "state" : { + "revision" : "10ed3b6736def7c26eb87135466b1cb46ea7e37f", + "version" : "2.4.0" + } + } + ], + "version" : 2 +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/AppDelegate.swift b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/AppDelegate.swift new file mode 100644 index 00000000..2be899de --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/AppDelegate.swift @@ -0,0 +1,40 @@ +// +// AppDelegate.swift +// BioExample +// +// Created by George Bafaloukas on 07/07/2021. +// + +// Swift +// +// AppDelegate.swift +import UIKit +import FRAuth + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + + return true + } + + // This method is one of AppDelegate protocol that is invoked when iOS tries to open the app using the app's dedicated URL + func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { + + let resumeURL = url // validate the resumeURI contains 'suspendedId' parameter + + // With given resumeURI, use FRSession to resume authenticate flow + FRSession.authenticate(resumeURI: resumeURL) { (token: Token?, node, error) in + // Handle Node, or the result of continuing the the authentication flow + } + + return true + } + + +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/AccentColor.colorset/Contents.json b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/AppIcon.appiconset/Contents.json b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..9221b9bb --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/Contents.json b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/Contents.json new file mode 100644 index 00000000..81c78a4e --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "approved@1x.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "approved@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "approved@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@1x.png b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@1x.png new file mode 100644 index 00000000..66c54a47 Binary files /dev/null and b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@1x.png differ diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@2x.png b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@2x.png new file mode 100644 index 00000000..318b554f Binary files /dev/null and b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@2x.png differ diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@3x.png b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@3x.png new file mode 100644 index 00000000..ba811b25 Binary files /dev/null and b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/ApprovedIcon.imageset/approved@3x.png differ diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/Contents.json b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/pebble-logo.imageset/Contents.json b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/pebble-logo.imageset/Contents.json new file mode 100644 index 00000000..0787471a --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/pebble-logo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "pebble-logo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/pebble-logo.imageset/pebble-logo.png b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/pebble-logo.imageset/pebble-logo.png new file mode 100644 index 00000000..278a8afe Binary files /dev/null and b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Assets.xcassets/pebble-logo.imageset/pebble-logo.png differ diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/AuthenticatedViewController.swift b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/AuthenticatedViewController.swift new file mode 100644 index 00000000..15ee451d --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/AuthenticatedViewController.swift @@ -0,0 +1,89 @@ +// +// AuthenticatedViewController.swift +// UnsummitAuthentication +// +// Created by George Bafaloukas on 10/05/2022. +// + +import UIKit +import FRAuth +import JGProgressHUD + +class AuthenticatedViewController: UIViewController { + + @IBOutlet weak var pebbleLogo: UIImageView! + @IBOutlet weak var nameLabel: UILabel! + @IBOutlet weak var infoTextView: UITextView! + @IBOutlet weak var logoutButton: UIButton! + + private var infoText: String = "" + private let hud = JGProgressHUD() + + override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.setHidesBackButton(true, animated: false) + self.updateStatus() + let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) + self.pebbleLogo.addGestureRecognizer(tap) + self.infoTextView.alpha = 0.0 + view.addGestureRecognizer(tap) + } + + @objc func handleTap() { + UIView.animate(withDuration: 1.0, delay: 0.1, options: [], animations: { + self.infoTextView.alpha = 1.0 + self.pebbleLogo.alpha = 0.0 + }, completion: nil) + } + + @IBAction func SettingsAction(_ sender: Any) { + self.performSegue(withIdentifier: "OpenSettings", sender: self) + } + + // MARK: - Private Methods + + private func updateStatus() { + if let user = FRUser.currentUser { + self.hud.textLabel.text = "Loading user info" + self.hud.show(in: self.view) + // Call the User Info endpoint and parse the results + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + user.getUserInfo { userInfoObject, error in + if let userInfoObject = userInfoObject { + self.infoText = "User is authenticated \n \n \n" + self.infoText = self.infoText + (userInfoObject.userInfo.debugDescription) + "\n \n" + self.infoText = self.infoText + (user.token?.debugDescription ?? "") + "\n \n" + self.updateText(userInfoObject) + } else { + self.logOutAndDismiss() + } + } + } + + } + } + + private func updateText(_ userInfoObject: UserInfo) { + DispatchQueue.main.async { + self.nameLabel.text = "Welcome \(userInfoObject.name ?? "")" + self.infoTextView.text = self.infoText + self.hud.dismiss() + } + } + + private func logOutAndDismiss() { + self.hud.textLabel.text = "Loging out" + self.hud.show(in: self.view) + FRUser.currentUser?.logout() + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + self.hud.dismiss(animated: true) + self.navigationController?.popViewController(animated: true) + } + } + + @IBAction func logoutAction(_ sender: Any) { + // Call Logout and navigate back + self.logOutAndDismiss() + } + +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Base.lproj/LaunchScreen.storyboard b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..865e9329 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Base.lproj/Main.storyboard b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f409de43 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Base.lproj/Main.storyboard @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/BioExample.entitlements b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/BioExample.entitlements new file mode 100644 index 00000000..d0dbd32d --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/BioExample.entitlements @@ -0,0 +1,10 @@ + + + + + keychain-access-groups + + $(AppIdentifierPrefix)com.forgerock.unsummitauthentication + + + diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Info.plist b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Info.plist new file mode 100644 index 00000000..d1872b75 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/Info.plist @@ -0,0 +1,110 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleURLTypes + + + CFBundleURLSchemes + + fb362269018758347 + + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.googleusercontent.apps.1091765886811-o3nq2d5non08be66qboob6qa3tbcaau1 + + + + CFBundleTypeRole + Editor + CFBundleURLName + com.forgerock.ios.frexample + CFBundleURLSchemes + + frauth + + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.googleusercontent.apps.662984678191-rh9p528s1cm26i8kgg1d22e6gdi7c279 + + + + CFBundleVersion + 1 + FacebookAppID + + FacebookClientToken + + FacebookDisplayName + + LSApplicationQueriesSchemes + + fbapi + fbapi20130214 + fbapi20130410 + fbapi20130702 + fbapi20131010 + fbapi20131219 + fbapi20140410 + fbapi20140116 + fbapi20150313 + fbapi20150629 + fbapi20160328 + fbauth + fb-messenger-share-api + fbauth2 + fbshareextension + + LSRequiresIPhoneOS + + NSBluetoothAlwaysUsageDescription + Use Bluetooth + NSFaceIDUsageDescription + Use FaceID for Web Authentication + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/LoginViewController.swift b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/LoginViewController.swift new file mode 100644 index 00000000..25cfb503 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/LoginViewController.swift @@ -0,0 +1,320 @@ +// +// ViewController.swift +// BioExample +// +// Created by George Bafaloukas on 07/07/2021. +// + +import UIKit +import FRAuth +import FRCore +import WebKit +import JGProgressHUD + +class LoginViewController: UIViewController { + + @IBOutlet weak var statusLabel: UILabel! + @IBOutlet weak var loginStackView: UIStackView! + @IBOutlet weak var nextButton: UIButton! + @IBOutlet weak var step1StackView: UIStackView! + @IBOutlet weak var step2StackView: UIStackView! + @IBOutlet weak var step3StackView: UIStackView! + @IBOutlet weak var step4StackView: UIStackView! + + private var currentNode: Node? + private var textFieldArray = [UITextField]() + private let hud = JGProgressHUD() + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + self.statusLabel?.text = "Welcome to Pebble Bank" + let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) + view.addGestureRecognizer(tap) // Add gesture recognizer to background view + self.navigationItem.setHidesBackButton(true, animated: false) + + // START the FR SDK + do { + try FRAuth.start(options: PebbleBankUtilities.frCongiguration()) + print("SDK initialized successfully") + FRLog.setLogLevel([.error, .network]) + + } + catch { + print(error) + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.step1StackView.alpha = 0.0 + self.step2StackView.alpha = 0.0 + self.step3StackView.alpha = 0.0 + self.step4StackView.alpha = 0.0 + + self.updateStatus() + self.hud.textLabel.text = "Loading" + self.hud.show(in: self.view) + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.beginAuthentication() + } + } + + // MARK: - Private Methods + private func beginAuthentication() { + if let _ = FRUser.currentUser { + self.updateStatus() + self.goToNext() + } else { + if currentNode == nil { + self.hud.textLabel.text = "Calling journey" + // Call the default Login Journey or the Biometrics Journey + let journeyName = (UserDefaults.standard.object(forKey: PebbleBankUtilities.biometricsEnabledKey) as? Bool ?? false) ? PebbleBankUtilities.biometricsAuthenticationJourney : PebbleBankUtilities.mainAuthenticationJourney + + FRSession.authenticate(authIndexValue: journeyName) { (result: Token?, node, error) in + self.handleNode(token: result, node: node, error: error) + } + } else { + // Submit the Username/Password to AM + guard let thisNode = currentNode else { return } + var index = 0 + for textField in textFieldArray { + if let thisCallback: SingleValueCallback = thisNode.callbacks[index] as? SingleValueCallback { + thisCallback.setValue(textField.text) + } + index += 1 + } + + self.textFieldArray = [UITextField]() + self.loginStackView.removeAllArrangedSubviews() + self.step2StackView.alpha = 1.0 + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.step3StackView.alpha = 1.0 + self.currentNode?.next { (token: Token?, node, error) in + self.handleNode(token: token, node: node, error: error) + } + } + + } + } + } + + private func updateStatus() { + DispatchQueue.main.async { + if let _ = FRUser.currentUser { + self.statusLabel?.text = "User is authenticated" + self.nextButton.setTitle("Logout", for: .normal) + } + else { + self.statusLabel?.text = "Welcome to Pebble Bank" + self.nextButton.setTitle("Login", for: .normal) + } + } + } + + private func goToNext() { + self.performSegue(withIdentifier: "goToAuthenticated", sender: self) + } + + @objc func handleTap() { + self.view.endEditing(true) + } + + @IBAction func loginButtonPressed(sender: UIButton) { + print("Login button is pressed") + self.hud.textLabel.text = "Authenticating" + self.hud.show(in: self.view) + self.step1StackView.alpha = 1.0 + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.beginAuthentication() + } + } + + func handleNode(token: Token?, node: Node?, error: Error?) { + self.currentNode = node + if let _ = token { + print("User is authenticated") + FRUser.currentUser?.getAccessToken(completion: { user, error in + if error != nil { + print("User unable to get AccessToken with error: \(String(describing: error?.localizedDescription))") + } + DispatchQueue.main.async { + self.step4StackView.alpha = 1.0 + self.hud.dismiss(afterDelay: 1.0) + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.updateStatus() + self.goToNext() + } + } + }) + } + else if let node = node { + print("Node object received, handle the node") + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.hud.dismiss() + for callback: Callback in node.callbacks { + + let textField = UITextField(frame: CGRect.zero) + textField.autocorrectionType = .no + textField.translatesAutoresizingMaskIntoConstraints = false + textField.backgroundColor = .white + textField.textColor = .black + textField.autocapitalizationType = .none + textField.borderStyle = .roundedRect + + if let nameCallback = callback as? NameCallback { + textField.placeholder = nameCallback.prompt + self.loginStackView.addArrangedSubview(textField) + self.textFieldArray.append(textField) + } + if let passwordCallback = callback as? PasswordCallback { + textField.isSecureTextEntry = true + textField.placeholder = passwordCallback.prompt + self.loginStackView.addArrangedSubview(textField) + self.textFieldArray.append(textField) + } + + if let choiceCallback = callback as? ChoiceCallback { + let alert = UIAlertController(title: "Choice", message: choiceCallback.prompt, preferredStyle: .alert) + for choice in choiceCallback.choices { + let action = UIAlertAction(title: choice, style: .default) { (action) in + if let title = action.title, let index = choiceCallback.choices.firstIndex(of: title) { + choiceCallback.setValue(index) + node.next { (token: Token?, node, error) in + self.handleNode(token: token, node: node, error: error) + } + } + } + alert.addAction(action) + } + + DispatchQueue.main.async { + self.present(alert, animated: true, completion: nil) + } + } + + if let authenticationCallback = callback as? WebAuthnAuthenticationCallback { + authenticationCallback.delegate = self + + // Note that the `Node` parameter in `.authenticate()` is an optional parameter. + // If the node is provided, the SDK automatically sets the assertion to the designated HiddenValueCallback + authenticationCallback.authenticate(node: node, usePasskeysIfAvailable: PebbleBankUtilities.usePasskeysIfAvailable) { (assertion) in + // Authentication is successful + // Submit the Node using Node.next() + node.next { (token: Token?, node, error) in + self.handleNode(token: token, node: node, error: error) + } + } onError: { (error) in + // An error occurred during the authentication process + // Submit the Node using Node.next() + let alert = UIAlertController(title: "WebAuthnError", message: "Something went wrong authenticating the device", preferredStyle: .alert) + let okAction = UIAlertAction(title: "OK", style: .default, handler: { (action) in + node.next { (token: Token?, node, error) in + self.handleNode(token: token, node: node, error: error) + } + }) + alert.addAction(okAction) + DispatchQueue.main.async { + self.present(alert, animated: true, completion: nil) + } + } + } + + if let registrationCallback = callback as? WebAuthnRegistrationCallback { + registrationCallback.delegate = self + + // Note that the `Node` parameter in `.register()` is an optional parameter. + // If the node is provided, the SDK automatically sets the error outcome or attestation to the designated HiddenValueCallback + registrationCallback.register(node: node, deviceName: UIDevice.current.name, usePasskeysIfAvailable: PebbleBankUtilities.usePasskeysIfAvailable) { (attestation) in + // Registration is successful + // Submit the Node using Node.next() + node.next { (token: Token?, node, error) in + self.handleNode(token: token, node: node, error: error) + } + } onError: { (error) in + // An error occurred during the registration process + // Submit the Node using Node.next() + let alert = UIAlertController(title: "WebAuthnError", message: "Something went wrong registering the device", preferredStyle: .alert) + let okAction = UIAlertAction(title: "OK", style: .default, handler: { (action) in + node.next { (token: Token?, node, error) in + self.handleNode(token: token, node: node, error: error) + } + }) + alert.addAction(okAction) + DispatchQueue.main.async { + self.present(alert, animated: true, completion: nil) + } + } + } + + } + } + } + else { + print ("Something went wrong: \(String(describing: error))") + } + } +} + +extension LoginViewController: PlatformAuthenticatorRegistrationDelegate, PlatformAuthenticatorAuthenticationDelegate { + func localKeyExistsAndPasskeysAreAvailable() {} + + // MARK: PlatformAuthenticatorRegistrationDelegate + + func excludeCredentialDescriptorConsent(consentCallback: @escaping WebAuthnUserConsentCallback) { + let alert = UIAlertController(title: "Exclude Credentials", message: nil, preferredStyle: .alert) + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in + consentCallback(.reject) + }) + let allowAction = UIAlertAction(title: "Allow", style: .default) { (_) in + consentCallback(.allow) + } + alert.addAction(cancelAction) + alert.addAction(allowAction) + + DispatchQueue.main.async { + self.present(alert, animated: true, completion: nil) + } + } + + func createNewCredentialConsent(keyName: String, rpName: String, rpId: String?, userName: String, userDisplayName: String, consentCallback: @escaping WebAuthnUserConsentCallback) { + let alert = UIAlertController(title: "Create Credentials", message: "KeyName: \(keyName) | Relying Party Name: \(rpName) | User Name: \(userName)", preferredStyle: .alert) + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in + consentCallback(.reject) + }) + let allowAction = UIAlertAction(title: "Allow", style: .default) { (_) in + consentCallback(.allow) + } + alert.addAction(cancelAction) + alert.addAction(allowAction) + + + DispatchQueue.main.async { + self.present(alert, animated: true, completion: nil) + } + } + + // MARK: PlatformAuthenticatorAuthenticationDelegate + func selectCredential(keyNames: [String], selectionCallback: @escaping WebAuthnCredentialsSelectionCallback) { + let actionSheet = UIAlertController(title: "Select Credentials", message: nil, preferredStyle: .actionSheet) + + for keyName in keyNames { + actionSheet.addAction(UIAlertAction(title: keyName, style: .default, handler: { (action) in + selectionCallback(keyName) + })) + } + + actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) in + selectionCallback(nil) + })) + + if actionSheet.popoverPresentationController != nil { + actionSheet.popoverPresentationController?.sourceView = self.view + actionSheet.popoverPresentationController?.sourceRect = self.view.bounds + } + + DispatchQueue.main.async { + self.present(actionSheet, animated: true, completion: nil) + } + } +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/PebbleBankUtilities.swift b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/PebbleBankUtilities.swift new file mode 100644 index 00000000..8403e3f9 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/PebbleBankUtilities.swift @@ -0,0 +1,78 @@ +// +// PebbleBankUtilities.swift +// UnsummitAuthentication +// +// Created by George Bafaloukas on 24/07/2023. +// + +import UIKit +import FRAuth +import FRCore + +class PebbleBankUtilities: NSObject { + static let usePasskeysIfAvailable = true + static let biometricsEnabledKey = "BiometricsEnabled" + static let mainAuthenticationJourney = "Login" + static let biometricsRegistrationJourney = "BlogWebAuthnRegistration" + static let biometricsAuthenticationJourney = "BlogWebAuthnAuthentication" + static let amURL = [AM URL] + static let cookieName = [COOKIE NAME] + static let realm = "alpha" + static let oauthClientId = [CLIENT ID] + static let oauthRedirectURI = "frauth://com.forgerock.ios.frexample" + static let oauthScopes = "openid profile email address" + + static func frCongiguration() -> FROptions { + return FROptions(url: self.amURL, realm: self.realm, cookieName: self.cookieName, authServiceName: self.mainAuthenticationJourney, oauthClientId: self.oauthClientId, oauthRedirectUri: self.oauthRedirectURI, oauthScope: self.oauthScopes) + } + + static func registerRequestInterceptors() { + FRRequestInterceptorRegistry.shared.registerInterceptors( + interceptors: [ + ForceAuthInterceptorBiometricRegistration() + ] + ) + } +} + + +// MARK: - Extensions + +extension UIStackView { + + func removeAllArrangedSubviews() { + + let removedSubviews = arrangedSubviews.reduce([]) { (allSubviews, subview) -> [UIView] in + self.removeArrangedSubview(subview) + return allSubviews + [subview] + } + + // Deactivate all constraints + NSLayoutConstraint.deactivate(removedSubviews.flatMap({ $0.constraints })) + + // Remove the views from self + removedSubviews.forEach({ $0.removeFromSuperview() }) + } +} + +// MARK: - Request Interceptors +class ForceAuthInterceptorBiometricRegistration: RequestInterceptor { + func intercept(request: Request, action: Action) -> Request { + if (action.type == "START_AUTHENTICATE" || action.type == "AUTHENTICATE"), + let payload = action.payload, + let treeName = payload["tree"] as? String, + treeName == PebbleBankUtilities.biometricsRegistrationJourney, + let sessionToken = FRSession.currentSession?.sessionToken?.value + { + var headers = request.headers + headers["Cookie"] = "\(PebbleBankUtilities.cookieName)=\(sessionToken)" + var urlParams = request.urlParams + urlParams["ForceAuth"] = "true" + let newRequest = Request(url: request.url, method: request.method, headers: headers, bodyParams: request.bodyParams, urlParams: urlParams, requestType: request.requestType, responseType: request.responseType, timeoutInterval: request.timeoutInterval) + return newRequest + } + else { + return request + } + } +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/SettingsViewController.swift b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/SettingsViewController.swift new file mode 100644 index 00000000..bf275b76 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/SettingsViewController.swift @@ -0,0 +1,133 @@ +// +// SettingsViewController.swift +// UnsummitAuthentication +// +// Created by George Bafaloukas on 24/07/2023. +// + +import UIKit +import FRAuth +import JGProgressHUD + +class SettingsViewController: UIViewController { + + @IBOutlet weak var faceIDSwitch: UISwitch! + private var currentNode: Node? + private let hud = JGProgressHUD() + + override func viewDidLoad() { + PebbleBankUtilities.registerRequestInterceptors() + self.faceIDSwitch.isOn = UserDefaults.standard.object(forKey: PebbleBankUtilities.biometricsEnabledKey) as? Bool ?? false + } + + @IBAction func changeFaceIDAction(_ sender: UISwitch) { + if sender.isOn { + FRSession.authenticate(authIndexValue: PebbleBankUtilities.biometricsRegistrationJourney) { result, node, error in + self.handleNodes(token: result, node: node, error: error) + } + } else { + UserDefaults.standard.set(nil, forKey: PebbleBankUtilities.biometricsEnabledKey) + } + } + + // MARK: - Private Methods + + func handleNodes(token: Token?, node: Node?, error: Error?) { + if let _ = token { + FRUser.currentUser?.getAccessToken(completion: { user, error in + if error != nil { + print("User unable to get AccessToken with error: \(String(describing: error?.localizedDescription))") + FRUser.currentUser?.logout() + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.hud.dismiss(animated: true) + self.navigationController?.popToRootViewController(animated: true) + return + } + } + DispatchQueue.main.async { + UserDefaults.standard.set(self.faceIDSwitch.isOn, forKey: PebbleBankUtilities.biometricsEnabledKey) + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.hud.dismiss(animated: true) + self.navigationController?.popViewController(animated: true) + } + } + }) + } else if let node = node { + self.currentNode = node + for callback in node.callbacks { + if let passwordCallback = callback as? PasswordCallback { + let alert = UIAlertController(title: "Verify account", message: "Please enter your Password", preferredStyle: .alert) + + DispatchQueue.main.async { + alert.addTextField { (textField) in + textField.placeholder = passwordCallback.prompt + textField.isSecureTextEntry = true + textField.autocorrectionType = .no + textField.autocapitalizationType = .none + } + + if let textfields = alert.textFields, textfields.count > 0 { + let submitAction = UIAlertAction(title: "Next", style: .default) { (_) in + for (index, textField) in textfields.enumerated() { + if let thisCallback = node.callbacks[index] as? SingleValueCallback { + thisCallback.setValue(textField.text) + } + } + node.next { (token: Token?, node, error) in + self.handleNodes(token: token, node: node, error: error) + } + } + alert.addAction(submitAction) + } + self.present(alert, animated: true, completion: nil) + } + } + if let registrationCallback = callback as? WebAuthnRegistrationCallback { + registrationCallback.delegate = self + DispatchQueue.main.async { + // Note that the `Node` parameter in `.register()` is an optional parameter. + // If the node is provided, the SDK automatically sets the error outcome or attestation to the designated HiddenValueCallback + registrationCallback.register(node: node, deviceName: UIDevice.current.name, usePasskeysIfAvailable: PebbleBankUtilities.usePasskeysIfAvailable) { (attestation) in + // Registration is successful + // Submit the Node using Node.next() + node.next { (token: Token?, node, error) in + DispatchQueue.main.async { + self.hud.textLabel.text = "Registering" + self.hud.show(in: self.view) + } + self.handleNodes(token: token, node: node, error: error) + } + } onError: { (error) in + // An error occurred during the registration process + // Submit the Node using Node.next() + let alert = UIAlertController(title: "WebAuthnError", message: "Something went wrong registering the device", preferredStyle: .alert) + let okAction = UIAlertAction(title: "OK", style: .default, handler: { (action) in + node.next { (token: Token?, node, error) in + self.handleNodes(token: token, node: node, error: error) + } + }) + alert.addAction(okAction) + DispatchQueue.main.async { + self.present(alert, animated: true, completion: nil) + } + } + } + } + } + } else { + print("Something went wrong with error: \(String(describing: error?.localizedDescription))") + FRUser.currentUser?.logout() + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.hud.dismiss(animated: true) + self.navigationController?.popToRootViewController(animated: true) + return + } + } + } +} + +extension SettingsViewController: PlatformAuthenticatorRegistrationDelegate { + func excludeCredentialDescriptorConsent(consentCallback: @escaping WebAuthnUserConsentCallback) {} + + func createNewCredentialConsent(keyName: String, rpName: String, rpId: String?, userName: String, userDisplayName: String, consentCallback: @escaping WebAuthnUserConsentCallback) {} +} diff --git a/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/UnsummitAuthentication.entitlements b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/UnsummitAuthentication.entitlements new file mode 100644 index 00000000..f5214aa5 --- /dev/null +++ b/SampleApps/PasskeysSample/UnsummitAuthentication/UnsummitAuthentication/UnsummitAuthentication.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.associated-domains + + webcredentials:example.com + + + diff --git a/SampleApps/QuickstartExample/Quickstart.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SampleApps/QuickstartExample/Quickstart.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/SampleApps/QuickstartExample/Quickstart.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + +