From 7a4978ad44ad59061146fe5b34e0b7b8f71b42de Mon Sep 17 00:00:00 2001 From: Ishan Gulhane <26394621+ishangulhane@users.noreply.github.com> Date: Fri, 8 Jun 2018 06:44:30 -0500 Subject: [PATCH] Rebrand, UserInfo, Swift 4 migration and token validation (#141) * Migrate to Swift 4 * Changes objective-c inference to default * Validates tokens (#137) * sync development branch * Add token validation * fix spacing * update deployment target * remove trailing whitespace * rebrand bluemix to ibm cloud (#140) * rebrand bluemix to ibm cloud * update gitignore file * update readme * udpate branding * rename workspace to IBMCloudAppID * Codacy Error Fix (#142) * rebrand bluemix to ibm cloud * update gitignore file * update readme * udpate branding * rename workspace to IBMCloudAppID * Codacy fix * codacy fix --- .gitignore | 6 +- .slather.yml | 8 +- .swift-version | 2 +- .travis.yml | 6 +- BluemixAppID.podspec | 14 - .../UserInterfaceState.xcuserstate | Bin 33273 -> 0 bytes IBMCloudAppID.podspec | 15 + .../project.pbxproj | 198 ++++--- .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcschemes/IBMCloudAppID.xcscheme | 36 +- .../xcschemes/IBMCloudAppIDTests.xcscheme | 12 +- .../AppIDAuthorizationManagerTests.swift | 64 +- .../AppIDTestConstants.swift | 22 +- .../AppIDTests.swift | 60 +- .../AuthorizationHeaderHelperTests.swift | 16 +- .../AuthorizationManagerTests.swift | 87 +-- .../AuthorizationUIManagerTests.swift | 58 +- .../ConfigTests.swift | 16 +- .../Info.plist | 2 +- .../OAuthClientTests.swift | 8 +- .../PreferencesTests.swift | 9 +- .../RegistrationManagerTests.swift | 88 +-- .../SecurityUtilsTests.swift | 26 +- .../TestHelpers.swift | 16 +- .../TokenManagerTests.swift | 545 +++++++++++++----- .../TokenTests.swift | 8 +- .../UserProfileTests.swift | 4 +- .../UtilsTests.swift | 28 +- Podfile | 16 +- README.md | 26 +- Source/BluemixAppID/.DS_Store | Bin 6148 -> 0 bytes .../api/AppID.swift | 40 +- .../api/AppIDAuthorizationManager.swift | 0 .../api/AuthorizationDelegate.swift | 0 .../api/AuthorizationError.swift | 0 .../api/IdentityToken.swift | 0 .../api/LoginWidget.swift | 0 .../api/TokenResponseDelegate.swift | 0 .../api/Tokens/AccessToken.swift | 0 .../api/Tokens/OAuthClient.swift | 0 .../api/Tokens/RefreshToken.swift | 0 .../api/UserAttributeError.swift | 0 .../api/UserProfileError.swift | 0 .../api/UserProfileManager.swift | 0 .../internal/AppIDConstants.swift | 81 ++- .../internal/AppIDError.swift | 0 .../internal/AuthorizationHeaderHelper.swift | 0 .../internal/AuthorizationManager.swift | 84 ++- .../internal/AuthorizationUIManager.swift | 0 .../internal/Config.swift | 28 +- .../internal/JSONPreference.swift | 0 .../internal/LoginWidgetImpl.swift | 8 +- .../internal/OAuthManager.swift | 0 .../internal/PreferenceManager.swift | 0 .../internal/RegistrationManager.swift | 2 +- .../internal/SecurityUtils.swift | 120 ++-- .../internal/StringPreference.swift | 0 .../internal/TokenManager.swift | 144 ++++- .../internal/UserProfileManagerImpl.swift | 0 .../internal/Utils.swift | 14 +- .../internal/safariView.swift | 0 .../internal/tokens/AbstractToken.swift | 0 .../internal/tokens/AccessTokenImpl.swift | 0 .../internal/tokens/IdentityTokenImpl.swift | 0 .../internal/tokens/OAuthClientImpl.swift | 0 .../internal/tokens/RefreshTokenImpl.swift | 0 .../{BluemixAppID.h => IBMCloudAppID.h} | 0 scripts/release.sh | 2 +- 69 files changed, 1153 insertions(+), 774 deletions(-) delete mode 100755 BluemixAppID.podspec delete mode 100644 BluemixAppID.xcodeproj/project.xcworkspace/xcuserdata/odedb.xcuserdatad/UserInterfaceState.xcuserstate create mode 100755 IBMCloudAppID.podspec rename {BluemixAppID.xcodeproj => IBMCloudAppID.xcodeproj}/project.pbxproj (86%) rename {BluemixAppID.xcodeproj => IBMCloudAppID.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) create mode 100644 IBMCloudAppID.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename BluemixAppID.xcodeproj/xcshareddata/xcschemes/BluemixAppID.xcscheme => IBMCloudAppID.xcodeproj/xcshareddata/xcschemes/IBMCloudAppID.xcscheme (74%) rename BluemixAppID.xcodeproj/xcshareddata/xcschemes/BluemixAppIDTests.xcscheme => IBMCloudAppID.xcodeproj/xcshareddata/xcschemes/IBMCloudAppIDTests.xcscheme (85%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/AppIDAuthorizationManagerTests.swift (96%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/AppIDTestConstants.swift (52%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/AppIDTests.swift (96%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/AuthorizationHeaderHelperTests.swift (95%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/AuthorizationManagerTests.swift (92%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/AuthorizationUIManagerTests.swift (96%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/ConfigTests.swift (80%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/Info.plist (95%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/OAuthClientTests.swift (97%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/PreferencesTests.swift (96%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/RegistrationManagerTests.swift (96%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/SecurityUtilsTests.swift (96%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/TestHelpers.swift (97%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/TokenManagerTests.swift (67%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/TokenTests.swift (98%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/UserProfileTests.swift (99%) rename {BluemixAppIDTests => IBMCloudAppIDTests}/UtilsTests.swift (97%) delete mode 100644 Source/BluemixAppID/.DS_Store rename Source/{BluemixAppID => IBMCloudAppID}/api/AppID.swift (87%) rename Source/{BluemixAppID => IBMCloudAppID}/api/AppIDAuthorizationManager.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/AuthorizationDelegate.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/AuthorizationError.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/IdentityToken.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/LoginWidget.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/TokenResponseDelegate.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/Tokens/AccessToken.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/Tokens/OAuthClient.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/Tokens/RefreshToken.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/UserAttributeError.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/UserProfileError.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/api/UserProfileManager.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/AppIDConstants.swift (95%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/AppIDError.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/AuthorizationHeaderHelper.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/AuthorizationManager.swift (95%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/AuthorizationUIManager.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/Config.swift (77%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/JSONPreference.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/LoginWidgetImpl.swift (98%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/OAuthManager.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/PreferenceManager.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/RegistrationManager.swift (98%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/SecurityUtils.swift (93%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/StringPreference.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/TokenManager.swift (59%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/UserProfileManagerImpl.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/Utils.swift (93%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/safariView.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/tokens/AbstractToken.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/tokens/AccessTokenImpl.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/tokens/IdentityTokenImpl.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/tokens/OAuthClientImpl.swift (100%) rename Source/{BluemixAppID => IBMCloudAppID}/internal/tokens/RefreshTokenImpl.swift (100%) rename Source/Resources/{BluemixAppID.h => IBMCloudAppID.h} (100%) diff --git a/.gitignore b/.gitignore index f74a8c6..7ca8cc5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -BluemixAppID.xcodeproj/ -BluemixAppID.xcworkspace/ +IBMCloudAppID.xcodeproj/ +IBMCloudAppID.xcworkspace/ Pods/ Podfile.lock .idea/ -*.DS_Store \ No newline at end of file +*.DS_Store diff --git a/.slather.yml b/.slather.yml index 3c20c54..3653a48 100644 --- a/.slather.yml +++ b/.slather.yml @@ -1,6 +1,6 @@ coverage_service: coveralls -workspace: BluemixAppID -xcodeproj: BluemixAppID.xcodeproj -scheme: BluemixAppIDTests +workspace: IBMCloudAppID +xcodeproj: IBMCloudAppID.xcodeproj +scheme: IBMCloudAppIDTests ignore: - - BluemixAppIDTests/* \ No newline at end of file + - IBMCloudAppIDTests/* diff --git a/.swift-version b/.swift-version index 9f55b2c..5186d07 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -3.0 +4.0 diff --git a/.travis.yml b/.travis.yml index a719d71..8cfd001 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ script: # Test that the framework can be installed and built, and passes all unit tests - travis_wait pod update - pod lib lint --allow-warnings - - xcodebuild -workspace 'BluemixAppID.xcworkspace' -scheme 'BluemixAppID' clean build CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO - - travis_retry xcodebuild -workspace 'BluemixAppID.xcworkspace' test -scheme 'BluemixAppIDTests' -destination 'platform=iOS Simulator,name=iPhone 6' -enableCodeCoverage YES - - slather coverage --coveralls --binary-basename BluemixAppID.framework -v + - xcodebuild -workspace 'IBMCloudAppID.xcworkspace' -scheme 'IBMCloudAppID' clean build CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO + - travis_retry xcodebuild -workspace 'IBMCloudAppID.xcworkspace' test -scheme 'IBMCloudAppIDTests' -destination 'platform=iOS Simulator,name=iPhone 6' -enableCodeCoverage YES + - slather coverage --coveralls --binary-basename IBMCloudAppID.framework -v # When merging or pushing to the master branch, release a new version and publish the API documentation #- if [ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ] ; then # bash scripts/release.sh; diff --git a/BluemixAppID.podspec b/BluemixAppID.podspec deleted file mode 100755 index db78a30..0000000 --- a/BluemixAppID.podspec +++ /dev/null @@ -1,14 +0,0 @@ -Pod::Spec.new do |s| - s.name = "BluemixAppID" - s.version = '3.0.1' - s.summary = "AppID Swift SDK" - s.homepage = "https://github.com/ibm-bluemix-mobile-services/appid-clientsdk-swift" - s.license = 'Apache License, Version 2.0' - s.author = { "IBM Bluemix Services Mobile SDK" => "mobilsdk@us.ibm.com" } - - s.source = { :git => 'https://github.com/ibm-bluemix-mobile-services/appid-clientsdk-swift.git', :tag => "#{s.version}" } - s.dependency 'BMSCore' - s.requires_arc = true - s.source_files = 'Source/**/*.swift', 'Source/Resources/BluemixAppID.h' - s.ios.deployment_target = '9.0' -end diff --git a/BluemixAppID.xcodeproj/project.xcworkspace/xcuserdata/odedb.xcuserdatad/UserInterfaceState.xcuserstate b/BluemixAppID.xcodeproj/project.xcworkspace/xcuserdata/odedb.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 4a0341fc24e716e9564f139ed10733b291716077..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33273 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 fha1;7ZfLyP#5N6Y@^S;w8g=`U+ diff --git a/IBMCloudAppID.podspec b/IBMCloudAppID.podspec new file mode 100755 index 0000000..5abf3f2 --- /dev/null +++ b/IBMCloudAppID.podspec @@ -0,0 +1,15 @@ +Pod::Spec.new do |s| + s.name = "IBMCloudAppID" + s.version = '4.0.0' + s.summary = "AppID Swift SDK" + s.homepage = "https://github.com/ibm-cloud-security/appid-clientsdk-swift" + s.license = 'Apache License, Version 2.0' + s.author = { "IBM Cloud Services Mobile SDK" => "mobilsdk@us.ibm.com" } + s.swift_version = "4.0" + s.source = { :git => 'https://github.com/ibm-cloud-security/appid-clientsdk-swift.git', :tag => "#{s.version}" } + s.dependency 'BMSCore' + s.dependency 'JOSESwift' + s.requires_arc = true + s.source_files = 'Source/**/*.swift', 'Source/Resources/IBMCloudAppID.h' + s.ios.deployment_target = '10.0' +end diff --git a/BluemixAppID.xcodeproj/project.pbxproj b/IBMCloudAppID.xcodeproj/project.pbxproj similarity index 86% rename from BluemixAppID.xcodeproj/project.pbxproj rename to IBMCloudAppID.xcodeproj/project.pbxproj index 6af969a..b0e3578 100644 --- a/BluemixAppID.xcodeproj/project.pbxproj +++ b/IBMCloudAppID.xcodeproj/project.pbxproj @@ -10,11 +10,11 @@ 181050421EE1BD9200AAA443 /* TokenResponseDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181050411EE1BD9200AAA443 /* TokenResponseDelegate.swift */; }; 4D42CF8A20173BD200EF40B6 /* RefreshToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D42CF8920173BD200EF40B6 /* RefreshToken.swift */; }; 4D42CF8C20173BDD00EF40B6 /* RefreshTokenImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D42CF8B20173BDD00EF40B6 /* RefreshTokenImpl.swift */; }; - 686FA7AB6F9EE8ACF04FFE5B /* Pods_BluemixAppID.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9518D9FBE5C06EEB62E45B4 /* Pods_BluemixAppID.framework */; }; - 9178A9196CA83023A3A1FC90 /* Pods_BluemixAppIDTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D5F58BDE9E7A759720873B7 /* Pods_BluemixAppIDTests.framework */; }; - BDC0D53F1E5EF68300444F9E /* UserAttributeManagerImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDC0D53E1E5EF68300444F9E /* UserAttributeManagerImpl.swift */; }; - BDF5878B1E65736B00393C0C /* BuildFile in Sources */ = {isa = PBXBuildFile; }; - BDF5878F1E66C55A00393C0C /* UserAttributeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDF5878E1E66C55A00393C0C /* UserAttributeTests.swift */; }; + 6749E62C81CCD62984862D58 /* Pods_IBMCloudAppID.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B1AE9343AB77B8B9C396E21 /* Pods_IBMCloudAppID.framework */; }; + 9539BBDF532A13A970EB051F /* Pods_IBMCloudAppIDTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB32128A91C6C77CEBDAC128 /* Pods_IBMCloudAppIDTests.framework */; }; + BDC0D53F1E5EF68300444F9E /* UserProfileManagerImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDC0D53E1E5EF68300444F9E /* UserProfileManagerImpl.swift */; }; + BDF5878B1E65736B00393C0C /* (null) in Sources */ = {isa = PBXBuildFile; }; + BDF5878F1E66C55A00393C0C /* UserProfileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDF5878E1E66C55A00393C0C /* UserProfileTests.swift */; }; EF3B3BE21E55C4E900DFFF13 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF3B3BE11E55C4E900DFFF13 /* AppDelegate.swift */; }; EF3B3BE41E55C4E900DFFF13 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF3B3BE31E55C4E900DFFF13 /* ViewController.swift */; }; EF3B3BE71E55C4E900DFFF13 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EF3B3BE51E55C4E900DFFF13 /* Main.storyboard */; }; @@ -67,8 +67,8 @@ EFBA20681E51F7D9000EB3F5 /* OAuthClientImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFBA20141E51F7D9000EB3F5 /* OAuthClientImpl.swift */; }; EFBA206A1E51F7D9000EB3F5 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFBA20151E51F7D9000EB3F5 /* Utils.swift */; }; EFBA206D1E51F7D9000EB3F5 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = EFBA20161E51F7D9000EB3F5 /* Info.plist */; }; - EFBBC76B1DF99BF6000CE39A /* BluemixAppID.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EFBBC7541DF99AFA000CE39A /* BluemixAppID.framework */; }; - EFD0251B1E55FC8D00AE1803 /* BluemixAppID.h in Headers */ = {isa = PBXBuildFile; fileRef = EFD0251A1E55FC8D00AE1803 /* BluemixAppID.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EFBBC76B1DF99BF6000CE39A /* IBMCloudAppID.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EFBBC7541DF99AFA000CE39A /* IBMCloudAppID.framework */; }; + EFD0251B1E55FC8D00AE1803 /* IBMCloudAppID.h in Headers */ = {isa = PBXBuildFile; fileRef = EFD0251A1E55FC8D00AE1803 /* IBMCloudAppID.h */; settings = {ATTRIBUTES = (Public, ); }; }; EFE8DC1D1DFDAE920039A5F2 /* BMSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EFE8DC1C1DFDAE920039A5F2 /* BMSCore.framework */; }; /* End PBXBuildFile section */ @@ -91,14 +91,20 @@ /* Begin PBXFileReference section */ 181050411EE1BD9200AAA443 /* TokenResponseDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenResponseDelegate.swift; sourceTree = ""; }; + 3A523D88E31CC7EC37CAFA1D /* Pods-IBMCloudAppID.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IBMCloudAppID.release.xcconfig"; path = "Pods/Target Support Files/Pods-IBMCloudAppID/Pods-IBMCloudAppID.release.xcconfig"; sourceTree = ""; }; 4D42CF8920173BD200EF40B6 /* RefreshToken.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshToken.swift; sourceTree = ""; }; 4D42CF8B20173BDD00EF40B6 /* RefreshTokenImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshTokenImpl.swift; sourceTree = ""; }; + 650D1FFAD2CCE197FAA0DE4F /* Pods-IBMCloudAppIDTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IBMCloudAppIDTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-IBMCloudAppIDTests/Pods-IBMCloudAppIDTests.release.xcconfig"; sourceTree = ""; }; 66E951CC5B401814BE794DBE /* Pods-BluemixAppIDTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BluemixAppIDTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BluemixAppIDTests/Pods-BluemixAppIDTests.debug.xcconfig"; sourceTree = ""; }; + 8B1AE9343AB77B8B9C396E21 /* Pods_IBMCloudAppID.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IBMCloudAppID.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8D5F58BDE9E7A759720873B7 /* Pods_BluemixAppIDTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BluemixAppIDTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A59C9CA3B04FBE6AC2A4D28C /* Pods-IBMCloudAppID.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IBMCloudAppID.debug.xcconfig"; path = "Pods/Target Support Files/Pods-IBMCloudAppID/Pods-IBMCloudAppID.debug.xcconfig"; sourceTree = ""; }; BDC0D53E1E5EF68300444F9E /* UserProfileManagerImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserProfileManagerImpl.swift; sourceTree = ""; }; BDF5878E1E66C55A00393C0C /* UserProfileTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserProfileTests.swift; sourceTree = ""; }; + CB32128A91C6C77CEBDAC128 /* Pods_IBMCloudAppIDTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IBMCloudAppIDTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D419D8062637A352B06716FC /* Pods-BluemixAppIDTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BluemixAppIDTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-BluemixAppIDTests/Pods-BluemixAppIDTests.release.xcconfig"; sourceTree = ""; }; D7C1B0698BAAA534E21A1C51 /* Pods-BluemixAppID.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BluemixAppID.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BluemixAppID/Pods-BluemixAppID.debug.xcconfig"; sourceTree = ""; }; + EAB745E0C2A5F53D2FA7CC32 /* Pods-IBMCloudAppIDTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IBMCloudAppIDTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-IBMCloudAppIDTests/Pods-IBMCloudAppIDTests.debug.xcconfig"; sourceTree = ""; }; EF37F8B91E534C2D0020E998 /* AuthorizationUIManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthorizationUIManagerTests.swift; sourceTree = ""; }; EF37F8BB1E5487C40020E998 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; }; EF3B3BDF1E55C4E900DFFF13 /* dummyAppForKeyChain.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dummyAppForKeyChain.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -154,9 +160,9 @@ EFBA20141E51F7D9000EB3F5 /* OAuthClientImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OAuthClientImpl.swift; sourceTree = ""; }; EFBA20151E51F7D9000EB3F5 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; EFBA20161E51F7D9000EB3F5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - EFBBC7541DF99AFA000CE39A /* BluemixAppID.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BluemixAppID.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - EFBBC7661DF99BF6000CE39A /* BluemixAppIDTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BluemixAppIDTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - EFD0251A1E55FC8D00AE1803 /* BluemixAppID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BluemixAppID.h; sourceTree = ""; }; + EFBBC7541DF99AFA000CE39A /* IBMCloudAppID.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IBMCloudAppID.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EFBBC7661DF99BF6000CE39A /* IBMCloudAppIDTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IBMCloudAppIDTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + EFD0251A1E55FC8D00AE1803 /* IBMCloudAppID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IBMCloudAppID.h; sourceTree = ""; }; EFD0251C1E56013B00AE1803 /* dummyAppForKeyChain.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = dummyAppForKeyChain.entitlements; sourceTree = ""; }; EFE8DC1C1DFDAE920039A5F2 /* BMSCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BMSCore.framework; path = "../Library/Developer/Xcode/DerivedData/AppIDworkspace-ctfiojsausdyvabbauzbpkzomohi/Build/Products/Debug-iphonesimulator/BMSCore.framework"; sourceTree = ""; }; F9518D9FBE5C06EEB62E45B4 /* Pods_BluemixAppID.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BluemixAppID.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -175,7 +181,7 @@ buildActionMask = 2147483647; files = ( EFE8DC1D1DFDAE920039A5F2 /* BMSCore.framework in Frameworks */, - 686FA7AB6F9EE8ACF04FFE5B /* Pods_BluemixAppID.framework in Frameworks */, + 6749E62C81CCD62984862D58 /* Pods_IBMCloudAppID.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -183,8 +189,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EFBBC76B1DF99BF6000CE39A /* BluemixAppID.framework in Frameworks */, - 9178A9196CA83023A3A1FC90 /* Pods_BluemixAppIDTests.framework in Frameworks */, + EFBBC76B1DF99BF6000CE39A /* IBMCloudAppID.framework in Frameworks */, + 9539BBDF532A13A970EB051F /* Pods_IBMCloudAppIDTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -198,6 +204,10 @@ EFB619554546A4A1C879BF50 /* Pods-BluemixAppID.release.xcconfig */, 66E951CC5B401814BE794DBE /* Pods-BluemixAppIDTests.debug.xcconfig */, D419D8062637A352B06716FC /* Pods-BluemixAppIDTests.release.xcconfig */, + A59C9CA3B04FBE6AC2A4D28C /* Pods-IBMCloudAppID.debug.xcconfig */, + 3A523D88E31CC7EC37CAFA1D /* Pods-IBMCloudAppID.release.xcconfig */, + EAB745E0C2A5F53D2FA7CC32 /* Pods-IBMCloudAppIDTests.debug.xcconfig */, + 650D1FFAD2CCE197FAA0DE4F /* Pods-IBMCloudAppIDTests.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -216,7 +226,7 @@ path = dummyAppForKeyChain; sourceTree = ""; }; - EFBA1FE61E51F7D9000EB3F5 /* BluemixAppIDTests */ = { + EFBA1FE61E51F7D9000EB3F5 /* IBMCloudAppIDTests */ = { isa = PBXGroup; children = ( EFBA1FE71E51F7D9000EB3F5 /* AppIDAuthorizationManagerTests.swift */, @@ -237,26 +247,26 @@ BDF5878E1E66C55A00393C0C /* UserProfileTests.swift */, EF37F8BB1E5487C40020E998 /* TestHelpers.swift */, ); - path = BluemixAppIDTests; + path = IBMCloudAppIDTests; sourceTree = ""; }; EFBA1FF11E51F7D9000EB3F5 /* Source */ = { isa = PBXGroup; children = ( - EFBA1FF21E51F7D9000EB3F5 /* BluemixAppID */, + EFBA1FF21E51F7D9000EB3F5 /* IBMCloudAppID */, EFBA20161E51F7D9000EB3F5 /* Info.plist */, EFBA20171E51F7D9000EB3F5 /* Resources */, ); path = Source; sourceTree = ""; }; - EFBA1FF21E51F7D9000EB3F5 /* BluemixAppID */ = { + EFBA1FF21E51F7D9000EB3F5 /* IBMCloudAppID */ = { isa = PBXGroup; children = ( EFBA1FF31E51F7D9000EB3F5 /* api */, EFBA20001E51F7D9000EB3F5 /* internal */, ); - path = BluemixAppID; + path = IBMCloudAppID; sourceTree = ""; }; EFBA1FF31E51F7D9000EB3F5 /* api */ = { @@ -326,7 +336,7 @@ EFBA20171E51F7D9000EB3F5 /* Resources */ = { isa = PBXGroup; children = ( - EFD0251A1E55FC8D00AE1803 /* BluemixAppID.h */, + EFD0251A1E55FC8D00AE1803 /* IBMCloudAppID.h */, ); path = Resources; sourceTree = ""; @@ -334,7 +344,7 @@ EFBBC74A1DF99AFA000CE39A = { isa = PBXGroup; children = ( - EFBA1FE61E51F7D9000EB3F5 /* BluemixAppIDTests */, + EFBA1FE61E51F7D9000EB3F5 /* IBMCloudAppIDTests */, EFBA1FF11E51F7D9000EB3F5 /* Source */, EF3B3BE01E55C4E900DFFF13 /* dummyAppForKeyChain */, EFBBC7551DF99AFA000CE39A /* Products */, @@ -346,8 +356,8 @@ EFBBC7551DF99AFA000CE39A /* Products */ = { isa = PBXGroup; children = ( - EFBBC7541DF99AFA000CE39A /* BluemixAppID.framework */, - EFBBC7661DF99BF6000CE39A /* BluemixAppIDTests.xctest */, + EFBBC7541DF99AFA000CE39A /* IBMCloudAppID.framework */, + EFBBC7661DF99BF6000CE39A /* IBMCloudAppIDTests.xctest */, EF3B3BDF1E55C4E900DFFF13 /* dummyAppForKeyChain.app */, ); name = Products; @@ -359,6 +369,8 @@ EFE8DC1C1DFDAE920039A5F2 /* BMSCore.framework */, F9518D9FBE5C06EEB62E45B4 /* Pods_BluemixAppID.framework */, 8D5F58BDE9E7A759720873B7 /* Pods_BluemixAppIDTests.framework */, + 8B1AE9343AB77B8B9C396E21 /* Pods_IBMCloudAppID.framework */, + CB32128A91C6C77CEBDAC128 /* Pods_IBMCloudAppIDTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -370,7 +382,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - EFD0251B1E55FC8D00AE1803 /* BluemixAppID.h in Headers */, + EFD0251B1E55FC8D00AE1803 /* IBMCloudAppID.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -394,9 +406,9 @@ productReference = EF3B3BDF1E55C4E900DFFF13 /* dummyAppForKeyChain.app */; productType = "com.apple.product-type.application"; }; - EFBBC7531DF99AFA000CE39A /* BluemixAppID */ = { + EFBBC7531DF99AFA000CE39A /* IBMCloudAppID */ = { isa = PBXNativeTarget; - buildConfigurationList = EFBBC75C1DF99AFA000CE39A /* Build configuration list for PBXNativeTarget "BluemixAppID" */; + buildConfigurationList = EFBBC75C1DF99AFA000CE39A /* Build configuration list for PBXNativeTarget "IBMCloudAppID" */; buildPhases = ( 9B0F74AF62A688CE46DB550D /* [CP] Check Pods Manifest.lock */, EFBBC74F1DF99AFA000CE39A /* Sources */, @@ -408,14 +420,14 @@ ); dependencies = ( ); - name = BluemixAppID; + name = IBMCloudAppID; productName = AppID; - productReference = EFBBC7541DF99AFA000CE39A /* BluemixAppID.framework */; + productReference = EFBBC7541DF99AFA000CE39A /* IBMCloudAppID.framework */; productType = "com.apple.product-type.framework"; }; - EFBBC7651DF99BF6000CE39A /* BluemixAppIDTests */ = { + EFBBC7651DF99BF6000CE39A /* IBMCloudAppIDTests */ = { isa = PBXNativeTarget; - buildConfigurationList = EFBBC76E1DF99BF6000CE39A /* Build configuration list for PBXNativeTarget "BluemixAppIDTests" */; + buildConfigurationList = EFBBC76E1DF99BF6000CE39A /* Build configuration list for PBXNativeTarget "IBMCloudAppIDTests" */; buildPhases = ( E60F8F4C37CAEC13C67E6269 /* [CP] Check Pods Manifest.lock */, EFBBC7621DF99BF6000CE39A /* Sources */, @@ -429,9 +441,9 @@ EFBBC76D1DF99BF6000CE39A /* PBXTargetDependency */, EFFD59361E55C50F00B47FCB /* PBXTargetDependency */, ); - name = BluemixAppIDTests; + name = IBMCloudAppIDTests; productName = AppIDTests; - productReference = EFBBC7661DF99BF6000CE39A /* BluemixAppIDTests.xctest */; + productReference = EFBBC7661DF99BF6000CE39A /* IBMCloudAppIDTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ @@ -441,12 +453,13 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Oded Betzalel"; TargetAttributes = { EF3B3BDE1E55C4E900DFFF13 = { CreatedOnToolsVersion = 8.1; DevelopmentTeam = TN6YQNGLXP; + LastSwiftMigration = 0930; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.Keychain = { @@ -456,17 +469,18 @@ }; EFBBC7531DF99AFA000CE39A = { CreatedOnToolsVersion = 8.1; - LastSwiftMigration = 0810; + LastSwiftMigration = 0930; ProvisioningStyle = Automatic; }; EFBBC7651DF99BF6000CE39A = { CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 0930; ProvisioningStyle = Automatic; TestTargetID = EF3B3BDE1E55C4E900DFFF13; }; }; }; - buildConfigurationList = EFBBC74E1DF99AFA000CE39A /* Build configuration list for PBXProject "BluemixAppID" */; + buildConfigurationList = EFBBC74E1DF99AFA000CE39A /* Build configuration list for PBXProject "IBMCloudAppID" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -479,8 +493,8 @@ projectDirPath = ""; projectRoot = ""; targets = ( - EFBBC7531DF99AFA000CE39A /* BluemixAppID */, - EFBBC7651DF99BF6000CE39A /* BluemixAppIDTests */, + EFBBC7531DF99AFA000CE39A /* IBMCloudAppID */, + EFBBC7651DF99BF6000CE39A /* IBMCloudAppIDTests */, EF3B3BDE1E55C4E900DFFF13 /* dummyAppForKeyChain */, ); }; @@ -526,43 +540,13 @@ ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-BluemixAppID-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-IBMCloudAppID-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - B97F0C1B172B2DD0986CA529 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BluemixAppID/Pods-BluemixAppID-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - C602D46B779B62E3A73AB724 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BluemixAppIDTests/Pods-BluemixAppIDTests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; E60F8F4C37CAEC13C67E6269 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -574,7 +558,7 @@ ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-BluemixAppIDTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-IBMCloudAppIDTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -587,18 +571,20 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-BluemixAppIDTests/Pods-BluemixAppIDTests-frameworks.sh", + "${SRCROOT}/Pods/Target Support Files/Pods-IBMCloudAppIDTests/Pods-IBMCloudAppIDTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/BMSAnalyticsAPI/BMSAnalyticsAPI.framework", "${BUILT_PRODUCTS_DIR}/BMSCore/BMSCore.framework", + "${BUILT_PRODUCTS_DIR}/JOSESwift/JOSESwift.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BMSAnalyticsAPI.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BMSCore.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JOSESwift.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BluemixAppIDTests/Pods-BluemixAppIDTests-frameworks.sh\"\n"; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-IBMCloudAppIDTests/Pods-IBMCloudAppIDTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -663,7 +649,7 @@ EF4994811E55F7BE008ACC27 /* SecurityUtilsTests.swift in Sources */, EF4994821E55F7BE008ACC27 /* AppIDTestConstants.swift in Sources */, EF4994831E55F7BE008ACC27 /* AppIDTests.swift in Sources */, - BDF5878B1E65736B00393C0C /* BuildFile in Sources */, + BDF5878B1E65736B00393C0C /* (null) in Sources */, EF4994841E55F7BE008ACC27 /* AuthorizationHeaderHelperTests.swift in Sources */, EF4994861E55F7BE008ACC27 /* PreferencesTests.swift in Sources */, EF4994871E55F7BE008ACC27 /* TokenManagerTests.swift in Sources */, @@ -684,7 +670,7 @@ /* Begin PBXTargetDependency section */ EFBBC76D1DF99BF6000CE39A /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = EFBBC7531DF99AFA000CE39A /* BluemixAppID */; + target = EFBBC7531DF99AFA000CE39A /* IBMCloudAppID */; targetProxy = EFBBC76C1DF99BF6000CE39A /* PBXContainerItemProxy */; }; EFFD59361E55C50F00B47FCB /* PBXTargetDependency */ = { @@ -725,7 +711,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = oded.dummyAppForKeyChain; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -740,7 +727,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = oded.dummyAppForKeyChain; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -753,15 +741,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = 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_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -786,7 +782,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.1; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -807,15 +803,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = 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_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -834,7 +838,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.1; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -847,7 +851,7 @@ }; EFBBC75D1DF99AFA000CE39A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D7C1B0698BAAA534E21A1C51 /* Pods-BluemixAppID.debug.xcconfig */; + baseConfigurationReference = A59C9CA3B04FBE6AC2A4D28C /* Pods-IBMCloudAppID.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; @@ -857,23 +861,24 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; HEADER_SEARCH_PATHS = ""; - INFOPLIST_FILE = BluemixAppIDTests/Info.plist; + INFOPLIST_FILE = IBMCloudAppIDTests/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MODULEMAP_FILE = ""; - PRODUCT_BUNDLE_IDENTIFIER = BluemixAppID; + PRODUCT_BUNDLE_IDENTIFIER = IBMCloudAppID; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0.1; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; USE_HEADERMAP = YES; }; name = Debug; }; EFBBC75E1DF99AFA000CE39A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = EFB619554546A4A1C879BF50 /* Pods-BluemixAppID.release.xcconfig */; + baseConfigurationReference = 3A523D88E31CC7EC37CAFA1D /* Pods-IBMCloudAppID.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; @@ -883,45 +888,48 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; HEADER_SEARCH_PATHS = ""; - INFOPLIST_FILE = BluemixAppIDTests/Info.plist; + INFOPLIST_FILE = IBMCloudAppIDTests/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MODULEMAP_FILE = ""; - PRODUCT_BUNDLE_IDENTIFIER = BluemixAppID; + PRODUCT_BUNDLE_IDENTIFIER = IBMCloudAppID; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 3.0.1; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; USE_HEADERMAP = YES; }; name = Release; }; EFBBC76F1DF99BF6000CE39A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 66E951CC5B401814BE794DBE /* Pods-BluemixAppIDTests.debug.xcconfig */; + baseConfigurationReference = EAB745E0C2A5F53D2FA7CC32 /* Pods-IBMCloudAppIDTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; GCC_GENERATE_TEST_COVERAGE_FILES = YES; - INFOPLIST_FILE = BluemixAppIDTests/Info.plist; + INFOPLIST_FILE = IBMCloudAppIDTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = oded.BluemixAppIDTests; + PRODUCT_BUNDLE_IDENTIFIER = oded.IBMCloudAppIDTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0.1; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/dummyAppForKeyChain.app/dummyAppForKeyChain"; }; name = Debug; }; EFBBC7701DF99BF6000CE39A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D419D8062637A352B06716FC /* Pods-BluemixAppIDTests.release.xcconfig */; + baseConfigurationReference = 650D1FFAD2CCE197FAA0DE4F /* Pods-IBMCloudAppIDTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; GCC_GENERATE_TEST_COVERAGE_FILES = YES; - INFOPLIST_FILE = BluemixAppIDTests/Info.plist; + INFOPLIST_FILE = IBMCloudAppIDTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = oded.BluemixAppIDTests; + PRODUCT_BUNDLE_IDENTIFIER = oded.IBMCloudAppIDTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0.1; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/dummyAppForKeyChain.app/dummyAppForKeyChain"; }; name = Release; @@ -938,7 +946,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - EFBBC74E1DF99AFA000CE39A /* Build configuration list for PBXProject "BluemixAppID" */ = { + EFBBC74E1DF99AFA000CE39A /* Build configuration list for PBXProject "IBMCloudAppID" */ = { isa = XCConfigurationList; buildConfigurations = ( EFBBC75A1DF99AFA000CE39A /* Debug */, @@ -947,7 +955,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - EFBBC75C1DF99AFA000CE39A /* Build configuration list for PBXNativeTarget "BluemixAppID" */ = { + EFBBC75C1DF99AFA000CE39A /* Build configuration list for PBXNativeTarget "IBMCloudAppID" */ = { isa = XCConfigurationList; buildConfigurations = ( EFBBC75D1DF99AFA000CE39A /* Debug */, @@ -956,7 +964,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - EFBBC76E1DF99BF6000CE39A /* Build configuration list for PBXNativeTarget "BluemixAppIDTests" */ = { + EFBBC76E1DF99BF6000CE39A /* Build configuration list for PBXNativeTarget "IBMCloudAppIDTests" */ = { isa = XCConfigurationList; buildConfigurations = ( EFBBC76F1DF99BF6000CE39A /* Debug */, diff --git a/BluemixAppID.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/IBMCloudAppID.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from BluemixAppID.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to IBMCloudAppID.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/IBMCloudAppID.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/IBMCloudAppID.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/IBMCloudAppID.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/BluemixAppID.xcodeproj/xcshareddata/xcschemes/BluemixAppID.xcscheme b/IBMCloudAppID.xcodeproj/xcshareddata/xcschemes/IBMCloudAppID.xcscheme similarity index 74% rename from BluemixAppID.xcodeproj/xcshareddata/xcschemes/BluemixAppID.xcscheme rename to IBMCloudAppID.xcodeproj/xcshareddata/xcschemes/IBMCloudAppID.xcscheme index fa951d1..5042cba 100644 --- a/BluemixAppID.xcodeproj/xcshareddata/xcschemes/BluemixAppID.xcscheme +++ b/IBMCloudAppID.xcodeproj/xcshareddata/xcschemes/IBMCloudAppID.xcscheme @@ -1,6 +1,6 @@ + BuildableName = "IBMCloudAppID.framework" + BlueprintName = "IBMCloudAppID" + ReferencedContainer = "container:IBMCloudAppID.xcodeproj"> @@ -26,17 +26,17 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> + BuildableName = "IBMCloudAppIDTests.xctest" + BlueprintName = "IBMCloudAppIDTests" + ReferencedContainer = "container:IBMCloudAppID.xcodeproj"> @@ -44,9 +44,9 @@ + BuildableName = "IBMCloudAppID.framework" + BlueprintName = "IBMCloudAppID" + ReferencedContainer = "container:IBMCloudAppID.xcodeproj"> @@ -66,9 +66,9 @@ + BuildableName = "IBMCloudAppID.framework" + BlueprintName = "IBMCloudAppID" + ReferencedContainer = "container:IBMCloudAppID.xcodeproj"> @@ -84,9 +84,9 @@ + BuildableName = "IBMCloudAppID.framework" + BlueprintName = "IBMCloudAppID" + ReferencedContainer = "container:IBMCloudAppID.xcodeproj"> diff --git a/BluemixAppID.xcodeproj/xcshareddata/xcschemes/BluemixAppIDTests.xcscheme b/IBMCloudAppID.xcodeproj/xcshareddata/xcschemes/IBMCloudAppIDTests.xcscheme similarity index 85% rename from BluemixAppID.xcodeproj/xcshareddata/xcschemes/BluemixAppIDTests.xcscheme rename to IBMCloudAppID.xcodeproj/xcshareddata/xcschemes/IBMCloudAppIDTests.xcscheme index 2f8c0fc..fab7f91 100644 --- a/BluemixAppID.xcodeproj/xcshareddata/xcschemes/BluemixAppIDTests.xcscheme +++ b/IBMCloudAppID.xcodeproj/xcshareddata/xcschemes/IBMCloudAppIDTests.xcscheme @@ -1,6 +1,6 @@ + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> + BuildableName = "IBMCloudAppIDTests.xctest" + BlueprintName = "IBMCloudAppIDTests" + ReferencedContainer = "container:IBMCloudAppID.xcodeproj"> diff --git a/BluemixAppIDTests/AppIDAuthorizationManagerTests.swift b/IBMCloudAppIDTests/AppIDAuthorizationManagerTests.swift similarity index 96% rename from BluemixAppIDTests/AppIDAuthorizationManagerTests.swift rename to IBMCloudAppIDTests/AppIDAuthorizationManagerTests.swift index 866ca80..060e61c 100644 --- a/BluemixAppIDTests/AppIDAuthorizationManagerTests.swift +++ b/IBMCloudAppIDTests/AppIDAuthorizationManagerTests.swift @@ -14,44 +14,44 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID public class AppIDAuthorizationManagerTests: XCTestCase { static var appid:AppID? = nil static var manager:AppIDAuthorizationManager? = nil - + override public func setUp() { super.setUp() - AppID.sharedInstance.initialize(tenantId: "123", bluemixRegion: "123") + AppID.sharedInstance.initialize(tenantId: "123", region: "123") AppIDAuthorizationManagerTests.appid = AppID.sharedInstance AppIDAuthorizationManagerTests.manager = AppIDAuthorizationManager(appid: AppIDAuthorizationManagerTests.appid!) } - + public func testIsAuthorizationRequired () { - + // 401 status, Www-Authenticate header exist, but invalid value XCTAssertFalse((AppIDAuthorizationManagerTests.manager?.isAuthorizationRequired(for: 401, httpResponseAuthorizationHeader: "Dummy"))!) - + // 401 status, Www-Authenticate header exists, Bearer exists, but not appid scope XCTAssertFalse((AppIDAuthorizationManagerTests.manager?.isAuthorizationRequired(for: 401, httpResponseAuthorizationHeader: "Bearer Dummy"))!) - + // 401 with bearer and correct scope XCTAssertTrue((AppIDAuthorizationManagerTests.manager?.isAuthorizationRequired(for: 401, httpResponseAuthorizationHeader: "Bearer scope=\"appid_default\""))!) - + // Check with http response - + let response = HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 401, httpVersion: nil, headerFields: [AppIDConstants.WWW_AUTHENTICATE_HEADER : "Bearer scope=\"appid_default\""]) XCTAssertTrue((AppIDAuthorizationManagerTests.manager?.isAuthorizationRequired(for: Response(responseData: nil, httpResponse: response, isRedirect: false)))!) } - + static var expectedResponse:Response = Response(responseData: nil, httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 401, httpVersion: nil, headerFields: [AppIDConstants.WWW_AUTHENTICATE_HEADER : "Bearer scope=\"appid_default\""]), isRedirect: false) - class MockAuthorizationManager: BluemixAppID.AuthorizationManager { + class MockAuthorizationManager: IBMCloudAppID.AuthorizationManager { static var res = "cancel" - + var shouldCallObtainTokensRefreshToken = false var obtainTokensRefreshTokenCalled = false - + override func launchAuthorizationUI(accessTokenString: String? = nil, authorizationDelegate:AuthorizationDelegate) { if MockAuthorizationManager.res == "success" { authorizationDelegate.onAuthorizationSuccess( @@ -64,16 +64,16 @@ public class AppIDAuthorizationManagerTests: XCTestCase { } else { authorizationDelegate.onAuthorizationCanceled() } - + } - + override func signinWithRefreshToken(refreshTokenString: String?, tokenResponseDelegate: TokenResponseDelegate) { obtainTokensRefreshTokenCalled = true if !shouldCallObtainTokensRefreshToken { XCTFail("Unexpected call to obtainTokensRefreshToken") } } - + func verify() { if shouldCallObtainTokensRefreshToken && !obtainTokensRefreshTokenCalled { XCTFail("Should have called obtainTokensRefreshToken, but the function wasn't called") @@ -81,9 +81,9 @@ public class AppIDAuthorizationManagerTests: XCTestCase { } } - + public func testObtainAuthorizationCanceled() { - + MockAuthorizationManager.res = "cancel" AppIDAuthorizationManagerTests.manager?.oAuthManager.authorizationManager = MockAuthorizationManager(oAuthManager: (AppIDAuthorizationManagerTests.manager?.oAuthManager)!) let callback:BMSCompletionHandler = {(response:Response?, error:Error?) in @@ -91,7 +91,7 @@ public class AppIDAuthorizationManagerTests: XCTestCase { XCTAssertEqual((error as? AuthorizationError)?.description, "Authorization canceled") } AppIDAuthorizationManagerTests.manager?.obtainAuthorization(completionHandler: callback) - + } public func testObtainAuthorizationSuccess() { @@ -106,15 +106,15 @@ public class AppIDAuthorizationManagerTests: XCTestCase { } AppIDAuthorizationManagerTests.manager?.obtainAuthorization(completionHandler: callback) } - + public func testObtainAuthorizationWithRefreshTokenSuccess() { MockAuthorizationManager.res = "failure" - + AppIDAuthorizationManagerTests.manager?.oAuthManager.authorizationManager = MockAuthorizationManager(oAuthManager: (AppIDAuthorizationManagerTests.manager?.oAuthManager)!) - + let tokenManager = TestHelpers.MockTokenManager( oAuthManager: AppIDAuthorizationManagerTests.manager!.oAuthManager) - + AppIDAuthorizationManagerTests.manager?.oAuthManager.tokenManager = tokenManager tokenManager.latestRefreshToken = RefreshTokenImpl(with: "ststs") tokenManager.shouldCallObtainWithRefresh = true @@ -125,7 +125,7 @@ public class AppIDAuthorizationManagerTests: XCTestCase { AppIDAuthorizationManagerTests.manager?.obtainAuthorization(completionHandler: callback) tokenManager.verify() } - + public func testObtainAuthorizationSuccessAfterRefreshFails() { MockAuthorizationManager.res = "success" AppIDAuthorizationManagerTests.manager?.oAuthManager.authorizationManager = MockAuthorizationManager(oAuthManager: (AppIDAuthorizationManagerTests.manager?.oAuthManager)!) @@ -149,7 +149,7 @@ public class AppIDAuthorizationManagerTests: XCTestCase { public func testObtainAuthorizationFailure() { - + MockAuthorizationManager.res = "failure" AppIDAuthorizationManagerTests.manager?.oAuthManager.authorizationManager = MockAuthorizationManager(oAuthManager: (AppIDAuthorizationManagerTests.manager?.oAuthManager)!) let callback:BMSCompletionHandler = {(response:Response?, error:Error?) in @@ -157,9 +157,9 @@ public class AppIDAuthorizationManagerTests: XCTestCase { XCTAssertEqual((error as? AuthorizationError)?.description, "someerr") } AppIDAuthorizationManagerTests.manager?.obtainAuthorization(completionHandler: callback) - + } - + public func testObtainAuthorizationFailsAfterRefreshFails() { MockAuthorizationManager.res = "failure" AppIDAuthorizationManagerTests.manager?.oAuthManager.authorizationManager = MockAuthorizationManager(oAuthManager: (AppIDAuthorizationManagerTests.manager?.oAuthManager)!) @@ -187,13 +187,13 @@ public class AppIDAuthorizationManagerTests: XCTestCase { self.iToken = idToken super.init(appid: AppIDAuthorizationManagerTests.appid!) } - + public override var accessToken: AccessToken? { get { return aToken } } - + public override var identityToken: IdentityToken? { get { return iToken @@ -206,8 +206,8 @@ public class AppIDAuthorizationManagerTests: XCTestCase { XCTAssertNil(AppIDAuthorizationManagerMock(accessToken: accessToken,idToken: nil).cachedAuthorizationHeader) XCTAssertNil(AppIDAuthorizationManagerMock(accessToken: nil,idToken: idToken).cachedAuthorizationHeader) XCTAssertEqual((AppIDAuthorizationManagerMock(accessToken: accessToken,idToken: idToken).cachedAuthorizationHeader), "Bearer " + accessToken!.raw + " " + idToken!.raw) - - - + + + } } diff --git a/BluemixAppIDTests/AppIDTestConstants.swift b/IBMCloudAppIDTests/AppIDTestConstants.swift similarity index 52% rename from BluemixAppIDTests/AppIDTestConstants.swift rename to IBMCloudAppIDTests/AppIDTestConstants.swift index 2c57a09..4f54a4d 100644 --- a/BluemixAppIDTests/AppIDTestConstants.swift +++ b/IBMCloudAppIDTests/AppIDTestConstants.swift @@ -9,16 +9,28 @@ import Foundation public class AppIDTestConstants { - - + + public static var publicKeyData:Data = Data(base64Encoded: "MEgCQQDh/pwAlN3AqKQM+v0sybg7VMjeJx4Z5PcnxfQxYhj3LVz28DF6H2b3fVnGEKrcPsN1lf8obovT6zlX1QYZOgpjAgMBAAE=", options: NSData.Base64DecodingOptions(rawValue:0))! - + public static var privateKeyData:Data = Data(base64Encoded: "MIIBOgIBAAJBAOH+nACU3cCopAz6/SzJuDtUyN4nHhnk9yfF9DFiGPctXPbwMXofZvd9WcYQqtw+w3WV/yhui9PrOVfVBhk6CmMCAwEAAQJAJ4H8QbnEnoacz0wdcHP/ShgDWZrbD0nQz1oy22M73BHidwDvy1rIeM6PgkK1tyHNWrqyo1kAnp7DuNVmfGbJ0QIhAc3gVBJCrVbiO23OasUuYTN2y2KrZ2DUcjLp5ZOID1/LAiB9Qo1mx3yz4HT4wJvddb9AqSTlmSrrdXcNGNhWFRT8yQIhAbepkD3lrL2lEy8+q9JRiQOFVKvzP7Aj6yVeE0Sx4virAiAk2ITbrOajyuzdl1rCBDbkAF1YJHwZkw4YDizk9YKc8QIhAV0VZFoZidVBTsoi7xeufS0GSDqPxskq7gJGY70p4dco", options: NSData.Base64DecodingOptions(rawValue:0))! - public static var ACCESS_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiZXhwIjoxNDg3MDg0ODc4LCJhdWQiOiIyNmNiMDEyZWIzMjdjNjEyZDkwYTY4MTkxNjNiNmJjYmQ0ODQ5Y2JiIiwiaWF0IjoxNDg3MDgxMjc4LCJhdXRoX2J5IjoiZmFjZWJvb2siLCJ0ZW5hbnQiOiI0ZGJhOTQzMC01NGU2LTRjZjItYTUxNi02ZjczZmViNzAyYmIiLCJzY29wZSI6ImFwcGlkX2RlZmF1bHQgYXBwaWRfcmVhZHByb2ZpbGUgYXBwaWRfcmVhZHVzZXJhdHRyIGFwcGlkX3dyaXRldXNlcmF0dHIifQ.RDUrrVlMMrhBHxMpKEzQwwQZ5i4hHLSloFVQHwo2SyDYlU83oDgAUXBsCqehXr19PEFPOL5kjXrEeU6V5W8nyRiz3iOBQX7z004-ddf_heY2HEuvAAjqwox9kMlhpYMlMGpwuYwtKYAEcC28qHvg5UKN4CPfzUmP6bSqK2X4A5J11d4oEYNzcHCJpiQgMqbJ_it6UFGXkiQU26SVUq74_gW0_AUHuPmQxCU3-abW1F_PenRE9mJhdcOG2iWYKv5qzP7-DUx0j02ar4ylXjcMmwK0xK3iigoD-ZN_MJs6tUGg2X5ZSk_6rNmtWUlpWZkQNQw4XOBL3K9OAu5pmE-YNg" public static var ID_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiYXVkIjoiMjZjYjAxMmViMzI3YzYxMmQ5MGE2ODE5MTYzYjZiY2JkNDg0OWNiYiIsImV4cCI6MTQ4NzA4NDg3OCwiYXV0aF9ieSI6ImZhY2Vib29rIiwidGVuYW50IjoiNGRiYTk0MzAtNTRlNi00Y2YyLWE1MTYtNmY3M2ZlYjcwMmJiIiwiaWF0IjoxNDg3MDgxMjc4LCJuYW1lIjoiRG9uIExvbiIsImVtYWlsIjoiZG9ubG9ucXdlcnR5QGdtYWlsLmNvbSIsImdlbmRlciI6Im1hbGUiLCJsb2NhbGUiOiJlbl9VUyIsInBpY3R1cmUiOiJodHRwczovL3Njb250ZW50Lnh4LmZiY2RuLm5ldC92L3QxLjAtMS9wNTB4NTAvMTM1MDE1NTFfMjg2NDA3ODM4Mzc4ODkyXzE3ODU3NjYyMTE3NjY3MzA2OTdfbi5qcGc_b2g9MjQyYmMyZmI1MDU2MDliNDQyODc0ZmRlM2U5ODY1YTkmb2U9NTkwN0IxQkMiLCJpZGVudGl0aWVzIjpbeyJwcm92aWRlciI6ImZhY2Vib29rIiwiaWQiOiIzNzc0NDAxNTkyNzU2NTkifV0sIm9hdXRoX2NsaWVudCI6eyJuYW1lIjoidGVzdEFwcERpc3BsYXlOYW1lIiwidHlwZSI6Im1vYmlsZWFwcCIsInNvZnR3YXJlX2lkIjoidGVzdEFwcCIsInNvZnR3YXJlX3ZlcnNpb24iOiIxLjAiLCJkZXZpY2VfaWQiOiI5NjAwRTAxRS1FNUYxLTRGREQtQjlDOS1EMjRDNDE4REE5NDciLCJkZXZpY2VfbW9kZWwiOiJpUGhvbmUiLCJkZXZpY2Vfb3MiOiJpUGhvbmUgT1MifX0.ejXqFMGKtZ3qQo-Uq6xLR9ZgfM2gNUwd_XwELHwd8bpgzSTYmfunM_rdzvEGaA4thH78gMK9vsSIEROkmiOpyB40sOmMexyWVPscNnaU3LNZu-ePpJbTkvurwhtscsnB-Vexua5m5ls-nVS3-i0y7J28TAf653UO0Xf8I04kXeFxYS7VbaQd0TttxtDqmYNokjCC22_MACPIxfOukDQY8PjPGysgugYHMfyERDTgi1RmgZMEc4XzZkMQjhfw30i3EATP2iTUWREjlJdyQXKTH3UqewEuPGFduUGPq9Jk1sHNhHB9U28PkFs_Gc5jVu3MnFbT5pSvJ7AwEhusl4G70Q" - + + public static let jwk = "{\"keys\":[{\"kty\":\"RSA\",\"use\":\"sig\",\"n\":\"AJ-E8O4KJT6So_lUkCIkU0QKW7QjMp9vG7S7vZx0M399idZ4mP7iWWW6OTvjLHpDTx7uapiwRQktDNx3GHigJDmbbu8_VtS5K6J6be1gVrvu6pxmZtrz8PazlH5WYxkuUIfUYpzyfUubZzqzuVWqQO0W9kOhFN7HILAxb1WsQREX-iLg14MGGafrQnJgXHBAwSH0OOJr7v-nRz8AFCAicN8v0uIar9lRA7JRHQCZtpI_lkSGKKBQT1Zae9-9YlWbZlfXErQS1uYoAb3j3uaLbJVO7SNjQqEsRTjYxfpBsTtkvJmwcwA0wV2gBO3JR6K6ep0Y_KyMR8w9Fd_lvJqdltU\",\"e\":\"AQAB\",\"kid\":\"appId-1504685961000-c2d3da94-c901-4392-8f27-d90efd28b5b7\"}]}" + + public static let kid = "appId-1504685961000-c2d3da94-c901-4392-8f27-d90efd28b5b7" + + public static let malformedAccessTokenInvalidAlg = "eyJraWQiOiJraWQiLCJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiZXhwIjoxNDg3MDg0ODc4LCJhdWQiOiIyNmNiMDEyZWIzMjdjNjEyZDkwYTY4MTkxNjNiNmJjYmQ0ODQ5Y2JiIiwiaWF0IjoxNDg3MDgxMjc4LCJhdXRoX2J5IjoiZmFjZWJvb2siLCJ0ZW5hbnQiOiI0ZGJhOTQzMC01NGU2LTRjZjItYTUxNi02ZjczZmViNzAyYmIiLCJzY29wZSI6ImFwcGlkX2RlZmF1bHQgYXBwaWRfcmVhZHByb2ZpbGUgYXBwaWRfcmVhZHVzZXJhdHRyIGFwcGlkX3dyaXRldXNlcmF0dHIifQ.HHterec250JSDY1965cM2DadBznl2wTKmzKNSnfjpdTAqax9VZvV3EwuFbEnGp9-i6AC-OlsVj7xvbALkdjwG2lZvpQx0M_gRc_3E0NiYuOGVolcm0wEXtbtDUFFqZQAf9BYYOPZ8OintdBiwUGETbH1ZRVtUvt3nalIko1OPE1Q12LvuRlhz5MClNHmvxJcXc7kucxCx4s4UFFy_HJA1gow7HWFqc9-PZf4JMWA-siYqPrdw_zYeBTBzE5co92F6JBEtGLLCjhJVz9eYgLLECXbak3z6hOaY9352Weuj7AgMOWxzw56jKKsiixMtvzrCzLVIcRUG96UJszwPHtPlA" + + public static let expAcessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJpbWYtYXV0aHNlcnZlci5zdGFnZTEubXlibHVlbWl4Lm5ldCIsImV4cCI6MTQ4OTk1NzQ1OSwiYXVkIjoiNDA4ZWIzNmEyYTA2OWFkODljZDE5Yzc4OWE5NmI3Y2YzNmI1NTBlYyIsInN1YiI6IjA5YjdmZWE1LTJlNGUtNDBiOC05ZDgxLWRmNTAwNzFhMzA1MyIsImFtciI6WyJmYWNlYm9vayJdLCJpYXQiOjE0ODczNjU0NTksInRlbmFudCI6IjUwZDBiZWVkLWFkZDctNDhkZC04YjBhLWM4MThjYjQ1NmJiNCIsInNjb3BlIjoiYXBwaWRfZGVmYXVsdCBhcHBpZF9yZWFkcHJvZmlsZSBhcHBpZF9yZWFkdXNlcmF0dHIgYXBwaWRfd3JpdGV1c2VyYXR0ciJ9.gQq4_IxbkPg1FsVZiiTqsejURL4E_Ijr8U1vDob-06GcsorVijS7HHf0kgWD84cDNa6z4Lp7HkmvI8vmiUIfV6ch-xJS_LSJphKy5nZxXqVHchRDJAMUNMiAYqC5ohZ4MXmjuGFIrVl1iZdTyP5Oz-5e6UzDccdAGkPokNs_IyXwiSmGWF5fOKSgfqANYwRBaC-JeXlzEcVZ697q92kiErBNl3ziuSFWxss86ZHHiKdLoHUpkDRKgPHwSQmE_Kwzj8v8Td9WuIVwXCF-D4koTuPJSe2aPqCLuV28PE9wRh5j3sFraKbQIcjuHuiAd5KBhzwaeVT20_0zrgyr3QG0Vg" + + public static let appAnonAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJhcHBJZC0xNTA0Njg1OTYxMDAwLWMyZDNkYTk0LWM5MDEtNDM5Mi04ZjI3LWQ5MGVmZDI4YjViNyJ9.eyJpc3MiOiJhcHBpZC1vYXV0aC5uZy5ibHVlbWl4Lm5ldCIsImV4cCI6MTUyOTY5NjQyNSwiYXVkIjoiMDZhNDIwNDY5YzRiZWEyYTY5NGFhN2U5NzFkMTU2ODBiYjY5Nzk0YSIsInN1YiI6Ijk2OWRlYmZlLTFhNzItNDk5NC1iZTE0LWNmODMyYTcxYjU5ZSIsImFtciI6WyJhcHBpZF9hbm9uIl0sImlhdCI6MTUyNzEwNDQyNSwidGVuYW50IjoiYzJkM2RhOTQtYzkwMS00MzkyLThmMjctZDkwZWZkMjhiNWI3Iiwic2NvcGUiOiJvcGVuaWQgYXBwaWRfZGVmYXVsdCBhcHBpZF9yZWFkcHJvZmlsZSBhcHBpZF9yZWFkdXNlcmF0dHIgYXBwaWRfd3JpdGV1c2VyYXR0ciJ9.WGnEmW7RstkIAkjXswJgwuwQauprUP808nE9pkKP_NpImc0vh6AsrVmmGuAh5tzGZ_8Y9_4vBR4LpRUzBWI3lRgWW6fX3hJqQdHv8zJpkIcg7FkpXmF_0TSll3_KeRes7ks5jEQ55MvOly6I3-PaKcX--cxNXnMBkjIRl3DQdSecxaIAWrov9efrrtee93eo6r8VGKVAgUEyj88WJQYSac9odhIx8PgA0NgdriGDqHp1oewDjpiM6Hxxv4Ph3LmnY46XdI2fg6pSTT6f9OGTAMoDWyDOEkVr0zUlhcEDYtofhCpO6mSJyvRzLQDVKhwHNeCYqhwh0xGuyXaCXKqvdA" + + public static let clientId = "06a420469c4bea2a694aa7e971d15680bb69794a" + public static var ID_TOKEN_WITH_SUBJECT = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJzdWIiOiIxMjMifQ.enbXHtja8BJd9_hlIbCgwyMXl8o9s74yDlqH4_11h7xLVasDO8Yy4jNyhVmIIb8jpl4fQfjWjqaOJoD2TqgfhqwQ-tGRjzYYR-f0qAMb99pNDtLS9IFf1yHYM2y65UerZ8qTD4g2s-ZWPk7yvxPMQx-Nrvu-X2uUwvdBCBr02rXpsHdMbeLYA6iwUs58p5hMxOxf3yKrBcTpTJ4EE164BhruEU5HyHhqSM9DTVLvliuapFFIK4CGV3FjvrKnT38yWdxSWtd9ETC79bfBwWTsE0ykMzb7Nq3vA2O0C_pv5IUixkLtTCiT3s5m55WZaqxdFCvOe4BjAt6AWH7slwgZdg" + } diff --git a/BluemixAppIDTests/AppIDTests.swift b/IBMCloudAppIDTests/AppIDTests.swift similarity index 96% rename from BluemixAppIDTests/AppIDTests.swift rename to IBMCloudAppIDTests/AppIDTests.swift index 2287871..a951d94 100644 --- a/BluemixAppIDTests/AppIDTests.swift +++ b/IBMCloudAppIDTests/AppIDTests.swift @@ -23,12 +23,12 @@ // static var callbackErr = false; // static var callbackResponse = false; // var pref = AppIDPreferences() -// +// // static let defaultCallBack : BMSCompletionHandler = {(response: Response?, error: Error?) in -// +// // } -// -// +// +// // class MockRegistrationManager : RegistrationManager { // var response:Response? = nil // var err:Error? = nil @@ -40,7 +40,7 @@ // } // } // var mockRegistrationManager:MockRegistrationManager? -// +// // class MockTokenManager : TokenManager { // var response:Response? = nil // var err:Error? = nil @@ -48,18 +48,18 @@ // callback?(response,err) // } // } -// +// // // var mockTokenManager:MockTokenManager? -// +// // override func setUp() { // mockRegistrationManager = MockRegistrationManager(preferences: pref) -// AppIDTests.appId.initialize(tenantId: AppIDTests.tenantId, bluemixRegion: BMSClient.Region.usSouth) +// AppIDTests.appId.initialize(tenantId: AppIDTests.tenantId, region: BMSClient.Region.usSouth) // AppIDTests.appId.registrationManager = mockRegistrationManager! // AppIDTests.appId.preferences.clientId.set(nil) // // appId.tokenManager = mockTokenManager! // super.setUp(); // } -// +// // func testLoginRegisterSuccess() { // let defaultCallBack:BMSCompletionHandler = {(response: Response?, error: Error?) in // } @@ -70,24 +70,24 @@ // AppIDConstants.JSON_SCOPE_KEY : AppIDConstants.OPEN_ID_VALUE, // AppIDConstants.JSON_USE_LOGIN_WIDGET : AppIDConstants.TRUE_VALUE, // ] -// +// // let url = AppID.sharedInstance.serverUrl + "/" + AppIDConstants.V3_AUTH_PATH + AppIDTests.tenantId + "/" + AppIDConstants.authorizationEndPoint + Utils.getQueryString(params: params) -// -// +// +// // let response = HTTPURLResponse(url: URL(string : "SOMEurl")!, statusCode: 200, httpVersion: nil, headerFields: nil) -// +// // mockRegistrationManager?.response = Response(responseData: nil, httpResponse: response, isRedirect: false) // mockRegistrationManager?.err = nil -// +// // AppIDTests.appId.login(onTokenCompletion: defaultCallBack) -// -// +// +// // var viewUrl = AppIDTests.appId.loginView!.url!.absoluteString // let firstPart = viewUrl.components(separatedBy: "state=")[0] // var secondPart = "" // let comp = viewUrl.components(separatedBy: "state=")[1].components(separatedBy: "&") // for i in 1...comp.count - 1 { -// +// // secondPart += comp[i] + (i == comp.count - 1 ? "" : "&") // } // viewUrl = firstPart + secondPart @@ -96,12 +96,12 @@ // XCTAssertNotNil(AppIDTests.appId.tokenRequest) // XCTAssertNotNil(AppIDTests.appId.loginView?.callback) // } -// -// -// -// +// +// +// +// // func testLoginRegisterFailed() { -// +// // //no saved client id tests // var callbackCalled = 0 // mockRegistrationManager?.response = nil @@ -124,7 +124,7 @@ // expectation2.fulfill() // } // AppIDTests.appId.login(onTokenCompletion: testCallBack2) -// +// // //saved client different tenant // pref.clientId.set("1") // pref.registrationTenantId.set("2") @@ -140,13 +140,13 @@ // } // } // } -// +// // class mockLoginView : safariView { // override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { // completion?() // } // } -// +// // func testTokens() { // let accessToken = "thisIsAccessToken" // let idToken = "thisIsAccessToken" @@ -159,7 +159,7 @@ // // XCTAssertEqual(AppIDTests.appId.accessToken, accessToken) // // XCTAssertEqual(AppIDTests.appId.idToken, idToken) // } -// +// // func testApplication() { // //happy flow // let testcode = "testcode" @@ -184,7 +184,7 @@ // expectation2.fulfill() // } // XCTAssertTrue(AppIDTests.appId.application(UIApplication.shared, open: URL(string: AppIDConstants.REDIRECT_URI_VALUE + "?notgrantcode=" + testcode)!, options: [:])) -// +// // waitForExpectations(timeout: 1) { error in // if let error = error { // XCTFail("err: \(error)") @@ -192,9 +192,9 @@ // } // //non happy flow // XCTAssertFalse(AppIDTests.appId.application(UIApplication.shared, open: URL(string: "someurl" + "?notgrantcode=" + testcode)!, options: [:])) -// +// // } -// -// +// +// // } // diff --git a/BluemixAppIDTests/AuthorizationHeaderHelperTests.swift b/IBMCloudAppIDTests/AuthorizationHeaderHelperTests.swift similarity index 95% rename from BluemixAppIDTests/AuthorizationHeaderHelperTests.swift rename to IBMCloudAppIDTests/AuthorizationHeaderHelperTests.swift index 9f1462b..fd93e3d 100644 --- a/BluemixAppIDTests/AuthorizationHeaderHelperTests.swift +++ b/IBMCloudAppIDTests/AuthorizationHeaderHelperTests.swift @@ -12,33 +12,33 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID public class AuthorizationHeaderHelperTests: XCTestCase { func testIsAuthorizationRequired() { var headers:[String: Any] = [:] headers["Dummy"] = ["Dummy"] - + // Non-401 status XCTAssertFalse(AuthorizationHeaderHelper.isAuthorizationRequired(statusCode: 200, header: nil)) - + // 401 status, but Www-Authenticate header is null XCTAssertFalse(AuthorizationHeaderHelper.isAuthorizationRequired(statusCode: 401, header: nil)) - + // 401 status, Www-Authenticate header exist, but invalid value XCTAssertFalse(AuthorizationHeaderHelper.isAuthorizationRequired(statusCode: 401, header: "Dummy")) - + // 401 status, Www-Authenticate header exists, Bearer exists, but not appid scope XCTAssertFalse(AuthorizationHeaderHelper.isAuthorizationRequired(statusCode: 401, header: "Bearer Dummy")) // 401 with bearer and correct scope XCTAssertTrue(AuthorizationHeaderHelper.isAuthorizationRequired(statusCode: 401, header: "Bearer scope=\"appid_default\"")) - + // Check with http response - + let response = HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 401, httpVersion: nil, headerFields: [AppIDConstants.WWW_AUTHENTICATE_HEADER : "Bearer scope=\"appid_default\""]) XCTAssertTrue(AuthorizationHeaderHelper.isAuthorizationRequired(for: Response(responseData: nil, httpResponse: response, isRedirect: false))) } - + } diff --git a/BluemixAppIDTests/AuthorizationManagerTests.swift b/IBMCloudAppIDTests/AuthorizationManagerTests.swift similarity index 92% rename from BluemixAppIDTests/AuthorizationManagerTests.swift rename to IBMCloudAppIDTests/AuthorizationManagerTests.swift index 280fbc9..f773822 100644 --- a/BluemixAppIDTests/AuthorizationManagerTests.swift +++ b/IBMCloudAppIDTests/AuthorizationManagerTests.swift @@ -13,12 +13,12 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID public class AuthorizationManagerTests : XCTestCase { func testGetAuthorizationUrl() { - let authManager = BluemixAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + let authManager = IBMCloudAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) authManager.registrationManager.preferenceManager.getStringPreference(name: AppIDConstants.client_id_String).clear() authManager.registrationManager.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).clear() let defaultLocale = Locale.current @@ -66,7 +66,7 @@ public class AuthorizationManagerTests : XCTestCase { } func testLaunchAuthorizationUI() { - let authManager = BluemixAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + let authManager = IBMCloudAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) class delegate: AuthorizationDelegate { var res:String @@ -115,7 +115,7 @@ public class AuthorizationManagerTests : XCTestCase { authManager.launchAuthorizationUI(authorizationDelegate:delegate(res: "failure", expectedErr: "Failed to register OAuth client")) // //mock with not error // authManager.registrationManager.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : "someclient", AppIDConstants.JSON_REDIRECT_URIS_KEY : ["redirect"]] as [String:Any]) - // TODO: think how to ovveride it? + // TODO: think how to ovveride it? // // no redirects // authManager.registrationManager.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : "someclient", AppIDConstants.JSON_REDIRECT_URIS_KEY : []] as [String:Any]) @@ -123,7 +123,7 @@ public class AuthorizationManagerTests : XCTestCase { } func testNoId() { - let authManager = BluemixAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + let authManager = IBMCloudAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) class delegate: AuthorizationDelegate { var res:String @@ -167,12 +167,12 @@ public class AuthorizationManagerTests : XCTestCase { testLaunchChangeDetailsAuthorizationUI_NO_IDToken(authManager: authManager, delegate:delegate(res: "failure", expectedErr: "No identity token found.")) } - func testLaunchChangePasswordAuthorizationUI_NO_IDToken(authManager: BluemixAppID.AuthorizationManager, delegate: AuthorizationDelegate) { + func testLaunchChangePasswordAuthorizationUI_NO_IDToken(authManager: IBMCloudAppID.AuthorizationManager, delegate: AuthorizationDelegate) { authManager.launchChangePasswordUI(authorizationDelegate: delegate) } - func testLaunchChangeDetailsAuthorizationUI_NO_IDToken(authManager: BluemixAppID.AuthorizationManager, delegate: AuthorizationDelegate) { + func testLaunchChangeDetailsAuthorizationUI_NO_IDToken(authManager: IBMCloudAppID.AuthorizationManager, delegate: AuthorizationDelegate) { authManager.launchChangeDetailsUI(authorizationDelegate:delegate) } @@ -180,7 +180,7 @@ public class AuthorizationManagerTests : XCTestCase { func test_ID_Token_Not_Of_CD() { let oAuthManager = OAuthManager(appId: AppID.sharedInstance) - let authManager = BluemixAppID.AuthorizationManager(oAuthManager: oAuthManager) + let authManager = IBMCloudAppID.AuthorizationManager(oAuthManager: oAuthManager) class delegate: AuthorizationDelegate { var res:String @@ -220,10 +220,10 @@ public class AuthorizationManagerTests : XCTestCase { } } - //id token not from cloud directory + // id token not from cloud directory let data = "{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiZXhwIjoxNDg3MDY2MzAyLCJhdWQiOiIxN2UxMjg5YjY3YTUzMjAwNDgxN2E1YTBiZDMxMzliOWNhYzg0MTQ4IiwiaWF0IjoxNDg3MDYyNzAyLCJhdXRoX2J5IjoiZmFjZWJvb2siLCJ0ZW5hbnQiOiI0ZGJhOTQzMC01NGU2LTRjZjItYTUxNi02ZjczZmViNzAyYmIiLCJzY29wZSI6ImFwcGlkX2RlZmF1bHQgYXBwaWRfcmVhZHByb2ZpbGUgYXBwaWRfcmVhZHVzZXJhdHRyIGFwcGlkX3dyaXRldXNlcmF0dHIifQ.enUpEwjdXGJYF9VHolYcKpT8yViYBCbcxp7p7e3n2JamUx68EDEwVPX3qQTyFCz4cXhGmhF8d3rsNGNxMuglor_LRhHDIzHtN5CPi0aqCh3QuF1dQrRBbmjOk2zjinP6pp5WaZvpbush8LEVa8CiZ3Cy2l9IHdY5f4ApKuh29oOj860wwrauYovX2M0f7bDLSwgwXTXydb9-ooawQI7NKkZOlVDI_Bxawmh34VLgAwepyqOR_38YEWyJm7mocJEkT4dqKMaGQ5_WW564JHtqy8D9kIsoN6pufIyr427ApsCdcj_KcYdCdZtJAgiP5x9J5aNmKLsyJYNZKtk2HTMmlw\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiYXVkIjoiMTdlMTI4OWI2N2E1MzIwMDQ4MTdhNWEwYmQzMTM5YjljYWM4NDE0OCIsImV4cCI6MTQ4NzA2NjMwMiwiYXV0aF9ieSI6ImZhY2Vib29rIiwidGVuYW50IjoiNGRiYTk0MzAtNTRlNi00Y2YyLWE1MTYtNmY3M2ZlYjcwMmJiIiwiaWF0IjoxNDg3MDYyNzAyLCJuYW1lIjoiRG9uIExvbiIsImVtYWlsIjoiZG9ubG9ucXdlcnR5QGdtYWlsLmNvbSIsImdlbmRlciI6Im1hbGUiLCJsb2NhbGUiOiJlbl9VUyIsInBpY3R1cmUiOiJodHRwczovL3Njb250ZW50Lnh4LmZiY2RuLm5ldC92L3QxLjAtMS9wNTB4NTAvMTM1MDE1NTFfMjg2NDA3ODM4Mzc4ODkyXzE3ODU3NjYyMTE3NjY3MzA2OTdfbi5qcGc_b2g9MjQyYmMyZmI1MDU2MDliNDQyODc0ZmRlM2U5ODY1YTkmb2U9NTkwN0IxQkMiLCJpZGVudGl0aWVzIjpbeyJwcm92aWRlciI6ImZhY2Vib29rIiwiaWQiOiIzNzc0NDAxNTkyNzU2NTkifV0sIm9hdXRoX2NsaWVudCI6eyJuYW1lIjoiT2RlZEFwcElEYXBwaWQiLCJ0eXBlIjoibW9iaWxlYXBwIiwic29mdHdhcmVfaWQiOiJPZGVkQXBwSURhcHBpZElEIiwic29mdHdhcmVfdmVyc2lvbiI6IjEuMCIsImRldmljZV9pZCI6Ijk5MDI0Njg4LUZGMTktNDg4Qy04RjJELUY3MTY2MDZDQTU5NCIsImRldmljZV9tb2RlbCI6ImlQaG9uZSIsImRldmljZV9vcyI6ImlQaG9uZSBPUyJ9fQ.kFPUtpi9AROmBvQqPa19LgX18aYSSbnjlea4Hg0OA4UUw8XYnuoufBWpmmzDpaqZVnN5LTWg9YK5-wtB5Hi9YwX8bhklkeciHP_1ue-fyNDLN2uCNUvBxh916mgFy8u1gFicBcCzQkVoSDSL4Pcjgo0VoTla8t36wLFRtEKmBQ-p8UOlvjD-dnAoNBDveUsNNyeaLMdVPRRfXi-RYWOH3E9bjvyhHd-Zea2OX3oC1XRpqNgrUBXQblskOi_mEll_iWAUX5oD23tOZB9cb0eph9B6_tDZutgvaY338ZD1W9St6YokIL8IltKbrX3q1_FFJSu9nfNPgILsKIAKqe9fHQ\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) - let tokenManager:TokenManager = TokenManager(oAuthManager: oAuthManager) + let tokenManager:TokenManager = MockTokenManagerWithValidateAToken(oAuthManager: oAuthManager) tokenManager.extractTokens(response: response, tokenResponseDelegate: delegate(res:"success", expectedErr: "")) oAuthManager.tokenManager = tokenManager @@ -232,20 +232,20 @@ public class AuthorizationManagerTests : XCTestCase { } - func testLaunchChangePassword_ID_Token_Not_Of_CD(authManager: BluemixAppID.AuthorizationManager, delegate: AuthorizationDelegate) { + func testLaunchChangePassword_ID_Token_Not_Of_CD(authManager: IBMCloudAppID.AuthorizationManager, delegate: AuthorizationDelegate) { authManager.launchChangePasswordUI(authorizationDelegate: delegate) } - func testLaunchChangeDetails_ID_Token_Not_Of_CD(authManager: BluemixAppID.AuthorizationManager, delegate: AuthorizationDelegate) { + func testLaunchChangeDetails_ID_Token_Not_Of_CD(authManager: IBMCloudAppID.AuthorizationManager, delegate: AuthorizationDelegate) { authManager.launchChangeDetailsUI(authorizationDelegate:delegate) } func testLaunchChangePassword_success() { let oAuthManager = OAuthManager(appId: AppID.sharedInstance) - AppID.sharedInstance.initialize(tenantId: "tenant1", bluemixRegion: "region2") - let authManager = BluemixAppID.AuthorizationManager(oAuthManager: oAuthManager) + AppID.sharedInstance.initialize(tenantId: "tenant1", region: "region2") + let authManager = IBMCloudAppID.AuthorizationManager(oAuthManager: oAuthManager) class delegate: AuthorizationDelegate { var res:String @@ -285,10 +285,10 @@ public class AuthorizationManagerTests : XCTestCase { } } - //id token from cloud directory + // id token from cloud directory let data = "{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiZXhwIjoxNDg3MDY2MzAyLCJhdWQiOiIxN2UxMjg5YjY3YTUzMjAwNDgxN2E1YTBiZDMxMzliOWNhYzg0MTQ4IiwiaWF0IjoxNDg3MDYyNzAyLCJhdXRoX2J5IjoiZmFjZWJvb2siLCJ0ZW5hbnQiOiI0ZGJhOTQzMC01NGU2LTRjZjItYTUxNi02ZjczZmViNzAyYmIiLCJzY29wZSI6ImFwcGlkX2RlZmF1bHQgYXBwaWRfcmVhZHByb2ZpbGUgYXBwaWRfcmVhZHVzZXJhdHRyIGFwcGlkX3dyaXRldXNlcmF0dHIifQ.enUpEwjdXGJYF9VHolYcKpT8yViYBCbcxp7p7e3n2JamUx68EDEwVPX3qQTyFCz4cXhGmhF8d3rsNGNxMuglor_LRhHDIzHtN5CPi0aqCh3QuF1dQrRBbmjOk2zjinP6pp5WaZvpbush8LEVa8CiZ3Cy2l9IHdY5f4ApKuh29oOj860wwrauYovX2M0f7bDLSwgwXTXydb9-ooawQI7NKkZOlVDI_Bxawmh34VLgAwepyqOR_38YEWyJm7mocJEkT4dqKMaGQ5_WW564JHtqy8D9kIsoN6pufIyr427ApsCdcj_KcYdCdZtJAgiP5x9J5aNmKLsyJYNZKtk2HTMmlw\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJvS3dTY21CRFdITjBMVEhnVDRpQjhpMjdZUjNYOF9IRWQ3Smo2RlEtcHhVIn0.eyJpc3MiOiJhcHBpZC1vYXV0aC5zdGFnZTEubXlibHVlbWl4Lm5ldCIsImF1ZCI6IjQxNDIzNzZmYjFiYjU1ZjE4ZjQxNTE0ZmU4NWNlMGQ2MjlmZjk0YmYiLCJleHAiOjE1MDA1NTE4NzUsInRlbmFudCI6IjIyOGUzMGMyLWM3ZWMtNGUwZS04ZWQxLTZhZWMwZTkzZDRlYSIsImlhdCI6MTUwMDU0ODI3NSwiZW1haWwiOiJyb3RlbUBpYm0uY29tIiwibmFtZSI6InJvdGVtQGlibS5jb20iLCJzdWIiOiI1ZWY3NjQ3Mi0xMGM0LTQ4YmItYTRlMS1iOTg1OGFhODdmODgiLCJpZGVudGl0aWVzIjpbeyJwcm92aWRlciI6ImNsb3VkX2RpcmVjdG9yeSIsImlkIjoiYmQ5OGU3YTgtNjAzNS00ZTA3LTlkOTQtMDRjMDRjOWZkN2FiIn1dLCJhbXIiOlsiY2xvdWRfZGlyZWN0b3J5Il0sIm9hdXRoX2NsaWVudCI6eyJuYW1lIjoiYXBwaWQiLCJ0eXBlIjoibW9iaWxlYXBwIiwic29mdHdhcmVfaWQiOiJjb20uaWJtLm1vYmlsZWZpcnN0cGxhdGZvcm0uYXBwaWQiLCJzb2Z0d2FyZV92ZXJzaW9uIjoiMS4wIiwiZGV2aWNlX2lkIjoiZjNhZWQ3ZWEtMGUzNC0zNGM0LWI2NDgtMTJjZTQwYmE5ZWFhIiwiZGV2aWNlX21vZGVsIjoiQW5kcm9pZCBTREsgYnVpbHQgZm9yIHg4Nl82NCIsImRldmljZV9vcyI6ImFuZHJvaWQifX0.A-cHskvxS947usTLm90DtOYh7qyyvZi61D3XUIZ2Kxtw6mJE_ShsTtsR0b1uavYVyZTXUeD6bqKKzEqDD8TDpB7KO8gAePuUdMyMPF-ObVcgF3mzHzusWOHUiVUr0sbtF-i9YbyPwO4r6cs_GhhfeY05e4sDL7Gy9l2ab9IoSOJ-zDGe4_cJjkevbZ6Sl31PcRqz89wip5ixvhhvApkusojKcO-WG-6hDLWKrlf8Iz5AP4YLN5vpB7-9nCS2Z5whRnlr9kVyott8h6AREI_pvcjUUCvA7hrhiVJv38oS6yeTMeWPj4Q5RI9iYdF3rzFVw44ODnIKtXeP9IOzJEvlqA\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) - let tokenManager:TokenManager = TokenManager(oAuthManager: oAuthManager) + let tokenManager:TokenManager = MockTokenManagerWithValidateAToken(oAuthManager: oAuthManager) tokenManager.extractTokens(response: response, tokenResponseDelegate: delegate(res:"success", expectedErr: "")) oAuthManager.tokenManager = tokenManager authManager.launchChangePasswordUI(authorizationDelegate:delegate(res:"", expectedErr:"")) @@ -299,7 +299,7 @@ public class AuthorizationManagerTests : XCTestCase { func tests_launchDetails() { let oAuthManager = OAuthManager(appId: AppID.sharedInstance) - AppID.sharedInstance.initialize(tenantId: "tenant1", bluemixRegion: "region2") + AppID.sharedInstance.initialize(tenantId: "tenant1", region: "region2") let authManager = MockAuthorizationManagerWithGoodResponse(oAuthManager: oAuthManager) let authManagerNoCode = MockAuthorizationManager(oAuthManager: oAuthManager) let authManagerRequestError = MockAuthorizationManagerWithRequestError(oAuthManager: oAuthManager) @@ -345,7 +345,7 @@ public class AuthorizationManagerTests : XCTestCase { //id token from cloud directory let data = "{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiZXhwIjoxNDg3MDY2MzAyLCJhdWQiOiIxN2UxMjg5YjY3YTUzMjAwNDgxN2E1YTBiZDMxMzliOWNhYzg0MTQ4IiwiaWF0IjoxNDg3MDYyNzAyLCJhdXRoX2J5IjoiZmFjZWJvb2siLCJ0ZW5hbnQiOiI0ZGJhOTQzMC01NGU2LTRjZjItYTUxNi02ZjczZmViNzAyYmIiLCJzY29wZSI6ImFwcGlkX2RlZmF1bHQgYXBwaWRfcmVhZHByb2ZpbGUgYXBwaWRfcmVhZHVzZXJhdHRyIGFwcGlkX3dyaXRldXNlcmF0dHIifQ.enUpEwjdXGJYF9VHolYcKpT8yViYBCbcxp7p7e3n2JamUx68EDEwVPX3qQTyFCz4cXhGmhF8d3rsNGNxMuglor_LRhHDIzHtN5CPi0aqCh3QuF1dQrRBbmjOk2zjinP6pp5WaZvpbush8LEVa8CiZ3Cy2l9IHdY5f4ApKuh29oOj860wwrauYovX2M0f7bDLSwgwXTXydb9-ooawQI7NKkZOlVDI_Bxawmh34VLgAwepyqOR_38YEWyJm7mocJEkT4dqKMaGQ5_WW564JHtqy8D9kIsoN6pufIyr427ApsCdcj_KcYdCdZtJAgiP5x9J5aNmKLsyJYNZKtk2HTMmlw\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJvS3dTY21CRFdITjBMVEhnVDRpQjhpMjdZUjNYOF9IRWQ3Smo2RlEtcHhVIn0.eyJpc3MiOiJhcHBpZC1vYXV0aC5zdGFnZTEubXlibHVlbWl4Lm5ldCIsImF1ZCI6IjQxNDIzNzZmYjFiYjU1ZjE4ZjQxNTE0ZmU4NWNlMGQ2MjlmZjk0YmYiLCJleHAiOjE1MDA1NTE4NzUsInRlbmFudCI6IjIyOGUzMGMyLWM3ZWMtNGUwZS04ZWQxLTZhZWMwZTkzZDRlYSIsImlhdCI6MTUwMDU0ODI3NSwiZW1haWwiOiJyb3RlbUBpYm0uY29tIiwibmFtZSI6InJvdGVtQGlibS5jb20iLCJzdWIiOiI1ZWY3NjQ3Mi0xMGM0LTQ4YmItYTRlMS1iOTg1OGFhODdmODgiLCJpZGVudGl0aWVzIjpbeyJwcm92aWRlciI6ImNsb3VkX2RpcmVjdG9yeSIsImlkIjoiYmQ5OGU3YTgtNjAzNS00ZTA3LTlkOTQtMDRjMDRjOWZkN2FiIn1dLCJhbXIiOlsiY2xvdWRfZGlyZWN0b3J5Il0sIm9hdXRoX2NsaWVudCI6eyJuYW1lIjoiYXBwaWQiLCJ0eXBlIjoibW9iaWxlYXBwIiwic29mdHdhcmVfaWQiOiJjb20uaWJtLm1vYmlsZWZpcnN0cGxhdGZvcm0uYXBwaWQiLCJzb2Z0d2FyZV92ZXJzaW9uIjoiMS4wIiwiZGV2aWNlX2lkIjoiZjNhZWQ3ZWEtMGUzNC0zNGM0LWI2NDgtMTJjZTQwYmE5ZWFhIiwiZGV2aWNlX21vZGVsIjoiQW5kcm9pZCBTREsgYnVpbHQgZm9yIHg4Nl82NCIsImRldmljZV9vcyI6ImFuZHJvaWQifX0.A-cHskvxS947usTLm90DtOYh7qyyvZi61D3XUIZ2Kxtw6mJE_ShsTtsR0b1uavYVyZTXUeD6bqKKzEqDD8TDpB7KO8gAePuUdMyMPF-ObVcgF3mzHzusWOHUiVUr0sbtF-i9YbyPwO4r6cs_GhhfeY05e4sDL7Gy9l2ab9IoSOJ-zDGe4_cJjkevbZ6Sl31PcRqz89wip5ixvhhvApkusojKcO-WG-6hDLWKrlf8Iz5AP4YLN5vpB7-9nCS2Z5whRnlr9kVyott8h6AREI_pvcjUUCvA7hrhiVJv38oS6yeTMeWPj4Q5RI9iYdF3rzFVw44ODnIKtXeP9IOzJEvlqA\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) - let tokenManager:TokenManager = TokenManager(oAuthManager: oAuthManager) + let tokenManager:TokenManager = MockTokenManagerWithValidateAToken(oAuthManager: oAuthManager) tokenManager.extractTokens(response: response, tokenResponseDelegate: delegate(res:"success", expectedErr: "")) oAuthManager.tokenManager = tokenManager @@ -354,23 +354,23 @@ public class AuthorizationManagerTests : XCTestCase { testLaunchChangeDetails_request_error(authManager: authManagerRequestError, delegate:delegate(res:"failure", expectedErr:"Unable to get response from server")) } - func testLaunchChangeDetails_success(authManager: BluemixAppID.AuthorizationManager, delegate: AuthorizationDelegate) { + func testLaunchChangeDetails_success(authManager: IBMCloudAppID.AuthorizationManager, delegate: AuthorizationDelegate) { authManager.launchChangeDetailsUI(authorizationDelegate:delegate) XCTAssertEqual(authManager.authorizationUIManager?.redirectUri as String!, "redirect") let expectedUrl: String! = "https://appid-oauthregion2/oauth/v3/tenant1/cloud_directory/change_details?code=1234&client_id=someclient&redirect_uri=redirect&language=" + Locale.current.identifier XCTAssertEqual(authManager.authorizationUIManager?.authorizationUrl as String!, expectedUrl) } - func testLaunchChangeDetails_no_code(authManager: BluemixAppID.AuthorizationManager, delegate: AuthorizationDelegate) { + func testLaunchChangeDetails_no_code(authManager: IBMCloudAppID.AuthorizationManager, delegate: AuthorizationDelegate) { authManager.launchChangeDetailsUI(authorizationDelegate:delegate) } - func testLaunchChangeDetails_request_error(authManager: BluemixAppID.AuthorizationManager, delegate: AuthorizationDelegate) { + func testLaunchChangeDetails_request_error(authManager: IBMCloudAppID.AuthorizationManager, delegate: AuthorizationDelegate) { authManager.launchChangeDetailsUI(authorizationDelegate:delegate) } func testLaunchSignUpAuthorizationUI() { - let authManager = BluemixAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + let authManager = IBMCloudAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) class delegate: AuthorizationDelegate { var res:String @@ -398,7 +398,7 @@ public class AuthorizationManagerTests : XCTestCase { XCTFail() } } - + func onAuthorizationSuccess(accessToken: AccessToken?, identityToken: IdentityToken?, refreshToken: RefreshToken?, @@ -426,7 +426,7 @@ public class AuthorizationManagerTests : XCTestCase { } func testLaunchForgotPasswordUI_registration_fails() { - let authManager = BluemixAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + let authManager = IBMCloudAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) class delegate: AuthorizationDelegate { var res:String @@ -454,7 +454,7 @@ public class AuthorizationManagerTests : XCTestCase { XCTFail() } } - + func onAuthorizationSuccess(accessToken: AccessToken?, identityToken: IdentityToken?, refreshToken: RefreshToken?, @@ -475,7 +475,7 @@ public class AuthorizationManagerTests : XCTestCase { } func testLaunchForgotPasswordUI_registration_success() { - let authManager = BluemixAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + let authManager = IBMCloudAppID.AuthorizationManager(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) class delegate: AuthorizationDelegate { var res:String @@ -503,7 +503,7 @@ public class AuthorizationManagerTests : XCTestCase { XCTFail() } } - + func onAuthorizationSuccess(accessToken: AccessToken?, identityToken: IdentityToken?, refreshToken: RefreshToken?, @@ -516,7 +516,7 @@ public class AuthorizationManagerTests : XCTestCase { } - AppID.sharedInstance.initialize(tenantId: "tenant1", bluemixRegion: ".region2") + AppID.sharedInstance.initialize(tenantId: "tenant1", region: ".region2") MockRegistrationManager.shouldFail = false authManager.registrationManager = MockRegistrationManager(oauthManager:OAuthManager(appId:AppID.sharedInstance)) authManager.launchForgotPasswordUI(authorizationDelegate: delegate(res: "failure", expectedErr: "")) @@ -576,18 +576,19 @@ public class AuthorizationManagerTests : XCTestCase { XCTFail("Should have called obtainTokensRefreshToken but it wasn't called") } } + } - class MockAuthorizationManager: BluemixAppID.AuthorizationManager { - var response : Response? = nil - var error : Error? = nil + class MockAuthorizationManager: IBMCloudAppID.AuthorizationManager { + var response : Response? = nil + var error : Error? = nil override func sendRequest(request: Request, internalCallBack: @escaping BMSCompletionHandler) { - internalCallBack(response, error) + internalCallBack(response, error) } } - class MockAuthorizationManagerWithGoodResponse: BluemixAppID.AuthorizationManager { + class MockAuthorizationManagerWithGoodResponse: IBMCloudAppID.AuthorizationManager { var response : Response? = Response(responseData: "1234".data(using: .utf8), httpResponse: nil, isRedirect: false) var error : Error? = nil @@ -597,12 +598,13 @@ public class AuthorizationManagerTests : XCTestCase { } } - class MockAuthorizationManagerWithRequestError: BluemixAppID.AuthorizationManager { + class MockAuthorizationManagerWithRequestError: IBMCloudAppID.AuthorizationManager { var response : Response? = nil class SomeError : Error { } + var error : Error? = SomeError() override func sendRequest(request: Request, internalCallBack: @escaping BMSCompletionHandler) { internalCallBack(response, error) @@ -619,6 +621,7 @@ public class AuthorizationManagerTests : XCTestCase { class SomeError : Error { } + class delegate: AuthorizationDelegate { var failed = false @@ -629,12 +632,12 @@ public class AuthorizationManagerTests : XCTestCase { func onAuthorizationCanceled() { } - + func onAuthorizationSuccess(accessToken: AccessToken?, identityToken: IdentityToken?, refreshToken: RefreshToken?, response:Response?) { - + } } @@ -643,8 +646,8 @@ public class AuthorizationManagerTests : XCTestCase { // happy flow: let redirect = AppIDConstants.REDIRECT_URI_VALUE - let goodData = "Found. Redirecting to "+redirect+"?code=w7DClMOnf03Dg8OxeyHCrwzChDXCnsOcw4cSw4nDuU_Dqkcmdy1zwoVKw5xEQMO5CsKYVcOiRsKYw4_Ds8OsBAfCpABrw4sAwqnDr37DiMOQwq7CjXMmw4PCt1knw7vCsMOXGHnCvBQ4wq7DjzMrDAJpwoHCmcKxAxbCjcKHSg1dw4vDr8OhHzE9w57CpygtIcOGwrE_wqdjwpw-VSvDg8K-wr7DvjTCoTMhwrV1w5Y6VGNPJG5IWwFFwqzCl8OAw4TDl8OefMOzSE1ofE4OQVTDkMOnPsO5wpTDuGPDigjDjFbDnkvDrVgWw7TClzjCk8O3AsKrRXLDjMKTwrbDv8Kmd0Nlw7rCn0LDgMKRCW_DtcKJOMK4wrjDpEJ-wqs" -let badData = "Found. Redirecting to "+redirect+"?error=ERROR1" + let goodData = "Found. Redirecting to "+redirect+"?code=w7DClMOnf03Dg8OxeyHCrwzChDXCnsOcw4cSw4nDuU_Dqkcmdy1zwoVKw5xEQMO5CsKYVcOiRsKYw4_Ds8OsBAfCpABrw4sAwqnDr37DiMOQwq7CjXMmw4PCt1knw7vCsMOXGHnCvBQ4wq7DjzMrDAJpwoHCmcKxAxbCjcKHSg1dw4vDr8OhHzE9w57CpygtIcOGwrE_wqdjwpw-VSvDg8K-wr7DvjTCoTMhwrV1w5Y6VGNPJG5IWwFFwqzCl8OAw4TDl8OefMOzSE1ofE4OQVTDkMOnPsO5wpTDuGPDigjDjFbDnkvDrVgWw7TClzjCk8O3AsKrRXLDjMKTwrbDv8Kmd0Nlw7rCn0LDgMKRCW_DtcKJOMK4wrjDpEJ-wqs" + let badData = "Found. Redirecting to "+redirect+"?error=ERROR1" let response = Response(responseData: goodData.data(using: .utf8), httpResponse: nil, isRedirect: false) authManager.response = response @@ -692,7 +695,7 @@ let badData = "Found. Redirecting to "+redirect+"?error=ERROR1" authManager.appid.oauthManager?.tokenManager = originalTokenManager } - + class TokenRespDelegate: TokenResponseDelegate { var failed = false @@ -805,4 +808,10 @@ let badData = "Found. Redirecting to "+redirect+"?error=ERROR1" mockTokenManager.verify() } + class MockTokenManagerWithValidateAToken: TokenManager { + + override internal func validateToken(token: Token, tokenResponseDelegate: TokenResponseDelegate, callback: @escaping () -> Void) { + callback() + } + } } diff --git a/BluemixAppIDTests/AuthorizationUIManagerTests.swift b/IBMCloudAppIDTests/AuthorizationUIManagerTests.swift similarity index 96% rename from BluemixAppIDTests/AuthorizationUIManagerTests.swift rename to IBMCloudAppIDTests/AuthorizationUIManagerTests.swift index e9276ff..4bf3e3f 100644 --- a/BluemixAppIDTests/AuthorizationUIManagerTests.swift +++ b/IBMCloudAppIDTests/AuthorizationUIManagerTests.swift @@ -13,7 +13,7 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID public class AuthorizationUIManagerTests: XCTestCase { @@ -30,18 +30,18 @@ public class AuthorizationUIManagerTests: XCTestCase { } } - + class MockSafariView: safariView { - + override func dismiss(animated flag: Bool, completion: (() -> Swift.Void)? = nil) { completion!() } - + } - + let oauthManager = OAuthManager(appId: AppID.sharedInstance) - + class delegate: AuthorizationDelegate { var exp: XCTestExpectation? var errMsg: String? @@ -49,47 +49,47 @@ public class AuthorizationUIManagerTests: XCTestCase { self.exp = exp self.errMsg = errMsg } - + func onAuthorizationFailure(error: AuthorizationError) { XCTAssertEqual(error.description, errMsg) self.exp?.fulfill() } - + func onAuthorizationCanceled() { XCTFail() } - + func onAuthorizationSuccess(accessToken: AccessToken?, identityToken: IdentityToken?, refreshToken: RefreshToken?, response:Response?) { self.exp?.fulfill() } - + } - + // happy flow func testApplicationHappyFlow() { - + let expectation1 = expectation(description: "Obtained tokens") oauthManager.tokenManager = MockTokenManager(oAuthManager: oauthManager, exp: expectation1) let manager = AuthorizationUIManager(oAuthManager: oauthManager, authorizationDelegate: delegate(exp: nil, errMsg: nil), authorizationUrl: "someurl", redirectUri: "someredirect") manager.loginView = MockSafariView(url:URL(string: "http://www.someurl.com")!) // happy flow XCTAssertTrue(manager.application(UIApplication.shared, open: URL(string:AppIDConstants.REDIRECT_URI_VALUE.lowercased() + "?code=somegrantcode")!, options: [:])) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } - + } - - + + // no code no err func testApplicationErr() { - + let expectation1 = expectation(description: "Obtained tokens") let manager = AuthorizationUIManager(oAuthManager: oauthManager, authorizationDelegate: delegate(exp: expectation1, errMsg: "Failed to extract grant code"), authorizationUrl: "someurl", redirectUri: "someredirect") manager.loginView = MockSafariView(url:URL(string: "http://www.someurl.com")!) @@ -100,16 +100,16 @@ public class AuthorizationUIManagerTests: XCTestCase { } } } - - + + // with err msg func testApplicationErr2() { - + let expectation1 = expectation(description: "Obtained tokens") let manager = AuthorizationUIManager(oAuthManager: oauthManager, authorizationDelegate: delegate(exp: expectation1, errMsg: "someerr"), authorizationUrl: "someurl", redirectUri: "someredirect") manager.loginView = MockSafariView(url:URL(string: "http://www.someurl.com")!) XCTAssertFalse(manager.application(UIApplication.shared, open: URL(string:AppIDConstants.REDIRECT_URI_VALUE.lowercased() + "?code=somecode&error=someerr")!, options: [:])) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") @@ -117,21 +117,25 @@ public class AuthorizationUIManagerTests: XCTestCase { } } - + func testApplicationErr3() { class MockRegistrationManager:RegistrationManager { static var expectation:XCTestExpectation? + public override func clearRegistrationData() { MockRegistrationManager.expectation?.fulfill() } + } - - class MockAuthorizationManager:BluemixAppID.AuthorizationManager { + + class MockAuthorizationManager:IBMCloudAppID.AuthorizationManager { static var expectation:XCTestExpectation? + public override func launchAuthorizationUI(accessTokenString: String?, authorizationDelegate: AuthorizationDelegate) { XCTAssertNil(accessTokenString) MockAuthorizationManager.expectation?.fulfill() } + } let expectation1 = expectation(description: "clear data") let expectation2 = expectation(description: "invoke registration") @@ -139,11 +143,11 @@ public class AuthorizationUIManagerTests: XCTestCase { MockRegistrationManager.expectation = expectation1 oauthManager.authorizationManager = MockAuthorizationManager(oAuthManager: oauthManager) MockAuthorizationManager.expectation = expectation2 - + let manager = AuthorizationUIManager(oAuthManager: oauthManager, authorizationDelegate: delegate(exp: expectation1, errMsg: "Failed to obtain access and identity tokens"), authorizationUrl: "someurl", redirectUri: "someredirect") manager.loginView = MockSafariView(url:URL(string: "http://www.someurl.com")!) XCTAssertFalse(manager.application(UIApplication.shared, open: URL(string:AppIDConstants.REDIRECT_URI_VALUE.lowercased() + "?code=somecode&error=invalid_client")!, options: [:])) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") @@ -184,5 +188,5 @@ public class AuthorizationUIManagerTests: XCTestCase { } - + } diff --git a/BluemixAppIDTests/ConfigTests.swift b/IBMCloudAppIDTests/ConfigTests.swift similarity index 80% rename from BluemixAppIDTests/ConfigTests.swift rename to IBMCloudAppIDTests/ConfigTests.swift index a1dfc82..f0cfd6f 100644 --- a/BluemixAppIDTests/ConfigTests.swift +++ b/IBMCloudAppIDTests/ConfigTests.swift @@ -13,7 +13,7 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID public class ConfigTests: XCTestCase { @@ -24,14 +24,18 @@ public class ConfigTests: XCTestCase { XCTAssertEqual("https://appid-oauth", Config.getServerUrl(appId: appid)) // with region and tenant - appid.initialize(tenantId: "sometenant", bluemixRegion: ".region") + appid.initialize(tenantId: "sometenant", region: ".region") XCTAssertEqual("https://appid-oauth.region/oauth/v3/sometenant", Config.getServerUrl(appId: appid)) - + + XCTAssertEqual("https://appid-oauth.region/oauth/v3/sometenant/publickeys", Config.getPublicKeyEndpoint(appId: appid)) + + XCTAssertEqual("appid-oauth.region", Config.getIssuer(appId: appid)) + // with overrideserverhost AppID.overrideServerHost = "somehost/" XCTAssertEqual("somehost/sometenant", Config.getServerUrl(appId: appid)) - - + + } - + } diff --git a/BluemixAppIDTests/Info.plist b/IBMCloudAppIDTests/Info.plist similarity index 95% rename from BluemixAppIDTests/Info.plist rename to IBMCloudAppIDTests/Info.plist index 232861c..6eb3a03 100644 --- a/BluemixAppIDTests/Info.plist +++ b/IBMCloudAppIDTests/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - BluemixAppID + IBMCloudAppID CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/BluemixAppIDTests/OAuthClientTests.swift b/IBMCloudAppIDTests/OAuthClientTests.swift similarity index 97% rename from BluemixAppIDTests/OAuthClientTests.swift rename to IBMCloudAppIDTests/OAuthClientTests.swift index e93061d..5f78102 100644 --- a/BluemixAppIDTests/OAuthClientTests.swift +++ b/IBMCloudAppIDTests/OAuthClientTests.swift @@ -13,10 +13,10 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID public class OAuthClientTests: XCTestCase { - + func testOAuthClient() { let idToken = IdentityTokenImpl(with: AppIDTestConstants.ID_TOKEN) let client = OAuthClientImpl(with: idToken!) @@ -42,7 +42,7 @@ public class OAuthClientTests: XCTestCase { XCTAssertNil(client?.deviceModel) client?.oauthClient?["device_os"] = [:] XCTAssertNil(client?.deviceOS) - + } - + } diff --git a/BluemixAppIDTests/PreferencesTests.swift b/IBMCloudAppIDTests/PreferencesTests.swift similarity index 96% rename from BluemixAppIDTests/PreferencesTests.swift rename to IBMCloudAppIDTests/PreferencesTests.swift index 9424792..66313fd 100644 --- a/BluemixAppIDTests/PreferencesTests.swift +++ b/IBMCloudAppIDTests/PreferencesTests.swift @@ -13,7 +13,7 @@ import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID class PreferencesTests: XCTestCase { override func setUp() { @@ -28,9 +28,9 @@ class PreferencesTests: XCTestCase { XCTAssertEqual(s.get(), "testValue") s.clear() XCTAssertNil(s.get()) - + } - + func testJSONPreference() { let manager = PreferenceManager() let s = manager.getJSONPreference(name: "testJSONPref") @@ -49,6 +49,5 @@ class PreferencesTests: XCTestCase { XCTAssertEqual(s.getAsJSON()?["key3"] as? String, "val3") } - + } - diff --git a/BluemixAppIDTests/RegistrationManagerTests.swift b/IBMCloudAppIDTests/RegistrationManagerTests.swift similarity index 96% rename from BluemixAppIDTests/RegistrationManagerTests.swift rename to IBMCloudAppIDTests/RegistrationManagerTests.swift index 6d996e4..bd5ef0c 100644 --- a/BluemixAppIDTests/RegistrationManagerTests.swift +++ b/IBMCloudAppIDTests/RegistrationManagerTests.swift @@ -13,20 +13,20 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID public class RegistrationManagerTests: XCTestCase { var oauthManager = OAuthManager(appId: AppID.sharedInstance) - + public override func setUp() { AppID.sharedInstance = AppID() - AppID.sharedInstance.initialize(tenantId: "tenant1", bluemixRegion: "region2") + AppID.sharedInstance.initialize(tenantId: "tenant1", region: "region2") oauthManager = OAuthManager(appId: AppID.sharedInstance) oauthManager.registrationManager?.clearRegistrationData() } - + func testClearRegistrationData() { let manager = RegistrationManager(oauthManager:OAuthManager(appId: AppID.sharedInstance)) manager.preferenceManager.getStringPreference(name: AppIDConstants.tenantPrefName).set("sometenant") @@ -37,7 +37,7 @@ public class RegistrationManagerTests: XCTestCase { XCTAssertNil( manager.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).get()) XCTAssertNil( manager.preferenceManager.getStringPreference(name: AppIDConstants.tenantPrefName).get()) } - + class MockRegistrationManagerWithSendRequest: RegistrationManager { var err:Error? var response:Response? @@ -46,15 +46,15 @@ public class RegistrationManagerTests: XCTestCase { self.response = response super.init(oauthManager:oauthManager) } - - + + override internal func generateKeyPair() throws { TestHelpers.clearDictValuesFromKeyChain([AppIDConstants.publicKeyIdentifier : kSecClassKey, AppIDConstants.privateKeyIdentifier : kSecClassKey]) TestHelpers.savePrivateKeyDataToKeyChain(AppIDTestConstants.privateKeyData, tag: AppIDConstants.privateKeyIdentifier) TestHelpers.savePublicKeyDataToKeyChain(AppIDTestConstants.publicKeyData, tag: AppIDConstants.publicKeyIdentifier) return } - + override internal func sendRequest(request:Request, registrationParamsAsData:Data?, internalCallBack: @escaping BMSCompletionHandler) { XCTAssertEqual(request.resourceUrl, Config.getServerUrl(appId: AppID.sharedInstance) + "/clients") @@ -63,15 +63,15 @@ public class RegistrationManagerTests: XCTestCase { XCTAssertEqual(request.timeout, BMSClient.sharedInstance.requestTimeout) let dataAsDictionary = try? Utils.parseJsonStringtoDictionary(String(data: registrationParamsAsData!, encoding: .utf8)!) XCTAssertEqual(try? Utils.JSONStringify(dataAsDictionary as AnyObject), "{\"token_endpoint_auth_method\":\"client_secret_basic\",\"device_model\":\"iPhone\",\"software_version\":\"1.0\",\"client_type\":\"mobileapp\",\"device_os\":\"iOS\",\"software_id\":\"oded.dummyAppForKeyChain\",\"grant_types\":[\"authorization_code\",\"password\"],\"jwks\":{\"keys\":[{\"e\":\"AQAB\",\"kty\":\"RSA\",\"n\":\"AOH-nACU3cCopAz6_SzJuDtUyN4nHhnk9yfF9DFiGPctXPbwMXofZvd9WcYQqtw-w3WV_yhui9PrOVfVBhk6CmM=\"}]},\"redirect_uris\":[\"oded.dummyAppForKeyChain:\\/\\/mobile\\/callback\"],\"device_id\":\"" + (UIDevice.current.identifierForVendor?.uuidString)! + "\",\"response_types\":[\"code\"],\"device_os_version\":\"" + UIDevice.current.systemVersion + "\"}") - + internalCallBack(response, err) } - + } // send request returns error func testRegisterOAuthClient1() { - + let expectation1 = expectation(description: "got to callback") let callback = {(error: Error?) in XCTAssertEqual((error as? AppIDError)?.description, "Failed to register OAuth client") @@ -83,7 +83,7 @@ public class RegistrationManagerTests: XCTestCase { let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let regManager = MockRegistrationManagerWithSendRequest(oauthManager:OAuthManager(appId: AppID.sharedInstance), response: nil, err: err) regManager.registerOAuthClient(callback: callback) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") @@ -91,41 +91,41 @@ public class RegistrationManagerTests: XCTestCase { } } - + // happy flow func testRegisterOAuthClient2() { - + let expectation1 = expectation(description: "got to callback") - + let callback = {(error: Error?) in XCTAssertNil(error) XCTAssertNotNil(self.oauthManager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).get()) XCTAssertEqual(self.oauthManager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).get(), try? Utils.JSONStringify(["key1": "val1", "key2": "val2"] as AnyObject)) XCTAssertEqual(self.oauthManager.registrationManager?.preferenceManager.getStringPreference(name: AppIDConstants.tenantPrefName).get(), "tenant1") - + expectation1.fulfill() } - - + + let response:Response = Response(responseData: try! Utils.JSONStringify(["key1": "val1", "key2": "val2"] as AnyObject).data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 200, httpVersion: nil, headerFields: nil), isRedirect: false) - + let regManager = MockRegistrationManagerWithSendRequest(oauthManager:oauthManager, response: response, err: nil) regManager.registerOAuthClient(callback: callback) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } - - + + } - - + + // send request returns unsuccessful response func testRegisterOAuthClient3() { - + let expectation1 = expectation(description: "got to callback") let callback = {(error: Error?) in XCTAssertEqual((error as? AppIDError)?.description, "Could not register client") @@ -134,23 +134,23 @@ public class RegistrationManagerTests: XCTestCase { expectation1.fulfill() } - + let response:Response = Response(responseData: "some text".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 401, httpVersion: nil, headerFields: nil), isRedirect: false) - + let regManager = MockRegistrationManagerWithSendRequest(oauthManager:OAuthManager(appId: AppID.sharedInstance), response: response, err: nil) regManager.registerOAuthClient(callback: callback) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - - + + // no error and no response func testRegisterOAuthClient4() { - + let expectation1 = expectation(description: "got to callback") let callback = {(error: Error?) in XCTAssertEqual((error as? AppIDError)?.description, "Could not register client") @@ -159,10 +159,10 @@ public class RegistrationManagerTests: XCTestCase { expectation1.fulfill() } - + let regManager = MockRegistrationManagerWithSendRequest(oauthManager:OAuthManager(appId: AppID.sharedInstance), response: nil, err: nil) regManager.registerOAuthClient(callback: callback) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") @@ -170,10 +170,10 @@ public class RegistrationManagerTests: XCTestCase { } } - + // no response text func testRegisterOAuthClient5() { - + let expectation1 = expectation(description: "got to callback") let callback = {(error: Error?) in XCTAssertEqual((error as? AppIDError)?.description, "Could not register client") @@ -182,12 +182,12 @@ public class RegistrationManagerTests: XCTestCase { expectation1.fulfill() } - + let response:Response = Response(responseData: nil, httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 401, httpVersion: nil, headerFields: nil), isRedirect: false) - + let regManager = MockRegistrationManagerWithSendRequest(oauthManager:OAuthManager(appId: AppID.sharedInstance), response: response, err: nil) regManager.registerOAuthClient(callback: callback) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") @@ -202,7 +202,7 @@ public class RegistrationManagerTests: XCTestCase { self.success = success super.init(oauthManager:oauthManager) } - + override internal func registerOAuthClient(callback :@escaping (Error?) -> Void) { if success == true { callback(nil) @@ -210,18 +210,18 @@ public class RegistrationManagerTests: XCTestCase { callback(AppIDError.registrationError(msg: "Failed to register OAuth client")) } } - + } // registration success MockRegistrationManager(oauthManager:OAuthManager(appId: AppID.sharedInstance), success: true).ensureRegistered(callback: {(error: Error?) -> Void in XCTAssertNil(error) }) - AppID.sharedInstance.initialize(tenantId: "sometenant", bluemixRegion: "region") + AppID.sharedInstance.initialize(tenantId: "sometenant", region: "region") // registraiton failure MockRegistrationManager(oauthManager:OAuthManager(appId: AppID.sharedInstance), success: false).ensureRegistered(callback: {(error: Error?) -> Void in XCTAssertNotNil(error) }) - + // already registered var regManager = MockRegistrationManager(oauthManager:OAuthManager(appId: AppID.sharedInstance), success: false) regManager.preferenceManager.getStringPreference(name: AppIDConstants.tenantPrefName).set("sometenant") @@ -229,7 +229,7 @@ public class RegistrationManagerTests: XCTestCase { regManager.ensureRegistered(callback: {(error: Error?) -> Void in XCTAssertNil(error) }) - + // already registered - different tenant regManager = MockRegistrationManager(oauthManager:OAuthManager(appId: AppID.sharedInstance), success: false) regManager.preferenceManager.getStringPreference(name: AppIDConstants.tenantPrefName).set("someothertenant") @@ -237,6 +237,6 @@ public class RegistrationManagerTests: XCTestCase { regManager.ensureRegistered(callback: {(error: Error?) -> Void in XCTAssertNotNil(error) }) - + } } diff --git a/BluemixAppIDTests/SecurityUtilsTests.swift b/IBMCloudAppIDTests/SecurityUtilsTests.swift similarity index 96% rename from BluemixAppIDTests/SecurityUtilsTests.swift rename to IBMCloudAppIDTests/SecurityUtilsTests.swift index ab2ebce..e9ad4ce 100644 --- a/BluemixAppIDTests/SecurityUtilsTests.swift +++ b/IBMCloudAppIDTests/SecurityUtilsTests.swift @@ -13,7 +13,7 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID class SecurityUtilsTest: XCTestCase { var itemLabel = "itemLabel" @@ -21,29 +21,29 @@ class SecurityUtilsTest: XCTestCase { var keySize = 512 var publicKeyTag = AppIDConstants.publicKeyIdentifier var privateKeyTag = AppIDConstants.privateKeyIdentifier - + override func setUp() { super.setUp() TestHelpers.clearDictValuesFromKeyChain([publicKeyTag : kSecClassKey, privateKeyTag : kSecClassKey]) TestHelpers.savePublicKeyDataToKeyChain(AppIDTestConstants.publicKeyData, tag: publicKeyTag) TestHelpers.savePrivateKeyDataToKeyChain(AppIDTestConstants.privateKeyData, tag: privateKeyTag) } - - + + func testKeyPairGeneration() { TestHelpers.clearDictValuesFromKeyChain([publicKeyTag : kSecClassKey, privateKeyTag : kSecClassKey]) XCTAssertNotNil(try? SecurityUtils.generateKeyPair(keySize, publicTag: publicKeyTag, privateTag: privateKeyTag)) } - - + + func testSaveItemToKeyChain() { _ = SecurityUtils.saveItemToKeyChain(itemData, label: itemLabel) XCTAssertEqual(SecurityUtils.getItemFromKeyChain(itemLabel), itemData) _ = SecurityUtils.removeItemFromKeyChain(itemLabel) XCTAssertNil(SecurityUtils.getItemFromKeyChain(itemLabel)) } - - + + func testGetJwksHeader() { // happy flow var jwks:[String:Any]? = try? SecurityUtils.getJWKSHeader() @@ -51,7 +51,7 @@ class SecurityUtilsTest: XCTestCase { XCTAssertEqual(jwks?["e"] as? String, "AQAB") XCTAssertEqual(jwks?["kty"] as? String, "RSA") XCTAssertEqual(jwks?["n"] as? String, "AOH-nACU3cCopAz6_SzJuDtUyN4nHhnk9yfF9DFiGPctXPbwMXofZvd9WcYQqtw-w3WV_yhui9PrOVfVBhk6CmM=") - + // no public key TestHelpers.clearDictValuesFromKeyChain([AppIDConstants.publicKeyIdentifier : kSecClassKey]) do { @@ -61,13 +61,13 @@ class SecurityUtilsTest: XCTestCase { XCTAssertEqual((e as? AppIDError)?.description, "General Error") } } - + func testSignString() { - + // happy flow let signature = try? SecurityUtils.signString("somepayload", keyIds: (publicKeyTag, privateKeyTag), keySize: keySize) XCTAssertEqual(signature, "ODT3jvWINoDIYrdMPMB-n548VKXnVT7wAg378q3vV4b20gkZq66DOPrkM9JmyOsVcrKO7FWCa0VaLu418rkC3w==") } - - + + } diff --git a/BluemixAppIDTests/TestHelpers.swift b/IBMCloudAppIDTests/TestHelpers.swift similarity index 97% rename from BluemixAppIDTests/TestHelpers.swift rename to IBMCloudAppIDTests/TestHelpers.swift index 4ccc76a..b468a38 100644 --- a/BluemixAppIDTests/TestHelpers.swift +++ b/IBMCloudAppIDTests/TestHelpers.swift @@ -13,7 +13,7 @@ import Foundation import BMSCore import XCTest -@testable import BluemixAppID +@testable import IBMCloudAppID public class TestHelpers { @@ -24,11 +24,11 @@ public class TestHelpers { kSecAttrApplicationTag: tag as AnyObject, kSecAttrKeyType : kSecAttrKeyTypeRSA, kSecAttrKeyClass : kSecAttrKeyClassPublic - + ] SecItemAdd(publicKeyAttr as CFDictionary, nil) } - + public static func savePrivateKeyDataToKeyChain(_ key:Data,tag:String) { let publicKeyAttr : [NSString:AnyObject] = [ kSecValueData: key as AnyObject, @@ -36,11 +36,11 @@ public class TestHelpers { kSecAttrApplicationTag: tag as AnyObject, kSecAttrKeyType : kSecAttrKeyTypeRSA, kSecAttrKeyClass : kSecAttrKeyClassPrivate - + ] SecItemAdd(publicKeyAttr as CFDictionary, nil) } - + public static func clearDictValuesFromKeyChain(_ dict : [String : NSString]) { for (tag, kSecClassName) in dict { if kSecClassName == kSecClassKey { @@ -55,7 +55,7 @@ public class TestHelpers { var shouldCallObtainWithRefresh = false var obtainWithRefreshShouldFail = false var obtainWithRefreshCalled = false - + override public func obtainTokensRefreshToken(refreshTokenString: String, tokenResponseDelegate: TokenResponseDelegate) { obtainWithRefreshCalled = true if !shouldCallObtainWithRefresh { @@ -68,13 +68,13 @@ public class TestHelpers { } } } - + func verify() { if shouldCallObtainWithRefresh && !obtainWithRefreshCalled { XCTFail("Should have called obtainTokensRefreshToken but it wasn't called") } } - + } diff --git a/BluemixAppIDTests/TokenManagerTests.swift b/IBMCloudAppIDTests/TokenManagerTests.swift similarity index 67% rename from BluemixAppIDTests/TokenManagerTests.swift rename to IBMCloudAppIDTests/TokenManagerTests.swift index 2633db2..7e32235 100644 --- a/BluemixAppIDTests/TokenManagerTests.swift +++ b/IBMCloudAppIDTests/TokenManagerTests.swift @@ -13,11 +13,12 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +import JOSESwift +@testable import IBMCloudAppID class TokenManagerTests: XCTestCase { var tokenManager:TokenManager = TokenManager(oAuthManager: OAuthManager(appId:AppID.sharedInstance)) - + override func setUp() { super.setUp() } @@ -26,19 +27,19 @@ class TokenManagerTests: XCTestCase { func testClearStoredTokens() { XCTAssertNil(tokenManager.latestAccessToken) XCTAssertNil(tokenManager.latestIdentityToken) - + tokenManager.latestAccessToken = AccessTokenImpl(with: AppIDTestConstants.ACCESS_TOKEN) tokenManager.latestIdentityToken = IdentityTokenImpl(with: AppIDTestConstants.ID_TOKEN) - + XCTAssertNotNil(tokenManager.latestAccessToken) XCTAssertNotNil(tokenManager.latestIdentityToken) - + tokenManager.clearStoredToken() XCTAssertNil(tokenManager.latestAccessToken) XCTAssertNil(tokenManager.latestIdentityToken) - + } - + static var clientId = "someclient" class MockTokenManagerWithSendRequest: TokenManager { var err:Error? @@ -50,7 +51,7 @@ class TokenManagerTests: XCTestCase { self.throwExc = throwExc super.init(oAuthManager:oauthManager) } - + override internal func extractTokens(response: Response, tokenResponseDelegate:TokenResponseDelegate) { XCTAssertEqual(response.responseData, self.response?.responseData) tokenResponseDelegate.onAuthorizationSuccess( @@ -59,18 +60,18 @@ class TokenManagerTests: XCTestCase { refreshToken: nil, response: response) } - + override internal func createAuthenticationHeader(clientId: String) throws -> String { if throwExc { - throw AppIDError.generalError + throw AppIDError.generalError } else { - XCTAssertEqual(clientId, TokenManagerTests.clientId) - return "Bearer signature" + XCTAssertEqual(clientId, TokenManagerTests.clientId) + return "Bearer signature" } } - + override internal func sendRequest(request:Request, body registrationParamsAsData:Data?, internalCallBack: @escaping BMSCompletionHandler) { - + XCTAssertEqual(request.resourceUrl, Config.getServerUrl(appId: AppID.sharedInstance) + "/token") XCTAssertEqual(request.httpMethod, HttpMethod.POST) XCTAssertEqual(request.headers.count, 2) @@ -78,12 +79,12 @@ class TokenManagerTests: XCTestCase { XCTAssertEqual(request.headers["Authorization"], "Bearer signature") XCTAssertEqual(request.timeout, BMSClient.sharedInstance.requestTimeout) XCTAssertEqual(String(data: registrationParamsAsData!, encoding: .utf8), "grant_type=authorization_code&code=thisisgrantcode&client_id=someclient&redirect_uri=redirect") - + internalCallBack(response, err) } - + } - + class MockTokenManagerWithSendRequestRop: TokenManager { var err:Error? var response:Response? @@ -94,7 +95,7 @@ class TokenManagerTests: XCTestCase { self.throwExc = throwExc super.init(oAuthManager:oauthManager) } - + override internal func extractTokens(response: Response, tokenResponseDelegate:TokenResponseDelegate) { XCTAssertEqual(response.responseData, self.response?.responseData) tokenResponseDelegate.onAuthorizationSuccess( @@ -103,7 +104,7 @@ class TokenManagerTests: XCTestCase { refreshToken: nil, response: response) } - + override internal func createAuthenticationHeader(clientId: String) throws -> String { if throwExc { throw AppIDError.generalError @@ -112,9 +113,9 @@ class TokenManagerTests: XCTestCase { return "Bearer signature" } } - + override internal func sendRequest(request:Request, body registrationParamsAsData:Data?, internalCallBack: @escaping BMSCompletionHandler) { - + XCTAssertEqual(request.resourceUrl, Config.getServerUrl(appId: AppID.sharedInstance) + "/token") XCTAssertEqual(request.httpMethod, HttpMethod.POST) XCTAssertEqual(request.headers.count, 2) @@ -122,12 +123,12 @@ class TokenManagerTests: XCTestCase { XCTAssertEqual(request.headers["Authorization"], "Bearer signature") XCTAssertEqual(request.timeout, BMSClient.sharedInstance.requestTimeout) XCTAssertEqual(String(data: registrationParamsAsData!, encoding: .utf8), "grant_type=password&username=thisisusername&password=thisispassword") - + internalCallBack(response, err) } - + } - + class MockTokenManagerWithSendRequestAssertion: TokenManager { var err:Error? var response:Response? @@ -139,7 +140,7 @@ class TokenManagerTests: XCTestCase { self.throwExc = throwExc super.init(oAuthManager:oauthManager) } - + override internal func extractTokens(response: Response, tokenResponseDelegate:TokenResponseDelegate) { XCTAssertEqual(response.responseData, self.response?.responseData) tokenResponseDelegate.onAuthorizationSuccess( @@ -148,7 +149,7 @@ class TokenManagerTests: XCTestCase { refreshToken: nil, response: response) } - + override internal func createAuthenticationHeader(clientId: String) throws -> String { if throwExc { throw AppIDError.generalError @@ -157,9 +158,9 @@ class TokenManagerTests: XCTestCase { return "Bearer signature" } } - + override internal func sendRequest(request:Request, body registrationParamsAsData:Data?, internalCallBack: @escaping BMSCompletionHandler) { - + XCTAssertEqual(request.resourceUrl, Config.getServerUrl(appId: AppID.sharedInstance) + "/token") XCTAssertEqual(request.httpMethod, HttpMethod.POST) XCTAssertEqual(request.headers.count, 2) @@ -168,13 +169,13 @@ class TokenManagerTests: XCTestCase { XCTAssertEqual(request.timeout, BMSClient.sharedInstance.requestTimeout) self.requestFormData = String(data: registrationParamsAsData!, encoding: .utf8) // XCTAssertEqual(String(data: registrationParamsAsData!, encoding: .utf8), "grant_type=password&appid_access_token=testAccessToken&username=thisisusername&password=thisispassword") - + internalCallBack(response, err) } - + } - - + + class delegate: AuthorizationDelegate { var exp:XCTestExpectation var msg:String @@ -184,18 +185,18 @@ class TokenManagerTests: XCTestCase { self.msg = msg self.success = success } - + func onAuthorizationCanceled() { - + } - + func onAuthorizationFailure(error: AuthorizationError) { if !success { XCTAssertEqual(error.description, msg) exp.fulfill() } } - + func onAuthorizationSuccess(accessToken: AccessToken?, identityToken: IdentityToken?, refreshToken: RefreshToken?, @@ -206,10 +207,10 @@ class TokenManagerTests: XCTestCase { exp.fulfill() } } - + } - - + + // no registration data func testObtainTokensFailWhenNotRegistered() { let expectation1 = expectation(description: "got to callback") @@ -217,7 +218,7 @@ class TokenManagerTests: XCTestCase { oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).clear() let tokenManager = MockTokenManagerWithSendRequest(oauthManager:oauthmanager, response: nil, err: nil) tokenManager.obtainTokensAuthCode(code: "thisisgrantcode", authorizationDelegate: delegate(exp:expectation1, msg: "Client not registered", success: false)) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") @@ -225,76 +226,76 @@ class TokenManagerTests: XCTestCase { } } - - + + // create auth header throws exception func testObtainTokens10() { - + let expectation1 = expectation(description: "got to callback") - // let err = AppIDError.registrationError(msg: "Failed to create authentication header") + // let err = AppIDError.registrationError(msg: "Failed to create authentication header") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId, AppIDConstants.JSON_REDIRECT_URIS_KEY : ["redirect"]] as [String:Any]) - - + + let tokenManager = MockTokenManagerWithSendRequest(oauthManager:oauthmanager, response: nil, err: nil, throwExc: true) tokenManager.obtainTokensAuthCode(code: "thisisgrantcode", authorizationDelegate: delegate(exp:expectation1, msg: "Failed to create authentication header")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } - + } - - + + func testObtainTokensUsingRop_no_response() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: nil, err: err) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + func testObtainTokensUsingRop_with_access_token() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let tokenManager = MockTokenManagerWithSendRequestAssertion(oauthManager:oauthmanager, response: nil, err: err) tokenManager.obtainTokensRoP(accessTokenString: "testAccessToken" ,username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } XCTAssertEqual(tokenManager.requestFormData, - "grant_type=password&appid_access_token=testAccessToken&username=thisisusername&password=thisispassword") + "grant_type=password&appid_access_token=testAccessToken&username=thisisusername&password=thisispassword") } - + func testObtainTokensUsingRefreshToken() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let tokenManager = MockTokenManagerWithSendRequestAssertion(oauthManager:oauthmanager, response: nil, err: err) tokenManager.obtainTokensRefreshToken(refreshTokenString: "xxtt", tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") @@ -304,254 +305,254 @@ class TokenManagerTests: XCTestCase { } func testObtainTokensUsingRop2_catch() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let response:Response = Response(responseData: "some text".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 400, httpVersion: nil, headerFields: nil), isRedirect: false) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: response, err: err) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + // no error and no response func testObtainTokensUsingRop_no_err_no_response() { - + let expectation1 = expectation(description: "got to callback") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : "someclient"]) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: nil, err: nil) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to extract tokens")) - - + + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + func testObtainTokensUsingRop4_no_error_description() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let response:Response = Response(responseData: "{{\"error\":\"invalid_grant\"}}".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 400, httpVersion: nil, headerFields: nil), isRedirect: false) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: response, err: err) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + func testObtainTokensUsingRop4_no_error() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let response:Response = Response(responseData: "{\"error_description\":\"some error\", \"baderror\":\"invalid_grant\"}".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 400, httpVersion: nil, headerFields: nil), isRedirect: false) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: response, err: err) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + func testObtainTokensUsingRop4_with_error_description() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let response:Response = Response(responseData: "{\"error_description\":\"some error\", \"error\":\"invalid_grant\"}".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 400, httpVersion: nil, headerFields: nil), isRedirect: false) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: response, err: err) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "some error")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + func testObtainTokensUsingRop4_casting_issue() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let response:Response = Response(responseData: "{\"error_description\":123, \"error\":123}".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 400, httpVersion: nil, headerFields: nil), isRedirect: false) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: response, err: err) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + // Pending User Verification func testObtainTokensUsingRop_403_response() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let response:Response = Response(responseData: "{\"error_description\":\"Pending User Verification\", \"error_code\":\"FORBIDDEN\"}".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 403, httpVersion: nil, headerFields: nil), isRedirect: false) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: response, err: err) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Pending User Verification")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + func testObtainTokensUsingRop_no_400() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId]) - + let response:Response = Response(responseData: "{\"error_description\":\"some error\", \"error\":\"invalid_grant\"}".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 500, httpVersion: nil, headerFields: nil), isRedirect: false) - + let tokenManager = MockTokenManagerWithSendRequestRop(oauthManager:oauthmanager, response: response, err: err) tokenManager.obtainTokensRoP(username: "thisisusername", password: "thisispassword",tokenResponseDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } } - + // with err func testObtainTokens() { - + let expectation1 = expectation(description: "got to callback") let err = AppIDError.registrationError(msg: "Failed to register OAuth client") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : TokenManagerTests.clientId, AppIDConstants.JSON_REDIRECT_URIS_KEY : ["redirect"]] as [String:Any]) - - + + let tokenManager = MockTokenManagerWithSendRequest(oauthManager:oauthmanager, response: nil, err: err) tokenManager.obtainTokensAuthCode(code: "thisisgrantcode", authorizationDelegate: delegate(exp:expectation1, msg: "Failed to retrieve tokens")) - + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } - + } - + // unsuccessful response func testObtainTokens2() { - + let expectation1 = expectation(description: "got to callback") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : "someclient", AppIDConstants.JSON_REDIRECT_URIS_KEY : ["redirect"]] as [String:Any]) let response:Response = Response(responseData: "some text".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 401, httpVersion: nil, headerFields: nil), isRedirect: false) - + let tokenManager = MockTokenManagerWithSendRequest(oauthManager:oauthmanager, response: response, err: nil) tokenManager.obtainTokensAuthCode(code: "thisisgrantcode", authorizationDelegate: delegate(exp:expectation1, msg: "Failed to extract tokens")) - - + + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } - + } - - + + // no error and no response func testObtainTokens3() { - + let expectation1 = expectation(description: "got to callback") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : "someclient", AppIDConstants.JSON_REDIRECT_URIS_KEY : ["redirect"]] as [String:Any]) - + let tokenManager = MockTokenManagerWithSendRequest(oauthManager:oauthmanager, response: nil, err: nil) tokenManager.obtainTokensAuthCode(code: "thisisgrantcode", authorizationDelegate: delegate(exp:expectation1, msg: "Failed to extract tokens")) - - + + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } - + } - - + + // happy flow func testObtainTokens4() { - + let expectation1 = expectation(description: "got to callback") let oauthmanager = OAuthManager(appId: AppID.sharedInstance) oauthmanager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : "someclient", AppIDConstants.JSON_REDIRECT_URIS_KEY : ["redirect"]] as [String:Any]) - + let response:Response = Response(responseData: "some text".data(using: .utf8), httpResponse: HTTPURLResponse(url: URL(string: "ADS")!, statusCode: 200, httpVersion: nil, headerFields: nil), isRedirect: false) let tokenManager = MockTokenManagerWithSendRequest(oauthManager:oauthmanager, response: response, err: nil) tokenManager.obtainTokensAuthCode(code: "thisisgrantcode", authorizationDelegate: delegate(exp:expectation1, success: true)) - - + + waitForExpectations(timeout: 1) { error in if let error = error { XCTFail("err: \(error)") } } - + } - + class ExtractTokensDelegate: AuthorizationDelegate { var res:String var expectedError:String var fails:Int = 0 var cancel:Int = 0 var success:Int = 0 - + var accessToken: AccessToken? var identityToken: IdentityToken? var refreshToken: RefreshToken? - + public init(res:String, expectedErr:String) { self.expectedError = expectedErr self.res = res } - + func onAuthorizationFailure(error: AuthorizationError) { XCTAssertEqual(error.description, expectedError) self.fails += 1 @@ -559,14 +560,14 @@ class TokenManagerTests: XCTestCase { XCTFail() } } - + func onAuthorizationCanceled() { self.cancel += 1 if res != "cancel" { XCTFail() } } - + func onAuthorizationSuccess(accessToken: AccessToken?, identityToken: IdentityToken?, refreshToken: RefreshToken?, @@ -579,12 +580,8 @@ class TokenManagerTests: XCTestCase { XCTFail() } } - + } - - let validIdTokenPayload = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiYXVkIjoiMTdlMTI4OWI2N2E1MzIwMDQ4MTdhNWEwYmQzMTM5YjljYWM4NDE0OCIsImV4cCI6MTQ4NzA2NjMwMiwiYXV0aF9ieSI6ImZhY2Vib29rIiwidGVuYW50IjoiNGRiYTk0MzAtNTRlNi00Y2YyLWE1MTYtNmY3M2ZlYjcwMmJiIiwiaWF0IjoxNDg3MDYyNzAyLCJuYW1lIjoiRG9uIExvbiIsImVtYWlsIjoiZG9ubG9ucXdlcnR5QGdtYWlsLmNvbSIsImdlbmRlciI6Im1hbGUiLCJsb2NhbGUiOiJlbl9VUyIsInBpY3R1cmUiOiJodHRwczovL3Njb250ZW50Lnh4LmZiY2RuLm5ldC92L3QxLjAtMS9wNTB4NTAvMTM1MDE1NTFfMjg2NDA3ODM4Mzc4ODkyXzE3ODU3NjYyMTE3NjY3MzA2OTdfbi5qcGc_b2g9MjQyYmMyZmI1MDU2MDliNDQyODc0ZmRlM2U5ODY1YTkmb2U9NTkwN0IxQkMiLCJpZGVudGl0aWVzIjpbeyJwcm92aWRlciI6ImZhY2Vib29rIiwiaWQiOiIzNzc0NDAxNTkyNzU2NTkifV0sIm9hdXRoX2NsaWVudCI6eyJuYW1lIjoiT2RlZEFwcElEYXBwaWQiLCJ0eXBlIjoibW9iaWxlYXBwIiwic29mdHdhcmVfaWQiOiJPZGVkQXBwSURhcHBpZElEIiwic29mdHdhcmVfdmVyc2lvbiI6IjEuMCIsImRldmljZV9pZCI6Ijk5MDI0Njg4LUZGMTktNDg4Qy04RjJELUY3MTY2MDZDQTU5NCIsImRldmljZV9tb2RlbCI6ImlQaG9uZSIsImRldmljZV9vcyI6ImlQaG9uZSBPUyJ9fQ.kFPUtpi9AROmBvQqPa19LgX18aYSSbnjlea4Hg0OA4UUw8XYnuoufBWpmmzDpaqZVnN5LTWg9YK5-wtB5Hi9YwX8bhklkeciHP_1ue-fyNDLN2uCNUvBxh916mgFy8u1gFicBcCzQkVoSDSL4Pcjgo0VoTla8t36wLFRtEKmBQ-p8UOlvjD-dnAoNBDveUsNNyeaLMdVPRRfXi-RYWOH3E9bjvyhHd-Zea2OX3oC1XRpqNgrUBXQblskOi_mEll_iWAUX5oD23tOZB9cb0eph9B6_tDZutgvaY338ZD1W9St6YokIL8IltKbrX3q1_FFJSu9nfNPgILsKIAKqe9fHQ" - - let validAccessTokenPayload = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiJtb2JpbGVjbGllbnRhY2Nlc3Muc3RhZ2UxLm5nLmJsdWVtaXgubmV0IiwiZXhwIjoxNDg3MDY2MzAyLCJhdWQiOiIxN2UxMjg5YjY3YTUzMjAwNDgxN2E1YTBiZDMxMzliOWNhYzg0MTQ4IiwiaWF0IjoxNDg3MDYyNzAyLCJhdXRoX2J5IjoiZmFjZWJvb2siLCJ0ZW5hbnQiOiI0ZGJhOTQzMC01NGU2LTRjZjItYTUxNi02ZjczZmViNzAyYmIiLCJzY29wZSI6ImFwcGlkX2RlZmF1bHQgYXBwaWRfcmVhZHByb2ZpbGUgYXBwaWRfcmVhZHVzZXJhdHRyIGFwcGlkX3dyaXRldXNlcmF0dHIifQ.enUpEwjdXGJYF9VHolYcKpT8yViYBCbcxp7p7e3n2JamUx68EDEwVPX3qQTyFCz4cXhGmhF8d3rsNGNxMuglor_LRhHDIzHtN5CPi0aqCh3QuF1dQrRBbmjOk2zjinP6pp5WaZvpbush8LEVa8CiZ3Cy2l9IHdY5f4ApKuh29oOj860wwrauYovX2M0f7bDLSwgwXTXydb9-ooawQI7NKkZOlVDI_Bxawmh34VLgAwepyqOR_38YEWyJm7mocJEkT4dqKMaGQ5_WW564JHtqy8D9kIsoN6pufIyr427ApsCdcj_KcYdCdZtJAgiP5x9J5aNmKLsyJYNZKtk2HTMmlw" func testExtractTokensFailsWhenNoResponseText() { let response = Response(responseData: nil, httpResponse: nil, isRedirect: false) @@ -606,7 +603,7 @@ class TokenManagerTests: XCTestCase { } func testExtractTokensFailsWhenNoAccessToken() { - let data = "{\"id_token\":\"\(validIdTokenPayload)\",\"expires_in\":3600}".data(using: .utf8) + let data = "{\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Failed to parse server response - no access or identity token") tokenManager.extractTokens(response: response, tokenResponseDelegate: tokenRespDelegate) @@ -614,9 +611,9 @@ class TokenManagerTests: XCTestCase { XCTAssertEqual(tokenRespDelegate.fails, 1) XCTAssertEqual(tokenRespDelegate.cancel, 0) } - + func testExtractTokensFailsWhenNoIdToken() { - let data = "{\"access_token\":\"\(validAccessTokenPayload)\",\"expires_in\":3600}".data(using: .utf8) + let data = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Failed to parse server response - no access or identity token") tokenManager.extractTokens(response: response, tokenResponseDelegate: tokenRespDelegate) @@ -626,9 +623,9 @@ class TokenManagerTests: XCTestCase { } func testExtractTokensFailsWhenNoParsableAccessToken() { - let data = "{\"access_token\":\"nonparsable\",\"id_token\":\"\(validIdTokenPayload)\",\"expires_in\":3600}".data(using: .utf8) + let data = "{\"access_token\":\"nonparsable\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) - let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Failed to parse tokens") + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Failed to parse server response - corrupt access or identity token") tokenManager.extractTokens(response: response, tokenResponseDelegate: tokenRespDelegate) XCTAssertEqual(tokenRespDelegate.success, 0) XCTAssertEqual(tokenRespDelegate.fails, 1) @@ -636,20 +633,149 @@ class TokenManagerTests: XCTestCase { } func testExtractTokensFailsWhenNoParsableIdToken() { - let data = "{\"access_token\":\"\(validAccessTokenPayload)\",\"id_token\":\"nonparsable\",\"expires_in\":3600}".data(using: .utf8) + let data = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"id_token\":\"nonparsable\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) - let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Failed to parse tokens") + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Failed to parse server response - corrupt access or identity token") tokenManager.extractTokens(response: response, tokenResponseDelegate: tokenRespDelegate) XCTAssertEqual(tokenRespDelegate.success, 0) XCTAssertEqual(tokenRespDelegate.fails, 1) XCTAssertEqual(tokenRespDelegate.cancel, 0) } - + + func testExtractTokensFailsMissingKid() { + let data = "{\"access_token\":\"\(AppIDTestConstants.ACCESS_TOKEN)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) + let response = Response(responseData: data, httpResponse: nil, isRedirect: false) + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Invalid token : Missing kid") + tokenManager.extractTokens(response: response, tokenResponseDelegate: tokenRespDelegate) + XCTAssertEqual(tokenRespDelegate.success, 0) + XCTAssertEqual(tokenRespDelegate.fails, 1) + XCTAssertEqual(tokenRespDelegate.cancel, 0) + } + + func testExtractTokensFailsInvalidAlg() { + let data = "{\"access_token\":\"\(AppIDTestConstants.malformedAccessTokenInvalidAlg)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) + let response = Response(responseData: data, httpResponse: nil, isRedirect: false) + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Invalid token : Invalid alg") + tokenManager.extractTokens(response: response, tokenResponseDelegate: tokenRespDelegate) + XCTAssertEqual(tokenRespDelegate.success, 0) + XCTAssertEqual(tokenRespDelegate.fails, 1) + XCTAssertEqual(tokenRespDelegate.cancel, 0) + } + + + func testValidateTokenFails() { + let respData = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) + let response = Response(responseData: respData, httpResponse: nil, isRedirect: false) + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Token verification failed") + let publicKeys = getPublicKeys() + guard let key = publicKeys[AppIDTestConstants.kid] else { + tokenRespDelegate.onAuthorizationFailure(error: .authorizationFailure("Failed to get public key")) + return + } + guard let expToken = AccessTokenImpl(with: AppIDTestConstants.expAcessToken) else { + tokenRespDelegate.onAuthorizationFailure(error: .authorizationFailure("Error in token creation")) + return + } + + tokenManager.validateToken(token: expToken, key: key, tokenResponseDelegate: tokenRespDelegate) {tokenRespDelegate.onAuthorizationSuccess(accessToken: expToken,identityToken: nil,refreshToken: nil,response:response)} + XCTAssertEqual(tokenRespDelegate.success, 0) + XCTAssertEqual(tokenRespDelegate.fails, 1) + XCTAssertEqual(tokenRespDelegate.cancel, 0) + } + + func testValidateTokenFailsInvalidIssuer() { + let respData = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) + let response = Response(responseData: respData, httpResponse: nil, isRedirect: false) + let tokenRespDelegatIssuer = ExtractTokensDelegate(res:"failure", expectedErr: "Token verification failed : invalid issuer") + let publicKeys = getPublicKeys() + guard let key = publicKeys[AppIDTestConstants.kid] else { + tokenRespDelegatIssuer.onAuthorizationFailure(error: .authorizationFailure("Failed to get public key")) + return + } + + guard let validToken = AccessTokenImpl(with: AppIDTestConstants.appAnonAccessToken) else { + tokenRespDelegatIssuer.onAuthorizationFailure(error: .authorizationFailure("Error in token creation")) + return + } + let mockAppId = MockAppId.sharedInstance + mockAppId.initialize(tenantId: "4dba9430-54e6-4cf2-a516", region: ".ng.bluemix.net") + let oauthManager = OAuthManager(appId: mockAppId) + oauthManager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : AppIDTestConstants.clientId]) + + let manager:TokenManager = TokenManager(oAuthManager: OAuthManager(appId: mockAppId)) + MockAppId.overrideServerHost = "https://app-oauth.ng.bluemix.net/oauth/v3/" + + manager.validateToken(token: validToken, key: key, tokenResponseDelegate: tokenRespDelegatIssuer) {tokenRespDelegatIssuer.onAuthorizationSuccess(accessToken: validToken,identityToken: nil,refreshToken: nil,response:response)} + XCTAssertEqual(tokenRespDelegatIssuer.success, 0) + XCTAssertEqual(tokenRespDelegatIssuer.fails, 1) + XCTAssertEqual(tokenRespDelegatIssuer.cancel, 0) + } + + func testValidateTokenFailsInvalidAud() { + let respData = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) + let response = Response(responseData: respData, httpResponse: nil, isRedirect: false) + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Token verification failed : invalid audience") + let publicKeys = getPublicKeys() + guard let key = publicKeys[AppIDTestConstants.kid] else { + tokenRespDelegate.onAuthorizationFailure(error: .authorizationFailure("Failed to get public key")) + return + } + + guard let validToken = AccessTokenImpl(with: AppIDTestConstants.appAnonAccessToken) else { + tokenRespDelegate.onAuthorizationFailure(error: .authorizationFailure("Error in token creation")) + return + } + + let mockAppId = MockAppId.sharedInstance + mockAppId.initialize(tenantId: "4dba9430-54e6-4cf2-a516", region: ".ng.bluemix.net") + let oauthManager = OAuthManager(appId: mockAppId) + oauthManager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : "clientId"]) + let manager:TokenManager = TokenManager(oAuthManager: oauthManager) + MockAppId.overrideServerHost = "https://appid-oauth.ng.bluemix.net/oauth/v3/" + + manager.validateToken(token: validToken, key: key, tokenResponseDelegate: tokenRespDelegate) {tokenRespDelegate.onAuthorizationSuccess(accessToken: validToken,identityToken: nil,refreshToken: nil,response:response)} + XCTAssertEqual(tokenRespDelegate.success, 0) + XCTAssertEqual(tokenRespDelegate.fails, 1) + XCTAssertEqual(tokenRespDelegate.cancel, 0) + } + + + + func testValidateTokenFailsInvalidTenant() { + let respData = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) + let response = Response(responseData: respData, httpResponse: nil, isRedirect: false) + let tokenRespDelegateTenant = ExtractTokensDelegate(res:"failure", expectedErr: "Token verification failed : invalid tenant") + let publicKeys = getPublicKeys() + guard let key = publicKeys[AppIDTestConstants.kid] else { + tokenRespDelegateTenant.onAuthorizationFailure(error: .authorizationFailure("Failed to get public key")) + return + } + + guard let validToken = AccessTokenImpl(with: AppIDTestConstants.appAnonAccessToken) else { + tokenRespDelegateTenant.onAuthorizationFailure(error: .authorizationFailure("Error in token creation")) + return + } + + let mockAppId = MockAppId.sharedInstance + mockAppId.initialize(tenantId: "4dba9430-54e6-4cf2-a516", region: ".ng.bluemix.net") + let oauthManager = OAuthManager(appId: mockAppId) + oauthManager.registrationManager?.preferenceManager.getJSONPreference(name: AppIDConstants.registrationDataPref).set([AppIDConstants.client_id_String : AppIDTestConstants.clientId]) + let manager:TokenManager = TokenManager(oAuthManager: OAuthManager(appId: mockAppId)) + MockAppId.overrideServerHost = "https://appid-oauth.ng.bluemix.net/oauth/v3/" + + manager.validateToken(token: validToken, key: key, tokenResponseDelegate: tokenRespDelegateTenant) {tokenRespDelegateTenant.onAuthorizationSuccess(accessToken: validToken,identityToken: nil,refreshToken: nil,response:response)} + XCTAssertEqual(tokenRespDelegateTenant.success, 0) + XCTAssertEqual(tokenRespDelegateTenant.fails, 1) + XCTAssertEqual(tokenRespDelegateTenant.cancel, 0) + } + func testExtractTokensHappyFlow() { - let data = "{\"access_token\":\"\(validAccessTokenPayload)\",\"id_token\":\"\(validIdTokenPayload)\",\"expires_in\":3600}".data(using: .utf8) + let data = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken )\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) let tokenRespDelegate = ExtractTokensDelegate(res:"success", expectedErr: "") - tokenManager.extractTokens(response: response, tokenResponseDelegate: tokenRespDelegate) + let manager:TokenManager = MockTokenManagerWithValidateAToken(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + manager.extractTokens(response: response, + tokenResponseDelegate: tokenRespDelegate) XCTAssertEqual(tokenRespDelegate.success, 1) XCTAssertEqual(tokenRespDelegate.fails, 0) XCTAssertEqual(tokenRespDelegate.cancel, 0) @@ -660,11 +786,12 @@ class TokenManagerTests: XCTestCase { func testExtractTokensHappyFlowWithRefreshToken() { let refreshTokenPayload = "no-matter-refresh-token-has-no-spec" - let data = "{\"access_token\":\"\(validAccessTokenPayload)\",\"id_token\":\"\(validIdTokenPayload)\",\"refresh_token\":\"\(refreshTokenPayload)\",\"expires_in\":3600}".data(using: .utf8) + let data = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"refresh_token\":\"\(refreshTokenPayload)\",\"expires_in\":3600}".data(using: .utf8) let response = Response(responseData: data, httpResponse: nil, isRedirect: false) let tokenRespDelegate = ExtractTokensDelegate(res:"success", expectedErr: "") - tokenManager.extractTokens(response: response, - tokenResponseDelegate: tokenRespDelegate) + let manager:TokenManager = MockTokenManagerWithValidateAToken(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + manager.extractTokens(response: response, + tokenResponseDelegate: tokenRespDelegate) XCTAssertEqual(tokenRespDelegate.success, 1) XCTAssertEqual(tokenRespDelegate.fails, 0) XCTAssertEqual(tokenRespDelegate.cancel, 0) @@ -674,4 +801,120 @@ class TokenManagerTests: XCTestCase { XCTAssertEqual(refreshTokenPayload, tokenRespDelegate.refreshToken!.raw!) } + func testExtractTokenPublicKeyFails() { + let respData = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) + let response = Response(responseData: respData, httpResponse: nil, isRedirect: false) + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Could not find public key for kid") + let manager:TokenManager = MockTokenManagerWithValidateATokenJWT(oAuthManager: OAuthManager(appId: AppID.sharedInstance)) + manager.extractTokens(response: response, + tokenResponseDelegate: tokenRespDelegate) + XCTAssertEqual(tokenRespDelegate.success, 0) + XCTAssertEqual(tokenRespDelegate.fails, 1) + XCTAssertEqual(tokenRespDelegate.cancel, 0) + } + + func testRetrievePublicKeysFailsNilResponse() { + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Failed to get public key from server") + let manager:TokenManager = MockTokenManagerWithRetrievePublicKeys(response: nil, err: nil) + manager.retrievePublicKeys(tokenResponseDelegate: tokenRespDelegate, callback: {}) + XCTAssertEqual(tokenRespDelegate.success, 0) + XCTAssertEqual(tokenRespDelegate.fails, 1) + XCTAssertEqual(tokenRespDelegate.cancel, 0) + } + + func testRetrievePublicKeysFailsInvalidJson() { + let data = "{\"access_token\":\"\(AppIDTestConstants.appAnonAccessToken)\",\"id_token\":\"\(AppIDTestConstants.ID_TOKEN)\",\"expires_in\":3600}".data(using: .utf8) + let response = Response(responseData: data, httpResponse: nil, isRedirect: false) + let tokenRespDelegate = ExtractTokensDelegate(res:"failure", expectedErr: "Failed to parse public key response from server") + let manager:TokenManager = MockTokenManagerWithRetrievePublicKeys(response: response, err: nil) + manager.retrievePublicKeys(tokenResponseDelegate: tokenRespDelegate, callback: {}) + XCTAssertEqual(tokenRespDelegate.success, 0) + XCTAssertEqual(tokenRespDelegate.fails, 1) + XCTAssertEqual(tokenRespDelegate.cancel, 0) + } + + func testRetrievePublicKeys() { + let data = AppIDTestConstants.jwk.data(using: .utf8) + let response = Response(responseData: data, httpResponse: nil, isRedirect: false) + let tokenRespDelegate = ExtractTokensDelegate(res:"success", expectedErr: "") + let err:Error? = nil + let manager:TokenManager = MockTokenManagerWithRetrievePublicKeys(response: response, err: err) + guard let accessToken = AccessTokenImpl(with: AppIDTestConstants.appAnonAccessToken) else { + tokenRespDelegate.onAuthorizationFailure(error: .authorizationFailure("Error in token creation")) + return + } + guard let idToken = IdentityTokenImpl(with: AppIDTestConstants.appAnonAccessToken) else { + tokenRespDelegate.onAuthorizationFailure(error: .authorizationFailure("Error in token creation")) + return + } + var refreshToken: RefreshTokenImpl? + manager.retrievePublicKeys(tokenResponseDelegate: tokenRespDelegate) { + tokenRespDelegate.onAuthorizationSuccess(accessToken: accessToken , identityToken: idToken, refreshToken: refreshToken, response: response) + return + } + XCTAssertEqual(tokenRespDelegate.success, 1) + XCTAssertEqual(tokenRespDelegate.fails, 0) + XCTAssertEqual(tokenRespDelegate.cancel, 0) + } + + class MockTokenManagerWithValidateAToken: TokenManager { + + override internal func validateToken(token: Token, tokenResponseDelegate: TokenResponseDelegate, callback: @escaping () -> Void) { + callback() + } + + } + + class MockTokenManagerWithValidateATokenJWT: TokenManager { + + override internal func validateToken(token: Token, key: SecKey, tokenResponseDelegate: TokenResponseDelegate, callback: @escaping () -> Void ) { + callback() + } + + override internal func retrievePublicKeys(tokenResponseDelegate: TokenResponseDelegate, callback: @escaping () -> Void) { + callback() + } + + } + + class MockTokenManagerWithRetrievePublicKeys: TokenManager { + var err:Error? + var response:Response? + + init(oAuthManager: OAuthManager = OAuthManager(appId: AppID.sharedInstance), response:Response?, err:Error?) { + super.init(oAuthManager: oAuthManager) + self.response = response + self.err = err + } + + override internal func sendRequest(request:Request, body registrationParamsAsData:Data?, internalCallBack: @escaping BMSCompletionHandler) { + internalCallBack(response, err) + } + + } + + func getPublicKeys() -> [String : SecKey] { + + guard let publicKeyJson = try? Utils.parseJsonStringtoDictionary(AppIDTestConstants.jwk), let keys = publicKeyJson["keys"] as? [[String: Any]] else { + return [:] + } + + let publicKeys = keys.reduce([String : SecKey]()) { result, key in + var result = result + print(key) + guard let keyKid = key["kid"] as? String, + let data = try? JSONSerialization.data(withJSONObject: key, options: .prettyPrinted), + let rsaPublicKey = try? RSAPublicKey(data: data), let publicKey = try? rsaPublicKey.converted(to: SecKey.self) else { + return result + } + + result[keyKid] = publicKey + return result + } + return publicKeys + } + + class MockAppId: AppID { + + } } diff --git a/BluemixAppIDTests/TokenTests.swift b/IBMCloudAppIDTests/TokenTests.swift similarity index 98% rename from BluemixAppIDTests/TokenTests.swift rename to IBMCloudAppIDTests/TokenTests.swift index b90750e..f671b5f 100644 --- a/BluemixAppIDTests/TokenTests.swift +++ b/IBMCloudAppIDTests/TokenTests.swift @@ -10,7 +10,7 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID class TokenTests: XCTestCase { @@ -51,7 +51,7 @@ class TokenTests: XCTestCase { XCTAssertNotNil(token?.payload) XCTAssertNotNil(token?.signature) XCTAssertEqual(token?.issuer, "mobileclientaccess.stage1.ng.bluemix.net") - + XCTAssertNil(token?.subject) XCTAssertEqual(token?.audience, "26cb012eb327c612d90a6819163b6bcbd4849cbb") XCTAssertTrue(token?.issuedAt == Date(timeIntervalSince1970: 1487081278 as Double)) @@ -59,7 +59,7 @@ class TokenTests: XCTestCase { XCTAssertEqual(token?.authenticationMethods?[0], nil) XCTAssertTrue(token!.isExpired) XCTAssertTrue(token?.expiration == Date(timeIntervalSince1970: 1487084878 as Double)) - + } - + } diff --git a/BluemixAppIDTests/UserProfileTests.swift b/IBMCloudAppIDTests/UserProfileTests.swift similarity index 99% rename from BluemixAppIDTests/UserProfileTests.swift rename to IBMCloudAppIDTests/UserProfileTests.swift index 013ecde..768fb9c 100644 --- a/BluemixAppIDTests/UserProfileTests.swift +++ b/IBMCloudAppIDTests/UserProfileTests.swift @@ -13,7 +13,7 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID public class UserProfileTests: XCTestCase { @@ -80,7 +80,7 @@ public class UserProfileTests: XCTestCase { } override public func setUp() { - AppID.sharedInstance.initialize(tenantId: "tenant", bluemixRegion: AppID.REGION_US_SOUTH) + AppID.sharedInstance.initialize(tenantId: "tenant", region: AppID.regionUSSouth) } func testGetAllAttributes () { diff --git a/BluemixAppIDTests/UtilsTests.swift b/IBMCloudAppIDTests/UtilsTests.swift similarity index 97% rename from BluemixAppIDTests/UtilsTests.swift rename to IBMCloudAppIDTests/UtilsTests.swift index c807cf8..47a6419 100644 --- a/BluemixAppIDTests/UtilsTests.swift +++ b/IBMCloudAppIDTests/UtilsTests.swift @@ -13,15 +13,15 @@ import Foundation import XCTest import BMSCore -@testable import BluemixAppID +@testable import IBMCloudAppID class UtilsTest: XCTestCase { - - + + func testJSONStringify() { - + let dict:[String:Any] = ["first":true,"second":3, "third" : ["item1","item2",["item3","item4"],"item5"]] let json = try? Utils.JSONStringify(dict as AnyObject) - + let jsonStringOption1 = "{\"first\":true,\"second\":3,\"third\":[\"item1\",\"item2\",[\"item3\",\"item4\"],\"item5\"]}" let jsonStringOption2 = "{\"first\":true,\"third\":[\"item1\",\"item2\",[\"item3\",\"item4\"],\"item5\"],\"second\":3}" let jsonStringOption3 = "{\"third\":[\"item1\",\"item2\",[\"item3\",\"item4\"],\"item5\"],\"first\":true,\"second\":3}" @@ -31,36 +31,36 @@ class UtilsTest: XCTestCase { let cond = (jsonStringOption1 == json || jsonStringOption2 == json || jsonStringOption3 == json || jsonStringOption4 == json || jsonStringOption5 == json || jsonStringOption6 == json) XCTAssertTrue(cond) } - + func testParseJsonStringtoDictionary() { let jsonString = "{\"first\":true,\"second\":3,\"third\":[\"item1\",\"item2\",[\"item3\",\"item4\"],\"item5\"]}" - + // var json = try! JSONSerialization.jsonObject(with: jsonString.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as! [AnyObject] let returnedDict:[String:Any]? = try? Utils.parseJsonStringtoDictionary(jsonString) XCTAssertNotNil(returnedDict) XCTAssertEqual(returnedDict!["first"] as? Bool, true) XCTAssertEqual(returnedDict!["second"] as? Int, 3) - + XCTAssertEqual((returnedDict!["third"] as? [AnyObject])?[0] as? String, "item1") XCTAssertEqual((returnedDict!["third"] as? [AnyObject])?[1] as? String, "item2") XCTAssertEqual(((returnedDict!["third"] as? [AnyObject])?[2] as? [String])!, ["item3","item4"]) XCTAssertEqual((returnedDict!["third"] as? [AnyObject])?[3] as? String, "item5") - - + + } - + private func stringToBase64Data(_ str:String) -> Data { let utf8str = str.data(using: String.Encoding.utf8) let base64EncodedStr = utf8str?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0)) return Data(base64Encoded: base64EncodedStr!, options: NSData.Base64DecodingOptions(rawValue: 0))! } - + func testGetApplicationDetails() { let appInfo = Utils.getApplicationDetails() XCTAssertNotNil(appInfo.name) XCTAssertNotNil(appInfo.version) } - + // func testGetDeviceDictionary() { // let deviceIdentity = AppIDDeviceIdentity() // let appIdentity = AppIDAppIdentity() @@ -82,5 +82,5 @@ class UtilsTest: XCTestCase { XCTAssertEqual(Utils.base64StringFromData(data, isSafeUrl: false),str) XCTAssertEqual(Utils.base64StringFromData(data, isSafeUrl: true),strSafe) } - + } diff --git a/Podfile b/Podfile index 9261f06..a0522ed 100644 --- a/Podfile +++ b/Podfile @@ -1,13 +1,15 @@ use_frameworks! - -target ‘BluemixAppID' do - platform :ios, '9.0' - pod ‘BMSCore’, '~> 2.3.1’ +def shared_pods + platform :ios, '10.0' + pod 'BMSCore', '~> 2.3.1' + pod 'JOSESwift', '~> 1.1.0' end -target 'BluemixAppIDTests' do - platform :ios, '9.0' - pod ‘BMSCore’, '~> 2.3.1’ +target 'IBMCloudAppID' do + shared_pods end +target 'IBMCloudAppIDTests' do + shared_pods +end diff --git a/README.md b/README.md index 2617856..bf18cf4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # IBM Cloud App ID iOS Swift SDK -[![Bluemix powered][img-bluemix-powered]][url-bluemix] +[![IBM Cloud powered][img-ibmcloud-powered]][url-ibmcloud] [![Travis][img-travis-master]][url-travis-master] [![Coveralls][img-coveralls-master]][url-coveralls-master] [![Codacy][img-codacy]][url-codacy] @@ -11,19 +11,19 @@ [![GithubForks][img-github-forks]][url-github-forks] ## Requirements -* Xcode 8.3 or above +* Xcode 9.0 or above * CocoaPods 1.1.0 or higher * MacOS 10.11.5 or higher -* iOS 9 or higher +* iOS 10.0 or higher ## Installing the SDK: -1. Add the 'BluemixAppID' dependency to your Podfile, for example: +1. Add the 'IBMCloudAppID' dependency to your Podfile, for example: ```swift target do use_frameworks! - pod 'BluemixAppID' + pod 'IBMCloudAppID' end ``` 2. From the terminal, run: @@ -36,14 +36,14 @@ 2. Under project setting > info > Url Types, Add $(PRODUCT_BUNDLE_IDENTIFIER) as a URL Scheme 3. Add the following import to your AppDelegate.swift file: ```swift - import BluemixAppID + import IBMCloudAppID ``` 4. Initialize the client SDK by passing the tenantId and region parameters to the initialize method. A common, though not mandatory, place to put the initialization code is in the application:didFinishLaunchingWithOptions: method of the AppDelegate in your Swift application. ```swift - AppID.sharedInstance.initialize(tenantId: , bluemixRegion: AppID.REGION_UK) + AppID.sharedInstance.initialize(tenantId: , region: AppID.regionUK) ``` * Replace "tenantId" with the App ID service tenantId. - * Replace the AppID.REGION_UK with the your App ID region (AppID.REGION_US_SOUTH, AppID.REGION_SYDNEY). + * Replace the AppID.regionUK with the your App ID region (AppID.regionUSSouth, AppID.regionSydney). 5. Add the following code to you AppDelegate file ```swift @@ -56,7 +56,7 @@ After the App ID client SDK is initialized, you can start authenticating users by launching the Login Widget. 1. Add the following import to the file in which you want to use with the login Widget: ```swift -import BluemixAppID +import IBMCloudAppID ``` 2. Add the following code to the same file: ```swift @@ -265,11 +265,11 @@ userProfileManager?.getUserInfo(accessTokenString: accessToken, identityTokenStr Add the following imports to the file in which you want to invoke a protected resource request: ```swift import BMSCore -import BluemixAppID +import IBMCloudAppID ``` Then add the following code: ```swift -BMSClient.sharedInstance.initialize(bluemixRegion: AppID.REGION_UK) +BMSClient.sharedInstance.initialize(region: AppID.regionUK) BMSClient.sharedInstance.authorizationManager = AppIDAuthorizationManager(appid:AppID.sharedInstance) var request:Request = Request(url: "") request.send(completionHandler: {(response:Response?, error:Error?) in @@ -280,8 +280,8 @@ request.send(completionHandler: {(response:Response?, error:Error?) in ## License This package contains code licensed under the Apache License, Version 2.0 (the "License"). You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 and may also view the License in the LICENSE file within this package. -[img-bluemix-powered]: https://img.shields.io/badge/bluemix-powered-blue.svg -[url-bluemix]: http://bluemix.net +[img-ibmcloud-powered]: https://img.shields.io/badge/ibm%20cloud-powered-blue.svg +[url-ibmcloud]: https://www.ibm.com/cloud/ [url-bintray]: https://bintray.com/ibmcloudsecurity/appid-clientsdk-swift [img-license]: https://img.shields.io/github/license/ibm-cloud-security/appid-clientsdk-swift.svg [img-version]: https://img.shields.io/bintray/v/ibmcloudsecurity/maven/appid-clientsdk-swift.svg diff --git a/Source/BluemixAppID/.DS_Store b/Source/BluemixAppID/.DS_Store deleted file mode 100644 index f5c2df16a870cbbd7f8668fbe9df0eb7af7decce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jx;?w5QX266p?6BQtlPFffa=lKF2IU7I%8rIsUu)pGhv<~7NovX;Yg_^`a$ za^kSKo#&TGhc%VjrGON;RKRC%+S2>~9oNMC?>RClAO-%Y0ybZ7)+@eT_SVsBdao^9 t_gp7qZlrUIR!l}K<_~YhH)nappBZnGLuHiHALXR}2)HgXDexN#d;!e7A6EbX diff --git a/Source/BluemixAppID/api/AppID.swift b/Source/IBMCloudAppID/api/AppID.swift similarity index 87% rename from Source/BluemixAppID/api/AppID.swift rename to Source/IBMCloudAppID/api/AppID.swift index 2deb57b..ba34eb8 100644 --- a/Source/BluemixAppID/api/AppID.swift +++ b/Source/IBMCloudAppID/api/AppID.swift @@ -17,32 +17,32 @@ import BMSCore public class AppID { private(set) var tenantId: String? - private(set) var bluemixRegion: String? + private(set) var region: String? private(set) var oauthManager: OAuthManager? public var loginWidget: LoginWidgetImpl? public var userProfileManager: UserProfileManagerImpl? - + public static var overrideServerHost: String? public static var overrideAttributesHost: String? public static var sharedInstance = AppID() internal static let logger = Logger.logger(name: AppIDConstants.AppIDLoggerName) - - static public let REGION_US_SOUTH = ".ng.bluemix.net" - static public let REGION_US_EAST = ".us-east.bluemix.net" - static public let REGION_UK = ".eu-gb.bluemix.net" - static public let REGION_SYDNEY = ".au-syd.bluemix.net" - static public let REGION_GERMANY = ".eu-de.bluemix.net" - + + static public let regionUSSouth = ".ng.bluemix.net" + static public let regionUSEast = ".us-east.bluemix.net" + static public let regionUK = ".eu-gb.bluemix.net" + static public let regionSydney = ".au-syd.bluemix.net" + static public let regionGermany = ".eu-de.bluemix.net" + internal init() {} - + /** Intializes the App ID instance @param tenantId The tenant Id. - @param bluemixRegion The bluemix region. + @param region The IBM Cloud region. */ - public func initialize(tenantId: String, bluemixRegion: String) { + public func initialize(tenantId: String, region: String) { self.tenantId = tenantId - self.bluemixRegion = bluemixRegion + self.region = region self.oauthManager = OAuthManager(appId: self) self.loginWidget = LoginWidgetImpl(oauthManager: self.oauthManager!) self.userProfileManager = UserProfileManagerImpl(appId: self) @@ -51,7 +51,7 @@ public class AppID { public func setPreferredLocale(_ locale: Locale) { self.oauthManager?.setPreferredLocale(locale) } - + public func signinAnonymously(accessTokenString:String? = nil, allowCreateNewAnonymousUsers: Bool = true, authorizationDelegate:AuthorizationDelegate) { oauthManager?.authorizationManager?.loginAnonymously(accessTokenString: accessTokenString, allowCreateNewAnonymousUsers: allowCreateNewAnonymousUsers, authorizationDelegate: authorizationDelegate) } @@ -62,8 +62,8 @@ public class AppID { /** Obtain new access and identity tokens using a refresh token. - - Note that the identity itself (user name/details) will not be refreshed by this operation, + + Note that the identity itself (user name/details) will not be refreshed by this operation, it will remain the same identity but in a new token (new expiration time) */ public func signinWithRefreshToken(refreshTokenString:String? = nil, tokenResponseDelegate:TokenResponseDelegate) { @@ -71,20 +71,20 @@ public class AppID { refreshTokenString: refreshTokenString, tokenResponseDelegate: tokenResponseDelegate) } - + @available(*, deprecated: 3.0, renamed: "signinAnonymously") public func loginAnonymously(accessTokenString:String? = nil, allowCreateNewAnonymousUsers: Bool = true, authorizationDelegate:AuthorizationDelegate) { self.signinAnonymously(accessTokenString: accessTokenString, allowCreateNewAnonymousUsers: allowCreateNewAnonymousUsers, authorizationDelegate: authorizationDelegate) } - + @available(*, deprecated: 3.0, renamed: "signinWithResourceOwnerPassword") public func obtainTokensWithROP(_ accessTokenString:String? = nil, username: String, password: String, tokenResponseDelegate:TokenResponseDelegate) { self.signinWithResourceOwnerPassword(accessTokenString, username: username, password: password, tokenResponseDelegate: tokenResponseDelegate) } - - + + public func application(_ application: UIApplication, open url: URL, options :[UIApplicationOpenURLOptionsKey: Any]) -> Bool { return (self.oauthManager?.authorizationManager?.application(application, open: url, options: options))! } diff --git a/Source/BluemixAppID/api/AppIDAuthorizationManager.swift b/Source/IBMCloudAppID/api/AppIDAuthorizationManager.swift similarity index 100% rename from Source/BluemixAppID/api/AppIDAuthorizationManager.swift rename to Source/IBMCloudAppID/api/AppIDAuthorizationManager.swift diff --git a/Source/BluemixAppID/api/AuthorizationDelegate.swift b/Source/IBMCloudAppID/api/AuthorizationDelegate.swift similarity index 100% rename from Source/BluemixAppID/api/AuthorizationDelegate.swift rename to Source/IBMCloudAppID/api/AuthorizationDelegate.swift diff --git a/Source/BluemixAppID/api/AuthorizationError.swift b/Source/IBMCloudAppID/api/AuthorizationError.swift similarity index 100% rename from Source/BluemixAppID/api/AuthorizationError.swift rename to Source/IBMCloudAppID/api/AuthorizationError.swift diff --git a/Source/BluemixAppID/api/IdentityToken.swift b/Source/IBMCloudAppID/api/IdentityToken.swift similarity index 100% rename from Source/BluemixAppID/api/IdentityToken.swift rename to Source/IBMCloudAppID/api/IdentityToken.swift diff --git a/Source/BluemixAppID/api/LoginWidget.swift b/Source/IBMCloudAppID/api/LoginWidget.swift similarity index 100% rename from Source/BluemixAppID/api/LoginWidget.swift rename to Source/IBMCloudAppID/api/LoginWidget.swift diff --git a/Source/BluemixAppID/api/TokenResponseDelegate.swift b/Source/IBMCloudAppID/api/TokenResponseDelegate.swift similarity index 100% rename from Source/BluemixAppID/api/TokenResponseDelegate.swift rename to Source/IBMCloudAppID/api/TokenResponseDelegate.swift diff --git a/Source/BluemixAppID/api/Tokens/AccessToken.swift b/Source/IBMCloudAppID/api/Tokens/AccessToken.swift similarity index 100% rename from Source/BluemixAppID/api/Tokens/AccessToken.swift rename to Source/IBMCloudAppID/api/Tokens/AccessToken.swift diff --git a/Source/BluemixAppID/api/Tokens/OAuthClient.swift b/Source/IBMCloudAppID/api/Tokens/OAuthClient.swift similarity index 100% rename from Source/BluemixAppID/api/Tokens/OAuthClient.swift rename to Source/IBMCloudAppID/api/Tokens/OAuthClient.swift diff --git a/Source/BluemixAppID/api/Tokens/RefreshToken.swift b/Source/IBMCloudAppID/api/Tokens/RefreshToken.swift similarity index 100% rename from Source/BluemixAppID/api/Tokens/RefreshToken.swift rename to Source/IBMCloudAppID/api/Tokens/RefreshToken.swift diff --git a/Source/BluemixAppID/api/UserAttributeError.swift b/Source/IBMCloudAppID/api/UserAttributeError.swift similarity index 100% rename from Source/BluemixAppID/api/UserAttributeError.swift rename to Source/IBMCloudAppID/api/UserAttributeError.swift diff --git a/Source/BluemixAppID/api/UserProfileError.swift b/Source/IBMCloudAppID/api/UserProfileError.swift similarity index 100% rename from Source/BluemixAppID/api/UserProfileError.swift rename to Source/IBMCloudAppID/api/UserProfileError.swift diff --git a/Source/BluemixAppID/api/UserProfileManager.swift b/Source/IBMCloudAppID/api/UserProfileManager.swift similarity index 100% rename from Source/BluemixAppID/api/UserProfileManager.swift rename to Source/IBMCloudAppID/api/UserProfileManager.swift diff --git a/Source/BluemixAppID/internal/AppIDConstants.swift b/Source/IBMCloudAppID/internal/AppIDConstants.swift similarity index 95% rename from Source/BluemixAppID/internal/AppIDConstants.swift rename to Source/IBMCloudAppID/internal/AppIDConstants.swift index 9d72d0c..b5c003e 100644 --- a/Source/BluemixAppID/internal/AppIDConstants.swift +++ b/Source/IBMCloudAppID/internal/AppIDConstants.swift @@ -15,25 +15,23 @@ import BMSCore import BMSAnalyticsAPI internal class AppIDConstants { - - - - + + internal static let base64EncodingTable:[Character] = [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/" ] - + internal static let base64EncodingTableUrlSafe:[Character] = [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", "_" ] - - + + internal static let base64DecodingTable: [Int8] = [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, @@ -52,7 +50,7 @@ internal class AppIDConstants { -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 ] - + internal static let base64DecodingTableUrlSafe: [Int8] = [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, @@ -70,13 +68,10 @@ internal class AppIDConstants { -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 - ] - - - - + ] + internal static let nameAndVer = Utils.getApplicationDetails() - + internal static var AppIDRequestManagerLoggerName = Logger.bmsLoggerPrefix + "AppIDRequestManager" internal static var RegistrationManagerLoggerName = Logger.bmsLoggerPrefix + "AppIDRegistrationManager" internal static var UserProfileManagerLoggerName = Logger.bmsLoggerPrefix + "AppIDUserProfileManager" @@ -84,16 +79,16 @@ internal class AppIDConstants { internal static var AuthorizationManagerLoggerName = Logger.bmsLoggerPrefix + "AppIDAuthorizationManager" internal static var AppIDLoggerName = Logger.bmsLoggerPrefix + "AppID" internal static var ConfigLoggerName = Logger.bmsLoggerPrefix + "Config" - + internal static var tokenEndPoint = "token" internal static var clientsEndPoint = "clients" internal static let userInfoEndPoint = "userinfo" internal static let attibutesEndpoint = "attributes" - + internal static var REDIRECT_URI_VALUE = Utils.getApplicationDetails().name + "://mobile/callback" internal static var authorizationEndPoint = "authorization" internal static var client_id_String = "client_id" - + internal static var authorization_code_String = "authorization_code" internal static var resource_owner_password_String = "password" internal static var refresh_token_String = "refresh_token" @@ -103,22 +98,23 @@ internal class AppIDConstants { internal static var JSON_MOD_KEY = "mod" internal static var JSON_EXP_KEY = "exp" internal static var JSON_JPK_KEY = "jpk" - - + + internal static var JSON_RESPONSE_TYPE_KEY = "response_type" internal static var JSON_IMF_USER_KEY = "imf.user" internal static var JSON_REDIRECT_URI_KEY = "redirect_uri" internal static var JSON_CODE_KEY = "code" - + internal static var JSON_ID = "id" internal static var JSON_PROVIDER = "provider" internal static var JSON_CLOUD_DIRECTORY = "cloud_directory" internal static var JSON_USER_ID = "user_id" - internal static let CHANGE_PASSWORD_PATH = "/cloud_directory/change_password" - internal static let GENERATE_CODE_PATH = "/cloud_directory/generate_code" - internal static let CHANGE_DETAILS_PATH = "/cloud_directory/change_details" + + internal static let changePasswordPath = "/cloud_directory/change_password" + internal static let generateCodePath = "/cloud_directory/generate_code" + internal static let changeDetailsPath = "/cloud_directory/change_details" internal static let FORGOT_PASSWORD_PATH = "/cloud_directory/forgot_password" - + internal static var JSON_SIGN_UP_KEY = "sign_up" internal static var JSON_FORGOT_PASSWORD_KEY = "forgot_password" internal static var JSON_GRANT_TYPE_KEY = "grant_type" @@ -127,9 +123,9 @@ internal class AppIDConstants { internal static var JSON_USERNAME = "username" internal static var JSON_PASSWORD = "password" internal static var APPID_ACCESS_TOKEN = "appid_access_token" - + internal static let MFP_SECURITY_PACKAGE = Logger.bmsLoggerPrefix + "security" - + internal static let BEARER = "Bearer" internal static let AUTHORIZATION_HEADER = "Authorization" internal static let BASIC_AUTHORIZATION_STRING = "Basic" @@ -141,22 +137,23 @@ internal class AppIDConstants { internal static let AUTH_SERVER_NAME = "imf-authserver" internal static let V3_AUTH_PATH = "oauth/v3/" internal static let OAUTH_AUTHORIZATION_PATH = "/authorization" - - + + + /** * Name of the standard "www-authenticate" header. */ - + internal static var FACEBOOK_COOKIE_NAME = "c_user" - - - + + + //JSON keys and values internal static let JSON_KEYS_KEY = "keys" internal static let JSON_JWKS_KEY = "jwks" internal static let JSON_DEVICE_ID_KEY = "device_id" internal static let JSON_OS_KEY = "device_os" - internal static let JSON_OS_VERSION_KEY = "device_os_version" + internal static let jsonOsVersionKey = "device_os_version" internal static let JSON_ENVIRONMENT_KEY = "environment" internal static let JSON_MODEL_KEY = "device_model" internal static let JSON_SOFTWARE_ID_KEY = "software_id" @@ -170,13 +167,11 @@ internal class AppIDConstants { internal static let MOBILE_APP_TYPE = "mobileapp" internal static let CLIENT_SECRET_BASIC = "client_secret_basic" internal static let PASSWORD_STRING = "password" - - - + internal static let tenantPrefName = "com.ibm.bluemix.appid.swift.tenantid" internal static let registrationDataPref = "com.ibm.bluemix.appid.swift.REGISTRATION_DATA" - - + + internal static let JSON_IOS_ENVIRONMENT_VALUE = "iOSnative" internal static let JSON_ACCESS_TOKEN_KEY = "access_token" internal static let JSON_ID_TOKEN_KEY = "id_token" @@ -185,7 +180,8 @@ internal class AppIDConstants { internal static var JSON_STATE_KEY = "state" internal static var OPEN_ID_VALUE = "openid" internal static var TRUE_VALUE = "true" - + + // label names internal static let KEY_CHAIN_PREFIX = "com.ibm.mobilefirstplatform.clientsdk.swift.bmssecurity" internal static let OAUTH_CERT_LABEL = "\(KEY_CHAIN_PREFIX).certificate" @@ -200,7 +196,7 @@ internal class AppIDConstants { internal static let DEVICE_IDENTITY_LABEL = "deviceIdentity" internal static let USER_IDENTITY_LABEL = "userIdentity" // labels - + internal static let AnonymousIdpName = "appid_anon" internal static let BMSSecurityErrorDomain = "com.ibm.mobilefirstplatform.clientsdk.swift.bmssecurity" internal static let privateKeyIdentifier = "\(_PRIVATE_KEY_LABEL):\(nameAndVer.name):\(nameAndVer.version)" @@ -212,8 +208,5 @@ internal class AppIDConstants { internal static let certificateIdentifier = "\(OAUTH_CERT_LABEL):\(nameAndVer.name):\(nameAndVer.version)" internal static let AuthorizationKeyChainTagsDictionary = [privateKeyIdentifier : kSecClassKey, publicKeyIdentifier : kSecClassKey, idTokenLabel : kSecClassGenericPassword, accessTokenLabel : kSecClassGenericPassword, certificateIdentifier : kSecClassCertificate] internal static let localeParamName = "language" - -} - - +} \ No newline at end of file diff --git a/Source/BluemixAppID/internal/AppIDError.swift b/Source/IBMCloudAppID/internal/AppIDError.swift similarity index 100% rename from Source/BluemixAppID/internal/AppIDError.swift rename to Source/IBMCloudAppID/internal/AppIDError.swift diff --git a/Source/BluemixAppID/internal/AuthorizationHeaderHelper.swift b/Source/IBMCloudAppID/internal/AuthorizationHeaderHelper.swift similarity index 100% rename from Source/BluemixAppID/internal/AuthorizationHeaderHelper.swift rename to Source/IBMCloudAppID/internal/AuthorizationHeaderHelper.swift diff --git a/Source/BluemixAppID/internal/AuthorizationManager.swift b/Source/IBMCloudAppID/internal/AuthorizationManager.swift similarity index 95% rename from Source/BluemixAppID/internal/AuthorizationManager.swift rename to Source/IBMCloudAppID/internal/AuthorizationManager.swift index 1583641..afa531e 100644 --- a/Source/BluemixAppID/internal/AuthorizationManager.swift +++ b/Source/IBMCloudAppID/internal/AuthorizationManager.swift @@ -15,7 +15,8 @@ import Foundation import BMSCore public class AuthorizationManager { - + + static var logger = Logger.logger(name: AppIDConstants.RegistrationManagerLoggerName) var registrationManager:RegistrationManager var appid:AppID @@ -27,7 +28,7 @@ public class AuthorizationManager { self.appid = oAuthManager.appId self.registrationManager = oAuthManager.registrationManager! } - + internal func getAuthorizationUrl(idpName : String?, accessToken : String?, responseType : String) -> String { var url = Config.getServerUrl(appId: self.appid) + AppIDConstants.OAUTH_AUTHORIZATION_PATH + "?" + AppIDConstants.JSON_RESPONSE_TYPE_KEY + "=" + responseType if let clientId = self.registrationManager.getRegistrationDataString(name: AppIDConstants.client_id_String) { @@ -47,9 +48,9 @@ public class AuthorizationManager { return url } - - internal func getChangePasswordUrl(userId : String, redirectUri : String) -> String{ - var url = Config.getServerUrl(appId: self.appid) + AppIDConstants.CHANGE_PASSWORD_PATH + "?" + AppIDConstants.JSON_USER_ID + "=" + userId + + internal func getChangePasswordUrl(userId : String, redirectUri : String) -> String { + var url = Config.getServerUrl(appId: self.appid) + AppIDConstants.changePasswordPath + "?" + AppIDConstants.JSON_USER_ID + "=" + userId if let clientId = self.registrationManager.getRegistrationDataString(name: AppIDConstants.client_id_String) { url += "&" + AppIDConstants.client_id_String + "=" + clientId } @@ -58,9 +59,9 @@ public class AuthorizationManager { return url } - - internal func getChangeDetailsUrl(code : String, redirectUri : String) -> String{ - var url = Config.getServerUrl(appId: self.appid) + AppIDConstants.CHANGE_DETAILS_PATH + "?" + AppIDConstants.JSON_CODE_KEY + "=" + code + + internal func getChangeDetailsUrl(code : String, redirectUri : String) -> String { + var url = Config.getServerUrl(appId: self.appid) + AppIDConstants.changeDetailsPath + "?" + AppIDConstants.JSON_CODE_KEY + "=" + code if let clientId = self.registrationManager.getRegistrationDataString(name: AppIDConstants.client_id_String) { url += "&" + AppIDConstants.client_id_String + "=" + clientId } @@ -69,7 +70,7 @@ public class AuthorizationManager { return url } - + internal func getForgotPasswordUrl(redirectUri: String) -> String { var url = Config.getServerUrl(appId: self.appid) + AppIDConstants.FORGOT_PASSWORD_PATH if let clientId = self.registrationManager.getRegistrationDataString(name: AppIDConstants.client_id_String) { @@ -79,7 +80,7 @@ public class AuthorizationManager { return url } - + internal func launchAuthorizationUI(accessTokenString:String? = nil, authorizationDelegate:AuthorizationDelegate) { self.registrationManager.ensureRegistered(callback: {(error:AppIDError?) in guard error == nil else { @@ -93,7 +94,7 @@ public class AuthorizationManager { self.authorizationUIManager?.launch() }) } - + internal func launchSignUpAuthorizationUI(authorizationDelegate:AuthorizationDelegate) { self.registrationManager.ensureRegistered(callback: {(error:AppIDError?) in guard error == nil else { @@ -106,9 +107,8 @@ public class AuthorizationManager { self.authorizationUIManager = AuthorizationUIManager(oAuthManager: self.oAuthManager, authorizationDelegate: authorizationDelegate, authorizationUrl: signUpAuthorizationUrl, redirectUri: redirectUri!) self.authorizationUIManager?.launch() }) - } - + internal func launchChangePasswordUI(authorizationDelegate:AuthorizationDelegate) { let currentIdToken:IdentityToken? = self.oAuthManager.tokenManager?.latestIdentityToken if currentIdToken == nil { @@ -123,7 +123,7 @@ public class AuthorizationManager { self.authorizationUIManager?.launch() } } - + internal func launchChangeDetailsUI(authorizationDelegate:AuthorizationDelegate) { let currentIdToken:IdentityToken? = self.oAuthManager.tokenManager?.latestIdentityToken if currentIdToken == nil { @@ -131,7 +131,7 @@ public class AuthorizationManager { } else if currentIdToken?.identities?.first?[AppIDConstants.JSON_PROVIDER] as? String != AppIDConstants.JSON_CLOUD_DIRECTORY { authorizationDelegate.onAuthorizationFailure(error: AuthorizationError.authorizationFailure("The identity token was not retrieved using cloud directory idp.")) } else { - let generateCodeURL = Config.getServerUrl(appId: self.appid) + AppIDConstants.GENERATE_CODE_PATH + let generateCodeURL = Config.getServerUrl(appId: self.appid) + AppIDConstants.generateCodePath let request:Request = Request(url: generateCodeURL) self.sendRequest(request: request, internalCallBack: {(response:Response?, error:Error?) in if error == nil { @@ -152,7 +152,7 @@ public class AuthorizationManager { }) } } - + internal func launchForgotPasswordUI(authorizationDelegate:AuthorizationDelegate) { self.registrationManager.ensureRegistered(callback: {(error:AppIDError?) in guard error == nil else { @@ -160,14 +160,14 @@ public class AuthorizationManager { authorizationDelegate.onAuthorizationFailure(error: AuthorizationError.authorizationFailure(error!.description)) return } - + let redirectUri = self.registrationManager.getRegistrationDataString(arrayName: AppIDConstants.JSON_REDIRECT_URIS_KEY, arrayIndex: 0) let forgotPasswordUrl = self.getForgotPasswordUrl(redirectUri: redirectUri!) self.authorizationUIManager = AuthorizationUIManager(oAuthManager:self.oAuthManager, authorizationDelegate:authorizationDelegate, authorizationUrl: forgotPasswordUrl, redirectUri: redirectUri!) self.authorizationUIManager?.launch() }) } - + internal func loginAnonymously(accessTokenString:String?, allowCreateNewAnonymousUsers: Bool, authorizationDelegate:AuthorizationDelegate) { self.registrationManager.ensureRegistered(callback: {(error:AppIDError?) in guard error == nil else { @@ -175,25 +175,23 @@ public class AuthorizationManager { authorizationDelegate.onAuthorizationFailure(error: AuthorizationError.authorizationFailure(error!.description)) return } - + let accessTokenToUse = accessTokenString != nil ? accessTokenString : self.oAuthManager.tokenManager?.latestAccessToken?.raw - if accessTokenToUse == nil && !allowCreateNewAnonymousUsers { authorizationDelegate.onAuthorizationFailure(error: AuthorizationError.authorizationFailure("Not allowed to create new anonymous users")) return } - + let authorizationUrl = self.getAuthorizationUrl(idpName: AppIDConstants.AnonymousIdpName, accessToken:accessTokenToUse, responseType: AppIDConstants.JSON_CODE_KEY) - + let internalCallback:BMSCompletionHandler = {(response: Response?, error: Error?) in if error == nil { if let unWrapperResponse = response { let urlString = self.extractUrlString(body : unWrapperResponse.responseText) if urlString != nil { let url = URL(string: urlString!) - + if url != nil { - if let err = Utils.getParamFromQuery(url: url!, paramName: "error") { // authorization endpoint returned error let errorDescription = Utils.getParamFromQuery(url: url!, paramName: "error_description") @@ -203,7 +201,7 @@ public class AuthorizationManager { AuthorizationManager.logger.error(message: "errorDescription: " + (errorDescription ?? "not available")) authorizationDelegate.onAuthorizationFailure(error: AuthorizationError.authorizationFailure("Failed to obtain access and identity tokens")) return - + } else { // authorization endpoint success if urlString!.lowercased().hasPrefix(AppIDConstants.REDIRECT_URI_VALUE.lowercased()) == true { @@ -221,14 +219,14 @@ public class AuthorizationManager { self.logAndFail(message: "Unable to get response from server", delegate: authorizationDelegate) } } - + let request = Request(url: authorizationUrl,method: HttpMethod.GET, headers: nil, queryParameters: nil, timeout: 0) request.timeout = BMSClient.sharedInstance.requestTimeout request.allowRedirects = false self.sendRequest(request: request, internalCallBack: internalCallback) - + }) - + } private func addLocaleQueryParam(_ url : String) -> String { @@ -240,25 +238,20 @@ public class AuthorizationManager { AuthorizationManager.logger.debug(message : message) delegate.onAuthorizationFailure( error: AuthorizationError.authorizationFailure(message)) } - + private func extractUrlString(body: String?) -> String? { - if let unWrappedBody = body { - let r = unWrappedBody.range(of: AppIDConstants.REDIRECT_URI_VALUE) - if r != nil { - return unWrappedBody.substring(from: r!.lowerBound) - - } else { - return nil - } - } else { + guard let body = body, + let r = body.range(of: AppIDConstants.REDIRECT_URI_VALUE) else { return nil } + + return String(body[r.lowerBound...]) } - + internal func sendRequest(request:Request, internalCallBack: @escaping BMSCompletionHandler) { request.send(completionHandler: internalCallBack) } - + internal func signinWithResourceOwnerPassword(accessTokenString:String? = nil, username: String, password: String, tokenResponseDelegate:TokenResponseDelegate) { var accessTokenToUse = accessTokenString if accessTokenToUse == nil { @@ -277,9 +270,9 @@ public class AuthorizationManager { return }) } - + internal func signinWithRefreshToken(refreshTokenString: String? = nil, tokenResponseDelegate: TokenResponseDelegate) { - + var refreshTokenToUse = refreshTokenString if refreshTokenToUse == nil { let latestRefreshToken = self.oAuthManager.tokenManager?.latestRefreshToken @@ -304,12 +297,9 @@ public class AuthorizationManager { }) } - + public func application(_ application: UIApplication, open url: URL, options :[UIApplicationOpenURLOptionsKey : Any]) -> Bool { return (self.authorizationUIManager?.application(application, open: url, options: options))! } - - - - + } diff --git a/Source/BluemixAppID/internal/AuthorizationUIManager.swift b/Source/IBMCloudAppID/internal/AuthorizationUIManager.swift similarity index 100% rename from Source/BluemixAppID/internal/AuthorizationUIManager.swift rename to Source/IBMCloudAppID/internal/AuthorizationUIManager.swift diff --git a/Source/BluemixAppID/internal/Config.swift b/Source/IBMCloudAppID/internal/Config.swift similarity index 77% rename from Source/BluemixAppID/internal/Config.swift rename to Source/IBMCloudAppID/internal/Config.swift index c27c68a..306c603 100644 --- a/Source/BluemixAppID/internal/Config.swift +++ b/Source/IBMCloudAppID/internal/Config.swift @@ -18,12 +18,13 @@ internal class Config { private static var serverUrlPrefix = "https://appid-oauth" private static var attributesUrlPrefix = "https://appid-profiles" + private static var publicKeysEndpoint = "/publickeys" internal static let logger = Logger.logger(name: AppIDConstants.ConfigLoggerName) internal static func getServerUrl(appId:AppID) -> String { - guard let region = appId.bluemixRegion, let tenant = appId.tenantId else { + guard let region = appId.region, let tenant = appId.tenantId else { logger.error(message: "Could not set server url properly, no tenantId or no region set") return serverUrlPrefix } @@ -32,24 +33,35 @@ internal class Config { if let overrideServerHost = AppID.overrideServerHost { serverUrl = overrideServerHost } - + serverUrl = serverUrl + tenant return serverUrl } - + internal static func getAttributesUrl(appId:AppID) -> String { - - guard let region = appId.bluemixRegion else { + + guard let region = appId.region else { logger.error(message: "Could not set server url properly, no region set") return serverUrlPrefix } - + var attributesUrl = Config.attributesUrlPrefix + region + "/api/v1/" if let overrideHost = AppID.overrideAttributesHost { attributesUrl = overrideHost } - + return attributesUrl } - + + internal static func getPublicKeyEndpoint(appId: AppID) -> String { + return getServerUrl(appId:appId) + publicKeysEndpoint + } + + internal static func getIssuer(appId: AppID) -> String? { + guard let url = URL(string: getServerUrl(appId:appId)) else { + return nil + } + return url.host + } + } diff --git a/Source/BluemixAppID/internal/JSONPreference.swift b/Source/IBMCloudAppID/internal/JSONPreference.swift similarity index 100% rename from Source/BluemixAppID/internal/JSONPreference.swift rename to Source/IBMCloudAppID/internal/JSONPreference.swift diff --git a/Source/BluemixAppID/internal/LoginWidgetImpl.swift b/Source/IBMCloudAppID/internal/LoginWidgetImpl.swift similarity index 98% rename from Source/BluemixAppID/internal/LoginWidgetImpl.swift rename to Source/IBMCloudAppID/internal/LoginWidgetImpl.swift index 72750bf..b0bed4c 100644 --- a/Source/BluemixAppID/internal/LoginWidgetImpl.swift +++ b/Source/IBMCloudAppID/internal/LoginWidgetImpl.swift @@ -23,19 +23,19 @@ public class LoginWidgetImpl: LoginWidget { public func launch(accessTokenString: String? = nil, delegate: AuthorizationDelegate) { self.oauthManager.authorizationManager?.launchAuthorizationUI(accessTokenString: accessTokenString, authorizationDelegate: delegate) } - + public func launchSignUp(_ delegate: AuthorizationDelegate) { self.oauthManager.authorizationManager?.launchSignUpAuthorizationUI(authorizationDelegate: delegate) } - + public func launchChangePassword(_ delegate: AuthorizationDelegate) { self.oauthManager.authorizationManager?.launchChangePasswordUI(authorizationDelegate: delegate) } - + public func launchChangeDetails(_ delegate: AuthorizationDelegate) { self.oauthManager.authorizationManager?.launchChangeDetailsUI(authorizationDelegate: delegate) } - + public func launchForgotPassword(_ delegate: AuthorizationDelegate) { self.oauthManager.authorizationManager?.launchForgotPasswordUI(authorizationDelegate: delegate) } diff --git a/Source/BluemixAppID/internal/OAuthManager.swift b/Source/IBMCloudAppID/internal/OAuthManager.swift similarity index 100% rename from Source/BluemixAppID/internal/OAuthManager.swift rename to Source/IBMCloudAppID/internal/OAuthManager.swift diff --git a/Source/BluemixAppID/internal/PreferenceManager.swift b/Source/IBMCloudAppID/internal/PreferenceManager.swift similarity index 100% rename from Source/BluemixAppID/internal/PreferenceManager.swift rename to Source/IBMCloudAppID/internal/PreferenceManager.swift diff --git a/Source/BluemixAppID/internal/RegistrationManager.swift b/Source/IBMCloudAppID/internal/RegistrationManager.swift similarity index 98% rename from Source/BluemixAppID/internal/RegistrationManager.swift rename to Source/IBMCloudAppID/internal/RegistrationManager.swift index ef0ea5a..1a14d13 100644 --- a/Source/BluemixAppID/internal/RegistrationManager.swift +++ b/Source/IBMCloudAppID/internal/RegistrationManager.swift @@ -101,7 +101,7 @@ internal class RegistrationManager { params[AppIDConstants.JSON_DEVICE_ID_KEY] = deviceIdentity.ID params[AppIDConstants.JSON_MODEL_KEY] = deviceIdentity.model params[AppIDConstants.JSON_OS_KEY] = deviceIdentity.OS - params[AppIDConstants.JSON_OS_VERSION_KEY] = deviceIdentity.OSVersion + params[AppIDConstants.jsonOsVersionKey] = deviceIdentity.OSVersion params[AppIDConstants.JSON_CLIENT_TYPE_KEY] = AppIDConstants.MOBILE_APP_TYPE diff --git a/Source/BluemixAppID/internal/SecurityUtils.swift b/Source/IBMCloudAppID/internal/SecurityUtils.swift similarity index 93% rename from Source/BluemixAppID/internal/SecurityUtils.swift rename to Source/IBMCloudAppID/internal/SecurityUtils.swift index bba3ea1..fff1fed 100644 --- a/Source/BluemixAppID/internal/SecurityUtils.swift +++ b/Source/IBMCloudAppID/internal/SecurityUtils.swift @@ -14,7 +14,7 @@ import Foundation internal class SecurityUtils { - + private static func getKeyBitsFromKeyChain(_ tag:String) throws -> Data { let keyAttr : [NSString:AnyObject] = [ kSecClass : kSecClassKey, @@ -23,50 +23,49 @@ internal class SecurityUtils { kSecReturnData : true as AnyObject ] var result: AnyObject? - let status = SecItemCopyMatching(keyAttr as CFDictionary, &result) - + guard status == errSecSuccess else { throw AppIDError.generalError } return result as! Data - + } - + internal static func generateKeyPair(_ keySize:Int, publicTag:String, privateTag:String) throws { //make sure keys are deleted _ = SecurityUtils.deleteKeyFromKeyChain(publicTag) _ = SecurityUtils.deleteKeyFromKeyChain(privateTag) - + var status:OSStatus = noErr var privateKey:SecKey? var publicKey:SecKey? - + let privateKeyAttr : [NSString:AnyObject] = [ kSecAttrIsPermanent : true as AnyObject, kSecAttrApplicationTag : privateTag as AnyObject, kSecAttrKeyClass : kSecAttrKeyClassPrivate ] - + let publicKeyAttr : [NSString:AnyObject] = [ kSecAttrIsPermanent : true as AnyObject, kSecAttrApplicationTag : publicTag as AnyObject, kSecAttrKeyClass : kSecAttrKeyClassPublic, ] - + let keyPairAttr : [NSString:AnyObject] = [ kSecAttrKeyType : kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits : keySize as AnyObject, kSecPublicKeyAttrs : publicKeyAttr as AnyObject, kSecPrivateKeyAttrs : privateKeyAttr as AnyObject ] - + status = SecKeyGeneratePair(keyPairAttr as CFDictionary, &publicKey, &privateKey) if (status != errSecSuccess) { throw AppIDError.generalError } } - + private static func getKeyRefFromKeyChain(_ tag:String) throws -> SecKey { let keyAttr : [NSString:AnyObject] = [ kSecClass : kSecClassKey, @@ -75,18 +74,18 @@ internal class SecurityUtils { kSecReturnRef : kCFBooleanTrue ] var result: AnyObject? - + let status = SecItemCopyMatching(keyAttr as CFDictionary, &result) - + guard status == errSecSuccess else { throw AppIDError.generalError } - + return result as! SecKey - + } - - + + internal static func getItemFromKeyChain(_ label:String) -> String? { let query: [NSString: AnyObject] = [ kSecClass: kSecClassGenericPassword, @@ -98,79 +97,79 @@ internal class SecurityUtils { if status == errSecSuccess { let data = results as! Data let password = String(data: data, encoding: String.Encoding.utf8)! - return password } - + return nil } - - + + public static func getJWKSHeader() throws ->[String:Any] { - + let publicKey = try? SecurityUtils.getKeyBitsFromKeyChain(AppIDConstants.publicKeyIdentifier) - - + + guard let unWrappedPublicKey = publicKey, let pkModulus : Data = getPublicKeyMod(unWrappedPublicKey), let pkExponent : Data = getPublicKeyExp(unWrappedPublicKey) else { throw AppIDError.generalError } - + let mod:String = Utils.base64StringFromData(pkModulus, isSafeUrl: true) - + let exp:String = Utils.base64StringFromData(pkExponent, isSafeUrl: true) - + let publicKeyJSON : [String:Any] = [ "e" : exp as AnyObject, "n" : mod as AnyObject, "kty" : AppIDConstants.JSON_RSA_VALUE ] - return publicKeyJSON } - + private static func getPublicKeyMod(_ publicKeyBits: Data) -> Data? { var iterator : Int = 0 iterator += 1 // TYPE - bit stream - mod + exp _ = derEncodingGetSizeFrom(publicKeyBits, at:&iterator) // Total size - iterator += 1 // TYPE - bit stream mod let mod_size : Int = derEncodingGetSizeFrom(publicKeyBits, at:&iterator) - if(mod_size == -1) { + + // Ensure we got an exponent size + guard mod_size != -1, let range = Range(NSMakeRange(iterator, mod_size)) else { return nil } - return publicKeyBits.subdata(in: NSMakeRange(iterator, mod_size).toRange()!) + + return publicKeyBits.subdata(in: range) } - + //Return public key exponent private static func getPublicKeyExp(_ publicKeyBits: Data) -> Data? { var iterator : Int = 0 iterator += 1 // TYPE - bit stream - mod + exp _ = derEncodingGetSizeFrom(publicKeyBits, at:&iterator) // Total size - iterator += 1// TYPE - bit stream mod let mod_size : Int = derEncodingGetSizeFrom(publicKeyBits, at:&iterator) iterator += mod_size - + iterator += 1 // TYPE - bit stream exp let exp_size : Int = derEncodingGetSizeFrom(publicKeyBits, at:&iterator) + //Ensure we got an exponent size - if(exp_size == -1) { + guard exp_size != -1, let range = Range(NSMakeRange(iterator, exp_size)) else { return nil } - return publicKeyBits.subdata(in: NSMakeRange(iterator, exp_size).toRange()!) + return publicKeyBits.subdata(in: range) } - + private static func derEncodingGetSizeFrom(_ buf : Data, at iterator: inout Int) -> Int{ - + // Have to cast the pointer to the right size //let pointer = UnsafePointer((buf as NSData).bytes) //let count = buf.count - + // Get our buffer pointer and make an array out of it //let buffer = UnsafeBufferPointer(start:pointer, count:count) let data = buf//[UInt8](buffer) - + var itr : Int = iterator var num_bytes :UInt8 = 1 var ret : Int = 0 @@ -178,26 +177,26 @@ internal class SecurityUtils { num_bytes = data[itr] - 0x80 itr += 1 } - + for i in 0 ..< Int(num_bytes) { ret = (ret * 0x100) + Int(data[itr + i]) } - + iterator = itr + Int(num_bytes) - + return ret } - - + + internal static func signString(_ payloadString:String, keyIds ids:(publicKey: String, privateKey: String), keySize: Int) throws -> String { do { let privateKeySec = try getKeyRefFromKeyChain(ids.privateKey) - + guard let payloadData : Data = payloadString.data(using: String.Encoding.utf8) else { throw AppIDError.generalError } let signedData = try signData(payloadData, privateKey:privateKeySec) - + //return signedData.base64EncodedString() return Utils.base64StringFromData(signedData, isSafeUrl: true) } @@ -205,8 +204,7 @@ internal class SecurityUtils { throw AppIDError.generalError } } - - + private static func signData(_ data:Data, privateKey:SecKey) throws -> Data { func doSha256(_ dataIn:Data) throws -> Data { var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) @@ -215,27 +213,26 @@ internal class SecurityUtils { } return Data(bytes: hash) } - guard let digest:Data = try? doSha256(data), let signedData: NSMutableData = NSMutableData(length: SecKeyGetBlockSize(privateKey)) else { throw AppIDError.generalError } - + var signedDataLength: Int = signedData.length - + let digestBytes: UnsafePointer = ((digest as NSData).bytes).bindMemory(to: UInt8.self, capacity: digest.count) let digestlen = digest.count let mutableBytes: UnsafeMutablePointer = signedData.mutableBytes.assumingMemoryBound(to: UInt8.self) - + let signStatus:OSStatus = SecKeyRawSign(privateKey, SecPadding.PKCS1SHA256, digestBytes, digestlen, mutableBytes, &signedDataLength) - + guard signStatus == errSecSuccess else { throw AppIDError.generalError } - + return signedData as Data } - + internal static func saveItemToKeyChain(_ data:String, label: String) -> Bool{ guard let stringData = data.data(using: String.Encoding.utf8) else { return false @@ -253,19 +250,18 @@ internal class SecurityUtils { } return status == errSecSuccess } - + internal static func removeItemFromKeyChain(_ label: String) -> Bool{ - + let delQuery : [NSString:AnyObject] = [ kSecClass: kSecClassGenericPassword, kSecAttrService: label as AnyObject ] - let delStatus:OSStatus = SecItemDelete(delQuery as CFDictionary) return delStatus == errSecSuccess - + } - + internal static func deleteKeyFromKeyChain(_ tag:String) -> Bool{ let delQuery : [NSString:AnyObject] = [ kSecClass : kSecClassKey, diff --git a/Source/BluemixAppID/internal/StringPreference.swift b/Source/IBMCloudAppID/internal/StringPreference.swift similarity index 100% rename from Source/BluemixAppID/internal/StringPreference.swift rename to Source/IBMCloudAppID/internal/StringPreference.swift diff --git a/Source/BluemixAppID/internal/TokenManager.swift b/Source/IBMCloudAppID/internal/TokenManager.swift similarity index 59% rename from Source/BluemixAppID/internal/TokenManager.swift rename to Source/IBMCloudAppID/internal/TokenManager.swift index 4738dcd..320e0cf 100644 --- a/Source/BluemixAppID/internal/TokenManager.swift +++ b/Source/IBMCloudAppID/internal/TokenManager.swift @@ -12,6 +12,8 @@ import Foundation import BMSCore +import JOSESwift + internal class TokenManager { private final var appid:AppID @@ -19,15 +21,13 @@ internal class TokenManager { internal var latestAccessToken:AccessToken? internal var latestIdentityToken:IdentityToken? internal var latestRefreshToken:RefreshToken? - + internal var publicKeys: [String: SecKey] = [:] internal static let logger = Logger.logger(name: AppIDConstants.TokenManagerLoggerName) - internal init(oAuthManager:OAuthManager) - { + internal init(oAuthManager:OAuthManager) { self.appid = oAuthManager.appId self.registrationManager = oAuthManager.registrationManager! } - public func obtainTokensAuthCode(code:String, authorizationDelegate:AuthorizationDelegate) { TokenManager.logger.debug(message: "obtainTokens") @@ -63,7 +63,7 @@ internal class TokenManager { } public func obtainTokensRefreshToken(refreshTokenString: String, - tokenResponseDelegate: TokenResponseDelegate) { + tokenResponseDelegate: TokenResponseDelegate) { TokenManager.logger.debug(message: "obtainTokens - with resource owner password") let bodyParams = [ @@ -87,7 +87,7 @@ internal class TokenManager { do { headers = [AppIDConstants.AUTHORIZATION_HEADER : try createAuthenticationHeader(clientId: clientId), Request.contentType : "application/x-www-form-urlencoded"] - } catch (_) { + } catch _ { TokenManager.logger.error(message: "Failed to create authentication header") tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Failed to create authentication header")) return @@ -115,8 +115,8 @@ internal class TokenManager { } TokenManager.logger.debug(message: "Could not retrieve tokens - " + - "Status code: \(response.statusCode ?? -1 ) " + - "Response: \(errorText)") + "Status code: \(response.statusCode ?? -1 ) " + + "Response: \(errorText)") if response.statusCode == 400, errorJson?["error"] == "invalid_grant" { tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure(errorDescription)) @@ -128,7 +128,7 @@ internal class TokenManager { } } - let request = Request(url: tokenUrl, method: HttpMethod.POST, headers: headers, queryParameters: nil, timeout: 0) + let request = Request(url: tokenUrl,method: HttpMethod.POST, headers: headers, queryParameters: nil, timeout: 0) request.timeout = BMSClient.sharedInstance.requestTimeout var body = "" for (index, (key: key, value: value)) in bodyParams.enumerated() { @@ -158,28 +158,32 @@ internal class TokenManager { do { var responseJson = try Utils.parseJsonStringtoDictionary(responseText) - guard let accessTokenString = (responseJson["access_token"] as? String), let idTokenString = (responseJson["id_token"] as? String) else { + guard let accessTokenString = responseJson["access_token"] as? String, let idTokenString = responseJson["id_token"] as? String else { TokenManager.logger.error(message: "Failed to parse server response - no access or identity token") tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Failed to parse server response - no access or identity token")) return } + guard let accessToken = AccessTokenImpl(with: accessTokenString), let identityToken:IdentityTokenImpl = IdentityTokenImpl(with: idTokenString) else { - TokenManager.logger.error(message: "Failed to parse tokens") - tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Failed to parse tokens")) + + TokenManager.logger.error(message: "Failed to parse server response - invalid access or identity token") + tokenResponseDelegate.onAuthorizationFailure(error: AuthorizationError.authorizationFailure("Failed to parse server response - corrupt access or identity token")) return } - let refreshTokenString = responseJson["refresh_token"] as? String - var refreshToken: RefreshTokenImpl? - if refreshTokenString != nil { - refreshToken = RefreshTokenImpl(with: refreshTokenString!) + + validateToken(token: accessToken, tokenResponseDelegate: tokenResponseDelegate) { + self.validateToken(token: identityToken, tokenResponseDelegate: tokenResponseDelegate) { + self.latestAccessToken = accessToken + self.latestIdentityToken = identityToken + if let refreshTokenString = responseJson["refresh_token"] as? String { + self.latestRefreshToken = RefreshTokenImpl(with: refreshTokenString) + } + tokenResponseDelegate.onAuthorizationSuccess(accessToken: self.latestAccessToken, + identityToken: self.latestIdentityToken, + refreshToken: self.latestRefreshToken, + response:response) + } } - self.latestAccessToken = accessToken - self.latestIdentityToken = identityToken - self.latestRefreshToken = refreshToken - tokenResponseDelegate.onAuthorizationSuccess(accessToken: accessToken, - identityToken: identityToken, - refreshToken: refreshToken, - response:response) } catch (_) { TokenManager.logger.error(message: "Failed to parse server response - failed to parse json") tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Failed to parse server response - failed to parse json")) @@ -188,6 +192,100 @@ internal class TokenManager { } + public func validateToken(token: Token, tokenResponseDelegate: TokenResponseDelegate, callback: @escaping () -> Void) { + guard let kid = token.header["kid"] as? String else { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Invalid token : Missing kid")) + return + } + + guard let alg = token.header["alg"] as? String else { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Invalid token : Missing alg")) + return + } + + if alg != "RS256" { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Invalid token : Invalid alg")) + return + } + + if let key = publicKeys[kid] { + validateToken(token: token, key: key, tokenResponseDelegate: tokenResponseDelegate, callback: callback) + } else { + retrievePublicKeys(tokenResponseDelegate: tokenResponseDelegate) { + guard let key = self.publicKeys[kid] else { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Could not find public key for kid")) + return + } + + self.validateToken(token: token, key: key, tokenResponseDelegate: tokenResponseDelegate, callback: callback) + } + } + } + + public func validateToken(token: Token, key: SecKey, tokenResponseDelegate: TokenResponseDelegate, callback: @escaping () -> Void ) { + + guard let jws = try? JWS(compactSerialization: token.raw), let _ = try? jws.validate(with: key), + let clientId = registrationManager.getRegistrationDataString(name: AppIDConstants.client_id_String) else { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Token verification failed")) + return + } + + if token.issuer != Config.getIssuer(appId: appid) { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Token verification failed : invalid issuer")) + return + } + + if token.audience != clientId { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Token verification failed : invalid audience")) + return + } + + if token.tenant != appid.tenantId { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Token verification failed : invalid tenant")) + return + } + + if token.isExpired { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Token verification failed : expired")) + return + } + + callback() + } + + public func retrievePublicKeys(tokenResponseDelegate: TokenResponseDelegate, callback: @escaping () -> Void) { + let publicKeyUrl = Config.getPublicKeyEndpoint(appId: appid) + + let request = Request(url: publicKeyUrl,method: HttpMethod.GET, headers: [:], queryParameters: nil, timeout: 0) + request.timeout = BMSClient.sharedInstance.requestTimeout + + sendRequest(request: request, body: nil) { (response, error) in + guard let response = response, error == nil, let text = response.responseText else { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Failed to get public key from server")) + return + } + + guard let publicKeyJson = try? Utils.parseJsonStringtoDictionary(text), let keys = publicKeyJson["keys"] as? [[String: Any]] else { + tokenResponseDelegate.onAuthorizationFailure(error: .authorizationFailure("Failed to parse public key response from server")) + return + } + + self.publicKeys = keys.reduce([String : SecKey]()) { result, key in + var result = result + guard let keyKid = key["kid"] as? String, + let data = try? JSONSerialization.data(withJSONObject: key, options: .prettyPrinted), + let rsaPublicKey = try? RSAPublicKey(data: data), let publicKey = try? rsaPublicKey.converted(to: SecKey.self) else { + return result + } + + result[keyKid] = publicKey + return result + } + + callback() + } + } + public func createAuthenticationHeader(clientId:String) throws -> String { let signed = try SecurityUtils.signString(clientId, keyIds: (AppIDConstants.publicKeyIdentifier, AppIDConstants.privateKeyIdentifier), keySize: 512) return AppIDConstants.BASIC_AUTHORIZATION_STRING + " " + (clientId + ":" + signed).data(using: .utf8)!.base64EncodedString() diff --git a/Source/BluemixAppID/internal/UserProfileManagerImpl.swift b/Source/IBMCloudAppID/internal/UserProfileManagerImpl.swift similarity index 100% rename from Source/BluemixAppID/internal/UserProfileManagerImpl.swift rename to Source/IBMCloudAppID/internal/UserProfileManagerImpl.swift diff --git a/Source/BluemixAppID/internal/Utils.swift b/Source/IBMCloudAppID/internal/Utils.swift similarity index 93% rename from Source/BluemixAppID/internal/Utils.swift rename to Source/IBMCloudAppID/internal/Utils.swift index 3240fd3..7fbc099 100644 --- a/Source/BluemixAppID/internal/Utils.swift +++ b/Source/IBMCloudAppID/internal/Utils.swift @@ -76,25 +76,25 @@ public class Utils { return nil } - let intLengthFixed:Int = (objPointer.characters.count) + let intLengthFixed:Int = (objPointer.count) var result:[Int8] = [Int8](repeating: 1, count: intLengthFixed) var i:Int=0, j:Int=0, k:Int var count = 0 - var intLengthMutated:Int = (objPointer.characters.count) - var current:Character = objPointer[objPointer.characters.index(objPointer.startIndex, offsetBy: count)] + var intLengthMutated:Int = (objPointer.count) + var current:Character = objPointer[objPointer.index(objPointer.startIndex, offsetBy: count)] while (current != "\0" && intLengthMutated > 0) { intLengthMutated-=1 if current == "=" { - if count < intLengthFixed && objPointer[objPointer.characters.index(objPointer.startIndex, offsetBy: count)] != "=" && i%4 == 1 { + if count < intLengthFixed && objPointer[objPointer.index(objPointer.startIndex, offsetBy: count)] != "=" && i%4 == 1 { return nil } if count == intLengthFixed { break } - current = objPointer[objPointer.characters.index(objPointer.startIndex, offsetBy: count)] + current = objPointer[objPointer.index(objPointer.startIndex, offsetBy: count)] count+=1 continue } @@ -104,7 +104,7 @@ public class Utils { let int8Current = isSafeUrl ? AppIDConstants.base64DecodingTableUrlSafe[intCurrent] :AppIDConstants.base64DecodingTable[intCurrent] if int8Current == -1 { - current = objPointer[objPointer.characters.index(objPointer.startIndex, offsetBy: count)] + current = objPointer[objPointer.index(objPointer.startIndex, offsetBy: count)] count+=1 continue } else if int8Current == -2 { @@ -134,7 +134,7 @@ public class Utils { break } count+=1 - current = objPointer[objPointer.characters.index(objPointer.startIndex, offsetBy: count)] + current = objPointer[objPointer.index(objPointer.startIndex, offsetBy: count)] } // mop things up if we ended on a boundary diff --git a/Source/BluemixAppID/internal/safariView.swift b/Source/IBMCloudAppID/internal/safariView.swift similarity index 100% rename from Source/BluemixAppID/internal/safariView.swift rename to Source/IBMCloudAppID/internal/safariView.swift diff --git a/Source/BluemixAppID/internal/tokens/AbstractToken.swift b/Source/IBMCloudAppID/internal/tokens/AbstractToken.swift similarity index 100% rename from Source/BluemixAppID/internal/tokens/AbstractToken.swift rename to Source/IBMCloudAppID/internal/tokens/AbstractToken.swift diff --git a/Source/BluemixAppID/internal/tokens/AccessTokenImpl.swift b/Source/IBMCloudAppID/internal/tokens/AccessTokenImpl.swift similarity index 100% rename from Source/BluemixAppID/internal/tokens/AccessTokenImpl.swift rename to Source/IBMCloudAppID/internal/tokens/AccessTokenImpl.swift diff --git a/Source/BluemixAppID/internal/tokens/IdentityTokenImpl.swift b/Source/IBMCloudAppID/internal/tokens/IdentityTokenImpl.swift similarity index 100% rename from Source/BluemixAppID/internal/tokens/IdentityTokenImpl.swift rename to Source/IBMCloudAppID/internal/tokens/IdentityTokenImpl.swift diff --git a/Source/BluemixAppID/internal/tokens/OAuthClientImpl.swift b/Source/IBMCloudAppID/internal/tokens/OAuthClientImpl.swift similarity index 100% rename from Source/BluemixAppID/internal/tokens/OAuthClientImpl.swift rename to Source/IBMCloudAppID/internal/tokens/OAuthClientImpl.swift diff --git a/Source/BluemixAppID/internal/tokens/RefreshTokenImpl.swift b/Source/IBMCloudAppID/internal/tokens/RefreshTokenImpl.swift similarity index 100% rename from Source/BluemixAppID/internal/tokens/RefreshTokenImpl.swift rename to Source/IBMCloudAppID/internal/tokens/RefreshTokenImpl.swift diff --git a/Source/Resources/BluemixAppID.h b/Source/Resources/IBMCloudAppID.h similarity index 100% rename from Source/Resources/BluemixAppID.h rename to Source/Resources/IBMCloudAppID.h diff --git a/scripts/release.sh b/scripts/release.sh index 4a19e00..f570c95 100644 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -11,7 +11,7 @@ git clone https://ibm-bluemix-mobile-services:${GITHUB_TOKEN}@github.com/ibm-blu cd appid-clientsdk-swift git remote rm origin git remote add origin https://ibm-bluemix-mobile-services:${GITHUB_TOKEN}@github.com/ibm-bluemix-mobile-services/appid-clientsdk-swift.git -version=$(grep -o 'version.*=.*[0-9]' BluemixAppID.podspec | cut -f 2 -d "'") +version=$(grep -o 'version.*=.*[0-9]' IBMCloudAppID.podspec | cut -f 2 -d "'") git fetch --tags if [[ ! "$(git tag)" =~ "${version}" ]]; then echo "Publishing new version ${version} ";