diff --git a/CHANGELOG.md b/CHANGELOG.md index 5508e73e..e68e92fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +# Version 1.6.00 + +### Bug fixes +- `MASAuthCredentialsJWT` credentials was marked as re-usable, so the Mobile SDK tried to consume the same credentials for a certain period of time. JWT credentials can now be consumed only one time, and is not reusable. [DE324462] +- Device deregistration was removing all credentials from the Mobile SDK regardless of the result of deregistration request. Now, the Mobile SDK removes credentials only when the deregistration request succeeds. [DE324142] +- Mobile SDK was changing `MASGrantFlow` to client credentials in a specific scenario with Cordova SDK. The Mobile SDK no longer switches the `MASGrantFlow` by itself. [DE311841] +- Mobile SDK enhances the device registration flow so it handles the device registration record more smoothly. This removes the hassle of developers seeing "This device has already been registered and has not been configured to accept updates" error message in development phase. [US406920] +- `MASConfiguration` was not properly updating the updated endpoint values when switching to a different configuration. It is fixed. [DE321925] +- `MASConfiguration` had some hard-coded values for client credentials device registration endpoint. `MASConfiguration` now reads the value from the configuration. [DE321921] +- `MASMQTTClient` was unable to reestablish MQTT connection when the user session was logged out, and logged in with a different account. Mobile SDK now properly handles session changes for MQTT connection. [US408725] +- Mobile SDK now stores all credentials only to the device. Data will not be backed-up or transferred with iCloud unless `[MAS setKeychainSynchroizable:]` is explicitly set to `YES`. [US388853] +- Mobile SDK's MQTT connection was unable to establish mutual SSL connection with public CA certificate. The Mobile SDK now establishes mutual SSL with public CA certificate when **entire certificate chain** is exported in JSON configuration. [US399506] + +### New features +- Mobile SDK introduces a secure way of storing and sharing data across multiple applications using same keychain sharing group with MASFoundation's `MASSharedStorage` class. [US416558] +- Mobile SDK introduces a new way of building API CRUD request with `MASRequestBuilder` and `MASRequest` classes to provide seamless developer experience Android SDK. [US374082] + +### Deprecated methods +- `[MASConfiguration setSecurityConfiguration:]` is deprecated. Please use `[MASSecurityConfiguration setSecurityConfiguration:error:]` for better handling of error cases when setting the security configuration object. [DE328373] + # Version 1.5.00 NOTE: From this version on the frameworks changed to Dynamic instead of Static library @@ -12,14 +32,14 @@ NOTE: From this version on the frameworks changed to Dynamic instead of Static l - The SDK no longer requires Keychain Sharing to be enabled in Xcode. However, to establish SSO across multiple applications, Keychain Sharing must be enabled. [US320771] - Mobile SDK now only validates against the leaf certificate for SSL pinning validation by default. The configuration can be changed to validate against entire certificate chain through `MASSecurityConfiguration`. [US374086] -### New Features +### New features - Mobile SDK introduces an ability to configure security configuration for external APIs (such as SSL pinning), so that Mobile SDK can securely connect to external API (other than primary Gateway). [US344780] - The SDK handles multiple concurrent API requests with proper authentication processes. [US362800] - The SDK supports dynamic framework. All you need to do is update your Xcode settings. [US367604] - The SDK introduces more flexible and extensible authentication with different types of credentials. For details, see `MASAuthCredentials`. [US349497] - The SDK introduces the ability to digitally sign the request as JWT. See `MASClaims` to sign the request. [US313137] -### Deprecated Methods +### Deprecated methods - `[MAS setUserLoginBlock:]` is deprecated. Please use `[MAS setAuthCredentials:]` block to perform implicit authentication with `MASAuthCredentials` object. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 38d86533..3b8d6f13 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,11 @@ -# Contribute to CA Mobile App Services SDK +# Contribute to iOS Mobile SDK Contributions are welcome and much appreciated. Just follow these easy steps to contribute. ## Code Standard and Guideline -For consistency, we ask that you adhere to some basic code guidelines when contributing to the MAS SDK. See the [Code Standard and Guideline][guidelines] for details. +For consistency, we ask that you adhere to some basic code guidelines when contributing to the iOS Mobile SDK. See the [Code Standard and Guideline][guidelines] for details. ## Our Development Process -To continue improving the SDK, the MAS development team will work on the same GitHub repos as you. The `develop branch` is used for development, and the `master branch` is used only for stable releases. +To continue improving the SDK, our development team will work on the same GitHub repos as you. The `develop branch` is used for development, and the `master branch` is used only for stable releases. **Note:** For production environments, please use releases only from the master branch. ### Pull Requests @@ -14,7 +14,7 @@ We welcome and encourage pull requests. When we get a pull request, it is peer r Follow these steps for pull requests: 1. Fork the repo and create your branch from `master`. -4. For any new code, add unit tests. +2. For any new code, add unit tests. 3. If you've changed APIs, update code comments for AppleDocs. 4. Verify that the test suite passes. 5. Verify that your code follows the [Code Standard Guideline][guidelines] @@ -44,12 +44,12 @@ Before filing a new issue, check Known Issues to see if your problem already exi * Anything else that seems relevant. ## License -By contributing to CA Mobile App Services SDK, you agree that your contributions will be licensed under its [license][license-link]. +By contributing to iOS Mobile SDK, you agree that your contributions will be licensed under its [license][license-link]. - [guidelines]: /GUIDELINES.md - [community]: https://communities.ca.com/community/ca-api-management-community/content?filterID=contentstatus%5Bpublished%5D~category%5Bca-mobile-api-gateway%5D - [license-link]: /LICENSE - [cla]: https://www.clahub.com/agreements/CAAPIM/iOS-MAS-Foundation - [casupport]: https://support.ca.com/irj/portal/implsvcnewcase - +[guidelines]: /GUIDELINES.md +[community]: https://communities.ca.com/community/ca-api-management-community/content?filterID=contentstatus%5Bpublished%5D~category%5Bca-mobile-api-gateway%5D +[license-link]: /LICENSE +[cla]: https://www.clahub.com/agreements/CAAPIM/iOS-MAS-Foundation +[casupport]: https://support.ca.com/irj/portal/implsvcnewcase + diff --git a/GUIDELINES.md b/GUIDELINES.md index 125ee546..28972890 100644 --- a/GUIDELINES.md +++ b/GUIDELINES.md @@ -1,21 +1,19 @@ -# CA Technologies Mobile App Services Objective-C Style Guide +# CA Technologies Objective-C Style Guide -This document describes the Objective-C coding style of iOS team for CA Technologies Mobile App Services. This guideline is recommended to comply with all Objective-C implementations of our products. +This document describes the Objective-C coding style of the iOS Mobile SDK team. This guideline is recommended to comply with all Objective-C implementations of our products. -## Review Apple's Official Coding Guideline +## Review Apple Official Coding Guideline -Beyond the guidelines defined in this document, we also recommend reviewing Apple's official coding guidelines. +Beyond the guidelines defined in this document, we also recommend reviewing the Apple official coding guidelines. * [Programming with Objective-C](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html) * [Cocoa Fundamentals Guide](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/Introduction/Introduction.html) * [Coding Guidelines for Cocoa](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html) * [App Programming Guide for iOS](http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/Introduction/Introduction.html) -### MAS Products +### iOS Mobile SDK -For more information about MAS, see [Mobile App Service developer](http://mas.ca.com). - -Mobile App Services consists of multiple functional products separated into individual frameworks. +The iOS Mobile SDK consists these frameworks. * MASFoundation * MASUI @@ -23,7 +21,7 @@ Mobile App Services consists of multiple functional products separated into indi * MASIdentityManagement * MASStorage -All of frameworks are recommended to comply with the coding guideline. +All of frameworks are recommended to comply with the coding guideline. For more information about the iOS Mobile SDK, see [developer website](http://mas.ca.com). ## Table of Contents @@ -346,7 +344,7 @@ typedef NS_ENUM(NSInteger, MASRequestResponseType) + (MASObject *)currentObject; - (void)setObject:(id)object forKeyedSubscript:(id )key; -``` +``` **Not:** @@ -356,7 +354,7 @@ typedef NS_ENUM(NSInteger, MASRequestResponseType) +(MASObject*)currentObject; -(void)setObject:(id)object forKeyedSubscript:(id)key; -``` +``` #### Newline diff --git a/MASFoundation.xcodeproj/project.pbxproj b/MASFoundation.xcodeproj/project.pbxproj index e3351493..acacfdcc 100644 --- a/MASFoundation.xcodeproj/project.pbxproj +++ b/MASFoundation.xcodeproj/project.pbxproj @@ -11,7 +11,8 @@ isa = PBXAggregateTarget; buildConfigurationList = 1059D3BC1B61C00500223267 /* Build configuration list for PBXAggregateTarget "UniversalFrameworkMASFoundation" */; buildPhases = ( - 1059D3BD1B61C00D00223267 /* ShellScript */, + 69DE19DB1F8E8A2300F4C7FE /* Log Build Settings */, + 1059D3BD1B61C00D00223267 /* Run Script */, ); dependencies = ( ); @@ -151,6 +152,12 @@ 10E027A51F72B10100EAB103 /* RNDecryptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E0279B1F72B10100EAB103 /* RNDecryptor.m */; }; 10E027A61F72B10100EAB103 /* RNEncryptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 10E0279C1F72B10100EAB103 /* RNEncryptor.h */; }; 10E027A71F72B10100EAB103 /* RNEncryptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E0279D1F72B10100EAB103 /* RNEncryptor.m */; }; + 69B7DF681F9675600056DD3A /* MASRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 699C17911F9585BC008C1B11 /* MASRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 69B7DF691F9675600056DD3A /* MASRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 699C17901F9585BC008C1B11 /* MASRequest.m */; }; + 69B7DF6A1F9675600056DD3A /* MASRequestBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 699C17921F9585BC008C1B11 /* MASRequestBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 69B7DF6B1F9675600056DD3A /* MASRequestBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 699C17931F9585BD008C1B11 /* MASRequestBuilder.m */; }; + 69B7DF6C1F96756B0056DD3A /* MASRequest+MASPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 699C17951F958660008C1B11 /* MASRequest+MASPrivate.h */; }; + 69B7DF6D1F96756B0056DD3A /* MASRequest+MASPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 699C17961F958660008C1B11 /* MASRequest+MASPrivate.m */; }; A4150E6F1BF1643900037E27 /* MASIJSONResponseSerializer+MASPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A4150E691BF1643900037E27 /* MASIJSONResponseSerializer+MASPrivate.h */; }; A4150E701BF1643900037E27 /* MASIJSONResponseSerializer+MASPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = A4150E6A1BF1643900037E27 /* MASIJSONResponseSerializer+MASPrivate.m */; }; A4150E711BF1643900037E27 /* NSMutableURLRequest+MASPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A4150E6B1BF1643900037E27 /* NSMutableURLRequest+MASPrivate.h */; }; @@ -286,6 +293,10 @@ A4F671331BAFC345000E2223 /* NSString+MASPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = A4F671311BAFC345000E2223 /* NSString+MASPrivate.m */; }; A858C6651D0978A6001FB9AD /* MASOTPService.h in Headers */ = {isa = PBXBuildFile; fileRef = A858C6631D0978A6001FB9AD /* MASOTPService.h */; }; A858C6661D0978A6001FB9AD /* MASOTPService.m in Sources */ = {isa = PBXBuildFile; fileRef = A858C6641D0978A6001FB9AD /* MASOTPService.m */; }; + C81CC3CC1FC2EA190058718E /* MASBrowserBasedAuthentication.h in Headers */ = {isa = PBXBuildFile; fileRef = C81CC3CA1FC2EA190058718E /* MASBrowserBasedAuthentication.h */; }; + C81CC3CD1FC2EA190058718E /* MASBrowserBasedAuthentication.m in Sources */ = {isa = PBXBuildFile; fileRef = C81CC3CB1FC2EA190058718E /* MASBrowserBasedAuthentication.m */; }; + C81CC3D01FC2EFBB0058718E /* UIAlertController+MAS.h in Headers */ = {isa = PBXBuildFile; fileRef = C81CC3CE1FC2EFBB0058718E /* UIAlertController+MAS.h */; }; + C81CC3D11FC2EFBB0058718E /* UIAlertController+MAS.m in Sources */ = {isa = PBXBuildFile; fileRef = C81CC3CF1FC2EFBB0058718E /* UIAlertController+MAS.m */; }; CB0A8ADF1D01F64F00B1DCCC /* MASProximityLogin.h in Headers */ = {isa = PBXBuildFile; fileRef = CB0A8ADD1D01F64F00B1DCCC /* MASProximityLogin.h */; settings = {ATTRIBUTES = (Public, ); }; }; CB0A8AE01D01F64F00B1DCCC /* MASProximityLogin.m in Sources */ = {isa = PBXBuildFile; fileRef = CB0A8ADE1D01F64F00B1DCCC /* MASProximityLogin.m */; }; CB0B58591E258C2A00BC0163 /* MASAuthorizationResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = CB0B58571E258C2A00BC0163 /* MASAuthorizationResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -303,6 +314,8 @@ CB1907F91C17950700A5EF16 /* MASAccessService.m in Sources */ = {isa = PBXBuildFile; fileRef = CB1907F71C17950700A5EF16 /* MASAccessService.m */; }; CB1C151E1E450109002B31A5 /* NSURL+MASPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = CB1C151C1E450109002B31A5 /* NSURL+MASPrivate.h */; }; CB1C151F1E450109002B31A5 /* NSURL+MASPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = CB1C151D1E450109002B31A5 /* NSURL+MASPrivate.m */; }; + CB1FD14B1FB23701000AFA25 /* MASSharedStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = CB1FD1491FB23701000AFA25 /* MASSharedStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CB1FD14C1FB23701000AFA25 /* MASSharedStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = CB1FD14A1FB23701000AFA25 /* MASSharedStorage.m */; }; CB2357921F0EF53600D4C420 /* MASURLSessionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = CB2357901F0EF53600D4C420 /* MASURLSessionManager.h */; }; CB2357931F0EF53600D4C420 /* MASURLSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = CB2357911F0EF53600D4C420 /* MASURLSessionManager.m */; }; CB2357961F0EFDEA00D4C420 /* MASSessionTaskOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = CB2357941F0EFDEA00D4C420 /* MASSessionTaskOperation.h */; }; @@ -563,6 +576,12 @@ 10E0279B1F72B10100EAB103 /* RNDecryptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNDecryptor.m; sourceTree = ""; }; 10E0279C1F72B10100EAB103 /* RNEncryptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNEncryptor.h; sourceTree = ""; }; 10E0279D1F72B10100EAB103 /* RNEncryptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNEncryptor.m; sourceTree = ""; }; + 699C17901F9585BC008C1B11 /* MASRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MASRequest.m; sourceTree = ""; }; + 699C17911F9585BC008C1B11 /* MASRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MASRequest.h; sourceTree = ""; }; + 699C17921F9585BC008C1B11 /* MASRequestBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MASRequestBuilder.h; sourceTree = ""; }; + 699C17931F9585BD008C1B11 /* MASRequestBuilder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MASRequestBuilder.m; sourceTree = ""; }; + 699C17951F958660008C1B11 /* MASRequest+MASPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MASRequest+MASPrivate.h"; sourceTree = ""; }; + 699C17961F958660008C1B11 /* MASRequest+MASPrivate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MASRequest+MASPrivate.m"; sourceTree = ""; }; A4150E691BF1643900037E27 /* MASIJSONResponseSerializer+MASPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MASIJSONResponseSerializer+MASPrivate.h"; sourceTree = ""; }; A4150E6A1BF1643900037E27 /* MASIJSONResponseSerializer+MASPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MASIJSONResponseSerializer+MASPrivate.m"; sourceTree = ""; }; A4150E6B1BF1643900037E27 /* NSMutableURLRequest+MASPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableURLRequest+MASPrivate.h"; sourceTree = ""; }; @@ -705,6 +724,10 @@ A4F671311BAFC345000E2223 /* NSString+MASPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+MASPrivate.m"; sourceTree = ""; }; A858C6631D0978A6001FB9AD /* MASOTPService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASOTPService.h; sourceTree = ""; }; A858C6641D0978A6001FB9AD /* MASOTPService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASOTPService.m; sourceTree = ""; }; + C81CC3CA1FC2EA190058718E /* MASBrowserBasedAuthentication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MASBrowserBasedAuthentication.h; sourceTree = ""; }; + C81CC3CB1FC2EA190058718E /* MASBrowserBasedAuthentication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MASBrowserBasedAuthentication.m; sourceTree = ""; }; + C81CC3CE1FC2EFBB0058718E /* UIAlertController+MAS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertController+MAS.h"; sourceTree = ""; }; + C81CC3CF1FC2EFBB0058718E /* UIAlertController+MAS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertController+MAS.m"; sourceTree = ""; }; CB0A8ADD1D01F64F00B1DCCC /* MASProximityLogin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASProximityLogin.h; sourceTree = ""; }; CB0A8ADE1D01F64F00B1DCCC /* MASProximityLogin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASProximityLogin.m; sourceTree = ""; }; CB0B58571E258C2A00BC0163 /* MASAuthorizationResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASAuthorizationResponse.h; sourceTree = ""; }; @@ -722,6 +745,8 @@ CB1907F71C17950700A5EF16 /* MASAccessService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASAccessService.m; sourceTree = ""; }; CB1C151C1E450109002B31A5 /* NSURL+MASPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+MASPrivate.h"; sourceTree = ""; }; CB1C151D1E450109002B31A5 /* NSURL+MASPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+MASPrivate.m"; sourceTree = ""; }; + CB1FD1491FB23701000AFA25 /* MASSharedStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MASSharedStorage.h; sourceTree = ""; }; + CB1FD14A1FB23701000AFA25 /* MASSharedStorage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MASSharedStorage.m; sourceTree = ""; }; CB2357901F0EF53600D4C420 /* MASURLSessionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASURLSessionManager.h; sourceTree = ""; }; CB2357911F0EF53600D4C420 /* MASURLSessionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASURLSessionManager.m; sourceTree = ""; }; CB2357941F0EFDEA00D4C420 /* MASSessionTaskOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASSessionTaskOperation.h; sourceTree = ""; }; @@ -1043,6 +1068,15 @@ path = libmosquitto123; sourceTree = ""; }; + 699C17941F958660008C1B11 /* Network */ = { + isa = PBXGroup; + children = ( + 699C17951F958660008C1B11 /* MASRequest+MASPrivate.h */, + 699C17961F958660008C1B11 /* MASRequest+MASPrivate.m */, + ); + path = Network; + sourceTree = ""; + }; A4150EBD1BF16D9A00037E27 /* network */ = { isa = PBXGroup; children = ( @@ -1320,6 +1354,10 @@ CB14D2181D02266D004F772E /* MASProximityLoginQRCode.m */, CBA3EB2C1E945F2400E64D9D /* MASClaims.h */, CBA3EB2D1E945F2400E64D9D /* MASClaims.m */, + CB1FD1491FB23701000AFA25 /* MASSharedStorage.h */, + CB1FD14A1FB23701000AFA25 /* MASSharedStorage.m */, + C81CC3CA1FC2EA190058718E /* MASBrowserBasedAuthentication.h */, + C81CC3CB1FC2EA190058718E /* MASBrowserBasedAuthentication.m */, ); path = models; sourceTree = ""; @@ -1374,6 +1412,8 @@ A4F6712F1BAFC321000E2223 /* categories */ = { isa = PBXGroup; children = ( + C81CC3CE1FC2EFBB0058718E /* UIAlertController+MAS.h */, + C81CC3CF1FC2EFBB0058718E /* UIAlertController+MAS.m */, CB1907ED1C1794F400A5EF16 /* MASIKeyChainStore+MASPrivate.h */, CB1907EE1C1794F400A5EF16 /* MASIKeyChainStore+MASPrivate.m */, A483C1FF1BE6D0C5007572CE /* CBCentralManager+MASPrivate.h */, @@ -1406,6 +1446,7 @@ isa = PBXGroup; children = ( CB99752B1EDCA749006CEBB1 /* AuthCredentials */, + 699C17941F958660008C1B11 /* Network */, CB1907F11C1794FC00A5EF16 /* MASAccess.h */, CB1907F21C1794FC00A5EF16 /* MASAccess.m */, A4831AE81BD1A87C007B4AE6 /* MASApplication+MASPrivate.h */, @@ -1455,6 +1496,10 @@ CB23578A1F0EE35A00D4C420 /* Network */ = { isa = PBXGroup; children = ( + 699C17911F9585BC008C1B11 /* MASRequest.h */, + 699C17901F9585BC008C1B11 /* MASRequest.m */, + 699C17921F9585BC008C1B11 /* MASRequestBuilder.h */, + 699C17931F9585BD008C1B11 /* MASRequestBuilder.m */, ); path = Network; sourceTree = ""; @@ -1650,6 +1695,9 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + CB1FD14B1FB23701000AFA25 /* MASSharedStorage.h in Headers */, + 69B7DF6A1F9675600056DD3A /* MASRequestBuilder.h in Headers */, + 69B7DF681F9675600056DD3A /* MASRequest.h in Headers */, CBAFD24C1F2BD46C0034DF02 /* MASSecurityConfiguration.h in Headers */, CB9975421EDF5761006CEBB1 /* MASAuthCredentials.h in Headers */, CB99754A1EDF57D6006CEBB1 /* MASAuthCredentialsPassword.h in Headers */, @@ -1688,9 +1736,11 @@ 105B2F4B1CA6B3EA0005A2D0 /* ripemd.h in Headers */, A46F49F11C2F5FC500A4C370 /* MASINTULocationRequestDefines.h in Headers */, CB5E4C641C1D1B56001B3B8A /* MASGetURLRequest.h in Headers */, + C81CC3CC1FC2EA190058718E /* MASBrowserBasedAuthentication.h in Headers */, 105B2F471CA6B3EA0005A2D0 /* pqueue.h in Headers */, 105B2F371CA6B3EA0005A2D0 /* kssl.h in Headers */, 105B2F511CA6B3EA0005A2D0 /* srtp.h in Headers */, + C81CC3D01FC2EFBB0058718E /* UIAlertController+MAS.h in Headers */, CBFA70F41F1ED5D6006D025D /* MASSecurityPolicy.h in Headers */, CBD25AF51E78C47C00DFB47F /* JWTCryptoKeyExtractor.h in Headers */, 105B2F5F1CA6B3EA0005A2D0 /* x509_vfy.h in Headers */, @@ -1873,6 +1923,7 @@ CBD25AFB1E78C47C00DFB47F /* JWTClaimsSet.h in Headers */, 105B2F461CA6B3EA0005A2D0 /* pkcs7.h in Headers */, 105B2F441CA6B3EA0005A2D0 /* pem2.h in Headers */, + 69B7DF6C1F96756B0056DD3A /* MASRequest+MASPrivate.h in Headers */, A417BA511BF033C300EC9BCB /* CLLocation+MASPrivate.h in Headers */, CBD25B011E78C47C00DFB47F /* JWTCoding+ResultTypes.h in Headers */, A4831AF61BD1A8CA007B4AE6 /* MASDevice+MASPrivate.h in Headers */, @@ -1984,18 +2035,33 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1059D3BD1B61C00D00223267 /* ShellScript */ = { + 1059D3BD1B61C00D00223267 /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); + name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\n#---------------\n#Framework Name\n#---------------\n\nFRAMEWORK_NAME=MASFoundation\n\n\n#---------------\n#SDK Directory\n#---------------\n\nSDK_DIR=../iOS_SDK\n\n\n#-----------------------\n#CleanUp Build Cache\n#-----------------------\n\nxcodebuild -project $PROJECT_NAME.xcodeproj -configuration Debug -alltargets clean\nxcodebuild -project $PROJECT_NAME.xcodeproj -configuration Release -alltargets clean\n\n\n#-----------------------\n#CleanUp Previous Builds\n#-----------------------\n\n# Remove the framework from the Project Folder\nrm -Rf \"${PROJECT_DIR}/${FRAMEWORK_NAME}.framework\"\n\n# Remove Build folder from DerivedData\nrm -Rf \"${BUILD_DIR}\"\n\n\n#-----------------------\n#Creating New Builds\n#-----------------------\n\n# define output folder environment variable\nUNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal\nARCHIVE_OUTPUTFOLDER=${BUILD_DIR}/../Intermediates/ArchiveIntermediates/$PROJECT_NAME/IntermediateBuildFilesPath/UninstalledProducts/iphoneos\n\n# Archive framework for iPhoneOS with BitCode enabled\n#xcodebuild -scheme $PROJECT_NAME -configuration Release archive\n\nxcodebuild OTHER_CFLAGS=\"-fembed-bitcode\" -scheme $PROJECT_NAME -configuration Release archive CODE_SIGN_IDENTITY=\"iPhone Distribution: CA, Inc (RAKRWMN9VH)\" -archivePath \"${BUILD_DIR}\"\n\n# Build framework for iPhoneOS\n#xcodebuild -target ${FRAMEWORK_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" CODE_SIGN_IDENTITY=\"iPhone Distribution: CA, Inc (RAKRWMN9VH)\"\n\n# Build framework for iPhoneSimulator\nxcodebuild -target ${FRAMEWORK_NAME} -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" CODE_SIGN_IDENTITY=\"iPhone Distribution: CA, Inc (RAKRWMN9VH)\"\n\n\n#-----------------------\n#Creating Universal Framework\n#-----------------------\n\nmkdir -p \"${UNIVERSAL_OUTPUTFOLDER}\"\nmkdir -p \"${SDK_DIR}\"\n\n\n# Build the universal library\nlipo -create -output \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}\" \"${ARCHIVE_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}\" \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}\"\n\n# Copy the .framework folder of iphoneos\ncp -R \"${ARCHIVE_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework\" \"${UNIVERSAL_OUTPUTFOLDER}/\"\n\n# Delete the library for iphoneos\nrm \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}\"\n\n# Move the Universal Library into our framework\nmv \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}\" \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/\"\n\n# Remove the _CodeSignature from the UniversalFramework\nrm -Rf \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/_CodeSignature\"\n\n# Copy the framework\ncp -R \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework\" \"${SDK_DIR}\"\n\n#-----------------------\n#Deleting Build Folder\n#-----------------------\n\n# Remove build folder from the Project Folder\nrm -Rf \"${PROJECT_DIR}/build\"\n\n"; + shellScript = "set -e\n\n#---------------\n#Framework Name\n#---------------\n\nFRAMEWORK_NAME=MASFoundation\n\n\n#---------------\n#SDK Directory\n#---------------\n\nSDK_DIR=../iOS_SDK\n\n\n#-----------------------\n#CleanUp Build Cache\n#-----------------------\n\nxcodebuild -project $PROJECT_NAME.xcodeproj -configuration Debug -alltargets clean\nxcodebuild -project $PROJECT_NAME.xcodeproj -configuration Release -alltargets clean\n\n\n#-----------------------\n#CleanUp Previous Builds\n#-----------------------\n\n# Remove the framework from the Project Folder\nrm -Rf \"${PROJECT_DIR}/${FRAMEWORK_NAME}.framework\"\n\n# Remove Build folder from DerivedData\nrm -Rf \"${BUILD_DIR}\"\n\n\n#-----------------------\n#Creating New Builds\n#-----------------------\n\n# define output folder environment variable\nUNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal\nARCHIVE_OUTPUTFOLDER=${OBJROOT}/ArchiveIntermediates/$PROJECT_NAME/IntermediateBuildFilesPath/UninstalledProducts/iphoneos\n\n# Archive framework for iPhoneOS with BitCode enabled\n#xcodebuild -scheme $PROJECT_NAME -configuration Release archive\n\nxcodebuild OTHER_CFLAGS=\"-fembed-bitcode\" -scheme $PROJECT_NAME -configuration Release archive CODE_SIGN_IDENTITY=\"iPhone Distribution: CA, Inc (RAKRWMN9VH)\" -archivePath \"${BUILD_DIR}\"\n\n# Build framework for iPhoneOS\n#xcodebuild -target ${FRAMEWORK_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" CODE_SIGN_IDENTITY=\"iPhone Distribution: CA, Inc (RAKRWMN9VH)\"\n\n# Build framework for iPhoneSimulator\nxcodebuild -target ${FRAMEWORK_NAME} -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" CODE_SIGN_IDENTITY=\"iPhone Distribution: CA, Inc (RAKRWMN9VH)\"\n\n\n#-----------------------\n#Creating Universal Framework\n#-----------------------\n\nmkdir -p \"${UNIVERSAL_OUTPUTFOLDER}\"\nmkdir -p \"${SDK_DIR}\"\n\n\n# Build the universal library\nlipo -create -output \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}\" \"${ARCHIVE_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}\" \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}\"\n\n# Copy the .framework folder of iphoneos\ncp -R \"${ARCHIVE_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework\" \"${UNIVERSAL_OUTPUTFOLDER}/\"\n\n# Delete the library for iphoneos\nrm \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}\"\n\n# Move the Universal Library into our framework\nmv \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}\" \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/\"\n\n# Remove the _CodeSignature from the UniversalFramework\nrm -Rf \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/_CodeSignature\"\n\n# Copy the framework\ncp -R \"${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework\" \"${SDK_DIR}\"\n\n#-----------------------\n#Deleting Build Folder\n#-----------------------\n\n# Remove build folder from the Project Folder\nrm -Rf \"${PROJECT_DIR}/build\"\n\n"; + }; + 69DE19DB1F8E8A2300F4C7FE /* Log Build Settings */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Log Build Settings"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/bash; + shellScript = export; }; /* End PBXShellScriptBuildPhase section */ @@ -2040,12 +2106,14 @@ A4150EFC1BF16EE200037E27 /* MASKeyChainService.m in Sources */, A47F12811C1D73530008E3F2 /* MASBluetoothPeripheral.m in Sources */, CBD25B061E78C47C00DFB47F /* JWTCoding+VersionThree.m in Sources */, + C81CC3D11FC2EFBB0058718E /* UIAlertController+MAS.m in Sources */, CBD25AED1E78C47C00DFB47F /* JWTAlgorithmDataHolderChain.m in Sources */, A46F49DA1C2F5FC500A4C370 /* MASINetworkActivityIndicatorManager.m in Sources */, A4831AAE1BD1A551007B4AE6 /* MASConfiguration.m in Sources */, CBA3EB2F1E945F2400E64D9D /* MASClaims.m in Sources */, CBD25B151E7A0A9200DFB47F /* MF_Base64Additions.m in Sources */, 10738A3B1C711C2F00B7E87E /* util_mosq.c in Sources */, + CB1FD14C1FB23701000AFA25 /* MASSharedStorage.m in Sources */, 10E027A71F72B10100EAB103 /* RNEncryptor.m in Sources */, 10738A2F1C711C2F00B7E87E /* read_handle.c in Sources */, CB9975571EDF5986006CEBB1 /* MASAuthCredentialsClientCredentials.m in Sources */, @@ -2099,6 +2167,8 @@ A46F49C51C2F5FC500A4C370 /* MASIHTTPRequestOperation.m in Sources */, A4150E701BF1643900037E27 /* MASIJSONResponseSerializer+MASPrivate.m in Sources */, A417BA521BF033C300EC9BCB /* CLLocation+MASPrivate.m in Sources */, + C81CC3CD1FC2EA190058718E /* MASBrowserBasedAuthentication.m in Sources */, + 69B7DF6D1F96756B0056DD3A /* MASRequest+MASPrivate.m in Sources */, A4831AB21BD1A551007B4AE6 /* MASFile.m in Sources */, CB0B585A1E258C2A00BC0163 /* MASAuthorizationResponse.m in Sources */, CB5E4C651C1D1B56001B3B8A /* MASGetURLRequest.m in Sources */, @@ -2121,6 +2191,7 @@ CB2357931F0EF53600D4C420 /* MASURLSessionManager.m in Sources */, 10738A291C711C2F00B7E87E /* mosquitto.c in Sources */, A4150EE81BF16E5B00037E27 /* MASFileService.m in Sources */, + 69B7DF691F9675600056DD3A /* MASRequest.m in Sources */, CBD25B081E78C47C00DFB47F /* JWTCoding+VersionTwo.m in Sources */, A483C2021BE6D0C5007572CE /* CBCentralManager+MASPrivate.m in Sources */, CBD25AFA1E78C47C00DFB47F /* JWTClaim.m in Sources */, @@ -2130,6 +2201,7 @@ CB5E4C751C1D26BA001B3B8A /* MASPatchURLRequest.m in Sources */, A46F49CB1C2F5FC500A4C370 /* MASINetworkActivityLogger.m in Sources */, A46F49BB1C2F5FC500A4C370 /* fmemopen.c in Sources */, + 69B7DF6B1F9675600056DD3A /* MASRequestBuilder.m in Sources */, A4150EFE1BF16EE200037E27 /* MASSecurityService.m in Sources */, 10738A371C711C2F00B7E87E /* time_mosq.c in Sources */, A46F49C21C2F5FC500A4C370 /* MASIKeyChainStore.m in Sources */, @@ -2262,7 +2334,7 @@ buildSettings = { CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CURRENT_PROJECT_VERSION = 1.5.00; + CURRENT_PROJECT_VERSION = 1.6.00; DEAD_CODE_STRIPPING = YES; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; @@ -2307,7 +2379,7 @@ buildSettings = { CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CURRENT_PROJECT_VERSION = 1.5.00; + CURRENT_PROJECT_VERSION = 1.6.00; DEAD_CODE_STRIPPING = YES; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; diff --git a/MASFoundation/Classes/MAS.h b/MASFoundation/Classes/MAS.h index c4431e1a..65d8de1c 100644 --- a/MASFoundation/Classes/MAS.h +++ b/MASFoundation/Classes/MAS.h @@ -12,7 +12,7 @@ #import "MASConstants.h" #import "MASClaims.h" - +#import "MASRequest.h" /** * The top level MAS object represents the Mobile App Services SDK in it's entirety. It @@ -111,6 +111,16 @@ +/** + * Sets Bool indicator of Browser Based Authentication (templatized login) enabled or not for authorization process. + * By default, it is disabled. + + @param enable BOOL value indicating whether Browser Based Authentication is enabled or not. + */ ++ (void)enableBrowserBasedAuthentication:(BOOL)enable; + + + /** * Sets the gateway monitoring block defined by the GatewayMonitorStatusBlock type. * This block will be triggered when any change to the current monitoring status @@ -148,6 +158,26 @@ +/** + * Sets BOOL indicator whether the Keychain is synchronized through iCloud. + * By default, the Keychain is not synchronized through iCloud. + * + * @param enabled BOOL YES to enable synchroniztion, NO to disable it. + */ ++ (void)setKeychainSynchronizable:(BOOL)enabled; + + + +/** + * Gets BOOL indicator of Keychain sincronization enabled or not. + * By default, the Keychain is not synchronized through iCloud. + * + * @return return BOOL value indicating Keychain sincronization is enabled or not + */ ++ (BOOL)isKeychainSynchronizable; + + + ///-------------------------------------- /// @name Start & Stop ///-------------------------------------- @@ -929,6 +959,28 @@ withParameters:(NSDictionary *_Nullable)parameterInfo completion:(MASResponseInfoErrorBlock _Nullable)completion; +/** + * Invoke the endpoint with the parameters defined in the MASRequest object + * + * If endPointPath is full URL format (including port number and http protocol), SDK will validate the server from the client side through SSL pinning (authentication challenge) with + * provided subjectKeyHash (also known as public key hash) in configuration in mag.mobile_sdk.trusted_cert_pinned_public_key_hashes and mag.mobile_sdk.enable_public_key_pinning. + * ALL of servers' public key hashes in certificate chain must be defined in the list. This means when it is configured to use public key hash pinning for SSL pinning, + * subjectKeyHash (public key hash) of the gateway must be also present within the list. The list can contain multiple hash values in array for multiple servers. + * + * When SDK fails to validate SSL with certificate or subjectKeyHash pinning for communication to HTTPs, SDK will cancel the request. + * + * If endPointPath is full URL format, upon successful SSL pinning validation, SDK will also validate the user session against primary gateway regardless the request is being made + * to the primary gateway or not. To ensure bypass the user session validation for public API, use [MAS deleteFrom:withParameters:requestType:responseType:isPublic:completion:] method + * with isPublic being YES. + * + * @param request MASRequest An object containing all parameters to call the endpoint + * When the value is set to true, all automatically injected credentials in SDK will be excluded in the request. + * @param completion An MASResponseInfoErrorBlock (NSDictionary *responseInfo, NSError *error) that will + * receive the JSON response object or an NSError object if there is a failure. + */ ++ (void)invoke:(nonnull MASRequest *)request completion:(nullable MASResponseInfoErrorBlock)completion; + + ///-------------------------------------- /// @name JWT Signing ///-------------------------------------- diff --git a/MASFoundation/Classes/MAS.m b/MASFoundation/Classes/MAS.m index d1981d96..ddda9014 100644 --- a/MASFoundation/Classes/MAS.m +++ b/MASFoundation/Classes/MAS.m @@ -92,12 +92,30 @@ + (void)setOTPCredentialsBlock:(MASOTPCredentialsBlock)oneTimePassword } ++ (void)enableBrowserBasedAuthentication:(BOOL)enable +{ + [MASModelService setBrowserBasedAuthentication:enable]; +} + + + (void)setGatewayMonitor:(MASGatewayMonitorStatusBlock)monitor { [MASNetworkingService setGatewayMonitor:monitor]; } ++ (void)setKeychainSynchronizable:(BOOL)enabled +{ + [MASAccessService setKeychainSynchronizable:enabled]; +} + + ++ (BOOL)isKeychainSynchronizable +{ + return [MASAccessService isKeychainSynchronizable]; +} + + + (MASState)MASState { // @@ -194,7 +212,7 @@ + (void)start:(MASCompletionErrorBlock)completion // // If the device is registered, and id_token exists, which means MSSO can be used for this application // - else if ([MASDevice currentDevice].isRegistered && [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeIdToken]) + else if ([MASDevice currentDevice].isRegistered && [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdToken]) { // // Make sure to register the client (application) @@ -1464,6 +1482,33 @@ + (void)putTo:(nonnull NSString *)endPoint } ++ (void)invoke:(nonnull MASRequest *)request completion:(nullable MASResponseInfoErrorBlock)completion +{ + // + // Process the request + // + if ([request.httpMethod isEqualToString:@"DELETE"]) + { + [self deleteFrom:request.endPoint withParameters:request.body andHeaders:request.header requestType:request.requestType responseType:request.responseType isPublic:request.isPublic completion:completion]; + } + else if ([request.httpMethod isEqualToString:@"GET"]) + { + [self getFrom:request.endPoint withParameters:request.body andHeaders:request.header requestType:request.requestType responseType:request.responseType isPublic:request.isPublic completion:completion]; + } + else if ([request.httpMethod isEqualToString:@"PATCH"]) + { + [self patchTo:request.endPoint withParameters:request.body andHeaders:request.header requestType:request.requestType responseType:request.responseType isPublic:request.isPublic completion:completion]; + } + else if ([request.httpMethod isEqualToString:@"POST"]) + { + [self postTo:request.endPoint withParameters:request.body andHeaders:request.header requestType:request.requestType responseType:request.responseType isPublic:request.isPublic completion:completion]; + } + else if ([request.httpMethod isEqualToString:@"PUT"]) + { + [self putTo:request.endPoint withParameters:request.body andHeaders:request.header requestType:request.requestType responseType:request.responseType isPublic:request.isPublic completion:completion]; + } +} + # pragma mark - Private @@ -1602,7 +1647,7 @@ + (NSString * _Nullable)signWithClaims:(MASClaims *_Nonnull)claims error:(NSErro // // Retrieve private key from registered device's client certificate // - SecKeyRef pemPrivateRef = [[MASAccessService sharedService] getAccessValueCryptoKeyWithType:MASAccessValueTypePrivateKey]; + SecKeyRef pemPrivateRef = [[MASAccessService sharedService] getAccessValueCryptoKeyWithStorageKey:MASKeychainStorageKeyPrivateKey]; NSData *privateKeyData = [NSData converKeyRefToNSData:pemPrivateRef]; return [self signWithClaims:claims privateKey:privateKeyData error:error]; diff --git a/MASFoundation/Classes/MASConstants.h b/MASFoundation/Classes/MASConstants.h index f6d668c3..00303ee1 100644 --- a/MASFoundation/Classes/MASConstants.h +++ b/MASFoundation/Classes/MASConstants.h @@ -91,6 +91,27 @@ typedef void (^MASOTPChannelSelectionBlock)(NSArray *_Nonnull supportedOTPChanne typedef void (^MASOTPCredentialsBlock)(MASOTPFetchCredentialsBlock _Nonnull otpBlock, NSError *_Nullable otpError); +/** + * The Selected Biometric modalities (NSArray *_Nullable biometricModalities, BOOL cancel, MASCompletionErrorBlock _Nullable) + * block. + */ +typedef void (^MASBiometricModalitiesBlock)(NSArray *_Nullable biometricModalities, BOOL cancel, MASCompletionErrorBlock _Nullable); + + +/** + * The Biometric registration with available modalities (NSArray *_Nonnull availableModalities, MASBiometricModalitiesBlock + * _Nonnull biometricModalitiesBlock) block. + */ +typedef void (^MASBiometricRegistrationModalitiesSelectionBlock)(NSArray *_Nonnull availableModalities, MASBiometricModalitiesBlock _Nonnull biometricModalitiesBlock); + + +/** + * The Biometric deregistration with available modalities (NSArray *_Nonnull availableModalities, MASBiometricModalitiesBlock + * _Nonnull biometricModalitiesBlock) block. + */ +typedef void (^MASBiometricDeregistrationModalitiesSelectionBlock)(NSArray *_Nonnull availableModalities, MASBiometricModalitiesBlock _Nonnull biometricModalitiesBlock); + + ///-------------------------------------- /// @name MAS Constants ///-------------------------------------- @@ -329,6 +350,12 @@ typedef NS_ENUM(NSInteger, MASFoundationErrorCode) MASFoundationErrorCodeConfigurationLoadingFailedJsonValidation = 100203, MASFoundationErrorCodeConfigurationInvalidEndpoint = 100204, + // + // Security Configuration + // + MASFoundationErrorCodeConfigurationInvalidHostForSecurityConfiguration = 100211, + MASFoundationErrorCodeConfigurationInvalidPinningInfoForSecurityConfiguration = 100212, + // // Geolocation // @@ -459,6 +486,15 @@ typedef NS_ENUM(NSInteger, MASFoundationErrorCode) MASFoundationErrorCodeJWTUnexpectedClassType = 170002, MASFoundationErrorCodeJWTSerializationError = 170003, + // + // Browser Based Login + // + MASFoundationErrorCodeBBANotEnabled = 180000, + // + // SharedStorage + // + MASFoundationErrorCodeSharedStorageNotNilKey = 180001, + MASFoundationErrorCodeCount = -999999 }; @@ -556,6 +592,13 @@ static NSString *const _Nonnull MASDeviceDidFailToDeregisterNotification = @"MAS static NSString *const _Nonnull MASDeviceDidDeregisterNotification = @"MASDeviceDidDeregisterNotification"; +/** + * The NSString constant for the device notification indicating that the MASDevice + * has reset locally. + */ +static NSString *const _Nonnull MASDeviceDidResetLocallyNotification = @"MASDeviceDidResetLocallyNotification"; + + ///-------------------------------------- /// @name User Notifications diff --git a/MASFoundation/Classes/MQTT/MASMQTTClient.m b/MASFoundation/Classes/MQTT/MASMQTTClient.m index 732fc50a..2221aefc 100644 --- a/MASFoundation/Classes/MQTT/MASMQTTClient.m +++ b/MASFoundation/Classes/MQTT/MASMQTTClient.m @@ -80,31 +80,45 @@ @implementation MASMQTTClient + (instancetype)sharedClient { - static dispatch_once_t onceToken; - if (!_sharedClient) { - dispatch_once(&onceToken, ^{ - + @synchronized(self) + { if ([MASUser currentUser].isAuthenticated && [MASDevice currentDevice].isRegistered) { - + // // Init MQTT client for current gateway // _sharedClient = [[MASMQTTClient alloc] initWithClientId:[MASMQTTHelper mqttClientId] cleanSession:NO]; } else { - + //Return nil in case Authentication or Registration is not done yet. _sharedClient = nil; } - }); + } } return _sharedClient; } +- (void)clearConnection +{ + __block MASMQTTClient *blockSelf = self; + [self disconnectWithCompletionHandler:^(NSUInteger code) { + + if ([blockSelf isEqual:_sharedClient]) + { + @synchronized(blockSelf) + { + _sharedClient = nil; + } + } + }]; +} + + // Initialize is called just before the first object is allocated - (void)initialize { @@ -151,6 +165,19 @@ - (MASMQTTClient *)initWithClientId:(NSString *)clientId cleanSession:(BOOL)clea // } self.queue = dispatch_queue_create(cstrClientId, NULL); + + // + // Subscribe following information to reset the current MQTT session due to the change in SDK's authenticated session + // + // - user logout + // - device de-registration + // - device reset locally + // - gateway switch + // + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearConnection) name:MASUserDidLogoutNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearConnection) name:MASDeviceDidDeregisterNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearConnection) name:MASDeviceDidResetLocallyNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearConnection) name:MASWillSwitchGatewayServerNotification object:nil]; } _sharedClient = self; @@ -158,6 +185,7 @@ - (MASMQTTClient *)initWithClientId:(NSString *)clientId cleanSession:(BOOL)clea return self; } + #pragma mark - Setup methods -(void)setUsername:(NSString *)username Password:(NSString *)password @@ -590,6 +618,7 @@ - (void)disconnectWithCompletionHandler:(MQTTDisconnectionHandler)completionHand mosquitto_disconnect(mosq); } + - (void)reconnect:(NSNotification *)notification { [self reconnect]; @@ -844,13 +873,13 @@ - (void)setupTLSWithServerCert:(NSString *)certPath withClientCert:(NSString *)c // if (!certPath) { - thisFile = [[MASSecurityService sharedService] getClientCertificate]; + thisFile = [[MASSecurityService sharedService] getServerCertificate]; certPath = [thisFile filePath]; //[[MASFile findFileWithName:@"MAS.crt"] filePath]; } if (!clientCertPath) { - thisFile = [[MASSecurityService sharedService] getSignedCertificate]; + thisFile = [[MASSecurityService sharedService] getDeviceClientCertificate]; clientCertPath = [thisFile filePath]; //[[MASFile findFileWithName:@"MASSigned.crt"] filePath]; } diff --git a/MASFoundation/Classes/MQTT/MASMQTTHelper.m b/MASFoundation/Classes/MQTT/MASMQTTHelper.m index cbe88579..56a5acb1 100644 --- a/MASFoundation/Classes/MQTT/MASMQTTHelper.m +++ b/MASFoundation/Classes/MQTT/MASMQTTHelper.m @@ -29,7 +29,7 @@ + (void)showLogMessage:(NSString *)message debugMode:(BOOL)debugMode + (NSString *)mqttClientId { - NSString *magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier]; + NSString *magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]; //MQTT ClientId is: :::: NSString *clientId = [NSString stringWithFormat:@"%@::%@::%@",magIdentifier,[MASApplication currentApplication].identifier,[MASUser currentUser].objectId]; diff --git a/MASFoundation/Classes/_private_/MASConstantsPrivate.h b/MASFoundation/Classes/_private_/MASConstantsPrivate.h index 3e0ff215..b0c98fe9 100644 --- a/MASFoundation/Classes/_private_/MASConstantsPrivate.h +++ b/MASFoundation/Classes/_private_/MASConstantsPrivate.h @@ -212,6 +212,11 @@ static NSString *_Nonnull const MASGrantTypeRefreshToken = @"refresh_token"; // static int const MASExceptionErrorCodeInvalidCertificate = 9999; // integer +# pragma mark - MASSharedStorage custom prefix + +static NSString *_Nonnull const MASSharedStorageCustomPrefix = @"MAS.customSharedStorage"; + + ///-------------------------------------- /// @name Location Monitoring Constants ///-------------------------------------- diff --git a/MASFoundation/Classes/_private_/_deprecated_/L7SBrowserURLProtocol.m b/MASFoundation/Classes/_private_/_deprecated_/L7SBrowserURLProtocol.m index 24f00524..5e0989d7 100644 --- a/MASFoundation/Classes/_private_/_deprecated_/L7SBrowserURLProtocol.m +++ b/MASFoundation/Classes/_private_/_deprecated_/L7SBrowserURLProtocol.m @@ -65,48 +65,18 @@ + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b { - (void)startLoading { NSMutableURLRequest *newRequest = [self.request mutableCopy]; - if ([MASApplication currentApplication].isAuthenticated) { - - if ([self.class isProtectedResource:self.request.URL]) - { - NSString *authorization = [MASUser authorizationBearerWithAccessToken]; - [newRequest setValue:authorization forHTTPHeaderField:@"Authorization"]; - [NSURLProtocol setProperty:@YES forKey:@"AuthorizationSet" inRequest:newRequest]; - } - else { - [NSURLProtocol setProperty:@NO forKey:@"AuthorizationSet" inRequest:newRequest]; - } - - self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self]; - } - else + + if ([MASApplication currentApplication].isAuthenticated && [self.class isProtectedResource:self.request.URL]) { - [self stopLoading]; - - [MAS setGrantFlow:MASGrantFlowClientCredentials]; - - [MAS start:^(BOOL completed, NSError *error) { - - if(error) - { - return; - } - else if (completed){ - - if ([self.class isProtectedResource:self.request.URL]) - { - NSString *authorization = [MASUser authorizationBearerWithAccessToken]; - [newRequest setValue:authorization forHTTPHeaderField:@"Authorization"]; - [NSURLProtocol setProperty:@YES forKey:@"AuthorizationSet" inRequest:newRequest]; - } - else { - [NSURLProtocol setProperty:@NO forKey:@"AuthorizationSet" inRequest:newRequest]; - } - - self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self]; - } - }]; + NSString *authorization = [MASUser authorizationBearerWithAccessToken]; + [newRequest setValue:authorization forHTTPHeaderField:@"Authorization"]; + [NSURLProtocol setProperty:@YES forKey:@"AuthorizationSet" inRequest:newRequest]; } + else { + [NSURLProtocol setProperty:@NO forKey:@"AuthorizationSet" inRequest:newRequest]; + } + + self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self]; } diff --git a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.h b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.h index b20b0bb4..a41079e6 100644 --- a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.h +++ b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.h @@ -644,9 +644,17 @@ /** * Create MASFoundationErrorDomainLocal NSError for MASFoundationErrorCodeProximityLoginInvalidAuthorizeURL. * - * @return REturns an NSError instance with the domain MASFoundationErrorDomainLocal and + * @return Returns an NSError instance with the domain MASFoundationErrorDomainLocal and * error MASFoundationErrorCodeProximityLoginInvalidAuthorizeURL */ + (NSError *)errorProximityLoginInvalidAuthroizeURL; + +/** + * Create MASFoundationErrorDomainLocal NSError for MASFoundationErrorCodeBBANotEnabled. + * + * @return Returns an NSError instance with the domain MASFoundationErrorDomainLocal and + * error MASFoundationErrorCodeBBANotEnabled + */ ++ (NSError *)errorBrowserBasedAuthenticaionNotEnabled; @end diff --git a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m index cfd4c0e4..9362038c 100644 --- a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m +++ b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m @@ -835,6 +835,11 @@ + (NSError *)errorProximityLoginInvalidAuthroizeURL } ++ (NSError *)errorBrowserBasedAuthenticaionNotEnabled +{ + return [self errorForFoundationCode:MASFoundationErrorCodeBBANotEnabled errorDomain:MASFoundationErrorDomainLocal]; +} + # pragma mark - Foundation Errors Private + (MASFoundationErrorCode)foundationErrorCodeForApiCode:(MASApiErrorCode)apiCode @@ -984,6 +989,12 @@ + (NSString *)descriptionForFoundationErrorCode:(MASFoundationErrorCode)errorCod case MASFoundationErrorCodeConfigurationLoadingFailedJsonValidation: return @"The configuration was successfully loaded, but the configuration is invalid for the following reason\n\n'%@'"; case MASFoundationErrorCodeConfigurationInvalidEndpoint: return @"Invalid endpoint"; + // + // Security Configuration + // + case MASFoundationErrorCodeConfigurationInvalidHostForSecurityConfiguration: return @"Invalid host information for security configuration. NSURL host or port cannot be nil."; + case MASFoundationErrorCodeConfigurationInvalidPinningInfoForSecurityConfiguration: return @"Invalid pinning information for security configuration. At least one pinning information should be provided or public PKI should be trusted."; + // // Device // @@ -1102,7 +1113,16 @@ + (NSString *)descriptionForFoundationErrorCode:(MASFoundationErrorCode)errorCod case MASFoundationErrorCodeJWTInvalidClaims: return @"MASClaims cannot be nil."; case MASFoundationErrorCodeJWTUnexpectedClassType: return @"Mis-match of reserved JWT claim value's type (%@)"; case MASFoundationErrorCodeJWTSerializationError: return @"Claim value (%@) cannot be serialized"; - + + // + // Shared Storage + // + case MASFoundationErrorCodeSharedStorageNotNilKey: return @"Data key cannot be nil or empty string."; + + // + // Browser Based Authentication + // + case MASFoundationErrorCodeBBANotEnabled : return @"MAS Browser Based Authentication is Not Enabled"; // // Default // diff --git a/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h new file mode 100644 index 00000000..ec8de498 --- /dev/null +++ b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h @@ -0,0 +1,23 @@ +// +// UIAlertController+MAS.h +// MASFoundation +// +// Created by nimma01 on 11/10/17. +// Copyright © 2017 CA Technologies. All rights reserved. +// + +#import + +@interface UIAlertController (MAS) + +///-------------------------------------- +/// @name Public +///------------------------------------- + +# pragma mark - Public + +/** + * Retrieve the currently visible UIViewController. + */ ++ (UIViewController *)rootViewController; +@end diff --git a/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m new file mode 100644 index 00000000..cbd86f3e --- /dev/null +++ b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m @@ -0,0 +1,59 @@ +// +// UIAlertController+MAS.m +// MASFoundation +// +// Created by nimma01 on 11/10/17. +// Copyright © 2017 CA Technologies. All rights reserved. +// + +#import "UIAlertController+MAS.h" +#import "MASUser.h" +@implementation UIAlertController (MAS) + +# pragma mark - Error Alert + ++ (UIViewController *) presentedViewController:(id)viewController +{ + if ([viewController isKindOfClass:[UINavigationController class]]) + { + UINavigationController *navigationController = (UINavigationController *)viewController; + return [self presentedViewController:navigationController.topViewController]; + } + if ([viewController isKindOfClass:[UIViewController class]]) + { + if ([viewController presentedViewController]) + { + if ([[viewController presentedViewController] isKindOfClass:[UINavigationController class]]) + { + UINavigationController *navigationController = (UINavigationController *)[viewController presentedViewController]; + + if (navigationController.isBeingDismissed) + { + return viewController; + } + } + + return [self presentedViewController:[viewController presentedViewController]]; + } + else { + return viewController; + } + } + else if ([viewController isKindOfClass:[UITabBarController class]]) + { + UITabBarController *tabBarController = (UITabBarController *)viewController; + return [self presentedViewController:tabBarController.presentedViewController]; + } + else { + return nil; + } +} + + +# pragma mark - Public + ++ (UIViewController *)rootViewController +{ + return [self presentedViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; +} +@end diff --git a/MASFoundation/Classes/_private_/models/AuthCredentials/MASAuthCredentials+MASPrivate.m b/MASFoundation/Classes/_private_/models/AuthCredentials/MASAuthCredentials+MASPrivate.m index 8673246c..79067d7f 100644 --- a/MASFoundation/Classes/_private_/models/AuthCredentials/MASAuthCredentials+MASPrivate.m +++ b/MASFoundation/Classes/_private_/models/AuthCredentials/MASAuthCredentials+MASPrivate.m @@ -333,7 +333,7 @@ - (void)loginWithCredential:(MASCompletionErrorBlock)completion { NSError *idTokenValidationError = nil; BOOL isIdTokenValid = [MASAccessService validateIdToken:[bodyInfo objectForKey:MASIdTokenBodyRequestResponseKey] - magIdentifier:[[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier] + magIdentifier:[[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier] error:&idTokenValidationError]; if (!isIdTokenValid && idTokenValidationError) @@ -355,7 +355,7 @@ - (void)loginWithCredential:(MASCompletionErrorBlock)completion // // Persist current authCredentials type // - [[MASAccessService sharedService] setAccessValueString:self.credentialsType withAccessValueType:MASAccessValueTypeCurrentAuthCredentialsGrantType]; + [[MASAccessService sharedService] setAccessValueString:self.credentialsType storageKey:MASKeychainStorageKeyCurrentAuthCredentialsGrantType]; // // Create a new instance of MASUser if not client credentials @@ -371,7 +371,7 @@ - (void)loginWithCredential:(MASCompletionErrorBlock)completion // set authenticated timestamp // NSNumber *authenticatedTimestamp = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]]; - [[MASAccessService sharedService] setAccessValueNumber:authenticatedTimestamp withAccessValueType:MASAccessValueTypeAuthenticatedTimestamp]; + [[MASAccessService sharedService] setAccessValueNumber:authenticatedTimestamp storageKey:MASKeychainStorageKeyAuthenticatedTimestamp]; // // Store credential information into keychain diff --git a/MASFoundation/Classes/_private_/models/AuthCredentials/MASAuthCredentialsClientCredentials.m b/MASFoundation/Classes/_private_/models/AuthCredentials/MASAuthCredentialsClientCredentials.m index 305ce1e2..b6d85197 100644 --- a/MASFoundation/Classes/_private_/models/AuthCredentials/MASAuthCredentialsClientCredentials.m +++ b/MASFoundation/Classes/_private_/models/AuthCredentials/MASAuthCredentialsClientCredentials.m @@ -109,14 +109,14 @@ - (NSDictionary *)getParameters else { // ClientId - NSString *clientId = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeClientId]; + NSString *clientId = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; if (clientId) { parameterInfo[MASClientIdentifierRequestResponseKey] = clientId; } // ClientSecret - NSString *clientSecret = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeClientSecret]; + NSString *clientSecret = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientSecret]; if (clientSecret) { parameterInfo[MASClientSecretRequestResponseKey] = clientSecret; diff --git a/MASFoundation/Classes/_private_/models/MASAccess.m b/MASFoundation/Classes/_private_/models/MASAccess.m index 3401a4e9..a3b7457b 100644 --- a/MASFoundation/Classes/_private_/models/MASAccess.m +++ b/MASFoundation/Classes/_private_/models/MASAccess.m @@ -60,14 +60,14 @@ + (MASAccess *)instanceFromStorage // // retrieve all values from keychain and initialize with dictionary as those values shouold be read only. // - NSString *accessToken = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeAccessToken]; - NSString *tokenType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeTokenType]; - NSString *refreshToken = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeRefreshToken]; - NSString *idToken = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeIdToken]; - NSString *idTokenType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeIdTokenType]; - NSNumber *expiresIn = [[MASAccessService sharedService] getAccessValueNumberWithType:MASAccessValueTypeExpiresIn]; - NSString *scopeAsString = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeScope]; - NSString *authCredentialsType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeCurrentAuthCredentialsGrantType]; + NSString *accessToken = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyAccessToken]; + NSString *tokenType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyTokenType]; + NSString *refreshToken = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyRefreshToken]; + NSString *idToken = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdToken]; + NSString *idTokenType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdTokenType]; + NSNumber *expiresIn = [[MASAccessService sharedService] getAccessValueNumberWithStorageKey:MASKeychainStorageKeyExpiresIn]; + NSString *scopeAsString = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyScope]; + NSString *authCredentialsType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyCurrentAuthCredentialsGrantType]; NSMutableDictionary *accessDictionary = [NSMutableDictionary dictionary]; @@ -149,14 +149,14 @@ - (void)saveToStorage // // Save to the keychain // - [[MASAccessService sharedService] setAccessValueString:self.accessToken withAccessValueType:MASAccessValueTypeAccessToken]; - [[MASAccessService sharedService] setAccessValueString:self.tokenType withAccessValueType:MASAccessValueTypeTokenType]; - [[MASAccessService sharedService] setAccessValueString:self.refreshToken withAccessValueType:MASAccessValueTypeRefreshToken]; - [[MASAccessService sharedService] setAccessValueString:self.idToken withAccessValueType:MASAccessValueTypeIdToken]; - [[MASAccessService sharedService] setAccessValueString:self.idTokenType withAccessValueType:MASAccessValueTypeIdTokenType]; - [[MASAccessService sharedService] setAccessValueNumber:self.expiresIn withAccessValueType:MASAccessValueTypeExpiresIn]; - [[MASAccessService sharedService] setAccessValueString:self.scopeAsString withAccessValueType:MASAccessValueTypeScope]; - [[MASAccessService sharedService] setAccessValueString:self.authCredentialsType withAccessValueType:MASAccessValueTypeCurrentAuthCredentialsGrantType]; + [[MASAccessService sharedService] setAccessValueString:self.accessToken storageKey:MASKeychainStorageKeyAccessToken]; + [[MASAccessService sharedService] setAccessValueString:self.tokenType storageKey:MASKeychainStorageKeyTokenType]; + [[MASAccessService sharedService] setAccessValueString:self.refreshToken storageKey:MASKeychainStorageKeyRefreshToken]; + [[MASAccessService sharedService] setAccessValueString:self.idToken storageKey:MASKeychainStorageKeyIdToken]; + [[MASAccessService sharedService] setAccessValueString:self.idTokenType storageKey:MASKeychainStorageKeyIdTokenType]; + [[MASAccessService sharedService] setAccessValueNumber:self.expiresIn storageKey:MASKeychainStorageKeyExpiresIn]; + [[MASAccessService sharedService] setAccessValueString:self.scopeAsString storageKey:MASKeychainStorageKeyScope]; + [[MASAccessService sharedService] setAccessValueString:self.authCredentialsType storageKey:MASKeychainStorageKeyCurrentAuthCredentialsGrantType]; } @@ -262,7 +262,7 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info // // authCredentialsType // - NSString *authCredentialsType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeCurrentAuthCredentialsGrantType]; + NSString *authCredentialsType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyCurrentAuthCredentialsGrantType]; if (authCredentialsType) { _authCredentialsType = authCredentialsType; @@ -278,29 +278,29 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info - (void)refresh { _accessToken = nil; - _accessToken = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeAccessToken]; + _accessToken = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyAccessToken]; _tokenType = nil; - _tokenType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeTokenType]; + _tokenType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyTokenType]; _refreshToken = nil; - _refreshToken = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeRefreshToken]; + _refreshToken = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyRefreshToken]; _idToken = nil; - _idToken = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeIdToken]; + _idToken = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdToken]; _idTokenType = nil; - _idTokenType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeIdTokenType]; + _idTokenType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdTokenType]; _expiresIn = nil; - _expiresIn = [[MASAccessService sharedService] getAccessValueNumberWithType:MASAccessValueTypeExpiresIn]; + _expiresIn = [[MASAccessService sharedService] getAccessValueNumberWithStorageKey:MASKeychainStorageKeyExpiresIn]; _scope = nil; _scopeAsString = nil; - _scopeAsString = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeScope]; + _scopeAsString = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyScope]; _authCredentialsType = nil; - _authCredentialsType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeCurrentAuthCredentialsGrantType]; + _authCredentialsType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyCurrentAuthCredentialsGrantType]; } @@ -328,7 +328,6 @@ - (void)reset } - - (void)deleteAll { @@ -336,40 +335,39 @@ - (void)deleteAll // remove all data from the keychain // _accessToken = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeAccessToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyAccessToken]; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeAuthenticatedUserObjectId]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyAuthenticatedUserObjectId]; - [[MASAccessService sharedService] setAccessValueNumber:nil withAccessValueType:MASAccessValueTypeAuthenticatedTimestamp]; + [[MASAccessService sharedService] setAccessValueNumber:nil storageKey:MASKeychainStorageKeyAuthenticatedTimestamp]; _tokenType = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeTokenType]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyTokenType]; _refreshToken = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeRefreshToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyRefreshToken]; _idToken = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeIdToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyIdToken]; _idTokenType = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeIdTokenType]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyIdTokenType]; _expiresIn = nil; - [[MASAccessService sharedService] setAccessValueNumber:nil withAccessValueType:MASAccessValueTypeExpiresIn]; + [[MASAccessService sharedService] setAccessValueNumber:nil storageKey:MASKeychainStorageKeyExpiresIn]; _scope = nil; _scopeAsString = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeScope]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyScope]; // // Clena up the tokens from Local Authentication protected keychain storage // - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeSecuredIdToken]; - [[MASAccessService sharedService] setAccessValueNumber:nil withAccessValueType:MASAccessValueTypeIsDeviceLocked]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeySecuredIdToken]; + [[MASAccessService sharedService] setAccessValueNumber:nil storageKey:MASKeychainStorageKeyIsDeviceLocked]; } - - (void)deleteForLogOff { @@ -377,24 +375,24 @@ - (void)deleteForLogOff // remove all data from the keychain // _accessToken = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeAccessToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyAccessToken]; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeAuthenticatedUserObjectId]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyAuthenticatedUserObjectId]; - [[MASAccessService sharedService] setAccessValueNumber:nil withAccessValueType:MASAccessValueTypeAuthenticatedTimestamp]; + [[MASAccessService sharedService] setAccessValueNumber:nil storageKey:MASKeychainStorageKeyAuthenticatedTimestamp]; _tokenType = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeTokenType]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyTokenType]; _refreshToken = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeRefreshToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyRefreshToken]; _expiresIn = nil; - [[MASAccessService sharedService] setAccessValueNumber:nil withAccessValueType:MASAccessValueTypeExpiresIn]; + [[MASAccessService sharedService] setAccessValueNumber:nil storageKey:MASKeychainStorageKeyExpiresIn]; _scope = nil; _scopeAsString = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeScope]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyScope]; } @@ -404,19 +402,19 @@ - (void)deleteForTokenExpiration // remove all data from the keychain // _accessToken = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeAccessToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyAccessToken]; - [[MASAccessService sharedService] setAccessValueNumber:nil withAccessValueType:MASAccessValueTypeAuthenticatedTimestamp]; + [[MASAccessService sharedService] setAccessValueNumber:nil storageKey:MASKeychainStorageKeyAuthenticatedTimestamp]; _tokenType = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeTokenType]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyTokenType]; _expiresIn = nil; - [[MASAccessService sharedService] setAccessValueNumber:nil withAccessValueType:MASAccessValueTypeExpiresIn]; + [[MASAccessService sharedService] setAccessValueNumber:nil storageKey:MASKeychainStorageKeyExpiresIn]; _scope = nil; _scopeAsString = nil; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeScope]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyScope]; } @@ -491,7 +489,7 @@ - (BOOL)isSessionLocked // MASAccessService *accessService = [MASAccessService sharedService]; - NSNumber *isLocked = [accessService getAccessValueNumberWithType:MASAccessValueTypeIsDeviceLocked]; + NSNumber *isLocked = [accessService getAccessValueNumberWithStorageKey:MASKeychainStorageKeyIsDeviceLocked]; return [isLocked boolValue]; } @@ -576,7 +574,7 @@ - (NSDate *)expiresInDate } // Authentication timestamp - NSNumber *authenticatedTimestamp = [[MASAccessService sharedService] getAccessValueNumberWithType:MASAccessValueTypeAuthenticatedTimestamp]; + NSNumber *authenticatedTimestamp = [[MASAccessService sharedService] getAccessValueNumberWithStorageKey:MASKeychainStorageKeyAuthenticatedTimestamp]; double expiresInDateNumber = [authenticatedTimestamp doubleValue] + [_expiresIn doubleValue]; NSDate *expiresInDate = [NSDate dateWithTimeIntervalSince1970:expiresInDateNumber]; @@ -589,7 +587,7 @@ - (NSDate *)clientCertificateExpirationDate { if (!_clientCertificateExpirationDate) { - NSNumber *clientCertExpTimestamp = [[MASAccessService sharedService] getAccessValueNumberWithType:MASAccessValueTypeSignedPublicCertificateExpirationDate]; + NSNumber *clientCertExpTimestamp = [[MASAccessService sharedService] getAccessValueNumberWithStorageKey:MASKeychainStorageKeyPublicCertificateExpirationDate]; if (clientCertExpTimestamp) { @@ -600,7 +598,7 @@ - (NSDate *)clientCertificateExpirationDate // // Extracting signed client certificate expiration date // - NSArray * cert = [[MASAccessService sharedService] getAccessValueCertificateWithType:MASAccessValueTypeSignedPublicCertificate]; + NSArray * cert = [[MASAccessService sharedService] getAccessValueCertificateWithStorageKey:MASKeychainStorageKeySignedPublicCertificate]; SecCertificateRef certificate = (__bridge SecCertificateRef)([cert objectAtIndex:0]); // @@ -608,7 +606,7 @@ - (NSDate *)clientCertificateExpirationDate // _clientCertificateExpirationDate = [[MASAccessService sharedService] extractExpirationDateFromCertificate:certificate]; [[MASAccessService sharedService] setAccessValueNumber:[NSNumber numberWithDouble:[_clientCertificateExpirationDate timeIntervalSince1970]] - withAccessValueType:MASAccessValueTypeSignedPublicCertificateExpirationDate]; + storageKey:MASKeychainStorageKeyPublicCertificateExpirationDate]; } } diff --git a/MASFoundation/Classes/_private_/models/MASApplication+MASPrivate.m b/MASFoundation/Classes/_private_/models/MASApplication+MASPrivate.m index 2c2291d3..8c4a9d2f 100644 --- a/MASFoundation/Classes/_private_/models/MASApplication+MASPrivate.m +++ b/MASFoundation/Classes/_private_/models/MASApplication+MASPrivate.m @@ -56,25 +56,24 @@ - (id)initWithConfiguration nil) forKey:@"redirectUri"]; MASAccessService *accessService = [MASAccessService sharedService]; - - NSData *trustedServerCertificate = [accessService getAccessValueDataWithType:MASAccessValueTypeTrustedServerCertificate]; - if(!trustedServerCertificate) + NSData *trustedServerCertificate = [accessService getAccessValueDataWithStorageKey:MASKeychainStorageKeyTrustedServerCertificate]; + if (!trustedServerCertificate) { // // Trusted Server Certificate (not sure if this really belongs here, think about that) // NSArray *certificates = [MASConfiguration currentConfiguration].gatewayCertificatesAsPEMData; - if(certificates && certificates.count > 0) + if (certificates && certificates.count > 0) { trustedServerCertificate = certificates[0]; - [accessService setAccessValueData:trustedServerCertificate withAccessValueType:MASAccessValueTypeTrustedServerCertificate]; + [accessService setAccessValueData:trustedServerCertificate storageKey:MASKeychainStorageKeyTrustedServerCertificate]; } } // // If the credentials are NOT dynamic set them here // - if(!configuration.applicationCredentialsAreDynamic) + if (!configuration.applicationCredentialsAreDynamic) { NSDictionary *credentialsFromConfiguration = @ { @@ -108,7 +107,7 @@ + (MASApplication *)instanceFromStorage // Attempt to retrieve from keychain // NSData *data = [[MASIKeyChainStore keyChainStoreWithService:[MASConfiguration currentConfiguration].gatewayUrl.absoluteString] dataForKey:[MASApplication.class description]]; - if(data) + if (data) { application = (MASApplication *)[NSKeyedUnarchiver unarchiveObjectWithData:data]; } @@ -160,14 +159,14 @@ - (void)saveToStorage // Save to the keychain // NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self]; - if(data) + if (data) { NSError *error; [[MASIKeyChainStore keyChainStoreWithService:[MASConfiguration currentConfiguration].gatewayUrl.absoluteString] setData:data forKey:[MASApplication.class description] error:&error]; - if(error) + if (error) { DLog(@"Error attempting to save data: %@", [error localizedDescription]); return; @@ -198,27 +197,27 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info // Client Expiration // NSNumber *clientExpiration = bodyInfo[MASClientExpirationRequestResponseKey]; - if(clientExpiration) + if (clientExpiration) { - [accessService setAccessValueNumber:clientExpiration withAccessValueType:MASAccessValueTypeClientExpiration]; + [accessService setAccessValueNumber:clientExpiration storageKey:MASKeychainStorageKeyClientExpiration]; } // // Client Key // NSString *clientId = bodyInfo[MASClientKeyRequestResponseKey]; - if(clientId) + if (clientId) { - [accessService setAccessValueString:clientId withAccessValueType:MASAccessValueTypeClientId]; + [accessService setAccessValueString:clientId storageKey:MASKeychainStorageKeyClientId]; } // // Client Secret // NSString *clientSecret = bodyInfo[MASClientSecretRequestResponseKey]; - if(clientSecret) + if (clientSecret) { - [accessService setAccessValueString:clientSecret withAccessValueType:MASAccessValueTypeClientSecret]; + [accessService setAccessValueString:clientSecret storageKey:MASKeychainStorageKeyClientSecret]; } // @@ -232,9 +231,9 @@ - (void)reset { MASAccessService *accessService = [MASAccessService sharedService]; - [accessService setAccessValueString:nil withAccessValueType:MASAccessValueTypeClientId]; - [accessService setAccessValueString:nil withAccessValueType:MASAccessValueTypeClientSecret]; - [accessService setAccessValueNumber:nil withAccessValueType:MASAccessValueTypeClientExpiration]; + [accessService setAccessValueString:nil storageKey:MASKeychainStorageKeyClientId]; + [accessService setAccessValueString:nil storageKey:MASKeychainStorageKeyClientSecret]; + [accessService setAccessValueNumber:nil storageKey:MASKeychainStorageKeyClientExpiration]; [[MASIKeyChainStore keyChainStoreWithService:[MASConfiguration currentConfiguration].gatewayUrl.absoluteString] removeItemForKey:[MASApplication.class description]]; } @@ -245,7 +244,7 @@ - (id)initWithEnterpriseInfo:(NSDictionary *)info //DLog(@"\n\ncalled with info: %@\n\n", info); self = [super init]; - if(self) + if (self) { [self setValue:info[MASApplicationIdRequestResponseKey] forKey:@"identifier"]; [self setValue:info[MASApplicationNameRequestResponseKey] forKey:@"name"]; @@ -268,8 +267,8 @@ + (NSDate *)expirationAsDate // MASAccessService *accessService = [MASAccessService sharedService]; - NSNumber *clientExpiration = [accessService getAccessValueNumberWithType:MASAccessValueTypeClientExpiration]; - if(!clientExpiration) + NSNumber *clientExpiration = [accessService getAccessValueNumberWithStorageKey:MASKeychainStorageKeyClientExpiration]; + if (!clientExpiration) { return nil; } @@ -291,8 +290,8 @@ - (NSString *)clientAuthorizationBasicHeaderValue // MASAccessService *accessService = [MASAccessService sharedService]; - NSString *clientId = [accessService getAccessValueStringWithType:MASAccessValueTypeClientId]; - NSString *clientSecret = [accessService getAccessValueStringWithType:MASAccessValueTypeClientSecret]; + NSString *clientId = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; + NSString *clientSecret = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientSecret]; NSString *clientAuthStr = [NSString stringWithFormat:@"%@:%@", clientId, clientSecret]; NSData *clientAuthData = [clientAuthStr dataUsingEncoding:NSUTF8StringEncoding]; @@ -310,14 +309,14 @@ - (BOOL)isExpired // MASAccessService *accessService = [MASAccessService sharedService]; - NSNumber *clientExpiration = [accessService getAccessValueNumberWithType:MASAccessValueTypeClientExpiration]; - NSString *clientId = [accessService getAccessValueStringWithType:MASAccessValueTypeClientId]; - NSString *clientSecret = [accessService getAccessValueStringWithType:MASAccessValueTypeClientSecret]; + NSNumber *clientExpiration = [accessService getAccessValueNumberWithStorageKey:MASKeychainStorageKeyClientExpiration]; + NSString *clientId = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; + NSString *clientSecret = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientSecret]; // // Expiration is nil, then it is considered expired // - if(!clientExpiration) + if (!clientExpiration) { isExpired = YES; } @@ -326,7 +325,7 @@ - (BOOL)isExpired // If the value is zero AND both the client id and secret are set then it is not expired and // the expiry is actually infinite // - else if([clientExpiration doubleValue] == 0 && clientId && clientSecret) + else if ([clientExpiration doubleValue] == 0 && clientId && clientSecret) { isExpired = NO; } @@ -334,7 +333,7 @@ - (BOOL)isExpired // // If a positive time interval remains compared to the current time and date then it is not expired // - else if([[MASApplication expirationAsDate] timeIntervalSinceNow] > 0) + else if ([[MASApplication expirationAsDate] timeIntervalSinceNow] > 0) { isExpired = NO; } @@ -349,7 +348,7 @@ - (NSString *)authenticationStatusAsString // // Detect status and respond appropriately // - switch([self authenticationStatus]) + switch ([self authenticationStatus]) { // // Not Logged In @@ -382,7 +381,7 @@ - (NSString *)scopeTypeToString:(MASScopeType)scopeType // // Detect type and respond appropriately // - switch(scopeType) + switch (scopeType) { // // OpenId diff --git a/MASFoundation/Classes/_private_/models/MASClaims+MASPrivate.m b/MASFoundation/Classes/_private_/models/MASClaims+MASPrivate.m index da45ebad..ccb5e2c8 100644 --- a/MASFoundation/Classes/_private_/models/MASClaims+MASPrivate.m +++ b/MASFoundation/Classes/_private_/models/MASClaims+MASPrivate.m @@ -48,8 +48,8 @@ - (NSString * __nullable)buildWithPrivateKey:(NSData * __nonnull)privateKey erro // If iss was not prepare upon MASClaims object construction which most likley happened due to registration status of the client, // re-prepare iss with registered client id // - NSString *magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier]; - NSString *clientId = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeClientId]; + NSString *magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]; + NSString *clientId = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; if (magIdentifier && clientId) { diff --git a/MASFoundation/Classes/_private_/models/MASDevice+MASPrivate.h b/MASFoundation/Classes/_private_/models/MASDevice+MASPrivate.h index 0b5c0fa9..ecbb5815 100644 --- a/MASFoundation/Classes/_private_/models/MASDevice+MASPrivate.h +++ b/MASFoundation/Classes/_private_/models/MASDevice+MASPrivate.h @@ -81,4 +81,13 @@ */ + (NSString *)deviceNameBase64Encoded; + +/** + * Retrieves the device vendor identifier that is uniquely generated for the + * specific device the framework is running upon. + * + * @return Returns the unique NSString device vendor identifier. + */ ++ (NSString *)deviceVendorId; + @end diff --git a/MASFoundation/Classes/_private_/models/MASDevice+MASPrivate.m b/MASFoundation/Classes/_private_/models/MASDevice+MASPrivate.m index 3ca228cf..5972031a 100644 --- a/MASFoundation/Classes/_private_/models/MASDevice+MASPrivate.m +++ b/MASFoundation/Classes/_private_/models/MASDevice+MASPrivate.m @@ -96,28 +96,28 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info NSString *jwt = headerInfo[MASJwtRequestResponseKey]; if (jwt) { - [accessService setAccessValueString:jwt withAccessValueType:MASAccessValueTypeJWT]; + [accessService setAccessValueString:jwt storageKey:MASKeychainStorageKeyJWT]; } // Mag Identifier NSString *magIdentifier = headerInfo[MASMagIdentifierRequestResponseKey]; if (magIdentifier) { - [accessService setAccessValueString:magIdentifier withAccessValueType:MASAccessValueTypeMAGIdentifier]; + [accessService setAccessValueString:magIdentifier storageKey:MASKeychainStorageKeyMAGIdentifier]; } // Id token NSString *idToken = headerInfo[MASIdTokenHeaderRequestResponseKey]; if (idToken) { - [accessService setAccessValueString:idToken withAccessValueType:MASAccessValueTypeIdToken]; + [accessService setAccessValueString:idToken storageKey:MASKeychainStorageKeyIdToken]; } // Id token type NSString *idTokenType = headerInfo[MASIdTokenTypeHeaderRequestResponseKey]; if (idTokenType) { - [accessService setAccessValueString:idTokenType withAccessValueType:MASAccessValueTypeIdTokenType]; + [accessService setAccessValueString:idTokenType storageKey:MASKeychainStorageKeyIdTokenType]; } // @@ -129,20 +129,29 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info if (certificateData) { - [accessService setAccessValueCertificate:certificateData withAccessValueType:MASAccessValueTypeSignedPublicCertificate]; - [accessService setAccessValueData:certificateData withAccessValueType:MASAccessValueTypeSignedPublicCertificateData]; + [accessService setAccessValueCertificate:certificateData storageKey:MASKeychainStorageKeySignedPublicCertificate]; + [accessService setAccessValueData:certificateData storageKey:MASKeychainStorageKeyPublicCertificateData]; // // Extracting signed client certificate expiration date // - NSArray * cert = [accessService getAccessValueCertificateWithType:MASAccessValueTypeSignedPublicCertificate]; + NSArray * cert = [accessService getAccessValueCertificateWithStorageKey:MASKeychainStorageKeySignedPublicCertificate]; SecCertificateRef certificate = (__bridge SecCertificateRef)([cert objectAtIndex:0]); // // Store client certificate expiration date into shared keychain storage // NSDate *expirationDate = [accessService extractExpirationDateFromCertificate:certificate]; - [accessService setAccessValueNumber:[NSNumber numberWithDouble:[expirationDate timeIntervalSince1970]] withAccessValueType:MASAccessValueTypeSignedPublicCertificateExpirationDate]; + [accessService setAccessValueNumber:[NSNumber numberWithDouble:[expirationDate timeIntervalSince1970]] storageKey:MASKeychainStorageKeyPublicCertificateExpirationDate]; + } + + // + // Device Vendor Id + // + NSString *deviceVendorId = [MASDevice deviceVendorId]; + if (deviceVendorId) + { + [accessService setAccessValueString:deviceVendorId storageKey:MASKeychainStorageKeyDeviceVendorId]; } // @@ -183,7 +192,7 @@ - (BOOL)isClientCertificateExpired + (NSString *)deviceIdBase64Encoded { - NSString *deviceId = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + NSString *deviceId = [MASDevice deviceVendorId]; // // If the sso is disabled, generate unique device id to differentiate the application's registration record from others. @@ -215,4 +224,11 @@ + (NSString *)deviceNameBase64Encoded; return [deviceNameData base64EncodedStringWithOptions:0]; } + ++ (NSString *)deviceVendorId +{ + return [[[UIDevice currentDevice] identifierForVendor] UUIDString]; +} + + @end diff --git a/MASFoundation/Classes/_private_/models/MASUser+MASPrivate.m b/MASFoundation/Classes/_private_/models/MASUser+MASPrivate.m index 630acfcd..567efc1f 100644 --- a/MASFoundation/Classes/_private_/models/MASUser+MASPrivate.m +++ b/MASFoundation/Classes/_private_/models/MASUser+MASPrivate.m @@ -29,7 +29,7 @@ @implementation MASUser (MASPrivate) - (id)initWithInfo:(NSDictionary *)info { self = [super init]; - if(self) + if (self) { [self saveWithUpdatedInfo:info]; } @@ -46,9 +46,9 @@ + (MASUser *)instanceFromStorage // Attempt to retrieve from keychain // - NSData *data = [[MASAccessService sharedService] getAccessValueDataWithType:MASAccessValueTypeMASUserObjectData]; + NSData *data = [[MASAccessService sharedService] getAccessValueDataWithStorageKey:MASKeychainStorageKeyMASUserObjectData]; - if(data) + if (data) { user = (MASUser *)[NSKeyedUnarchiver unarchiveObjectWithData:data]; } @@ -63,9 +63,9 @@ - (void)saveToStorage // Save to the keychain // NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self]; - if(data) + if (data) { - [[MASAccessService sharedService] setAccessValueData:data withAccessValueType:MASAccessValueTypeMASUserObjectData]; + [[MASAccessService sharedService] setAccessValueData:data storageKey:MASKeychainStorageKeyMASUserObjectData]; } } @@ -88,13 +88,19 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info // Uid --> ObjectId // NSString *uid = bodyInfo[MASUserPreferredNameRequestResponseKey]; - if(uid && ![uid isKindOfClass:[NSNull class]]) [self setValue:uid forKey:@"objectId"]; + if (uid && ![uid isKindOfClass:[NSNull class]]) + { + [self setValue:uid forKey:@"objectId"]; + } // // Preferred UserName // NSString *userName = bodyInfo[MASUserPreferredNameRequestResponseKey]; - if(userName && ![userName isKindOfClass:[NSNull class]]) [self setValue:userName forKey:@"userName"]; + if (userName && ![userName isKindOfClass:[NSNull class]]) + { + [self setValue:userName forKey:@"userName"]; + } // // Family Name @@ -116,24 +122,33 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info NSMutableString *mutableCopy = [NSMutableString new]; // Given name, if any - if(self.givenName && ![self.givenName isKindOfClass:[NSNull class]]) [mutableCopy appendString:self.givenName]; + if (self.givenName && ![self.givenName isKindOfClass:[NSNull class]]) + { + [mutableCopy appendString:self.givenName]; + } // Family name, if any - if(self.familyName && ![self.familyName isKindOfClass:[NSNull class]]) + if (self.familyName && ![self.familyName isKindOfClass:[NSNull class]]) { // Check if there was a given name first, if so add a space - if(mutableCopy.length > 0) [mutableCopy appendString:MASDefaultEmptySpace]; + if (mutableCopy.length > 0) + { + [mutableCopy appendString:MASDefaultEmptySpace]; + } [mutableCopy appendString:self.familyName]; } - if(mutableCopy.length > 0) [self setValue:mutableCopy forKey:@"formattedName"]; + if (mutableCopy.length > 0) + { + [self setValue:mutableCopy forKey:@"formattedName"]; + } // // Email Addresses // NSString *emailValue = bodyInfo[MASUserEmailRequestResponseKey]; - if(emailValue && ![emailValue isKindOfClass:[NSNull class]]) + if (emailValue && ![emailValue isKindOfClass:[NSNull class]]) { [self setValue:@{ MASInfoTypeWork : emailValue } forKey:@"emailAddresses"]; } @@ -142,7 +157,7 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info // Phone Numbers // NSString *phoneValue = bodyInfo[MASUserPhoneRequestResponseKey]; - if(phoneValue && ![phoneValue isKindOfClass:[NSNull class]]) + if (phoneValue && ![phoneValue isKindOfClass:[NSNull class]]) { [self setValue:@{ MASInfoTypeWork : phoneValue } forKey:@"phoneNumbers"]; } @@ -151,7 +166,7 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info // Addresses // NSDictionary *addressInfo = bodyInfo[MASUserAddressRequestResponseKey]; - if(addressInfo && ![addressInfo isKindOfClass:[NSNull class]]) + if (addressInfo && ![addressInfo isKindOfClass:[NSNull class]]) { [self setValue:@{ MASInfoTypeWork : addressInfo } forKey:@"addresses"]; } @@ -160,7 +175,7 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info // Picture // NSString *imageUriAsString = bodyInfo[MASUserPictureRequestResponseKey]; - if(imageUriAsString && ![imageUriAsString isKindOfClass:[NSNull class]]) + if (imageUriAsString && ![imageUriAsString isKindOfClass:[NSNull class]]) { NSURL *imageUrl = [NSURL URLWithString:imageUriAsString]; NSData *imageData = [NSData dataWithContentsOfURL:imageUrl]; @@ -172,12 +187,12 @@ - (void)saveWithUpdatedInfo:(NSDictionary *)info // set authenticated timestamp // NSNumber *authenticatedTimestamp = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]]; - [accessService setAccessValueNumber:authenticatedTimestamp withAccessValueType:MASAccessValueTypeAuthenticatedTimestamp]; + [accessService setAccessValueNumber:authenticatedTimestamp storageKey:MASKeychainStorageKeyAuthenticatedTimestamp]; // // set authenticated user's objectId // - [accessService setAccessValueString:self.objectId withAccessValueType:MASAccessValueTypeAuthenticatedUserObjectId]; + [accessService setAccessValueString:self.objectId storageKey:MASKeychainStorageKeyAuthenticatedUserObjectId]; // // storing access information into keychain @@ -203,7 +218,7 @@ - (void)reset { [self resetPartial]; - [[MASAccessService sharedService] setAccessValueData:nil withAccessValueType:MASAccessValueTypeMASUserObjectData]; + [[MASAccessService sharedService] setAccessValueData:nil storageKey:MASKeychainStorageKeyMASUserObjectData]; } - (void)resetPartial @@ -223,7 +238,10 @@ - (void)setWasLoggedOffAndSave:(BOOL)wasLoggedOff // // If was logged off remove the keychain stored values // - if(wasLoggedOff) [self resetPartial]; + if (wasLoggedOff) + { + [self resetPartial]; + } // // Save diff --git a/MASFoundation/Classes/_private_/models/Network/MASRequest+MASPrivate.h b/MASFoundation/Classes/_private_/models/Network/MASRequest+MASPrivate.h new file mode 100644 index 00000000..a43d5946 --- /dev/null +++ b/MASFoundation/Classes/_private_/models/Network/MASRequest+MASPrivate.h @@ -0,0 +1,23 @@ +// +// MASRequest+MASPrivate.h +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import + +@interface MASRequest (MASPrivate) + +/** + Private initializer for MASRequest. + + @param url NSURL of the target domain + @return MASRequest object + */ +- (instancetype)initWithBuilder:(MASRequestBuilder *)builder; + +@end diff --git a/MASFoundation/Classes/_private_/models/Network/MASRequest+MASPrivate.m b/MASFoundation/Classes/_private_/models/Network/MASRequest+MASPrivate.m new file mode 100644 index 00000000..746cadce --- /dev/null +++ b/MASFoundation/Classes/_private_/models/Network/MASRequest+MASPrivate.m @@ -0,0 +1,81 @@ +// +// MASRequest+MASPrivate.m +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import "MASRequest+MASPrivate.h" + + +@interface MASRequest () + +@property (nonatomic, readwrite) NSString *endPoint; +@property (nonatomic, readwrite) NSString *httpMethod; +@property (nonatomic, readwrite) NSData *privateKey; +@property (nonatomic, readwrite) NSDictionary *header; +@property (nonatomic, readwrite) NSDictionary *body; +@property (nonatomic, readwrite) NSDictionary *query; +@property (assign, readwrite) BOOL isPublic; +@property (assign, readwrite) BOOL sign; +@property (assign, readwrite) MASRequestResponseType requestType; +@property (assign, readwrite) MASRequestResponseType responseType; + +@end + +@implementation MASRequest (MASPrivate) + +# pragma mark - Lifecycle + +- (instancetype)initWithBuilder:(MASRequestBuilder *)builder +{ + self = [super init]; + if(self) + { + // + // copy parameters from builder + // + self.endPoint = builder.endPoint; + self.isPublic = builder.isPublic; + self.sign = builder.sign; + self.requestType = builder.requestType; + self.responseType = builder.responseType; + self.httpMethod = builder.httpMethod; + self.privateKey = builder.privateKey; + self.header = builder.header; + self.body = builder.body; + self.query = builder.query; + + + // + // check if query parameters are provided + // + if(self.query) + { + // + // add query parameters into URL + // + NSURL *url = [NSURL URLWithString:self.endPoint]; + + NSMutableArray *queryItems = [NSMutableArray array]; + for (NSString *key in self.query) { + NSURLQueryItem *queryItem = [NSURLQueryItem queryItemWithName:key value:self.query[key]]; + [queryItems addObject:queryItem]; + } + + NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; + components.queryItems = [queryItems copy]; + + self.endPoint = [components.URL absoluteString]; + } + + } + + return self; +} + + +@end diff --git a/MASFoundation/Classes/_private_/services/MASServiceRegistry.h b/MASFoundation/Classes/_private_/services/MASServiceRegistry.h index 694f9508..d2c18078 100644 --- a/MASFoundation/Classes/_private_/services/MASServiceRegistry.h +++ b/MASFoundation/Classes/_private_/services/MASServiceRegistry.h @@ -187,4 +187,15 @@ typedef NS_ENUM(NSInteger, MASRegistryState) - (BOOL)uiServiceWillHandleOTPChannelSelection:(NSArray *)supportedChannels otpGenerationBlock:(MASOTPGenerationBlock)generationBlock; + +/** + * Calling this method will attempt to launch a browser which handles the user authentication steps. + * For this method to handle authentication it requires browser based login to be enabled. + * @see enableBrowserBasedAuthentication + * + * @param bbaLoginBlock The MASAuthCredentialsBlock to receive login result. + * @return Return YES if handled, NO if not. + */ +- (BOOL)browserBasedLoginWillHandleAuthentication : (MASAuthCredentialsBlock)bbaLoginBlock; + @end diff --git a/MASFoundation/Classes/_private_/services/MASServiceRegistry.m b/MASFoundation/Classes/_private_/services/MASServiceRegistry.m index 9c375214..f0b11b73 100644 --- a/MASFoundation/Classes/_private_/services/MASServiceRegistry.m +++ b/MASFoundation/Classes/_private_/services/MASServiceRegistry.m @@ -15,6 +15,8 @@ #import "MASConfigurationService.h" #import "MASModelService.h" #import "MASService.h" +#import "MASServiceRegistry.h" +#import "MASBrowserBasedAuthentication.h" // @@ -932,4 +934,17 @@ - (BOOL)uiServiceWillHandleOTPChannelSelection:(NSArray *)supportedChannels return YES; } + +- (BOOL)browserBasedLoginWillHandleAuthentication : (MASAuthCredentialsBlock)bbaLoginBlock +{ + if(![MASModelService browserBasedAuthentication]) + { + return NO; + } + + [[MASBrowserBasedAuthentication sharedInstance] loadWebLoginTemplate:bbaLoginBlock]; + return YES; + +} + @end diff --git a/MASFoundation/Classes/_private_/services/access/MASAccessService.h b/MASFoundation/Classes/_private_/services/access/MASAccessService.h index 64dc044b..dfb9c3f0 100644 --- a/MASFoundation/Classes/_private_/services/access/MASAccessService.h +++ b/MASFoundation/Classes/_private_/services/access/MASAccessService.h @@ -16,42 +16,38 @@ @class MASIKeyChainStore; - -/** - * The enumerated MASAccessValueType - */ -typedef NS_ENUM(NSInteger, MASAccessValueType) -{ - MASAccessValueTypeUknonw = -1, - MASAccessValueTypeAccessToken, - MASAccessValueTypeAuthenticatedTimestamp, - MASAccessValueTypeAuthenticatedUserObjectId, - MASAccessValueTypeConfiguration, - MASAccessValueTypeClientExpiration, - MASAccessValueTypeClientId, - MASAccessValueTypeClientSecret, - MASAccessValueTypeExpiresIn, - MASAccessValueTypeIdToken, - MASAccessValueTypeIdTokenType, - MASAccessValueTypeIsDeviceLocked, - MASAccessValueTypeJWT, - MASAccessValueTypeMAGIdentifier, - MASAccessValueTypeMSSOEnabled, - MASAccessValueTypePrivateKey, - MASAccessValueTypePrivateKeyBits, - MASAccessValueTypePublicKey, - MASAccessValueTypeRefreshToken, - MASAccessValueTypeScope, - MASAccessValueTypeSecuredIdToken, - MASAccessValueTypeSignedPublicCertificate, - MASAccessValueTypeSignedPublicCertificateData, - MASAccessValueTypeSignedPublicCertificateExpirationDate, - MASAccessValueTypeTokenExpiration, - MASAccessValueTypeTokenType, - MASAccessValueTypeTrustedServerCertificate, - MASAccessValueTypeCurrentAuthCredentialsGrantType, - MASAccessValueTypeMASUserObjectData, -}; +// +// List of constant NSString values for reserved storage keys +// +extern NSString * const MASKeychainStorageKeyConfiguration; +extern NSString * const MASKeychainStorageKeyAccessToken; +extern NSString * const MASKeychainStorageKeyAuthenticatedUserObjectId; +extern NSString * const MASKeychainStorageKeyRefreshToken; +extern NSString * const MASKeychainStorageKeyScope; +extern NSString * const MASKeychainStorageKeyTokenType; +extern NSString * const MASKeychainStorageKeyExpiresIn; +extern NSString * const MASKeychainStorageKeyTokenExpiration; +extern NSString * const MASKeychainStorageKeySecuredIdToken; +extern NSString * const MASKeychainStorageKeyIdToken; +extern NSString * const MASKeychainStorageKeyIdTokenType; +extern NSString * const MASKeychainStorageKeyClientExpiration; +extern NSString * const MASKeychainStorageKeyClientId; +extern NSString * const MASKeychainStorageKeyClientSecret; +extern NSString * const MASKeychainStorageKeyJWT; +extern NSString * const MASKeychainStorageKeyMAGIdentifier; +extern NSString * const MASKeychainStorageKeyMSSOEnabled; +extern NSString * const MASKeychainStorageKeyPrivateKey; +extern NSString * const MASKeychainStorageKeyPrivateKeyBits; +extern NSString * const MASKeychainStorageKeyPublicKey; +extern NSString * const MASKeychainStorageKeyTrustedServerCertificate; +extern NSString * const MASKeychainStorageKeySignedPublicCertificate; +extern NSString * const MASKeychainStorageKeyPublicCertificateData; +extern NSString * const MASKeychainStorageKeyPublicCertificateExpirationDate; +extern NSString * const MASKeychainStorageKeyAuthenticatedTimestamp; +extern NSString * const MASKeychainStorageKeyIsDeviceLocked; +extern NSString * const MASKeychainStorageKeyCurrentAuthCredentialsGrantType; +extern NSString * const MASKeychainStorageKeyMASUserObjectData; +extern NSString * const MASKeychainStorageKeyDeviceVendorId; /** @@ -99,6 +95,24 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) +/** + * Static boolean property indicating Keychain sincronization is enabled or not. + * + * @return return BOOL value indicating Keychain sincronization is enabled or not + */ ++ (BOOL)isKeychainSynchronizable; + + + +/** + * Setter of static boolean property indicating Keychain sincronization is enabled or not. + * + * @param enable BOOL value indicating Keychain sincronization is enabled or not + */ ++ (void)setKeychainSynchronizable:(BOOL)enable; + + + ///-------------------------------------- /// @name Shared Service ///-------------------------------------- @@ -114,6 +128,10 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) +///-------------------------------------- +/// @name MASAccess object +///-------------------------------------- + # pragma mark - MASAccess object /** @@ -126,9 +144,11 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) -# pragma mark - Storage methods - +///-------------------------------------- +/// @name Storage methods +///-------------------------------------- +# pragma mark - Storage methods /** * Retrieve list of identities in keychain @@ -143,41 +163,65 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) * Store the certificate as data format into keychain * * @param certificate NSData form of certificate - * @param type MASAccessValueType enum specifying the value key + * @param storageKey NSString value for the data key */ -- (void)setAccessValueCertificate:(NSData *)certificate withAccessValueType:(MASAccessValueType)type; +- (void)setAccessValueCertificate:(NSData *)certificate storageKey:(NSString *)storageKey; /** * Retrieve the certificate data by the value key * - * @param type MASAccessValueType enum value for key + * @param storageKey NSString value for the data key * * @return Certificate value by the specified value key */ -- (id)getAccessValueCertificateWithType:(MASAccessValueType)type; +- (id)getAccessValueCertificateWithStorageKey:(NSString *)storageKey; /** - * Store NSData of access value into keychain - * - * @param data NSData to store into keychain - * @param type MASAccessValueType enum value for the value key + Store NSData of access value into keychain + + @param data NSData to be stored into keychain + @param storageKey NSString value for the data key + @return BOOL result of operation + */ +- (BOOL)setAccessValueData:(NSData *)data storageKey:(NSString *)storageKey; + + + +/** + Store NSData of access value into keychain + + @param data NSData to be stored into keychain + @param storageKey NSString value for the data key + @param error NSError reference object to notify if there is any error while keychain operation + @return BOOL result of operation */ -- (void)setAccessValueData:(NSData *)data withAccessValueType:(MASAccessValueType)type; +- (BOOL)setAccessValueData:(NSData *)data storageKey:(NSString *)storageKey error:(NSError **)error; /** * Retrieve NSData of access value from keychain * - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key * * @return NSData of the access data by the specified value key */ -- (NSData *)getAccessValueDataWithType:(MASAccessValueType)type; +- (NSData *)getAccessValueDataWithStorageKey:(NSString *)storageKey; + + + +/** + Retrieve NSData of access value from keychain + + @param storageKey NSString value for the data key + @param error NSError reference object to notify if there is any error while keychain operation + @return NSData of the access data by the specified value key + */ +- (NSData *)getAccessValueDataWithStorageKey:(NSString *)storageKey error:(NSError **)error; @@ -185,20 +229,44 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) * Store NSString of access value into keychain * * @param string NSString to store into keychain - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key + * @return BOOL result of operation */ -- (void)setAccessValueString:(NSString *)string withAccessValueType:(MASAccessValueType)type; +- (BOOL)setAccessValueString:(NSString *)string storageKey:(NSString *)storageKey; + + + +/** + Store NSString of access value into keychain + + @param string NSString to store into keychain + @param storageKey NSString value for the data key + @param error NSError reference object to notify if there is any error while keychain operation + @return BOOL result of operation + */ +- (BOOL)setAccessValueString:(NSString *)string storageKey:(NSString *)storageKey error:(NSError **)error; /** * Retrieve NSString of access value from keychain * - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key * * @return NSString of the access data by the specified value key */ -- (NSString *)getAccessValueStringWithType:(MASAccessValueType)type; +- (NSString *)getAccessValueStringWithStorageKey:(NSString *)storageKey; + + + +/** + Retrieve NSString of access value from keychain + + @param storageKey NSString value for the data key + @param error NSError reference object to notify if there is any error while keychain operation + @return NSString of the access data by the specified value key + */ +- (NSString *)getAccessValueStringWithStorageKey:(NSString *)storageKey error:(NSError **)error; @@ -206,20 +274,20 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) * Store NSDictionary of access value into keychain * * @param dictionary NSDictionary to store into keychain - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key */ -- (void)setAccessValueDictionary:(NSDictionary *)dictionary withAccessValueType:(MASAccessValueType)type; +- (BOOL)setAccessValueDictionary:(NSDictionary *)dictionary storageKey:(NSString *)storageKey; /** * Retrieve NSDictionary of access value from keychain * - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key * * @return NSDictionary of the access data by the specified value key */ -- (NSDictionary *)getAccessValueDictionaryWithType:(MASAccessValueType)type; +- (NSDictionary *)getAccessValueDictionaryWithStorageKey:(NSString *)storageKey; @@ -227,20 +295,20 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) * Store NSNumber of access value into keychain * * @param number NSNumber to store into keychain - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key */ -- (void)setAccessValueNumber:(NSNumber *)number withAccessValueType:(MASAccessValueType)type; +- (BOOL)setAccessValueNumber:(NSNumber *)number storageKey:(NSString *)storageKey; /** * Retrieve NSNumber of access value from keychain * - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key * * @return NSNumber of the access data by the specified value key */ -- (NSNumber *)getAccessValueNumberWithType:(MASAccessValueType)type; +- (NSNumber *)getAccessValueNumberWithStorageKey:(NSString *)storageKey; @@ -252,9 +320,9 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) * Other access type value will not be stored. * * @param cryptoKey SecKeyRef to store into keychain - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key */ -- (void)setAccessValueCryptoKey:(SecKeyRef)cryptoKey withAccessValueType:(MASAccessValueType)type; +- (void)setAccessValueCryptoKey:(SecKeyRef)cryptoKey storageKey:(NSString *)storageKey; @@ -265,12 +333,27 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) * MASAccessValueTypePublicKey and MASAccessValueTypePrivateKey. * Other access type value will not be retrieved. * - * @param type MASAccessValueType enum value for the value key + * @param storageKey NSString value for the data key * * @return SecKeyRef of the access data by the specified value key */ -- (SecKeyRef)getAccessValueCryptoKeyWithType:(MASAccessValueType)type; +- (SecKeyRef)getAccessValueCryptoKeyWithStorageKey:(NSString *)storageKey; + + + +/** + Deletes keychain storage item based on storage key + + @param storageKey NSString of storage key. + @param error NSError object reference. + */ +- (void)deleteForStorageKey:(NSString *)storageKey error:(NSError **)error; + + +///-------------------------------------- +/// @name Public +///-------------------------------------- # pragma mark - Public @@ -284,6 +367,8 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) */ + (BOOL)validateIdToken:(NSString *)idToken magIdentifier:(NSString *)magIdentifier error:(NSError *__autoreleasing *)error; + + /** * Validate the expiration date in id_token * @@ -294,6 +379,13 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) + (BOOL)isIdTokenExpired:(NSString *)idToken error:(NSError *__autoreleasing *)error; + +/** + Extracts the expiration date from the SecCertificateRef + + @param certificate SecCertificateRef of the certificate + @return NSDate of the expiration date from SecCertificateRef + */ - (NSDate *)extractExpirationDateFromCertificate:(SecCertificateRef)certificate; @@ -309,7 +401,6 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) - /** Unlock id_token, access_token, and refresh_token from secure keychain storage protected by device's local authentication (passcode and/or fingerprint) @@ -329,6 +420,16 @@ typedef NS_ENUM(NSInteger, MASAccessValueType) +/** + Internal method to determine whether the key is reserved for internal system data or not + + @param storageKey NSString of key to be stored + @return BOOL result of whether the key is reserved or not by internal system data + */ +- (BOOL)isInternalDataForStorageKey:(NSString *)storageKey; + + + # pragma mark - Debug only - (void)clearLocal; diff --git a/MASFoundation/Classes/_private_/services/access/MASAccessService.m b/MASFoundation/Classes/_private_/services/access/MASAccessService.m index 441a2d23..cedf6246 100644 --- a/MASFoundation/Classes/_private_/services/access/MASAccessService.m +++ b/MASFoundation/Classes/_private_/services/access/MASAccessService.m @@ -25,9 +25,43 @@ static NSString *const kMASAccessSharedStorageKey = @"sharedStorage"; static NSString *const kMASAccessLocalStorageKey = @"localStorage"; +static NSString *const kMASAccessCustomSharedStorageKey = @"customSharedStorage"; static NSString *const kMASAccessIsNotFreshInstallFlag = @"isNotFreshInstall"; +# pragma mark - Keychain Storage Key + +NSString * const MASKeychainStorageKeyConfiguration = @"kMASKeyChainConfiguration"; +NSString * const MASKeychainStorageKeyAccessToken = @"kMASKeyChainAccessToken"; +NSString * const MASKeychainStorageKeyAuthenticatedUserObjectId = @"MASAccessValueTypeAuthenticatedUserObjectId"; +NSString * const MASKeychainStorageKeyRefreshToken = @"kMASKeyChainRefreshToken"; +NSString * const MASKeychainStorageKeyScope = @"kMASKeyChainScope"; +NSString * const MASKeychainStorageKeyTokenType = @"kMASKeyChainTokenType"; +NSString * const MASKeychainStorageKeyExpiresIn = @"kMASKeyChainExpiresIn"; +NSString * const MASKeychainStorageKeyTokenExpiration = @"kMASKeyChainTokenExpiration"; +NSString * const MASKeychainStorageKeySecuredIdToken = @"kMASKeyChainSecuredIdToken"; +NSString * const MASKeychainStorageKeyIdToken = @"kMASKeyChainIdToken"; +NSString * const MASKeychainStorageKeyIdTokenType = @"kMASKeyChainIdTokenType"; +NSString * const MASKeychainStorageKeyClientExpiration = @"kMASKeyChainClientExpiration"; +NSString * const MASKeychainStorageKeyClientId = @"kMASKeyChainClientId"; +NSString * const MASKeychainStorageKeyClientSecret = @"kMASKeyChainClientSecret"; +NSString * const MASKeychainStorageKeyJWT = @"kMASKeyChainJwt"; +NSString * const MASKeychainStorageKeyMAGIdentifier = @"kMASKeyChainMagIdentifier"; +NSString * const MASKeychainStorageKeyMSSOEnabled = @"kMASAccessValueTypeMSSOEnabled"; +NSString * const MASKeychainStorageKeyPrivateKey = @"kMASKeyChainPrivateKey"; +NSString * const MASKeychainStorageKeyPrivateKeyBits = @"kMASKeyChainPrivateKeyBits"; +NSString * const MASKeychainStorageKeyPublicKey = @"kMASKeyChainPublicKey"; +NSString * const MASKeychainStorageKeyTrustedServerCertificate = @"kMASKeyChainTrustedServerCertificate"; +NSString * const MASKeychainStorageKeySignedPublicCertificate = @"kMASKeyChainSignedPublicCertificate"; +NSString * const MASKeychainStorageKeyPublicCertificateData = @"kMASKeyChainSignedPublicCertificateData"; +NSString * const MASKeychainStorageKeyPublicCertificateExpirationDate = @"kMASAccessValueTypeSignedPublicCertificateExpirationDate"; +NSString * const MASKeychainStorageKeyAuthenticatedTimestamp = @"kMASAccessValueTypeAuthenticatedTimestamp"; +NSString * const MASKeychainStorageKeyIsDeviceLocked = @"kMASAccessValueTypeIsDeviceLocked"; +NSString * const MASKeychainStorageKeyCurrentAuthCredentialsGrantType = @"kMASAccessValueTypeCurrentAuthCredentialsGrantType"; +NSString * const MASKeychainStorageKeyMASUserObjectData = @"kMASAccessValueTypeMASUserObjectData"; +NSString * const MASKeychainStorageKeyDeviceVendorId = @"kMASKeyChainDeviceVendorId"; + + @interface MASAccessService () # pragma mark - Properties @@ -36,12 +70,17 @@ @interface MASAccessService () @property (strong, nonatomic, readwrite) NSString *sharedStorageServiceName; @property (strong, nonatomic, readwrite) NSString *localStorageServiceName; +@property (strong, nonatomic, readwrite) NSString *customSharedStorageServiceName; @property (strong, nonatomic, readwrite) NSString *gatewayHostName; @property (strong, nonatomic, readwrite) NSString *gatewayIdentifier; @property (assign) BOOL isSharedKeychainEnabled; +@property (strong, nonatomic, readwrite) NSArray *sharedStorageKeys; +@property (strong, nonatomic, readwrite) NSArray *localStorageKeys; +@property (strong, nonatomic, readwrite) NSArray *secureStorageKeys; + @end @@ -49,6 +88,7 @@ @implementation MASAccessService static BOOL _isPKCEEnabled_ = YES; +static BOOL _isKeychainSynchronizable_ = NO; # pragma mark - Properties @@ -64,6 +104,18 @@ + (void)enablePKCE:(BOOL)enable } ++ (BOOL)isKeychainSynchronizable +{ + return _isKeychainSynchronizable_; +} + + ++ (void)setKeychainSynchronizable:(BOOL)enable +{ + _isKeychainSynchronizable_ = enable; +} + + # pragma mark - Shared Service + (instancetype)sharedService @@ -89,53 +141,94 @@ + (NSString *)serviceUUID - (void)serviceDidLoad { - [super serviceDidLoad]; } - (void)serviceWillStart { + // + // Define a list of keys for secured storage + // + _secureStorageKeys = @[MASKeychainStorageKeySecuredIdToken]; + + // + // Define a list of keys to be stored in local keychain storage + // + _localStorageKeys = @[MASKeychainStorageKeyConfiguration, + MASKeychainStorageKeyAccessToken, + MASKeychainStorageKeyRefreshToken, + MASKeychainStorageKeyScope, + MASKeychainStorageKeyTokenType, + MASKeychainStorageKeyExpiresIn, + MASKeychainStorageKeyTokenExpiration, + MASKeychainStorageKeyClientExpiration, + MASKeychainStorageKeyClientId, + MASKeychainStorageKeyClientSecret, + MASKeychainStorageKeyAuthenticatedTimestamp]; + + // + // Define a list of keys to be stored in shared keychain storage + // + _sharedStorageKeys = @[MASKeychainStorageKeyAuthenticatedUserObjectId, + MASKeychainStorageKeySecuredIdToken, + MASKeychainStorageKeyIdToken, + MASKeychainStorageKeyIdTokenType, + MASKeychainStorageKeyJWT, + MASKeychainStorageKeyMAGIdentifier, + MASKeychainStorageKeyMSSOEnabled, + MASKeychainStorageKeyPrivateKey, + MASKeychainStorageKeyPrivateKeyBits, + MASKeychainStorageKeyPublicKey, + MASKeychainStorageKeyTrustedServerCertificate, + MASKeychainStorageKeySignedPublicCertificate, + MASKeychainStorageKeyPublicCertificateData, + MASKeychainStorageKeyPublicCertificateExpirationDate, + MASKeychainStorageKeyCurrentAuthCredentialsGrantType, + MASKeychainStorageKeyIsDeviceLocked, + MASKeychainStorageKeyMASUserObjectData, + MASKeychainStorageKeyDeviceVendorId]; + // // Retrieve gatewayUrl which is combination of hostname, port number, and prefix of the gateway. // The gatewayUrl can be unique identifier for each server. // _gatewayIdentifier = [MASConfiguration currentConfiguration].gatewayUrl.absoluteString; - _localStorageServiceName = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, kMASAccessLocalStorageServiceName]; - _sharedStorageServiceName = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, kMASAccessSharedStorageServiceName]; + _customSharedStorageServiceName = [NSString stringWithFormat:@"MAS.%@", kMASAccessCustomSharedStorageKey]; + + // + // Custom shared storage + // + MASIKeyChainStore *customSharedStorage = [MASIKeyChainStore keyChainStoreWithService:_customSharedStorageServiceName accessGroup:self.accessGroup]; + customSharedStorage.synchronizable = _isKeychainSynchronizable_; + // + // Local storage + // + MASIKeyChainStore *localStorage = [MASIKeyChainStore keyChainStoreWithService:_localStorageServiceName]; + localStorage.synchronizable = _isKeychainSynchronizable_; + if ([MASConfiguration currentConfiguration].ssoEnabled && [self isAccessGroupAccessible]) { - - // - // Local storage - // - MASIKeyChainStore *localStorage = [MASIKeyChainStore keyChainStoreWithService:_localStorageServiceName]; - // // Shared storage // MASIKeyChainStore *sharedStorage = [MASIKeyChainStore keyChainStoreWithService:_sharedStorageServiceName accessGroup:self.accessGroup]; - + sharedStorage.synchronizable = _isKeychainSynchronizable_; + // // storage dictionary property // - _storages = [NSDictionary dictionaryWithObjectsAndKeys:localStorage, kMASAccessLocalStorageKey, sharedStorage, kMASAccessSharedStorageKey, nil]; + _storages = [NSDictionary dictionaryWithObjectsAndKeys:localStorage, kMASAccessLocalStorageKey, sharedStorage, kMASAccessSharedStorageKey, customSharedStorage, kMASAccessCustomSharedStorageKey, nil]; } else { - - // - // Local storage - // - MASIKeyChainStore *localStorage = [MASIKeyChainStore keyChainStoreWithService:_localStorageServiceName]; - // // storage dictionary property // - _storages = [NSDictionary dictionaryWithObjectsAndKeys:localStorage, kMASAccessLocalStorageKey, localStorage, kMASAccessSharedStorageKey, nil]; + _storages = [NSDictionary dictionaryWithObjectsAndKeys:localStorage, kMASAccessLocalStorageKey, localStorage, kMASAccessSharedStorageKey, customSharedStorage, kMASAccessCustomSharedStorageKey, nil]; } @@ -208,7 +301,7 @@ - (void)saveAccessValuesWithDictionary:(NSDictionary *)dictionary forceToOverwri // // if the user chooses to overwite whatever SDK contains with the provided dictionary, reset the object // - if(forceToOverwrite) + if (forceToOverwrite) { [_currentAccessObj reset]; _currentAccessObj = nil; @@ -233,11 +326,22 @@ - (void)saveAccessValuesWithDictionary:(NSDictionary *)dictionary forceToOverwri # pragma mark - Storage methods -- (void)setAccessValueCertificate:(NSData *)certificate withAccessValueType:(MASAccessValueType)type +- (id)getAccessValueIdentities { - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; - NSString *accessValueAsString = [self convertAccessTypeToString:type]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; + //DLog(@"\n\ncalled\n\n"); + + MASIKeyChainStore *keychainStore = [MASIKeyChainStore keyChainStore]; + NSArray *identities = [keychainStore identitiesWithCertificateLabel:[self convertKeyString:MASKeychainStorageKeySignedPublicCertificate]]; + + return identities; +} + + +- (void)setAccessValueCertificate:(NSData *)certificate storageKey:(NSString *)storageKey +{ + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + NSString *accessValueAsString = [self convertKeyString:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; NSData * certData = nil; @@ -262,35 +366,31 @@ - (void)setAccessValueCertificate:(NSData *)certificate withAccessValueType:(MAS } -- (id)getAccessValueCertificateWithType:(MASAccessValueType)type +- (id)getAccessValueCertificateWithStorageKey:(NSString *)storageKey { - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; - NSString *accessValueAsString = [self convertAccessTypeToString:type]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + NSString *accessValueAsString = [self convertKeyString:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; return [destinationStorage certificateForKey:accessValueAsString]; } -- (id)getAccessValueIdentities +- (BOOL)setAccessValueData:(NSData *)data storageKey:(NSString *)storageKey { - //DLog(@"\n\ncalled\n\n"); - - MASIKeyChainStore *keychainStore = [MASIKeyChainStore keyChainStore]; - NSArray *identities = [keychainStore identitiesWithCertificateLabel:[self convertAccessTypeToString:MASAccessValueTypeSignedPublicCertificate]]; - - return identities; + return [self setAccessValueData:data storageKey:storageKey error:nil]; } -- (void)setAccessValueData:(NSData *)data withAccessValueType:(MASAccessValueType)type +- (BOOL)setAccessValueData:(NSData *)data storageKey:(NSString *)storageKey error:(NSError **)error { + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + NSString *accessValueAsString = [self convertKeyString:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; + NSError *operationError = nil; - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; - NSString *accessValueAsString = [self convertAccessTypeToString:type]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; - - BOOL isSecuredData = [self isSecuredData:type]; + BOOL isSecuredData = [self isSecureData:storageKey]; + BOOL result = NO; if (isSecuredData) { @@ -302,50 +402,70 @@ - (void)setAccessValueData:(NSData *)data withAccessValueType:(MASAccessValueTyp // if (data) { - [destinationStorage setData:data forKey:accessValueAsString]; + result = [destinationStorage setData:data forKey:accessValueAsString error:&operationError]; } // // Removal // else { - [destinationStorage removeItemForKey:accessValueAsString]; + result = [destinationStorage removeItemForKey:accessValueAsString error:&operationError]; } if (isSecuredData) { [destinationStorage setAccessibility:MASIKeyChainStoreAccessibilityAfterFirstUnlock authenticationPolicy:0]; } + + if (error) + { + *error = operationError; + } + + return result; } -- (NSData *)getAccessValueDataWithType:(MASAccessValueType)type +- (NSData *)getAccessValueDataWithStorageKey:(NSString *)storageKey { + return [self getAccessValueDataWithStorageKey:storageKey error:nil]; +} + + +- (NSData *)getAccessValueDataWithStorageKey:(NSString *)storageKey error:(NSError **)error +{ + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + NSString *accessValueAsString = [self convertKeyString:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; + NSError *operationError = nil; - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; - NSString *accessValueAsString = [self convertAccessTypeToString:type]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; + NSData *keychainData = [destinationStorage dataForKey:accessValueAsString error:&operationError]; + + if (error) + { + *error = operationError; + } - NSData *keychainData = [destinationStorage dataForKey:accessValueAsString]; - return keychainData; } -- (void)setAccessValueString:(NSString *)string withAccessValueType:(MASAccessValueType)type +- (BOOL)setAccessValueString:(NSString *)string storageKey:(NSString *)storageKey { - [self setAccessValueString:string withAccessValueType:type error:nil]; + return [self setAccessValueString:string storageKey:storageKey error:nil]; } -- (BOOL)setAccessValueString:(NSString *)string withAccessValueType:(MASAccessValueType)type error:(NSError * __nullable __autoreleasing * __nullable)error +- (BOOL)setAccessValueString:(NSString *)string storageKey:(NSString *)storageKey error:(NSError **)error { - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; - NSString *accessValueAsString = [self convertAccessTypeToString:type]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + NSString *accessValueAsString = [self convertKeyString:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; + NSError *operationError = nil; - BOOL isSecuredData = [self isSecuredData:type]; + BOOL result = NO; + BOOL isSecuredData = [self isSecureData:storageKey]; if (isSecuredData) { @@ -357,14 +477,14 @@ - (BOOL)setAccessValueString:(NSString *)string withAccessValueType:(MASAccessVa // if (string) { - [destinationStorage setString:string forKey:accessValueAsString error:error]; + result = [destinationStorage setString:string forKey:accessValueAsString error:&operationError]; } // // Removal // else { - [destinationStorage removeItemForKey:accessValueAsString error:error]; + result = [destinationStorage removeItemForKey:accessValueAsString error:&operationError]; } if (isSecuredData) @@ -374,70 +494,82 @@ - (BOOL)setAccessValueString:(NSString *)string withAccessValueType:(MASAccessVa if (error) { - return NO; - } - else { - return YES; + *error = operationError; } + + return result; } -- (NSString *)getAccessValueStringWithType:(MASAccessValueType)type +- (NSString *)getAccessValueStringWithStorageKey:(NSString *)storageKey { - - return [self getAccessValueStringWithType:type error:nil]; + return [self getAccessValueStringWithStorageKey:storageKey error:nil]; } -- (NSString *)getAccessValueStringWithType:(MASAccessValueType)type userOperationPrompt:(NSString *)userOperationPrompt error:(NSError * __nullable __autoreleasing * __nullable)error +- (NSString *)getAccessValueStringWithStorageKey:(NSString *)storageKey userOperationPrompt:(NSString *)userOperationPrompt error:(NSError **)error { - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; - NSString *accessValueAsString = [self convertAccessTypeToString:type]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + NSString *accessValueAsString = [self convertKeyString:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; + NSError *operationError = nil; + + NSString *securedString = [destinationStorage stringForKey:accessValueAsString userOperationPrompt:userOperationPrompt error:&operationError]; - NSString *securedString = [destinationStorage stringForKey:accessValueAsString userOperationPrompt:userOperationPrompt error:error]; + if (error) + { + *error = operationError; + } return securedString; } -- (NSString *)getAccessValueStringWithType:(MASAccessValueType)type error:(NSError * __nullable __autoreleasing * __nullable)error +- (NSString *)getAccessValueStringWithStorageKey:(NSString *)storageKey error:(NSError **)error { + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + NSString *accessValueAsString = [self convertKeyString:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; + NSError *operationError = nil; - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; - NSString *accessValueAsString = [self convertAccessTypeToString:type]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; + NSString *securedString = [destinationStorage stringForKey:accessValueAsString error:&operationError]; - NSString *securedString = [destinationStorage stringForKey:accessValueAsString error:error]; + if (error) + { + *error = operationError; + } return securedString; } -- (void)setAccessValueDictionary:(NSDictionary *)dictionary withAccessValueType:(MASAccessValueType)type +- (BOOL)setAccessValueDictionary:(NSDictionary *)dictionary storageKey:(NSString *)storageKey { // // convert dictionary to data // NSData *thisData = [NSKeyedArchiver archivedDataWithRootObject:dictionary]; + BOOL result = NO; // // make sure the data exists // - if(thisData) + if (thisData) { - [self setAccessValueData:thisData withAccessValueType:type]; + result = [self setAccessValueData:thisData storageKey:storageKey]; } + + return result; } -- (NSDictionary *)getAccessValueDictionaryWithType:(MASAccessValueType)type +- (NSDictionary *)getAccessValueDictionaryWithStorageKey:(NSString *)storageKey { // // get data from keychain as NSData first // - NSData *thisData = [self getAccessValueDataWithType:type]; + NSData *thisData = [self getAccessValueDataWithStorageKey:storageKey]; // // return nil if NSData is nil @@ -446,28 +578,31 @@ - (NSDictionary *)getAccessValueDictionaryWithType:(MASAccessValueType)type } -- (void)setAccessValueNumber:(NSNumber *)number withAccessValueType:(MASAccessValueType)type +- (BOOL)setAccessValueNumber:(NSNumber *)number storageKey:(NSString *)storageKey { // convert dictionary to data // NSData *thisData = [NSKeyedArchiver archivedDataWithRootObject:number]; + BOOL result = NO; // // make sure the data exists // - if(thisData) + if (thisData) { - [self setAccessValueData:thisData withAccessValueType:type]; + result = [self setAccessValueData:thisData storageKey:storageKey]; } + + return result; } -- (NSNumber *)getAccessValueNumberWithType:(MASAccessValueType)type +- (NSNumber *)getAccessValueNumberWithStorageKey:(NSString *)storageKey { // // get data from keychain as NSData first // - NSData *thisData = [self getAccessValueDataWithType:type]; + NSData *thisData = [self getAccessValueDataWithStorageKey:storageKey]; // // return nil if NSData is nil @@ -476,19 +611,20 @@ - (NSNumber *)getAccessValueNumberWithType:(MASAccessValueType)type } -- (void)setAccessValueCryptoKey:(SecKeyRef)cryptoKey withAccessValueType:(MASAccessValueType)type +- (void)setAccessValueCryptoKey:(SecKeyRef)cryptoKey storageKey:(NSString *)storageKey { - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; + NSString *storageType = [self getStorageTypeWithKey:storageKey]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; NSString *keyIdentifierStr = nil; - if (type == MASAccessValueTypePublicKey) + + if ([storageKey isEqualToString:MASKeychainStorageKeyPublicKey]) { keyIdentifierStr = [NSString stringWithFormat:@"%@.%@", [MASConfiguration currentConfiguration].gatewayUrl.absoluteString, @"publicKey"]; } - else if (type == MASAccessValueTypePrivateKey) + else if ([storageKey isEqualToString:MASKeychainStorageKeyPrivateKey]) { keyIdentifierStr = [NSString stringWithFormat:@"%@.%@", [MASConfiguration currentConfiguration].gatewayUrl.absoluteString, @"privateKey"]; } @@ -503,20 +639,20 @@ - (void)setAccessValueCryptoKey:(SecKeyRef)cryptoKey withAccessValueType:(MASAcc } -- (SecKeyRef)getAccessValueCryptoKeyWithType:(MASAccessValueType)type +- (SecKeyRef)getAccessValueCryptoKeyWithStorageKey:(NSString *)storageKey { - NSString *storageKey = [self getStorageKeyWithAccessValueType:type]; - MASIKeyChainStore *destinationStorage = _storages[storageKey]; + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; NSString *keyIdentifierStr = nil; - if (type == MASAccessValueTypePublicKey) + if ([storageKey isEqualToString:MASKeychainStorageKeyPublicKey]) { keyIdentifierStr = [NSString stringWithFormat:@"%@.%@", [MASConfiguration currentConfiguration].gatewayUrl.absoluteString, @"publicKey"]; } - else if (type == MASAccessValueTypePrivateKey) + else if ([storageKey isEqualToString:MASKeychainStorageKeyPrivateKey]) { keyIdentifierStr = [NSString stringWithFormat:@"%@.%@", [MASConfiguration currentConfiguration].gatewayUrl.absoluteString, @"privateKey"]; } @@ -535,9 +671,26 @@ - (SecKeyRef)getAccessValueCryptoKeyWithType:(MASAccessValueType)type } +- (void)deleteForStorageKey:(NSString *)storageKey error:(NSError **)error +{ + NSString *storageType = [self getStorageTypeWithKey:storageKey]; + NSString *accessValueAsString = [self convertKeyString:storageKey]; + MASIKeyChainStore *destinationStorage = _storages[storageType]; + + NSError *operationError = nil; + + [destinationStorage removeItemForKey:accessValueAsString error:&operationError]; + + if (operationError && error) + { + *error = operationError; + } +} + + #pragma mark - Private -+ (NSString *)padding: (NSString *) encodedString{ ++ (NSString *)padding:(NSString *)encodedString{ unsigned long lengthtRequired = (int)(4 * ceil((float)[encodedString length] / 4.0)); long numPaddings = lengthtRequired - [encodedString length]; @@ -555,6 +708,7 @@ + (NSString *)padding: (NSString *) encodedString{ return encodedString; } + + (NSDictionary *)getIdTokenSegments:(NSString *)idToken error:(NSError *__autoreleasing *)error { NSDictionary *segmentsDict = nil; @@ -591,6 +745,7 @@ + (NSDictionary *)getIdTokenSegments:(NSString *)idToken error:(NSError *__autor return segmentsDict; } + + (NSDictionary *)unwrap:(NSString *)data { NSDictionary *dictionary = nil; @@ -608,272 +763,59 @@ + (NSDictionary *)unwrap:(NSString *)data return dictionary; } -- (BOOL)isSecuredData:(MASAccessValueType)type + +- (NSString *)convertKeyString:(NSString *)key { - BOOL isSecuredData = NO; + NSString *accessTypeToString = nil; - switch (type) { - case MASAccessValueTypeSecuredIdToken: - isSecuredData = YES; - break; + // + // Internal system data + // + if ([_sharedStorageKeys containsObject:key] || [_localStorageKeys containsObject:key]) + { + accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, key]; - default: - isSecuredData = NO; - break; + // + // When access gruop is not accessiable, differentiate the key to make sure there is no conflict of device registration record in the future + // + if (![self isAccessGroupAccessible]) + { + accessTypeToString = [NSString stringWithFormat:@"_%@", accessTypeToString]; + } + } + // + // External custom data in shared keychain storage + // + else { + accessTypeToString = key; } - return isSecuredData; + return accessTypeToString; } -- (NSString *)getStorageKeyWithAccessValueType:(MASAccessValueType)type +- (BOOL)isSecureData:(NSString *)key { - NSString *storageKey = @""; - - switch (type) { - //Configuration - case MASAccessValueTypeConfiguration: - storageKey = kMASAccessLocalStorageKey; - break; - //AccessToken - case MASAccessValueTypeAccessToken: - storageKey = kMASAccessLocalStorageKey; - break; - //Authenticated username - case MASAccessValueTypeAuthenticatedUserObjectId: - storageKey = kMASAccessSharedStorageKey; - break; - //RefreshToken - case MASAccessValueTypeRefreshToken: - storageKey = kMASAccessLocalStorageKey; - break; - //Scope - case MASAccessValueTypeScope: - storageKey = kMASAccessLocalStorageKey; - break; - //TokenType - case MASAccessValueTypeTokenType: - storageKey = kMASAccessLocalStorageKey; - break; - //ExpiresIn - case MASAccessValueTypeExpiresIn: - storageKey = kMASAccessLocalStorageKey; - break; - //TokenExpiration - case MASAccessValueTypeTokenExpiration: - storageKey = kMASAccessLocalStorageKey; - break; - //IdToken with secured local authentication - case MASAccessValueTypeSecuredIdToken: - storageKey = kMASAccessSharedStorageKey; - break; - //IdToken - case MASAccessValueTypeIdToken: - storageKey = kMASAccessSharedStorageKey; - break; - //IdTokenType - case MASAccessValueTypeIdTokenType: - storageKey = kMASAccessSharedStorageKey; - break; - //ClientExpiration - case MASAccessValueTypeClientExpiration: - storageKey = kMASAccessLocalStorageKey; - break; - //ClientId - case MASAccessValueTypeClientId: - storageKey = kMASAccessLocalStorageKey; - break; - //ClientSecret - case MASAccessValueTypeClientSecret: - storageKey = kMASAccessLocalStorageKey; - break; - //JWT - case MASAccessValueTypeJWT: - storageKey = kMASAccessSharedStorageKey; - break; - //MAGIdentifier - case MASAccessValueTypeMAGIdentifier: - storageKey = kMASAccessSharedStorageKey; - break; - case MASAccessValueTypeMSSOEnabled: - storageKey = kMASAccessSharedStorageKey; - break; - //PrivateKey - case MASAccessValueTypePrivateKey: - storageKey = kMASAccessSharedStorageKey; - break; - case MASAccessValueTypePrivateKeyBits: - storageKey = kMASAccessSharedStorageKey; - break; - //PublicKey - case MASAccessValueTypePublicKey: - storageKey = kMASAccessSharedStorageKey; - break; - //TrustedServerCertificate - case MASAccessValueTypeTrustedServerCertificate: - storageKey = kMASAccessSharedStorageKey; - break; - //PublicCertificate - case MASAccessValueTypeSignedPublicCertificate: - storageKey = kMASAccessSharedStorageKey; - break; - //PublicCertificate as NSData - case MASAccessValueTypeSignedPublicCertificateData: - storageKey = kMASAccessSharedStorageKey; - break; - //PublicCertificate Expiration Date - case MASAccessValueTypeSignedPublicCertificateExpirationDate: - storageKey = kMASAccessSharedStorageKey; - break; - //authentication timestamp - case MASAccessValueTypeAuthenticatedTimestamp: - storageKey = kMASAccessLocalStorageKey; - break; - case MASAccessValueTypeCurrentAuthCredentialsGrantType: - storageKey = kMASAccessSharedStorageKey; - break; - case MASAccessValueTypeIsDeviceLocked: - storageKey = kMASAccessSharedStorageKey; - break; - case MASAccessValueTypeMASUserObjectData: - storageKey = kMASAccessSharedStorageKey; - break; - default: - // - // MASAccessValueTypeUknonw - // - break; - } - - return storageKey; + return [_secureStorageKeys containsObject:key]; } -- (NSString *)convertAccessTypeToString:(MASAccessValueType)type +- (NSString *)getStorageTypeWithKey:(NSString *)key { - - NSString *accessTypeToString = @""; - - switch (type) { - //Configuration - case MASAccessValueTypeConfiguration: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainConfiguration"]; - break; - //AccessToken - case MASAccessValueTypeAccessToken: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainAccessToken"]; - break; - //Authenticated username - case MASAccessValueTypeAuthenticatedUserObjectId: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"MASAccessValueTypeAuthenticatedUserObjectId"]; - break; - //RefreshToken - case MASAccessValueTypeRefreshToken: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainRefreshToken"]; - break; - //Scope - case MASAccessValueTypeScope: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainScope"]; - break; - //TokenType - case MASAccessValueTypeTokenType: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainTokenType"]; - break; - //ExpiresIn - case MASAccessValueTypeExpiresIn: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainExpiresIn"]; - break; - //TokenExpiration - case MASAccessValueTypeTokenExpiration: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainTokenExpiration"]; - break; - //IdToken with secured local authentication - case MASAccessValueTypeSecuredIdToken: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainSecuredIdToken"]; - break; - //IdToken - case MASAccessValueTypeIdToken: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainIdToken"]; - break; - //IdTokenType - case MASAccessValueTypeIdTokenType: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainIdTokenType"]; - break; - //ClientExpiration - case MASAccessValueTypeClientExpiration: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainClientExpiration"]; - break; - //ClientId - case MASAccessValueTypeClientId: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainClientId"]; - break; - //ClientSecret - case MASAccessValueTypeClientSecret: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainClientSecret"]; - break; - //JWT - case MASAccessValueTypeJWT: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainJwt"]; - break; - //MAGIdentifier - case MASAccessValueTypeMAGIdentifier: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainMagIdentifier"]; - break; - case MASAccessValueTypeMSSOEnabled: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASAccessValueTypeMSSOEnabled"]; - break; - //PrivateKey - case MASAccessValueTypePrivateKey: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainPrivateKey"]; - break; - //PrivateKeyBits - case MASAccessValueTypePrivateKeyBits: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainPrivateKeyBits"]; - break; - //PublicKey - case MASAccessValueTypePublicKey: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainPublicKey"]; - break; - //TrustedServerCertificate - case MASAccessValueTypeTrustedServerCertificate: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainTrustedServerCertificate"]; - break; - //PublicCertificate - case MASAccessValueTypeSignedPublicCertificate: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainSignedPublicCertificate"]; - break; - //PublicCertificate as NSData - case MASAccessValueTypeSignedPublicCertificateData: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASKeyChainSignedPublicCertificateData"]; - break; - //PublicCertificate Expiration Date - case MASAccessValueTypeSignedPublicCertificateExpirationDate: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASAccessValueTypeSignedPublicCertificateExpirationDate"]; - break; - case MASAccessValueTypeAuthenticatedTimestamp: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASAccessValueTypeAuthenticatedTimestamp"]; - break; - case MASAccessValueTypeIsDeviceLocked: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASAccessValueTypeIsDeviceLocked"]; - break; - case MASAccessValueTypeCurrentAuthCredentialsGrantType: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayIdentifier, @"kMASAccessValueTypeCurrentAuthCredentialsGrantType"]; - break; - case MASAccessValueTypeMASUserObjectData: - accessTypeToString = [NSString stringWithFormat:@"%@.%@", _gatewayHostName, @"kMASAccessValueTypeMASUserObjectData"]; - default: - // - // MASAccessValueTypeUknonw - // - break; + if ([_sharedStorageKeys containsObject:key]) + { + return kMASAccessSharedStorageKey; } - - if (![self isAccessGroupAccessible]) + else if ([_localStorageKeys containsObject:key]) { - accessTypeToString = [NSString stringWithFormat:@"_%@", accessTypeToString]; + return kMASAccessLocalStorageKey; + } + // + // If the key is not defined in either of shared nor local storage, the key must be custom data which will always be stored in shared + // + else { + return kMASAccessCustomSharedStorageKey; } - - return accessTypeToString; } @@ -912,7 +854,7 @@ - (NSString *)accessGroup // // if accessGroup is not defined // - if(!_accessGroup) + if (!_accessGroup) { NSString *groupSuffix = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MSSOSDKKeychainGroup"]; @@ -1015,7 +957,7 @@ - (BOOL)lockSession:(NSError * __nullable __autoreleasing * __nullable)error // if (!localError) { - [self setAccessValueString:idToken withAccessValueType:MASAccessValueTypeSecuredIdToken error:&localError]; + [self setAccessValueString:idToken storageKey:MASKeychainStorageKeySecuredIdToken error:&localError]; } } @@ -1029,7 +971,7 @@ - (BOOL)lockSession:(NSError * __nullable __autoreleasing * __nullable)error // if (![MASUser currentUser].isSessionLocked) { - [self setAccessValueString:nil withAccessValueType:MASAccessValueTypeSecuredIdToken]; + [self setAccessValueString:nil storageKey:MASKeychainStorageKeySecuredIdToken]; } if (error != NULL) @@ -1042,10 +984,10 @@ - (BOOL)lockSession:(NSError * __nullable __autoreleasing * __nullable)error // else { - [self setAccessValueString:nil withAccessValueType:MASAccessValueTypeAccessToken]; - [self setAccessValueString:nil withAccessValueType:MASAccessValueTypeRefreshToken]; - [self setAccessValueString:nil withAccessValueType:MASAccessValueTypeIdToken]; - [self setAccessValueNumber:[NSNumber numberWithBool:YES] withAccessValueType:MASAccessValueTypeIsDeviceLocked]; + [self setAccessValueString:nil storageKey:MASKeychainStorageKeyAccessToken]; + [self setAccessValueString:nil storageKey:MASKeychainStorageKeyRefreshToken]; + [self setAccessValueString:nil storageKey:MASKeychainStorageKeyIdToken]; + [self setAccessValueNumber:[NSNumber numberWithBool:YES] storageKey:MASKeychainStorageKeyIsDeviceLocked]; // // Refresh the currentAccessObj to reflect the current status @@ -1101,7 +1043,7 @@ - (BOOL)unlockSessionWithUserOperationPromptMessage:(NSString *)userOperationPro // if (!localError) { - idToken = [self getAccessValueStringWithType:MASAccessValueTypeSecuredIdToken userOperationPrompt:userOperationPrompt error:&localError]; + idToken = [self getAccessValueStringWithStorageKey:MASKeychainStorageKeySecuredIdToken userOperationPrompt:userOperationPrompt error:&localError]; } if (idToken) @@ -1110,7 +1052,7 @@ - (BOOL)unlockSessionWithUserOperationPromptMessage:(NSString *)userOperationPro // Validate id_token whether it is valid or not // BOOL isIdTokenValid = [MASAccessService validateIdToken:idToken - magIdentifier:[[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier] + magIdentifier:[[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier] error:&localError]; if (localError && localError.code != MASFoundationErrorCodeTokenIdTokenExpired) @@ -1132,9 +1074,9 @@ - (BOOL)unlockSessionWithUserOperationPromptMessage:(NSString *)userOperationPro // if (!localError) { - [self setAccessValueString:idToken withAccessValueType:MASAccessValueTypeIdToken]; - [self setAccessValueString:nil withAccessValueType:MASAccessValueTypeSecuredIdToken]; - [self setAccessValueNumber:[NSNumber numberWithBool:NO] withAccessValueType:MASAccessValueTypeIsDeviceLocked]; + [self setAccessValueString:idToken storageKey:MASKeychainStorageKeyIdToken]; + [self setAccessValueString:nil storageKey:MASKeychainStorageKeySecuredIdToken]; + [self setAccessValueNumber:[NSNumber numberWithBool:NO] storageKey:MASKeychainStorageKeyIsDeviceLocked]; // // Refresh the currentAccessObj to reflect the current status @@ -1156,8 +1098,8 @@ - (BOOL)unlockSessionWithUserOperationPromptMessage:(NSString *)userOperationPro - (void)removeSessionLock { - [self setAccessValueString:nil withAccessValueType:MASAccessValueTypeSecuredIdToken]; - [self setAccessValueNumber:[NSNumber numberWithBool:NO] withAccessValueType:MASAccessValueTypeIsDeviceLocked]; + [self setAccessValueString:nil storageKey:MASKeychainStorageKeySecuredIdToken]; + [self setAccessValueNumber:[NSNumber numberWithBool:NO] storageKey:MASKeychainStorageKeyIsDeviceLocked]; // // Refresh the currentAccessObj to reflect the current status @@ -1194,7 +1136,8 @@ + (BOOL)validateIdToken:(NSString *)idToken magIdentifier:(NSString *)magIdentif // NSDictionary *headerDisctionary = [MASAccessService unwrap:headerString]; - if ([[headerDisctionary objectForKey:@"alg"] isEqualToString:@"HS256"]){ + if ([[headerDisctionary objectForKey:@"alg"] isEqualToString:@"HS256"]) + { // // check signature @@ -1204,7 +1147,7 @@ + (BOOL)validateIdToken:(NSString *)idToken magIdentifier:(NSString *)magIdentif [signatureSegments addObject:payload]; NSString *signingInput = [signatureSegments componentsJoinedByString:@"."]; - NSString *clientSecret = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeClientSecret]; + NSString *clientSecret = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientSecret]; NSData *signedInput = [NSData sign:signingInput key:clientSecret]; NSString *encodedSignedInput = [signedInput base64Encoding]; @@ -1230,7 +1173,8 @@ + (BOOL)validateIdToken:(NSString *)idToken magIdentifier:(NSString *)magIdentif NSString *azp = [payloadDictionary valueForKey:@"azp"]; NSDate *exp = [NSDate dateWithTimeIntervalSince1970:[[payloadDictionary valueForKey:@"exp"] floatValue]]; - if (!aud || !azp || !exp){ + if (!aud || !azp || !exp) + { if (error) { @@ -1242,7 +1186,8 @@ + (BOOL)validateIdToken:(NSString *)idToken magIdentifier:(NSString *)magIdentif // // case 2: aud doesn't match with clientId // - if (![aud isEqualToString:[[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeClientId]]){ + if (![aud isEqualToString:[[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]]) + { if (error) { @@ -1254,7 +1199,8 @@ + (BOOL)validateIdToken:(NSString *)idToken magIdentifier:(NSString *)magIdentif // // case 3: azp doesn't match with mag-identifier // - if (![azp isEqualToString:magIdentifier]){ + if (![azp isEqualToString:magIdentifier]) + { if (error) { @@ -1266,7 +1212,8 @@ + (BOOL)validateIdToken:(NSString *)idToken magIdentifier:(NSString *)magIdentif // // case 4: JWT expired // - if ([exp timeIntervalSinceNow] < 0){ + if ([exp timeIntervalSinceNow] < 0) + { if (error) { @@ -1339,9 +1286,11 @@ - (NSDate *)extractExpirationDateFromCertificate:(SecCertificateRef)certificate if (certificateX509 != NULL) { ASN1_TIME *certificateExpiryASN1 = X509_get_notAfter(certificateX509); - if (certificateExpiryASN1 != NULL) { + if (certificateExpiryASN1 != NULL) + { ASN1_GENERALIZEDTIME *certificateExpiryASN1Generalized = ASN1_TIME_to_generalizedtime(certificateExpiryASN1, NULL); - if (certificateExpiryASN1Generalized != NULL) { + if (certificateExpiryASN1Generalized != NULL) + { unsigned char *certificateExpiryData = ASN1_STRING_data(certificateExpiryASN1Generalized); // ASN1 generalized times look like this: "20131114230046Z" @@ -1374,6 +1323,19 @@ - (NSDate *)extractExpirationDateFromCertificate:(SecCertificateRef)certificate } +- (BOOL)isInternalDataForStorageKey:(NSString *)storageKey +{ + BOOL isInternalData = NO; + + if ([_localStorageKeys containsObject:storageKey] || [_sharedStorageKeys containsObject:storageKey]) + { + isInternalData = YES; + } + + return isInternalData; +} + + # pragma mark - Debug only - (void)clearLocal @@ -1386,13 +1348,13 @@ - (void)clearLocal - (void)clearShared; { - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeMAGIdentifier]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyMAGIdentifier]; [_storages[kMASAccessSharedStorageKey] removeAllItems]; // // Retrieve the key for certificate // - NSString *certificateKey = [self convertAccessTypeToString:MASAccessValueTypeSignedPublicCertificate]; + NSString *certificateKey = [self convertKeyString:MASKeychainStorageKeySignedPublicCertificate]; [[MASIKeyChainStore keyChainStore] clearCertificatesAndIdentitiesWithCertificateLabelKey:certificateKey]; // @@ -1412,7 +1374,7 @@ - (NSString *)debugSecuredDescription NSString *value = [NSString stringWithFormat:@"\n\n(MASAccessService)\n\n Local (%@):\n", kMASAccessLocalStorageServiceName]; NSMutableString *keychainDescription = [[NSMutableString alloc] initWithString:value]; - for(NSString *key in [_storages[kMASAccessLocalStorageKey] allKeys]) + for (NSString *key in [_storages[kMASAccessLocalStorageKey] allKeys]) { [keychainDescription appendString:[NSString stringWithFormat:@"\n key: %@", key]]; } @@ -1423,7 +1385,18 @@ - (NSString *)debugSecuredDescription value = [NSString stringWithFormat:@"\n\n Shared (%@):\n", kMASAccessSharedStorageServiceName]; [keychainDescription appendString:value]; - for(NSString *key in [_storages[kMASAccessSharedStorageKey] allKeys]) + for (NSString *key in [_storages[kMASAccessSharedStorageKey] allKeys]) + { + [keychainDescription appendString:[NSString stringWithFormat:@"\n key: %@", key]]; + } + + // + // Custom + // + value = [NSString stringWithFormat:@"\n\n Custom (%@):\n", kMASAccessCustomSharedStorageKey]; + [keychainDescription appendString:value]; + + for (NSString *key in [_storages[kMASAccessCustomSharedStorageKey] allKeys]) { [keychainDescription appendString:[NSString stringWithFormat:@"\n key: %@", key]]; } diff --git a/MASFoundation/Classes/_private_/services/file/MASFileService.m b/MASFoundation/Classes/_private_/services/file/MASFileService.m index e10ef761..8e0abe97 100644 --- a/MASFoundation/Classes/_private_/services/file/MASFileService.m +++ b/MASFoundation/Classes/_private_/services/file/MASFileService.m @@ -57,7 +57,7 @@ - (NSString *)debugDescription // // ServerCertificate // - MASFile *file = [[MASSecurityService sharedService] getClientCertificate]; //[self findFileWithName:MASCertificate]; + MASFile *file = [[MASSecurityService sharedService] getServerCertificate]; //[self findFileWithName:MASCertificate]; if(file) { filesFound = YES; @@ -68,7 +68,7 @@ - (NSString *)debugDescription // // SignedCertificate // - file = [[MASSecurityService sharedService] getSignedCertificate]; //[self findFileWithName:MASSignedCertificate]; + file = [[MASSecurityService sharedService] getDeviceClientCertificate]; //[self findFileWithName:MASSignedCertificate]; if(file) { filesFound = YES; diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.h b/MASFoundation/Classes/_private_/services/model/MASModelService.h index 50b63377..d2c356cd 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.h +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.h @@ -82,6 +82,25 @@ - (void)setUserObject:(MASUser *)user; + +/** + * Sets the browser based authentication property. Default is NO. + * + * @param browserBasedLogin The state of browser based authentication. + * If this is set to true, a URL which has a templatized login is launched in a browser and this would disable the Social Login, Proximity Login and also prevents the launch of MASUI. + */ ++ (void)setBrowserBasedAuthentication:(BOOL)browserBasedAuthentication; + + + +/** + * The current state of browser based login. + * + * @return BOOL value is returned. + */ ++ (BOOL)browserBasedAuthentication; + + ///-------------------------------------- /// @name Application ///-------------------------------------- diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.m b/MASFoundation/Classes/_private_/services/model/MASModelService.m index 92284303..205ce5e3 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.m +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.m @@ -30,6 +30,7 @@ @interface MASModelService () @property (nonatomic, strong, readwrite) MASAuthenticationProviders *currentProviders; + @end @@ -38,8 +39,7 @@ @implementation MASModelService static MASGrantFlow _grantFlow_ = MASGrantFlowClientCredentials; static MASUserLoginWithUserCredentialsBlock _userLoginBlock_ = nil; static MASUserAuthCredentialsBlock _userAuthCredentialsBlock_ = nil; - - +static BOOL _isBrowserBasedAuthentication_ = NO; # pragma mark - Properties @@ -71,6 +71,19 @@ - (void)setUserObject:(MASUser *)user _currentUser = user; } + ++ (void)setBrowserBasedAuthentication : (BOOL)browserBasedAuthentication +{ + _isBrowserBasedAuthentication_ = browserBasedAuthentication; +} + + ++ (BOOL)browserBasedAuthentication +{ + return _isBrowserBasedAuthentication_; +} + + # pragma mark - Shared Service + (instancetype)sharedService @@ -155,9 +168,9 @@ - (void)serviceWillStart // if (![keychainApplication.identifier isEqualToString:_currentApplication.identifier]) { - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeClientId]; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeClientSecret]; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeClientExpiration]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyClientId]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyClientSecret]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyClientExpiration]; [[MASModelService sharedService] clearCurrentUserForLogout]; } @@ -367,7 +380,7 @@ - (void)retrieveAuthenticationProviders:(MASObjectResponseErrorBlock)completion // // If the user was already authenticated, we don't have to retrieve the authentication provider // - if (([MASApplication currentApplication].isAuthenticated && [MASApplication currentApplication].authenticationStatus == MASAuthenticationStatusLoginWithUser) || [MASAccess currentAccess].isSessionLocked) + if (([MASApplication currentApplication].isAuthenticated && [MASApplication currentApplication].authenticationStatus == MASAuthenticationStatusLoginWithUser) || [MASAccess currentAccess].isSessionLocked || _isBrowserBasedAuthentication_) { // @@ -396,7 +409,7 @@ - (void)retrieveAuthenticationProviders:(MASObjectResponseErrorBlock)completion MASIMutableOrderedDictionary *parameterInfo = [MASIMutableOrderedDictionary new]; // ClientId - parameterInfo[MASClientKeyRequestResponseKey] = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeClientId]; + parameterInfo[MASClientKeyRequestResponseKey] = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; // RedirectUri parameterInfo[MASRedirectUriRequestResponseKey] = [[MASApplication currentApplication].redirectUri absoluteString]; @@ -684,6 +697,11 @@ - (void)deregisterCurrentDeviceWithCompletion:(MASCompletionErrorBlock)completio // MASIMutableOrderedDictionary *mutableHeaderInfo = [MASIMutableOrderedDictionary new]; + // + // Post the Mobile SDK will attempt to deregister device + // + [[NSNotificationCenter defaultCenter] postNotificationName:MASDeviceWillDeregisterNotification object:self]; + __block MASModelService *blockSelf = self; // @@ -694,6 +712,23 @@ - (void)deregisterCurrentDeviceWithCompletion:(MASCompletionErrorBlock)completio andHeaders:mutableHeaderInfo completion:^(NSDictionary *responseInfo, NSError *error) { + // + // Detect if error, if so stop here + // + if(error) + { + // + // Post the did fail to deregister in cloud notification + // + [[NSNotificationCenter defaultCenter] postNotificationName:MASDeviceDidFailToDeregisterNotification object:self]; + + // + // Notify + // + if(completion) completion(NO, [NSError errorFromApiResponseInfo:responseInfo andError:error]); + + return; + } // // Clear currentUser object upon log-out @@ -727,24 +762,6 @@ - (void)deregisterCurrentDeviceWithCompletion:(MASCompletionErrorBlock)completio // [[NSNotificationCenter defaultCenter] postNotificationName:MASDeviceDidDeregisterOnDeviceNotification object:self]; - // - // Detect if error, if so stop here - // - if(error) - { - // - // Post the did fail to deregister in cloud notification - // - [[NSNotificationCenter defaultCenter] postNotificationName:MASDeviceDidFailToDeregisterNotification object:self]; - - // - // Notify - // - if(completion) completion(NO, [NSError errorFromApiResponseInfo:responseInfo andError:error]); - - return; - } - // // Post the did deregister in cloud notification // @@ -902,9 +919,15 @@ - (void)registerDeviceWithCompletion:(MASCompletionErrorBlock)completion @"\n\n********************************************************\n\n\n"); // - // If the UI handling framework is present and will handle this stop here + // If the UI handling framework or browser based login is present and will handle this stop here // MASServiceRegistry *serviceRegistry = [MASServiceRegistry sharedRegistry]; + + if([serviceRegistry browserBasedLoginWillHandleAuthentication:authCredentialsBlock]) + { + return; + } + if([serviceRegistry uiServiceWillHandleWithAuthCredentialsBlock:authCredentialsBlock]) { return; @@ -1304,15 +1327,15 @@ - (void)renewClientCertificateWithCompletion:(MASCompletionErrorBlock)completion // // Remove signed client certificate from the keychain storage // - [[MASAccessService sharedService] setAccessValueData:nil withAccessValueType:MASAccessValueTypeSignedPublicCertificateData]; - [[MASAccessService sharedService] setAccessValueCertificate:nil withAccessValueType:MASAccessValueTypeSignedPublicCertificate]; - [[MASAccessService sharedService] setAccessValueNumber:[NSNumber numberWithInt:0] withAccessValueType:MASAccessValueTypeSignedPublicCertificateExpirationDate]; + [[MASAccessService sharedService] setAccessValueData:nil storageKey:MASKeychainStorageKeyPublicCertificateData]; + [[MASAccessService sharedService] setAccessValueCertificate:nil storageKey:MASKeychainStorageKeySignedPublicCertificate]; + [[MASAccessService sharedService] setAccessValueNumber:[NSNumber numberWithInt:0] storageKey:MASKeychainStorageKeyPublicCertificateExpirationDate]; // - // Remove signedCertificate MASFile for re-generation + // Remove device's client MASFile for re-generation // - MASFile *signedCertificate = [[MASSecurityService sharedService] getSignedCertificate]; - [MASFile removeItemAtFilePath:[signedCertificate filePath]]; + MASFile *deviceClientCert = [[MASSecurityService sharedService] getDeviceClientCertificate]; + [MASFile removeItemAtFilePath:[deviceClientCert filePath]]; // // Updated with latest info @@ -1402,7 +1425,7 @@ - (void)logOutDeviceAndClearLocalAccessToken:(BOOL)clearLocal completion:(MASCom // // Detect if device is already logged out (which is basically checking if id_token exists), if so stop here // - if(![accessService getAccessValueStringWithType:MASAccessValueTypeIdToken]) + if(![accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdToken]) { // // Notify @@ -1440,14 +1463,14 @@ - (void)logOutDeviceAndClearLocalAccessToken:(BOOL)clearLocal completion:(MASCom parameterInfo[MASDeviceLogoutAppRequestResponseKey] = [MASConfiguration currentConfiguration].ssoEnabled ? @"true" : @"false"; // IdToken - NSString *idToken = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeIdToken]; + NSString *idToken = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdToken]; if (idToken) { parameterInfo[MASIdTokenBodyRequestResponseKey] = idToken; } // IdTokenType - NSString *idTokenType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeIdTokenType]; + NSString *idTokenType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdTokenType]; if (idTokenType) { parameterInfo[MASIdTokenTypeBodyRequestResponseKey]= idTokenType; @@ -1480,7 +1503,7 @@ - (void)logOutDeviceAndClearLocalAccessToken:(BOOL)clearLocal completion:(MASCom // // Post the notification // - [[NSNotificationCenter defaultCenter] postNotificationName:MASDeviceDidFailToRegisterNotification object:blockSelf]; + [[NSNotificationCenter defaultCenter] postNotificationName:MASUserDidFailToLogoutNotification object:blockSelf]; return; } @@ -1496,11 +1519,16 @@ - (void)logOutDeviceAndClearLocalAccessToken:(BOOL)clearLocal completion:(MASCom [blockSelf clearCurrentUserForLogout]; } + // + // Post the notification + // + [[NSNotificationCenter defaultCenter] postNotificationName:MASUserDidLogoutNotification object:blockSelf]; + // // Set id_token and id_token_type to nil // - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeIdToken]; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeIdTokenType]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyIdToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyIdTokenType]; [[MASAccessService sharedService].currentAccessObj refresh]; // @@ -1703,6 +1731,11 @@ - (void)loginUsingUserCredentials:(MASCompletionErrorBlock)completion // If the UI handling framework is present and will handle this stop here // MASServiceRegistry *serviceRegistry = [MASServiceRegistry sharedRegistry]; + if([serviceRegistry browserBasedLoginWillHandleAuthentication:authCredentialsBlock]) + { + return; + } + if([serviceRegistry uiServiceWillHandleWithAuthCredentialsBlock:authCredentialsBlock]) { return; @@ -1937,7 +1970,7 @@ - (void)loginAsRefreshTokenWithCompletion:(MASCompletionErrorBlock)completion if(clientAuthorization) headerInfo[MASAuthorizationRequestResponseKey] = clientAuthorization; // MAG Identifier - NSString *magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier]; + NSString *magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]; if(magIdentifier) headerInfo[MASMagIdentifierRequestResponseKey] = magIdentifier; // @@ -2006,7 +2039,7 @@ - (void)loginAsRefreshTokenWithCompletion:(MASCompletionErrorBlock)completion // // If authenticate user with refresh_token, we should invalidate local refresh_token, and re-validate the user's session with alternative method. // - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeRefreshToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyRefreshToken]; [[MASAccessService sharedService].currentAccessObj refresh]; [blockSelf validateCurrentUserSession:completion]; @@ -2030,7 +2063,7 @@ - (void)loginAsRefreshTokenWithCompletion:(MASCompletionErrorBlock)completion { NSError *idTokenValidationError = nil; BOOL isIdTokenValid = [MASAccessService validateIdToken:[bodayInfo objectForKey:MASIdTokenBodyRequestResponseKey] - magIdentifier:[[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier] + magIdentifier:[[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier] error:&idTokenValidationError]; if (!isIdTokenValid && idTokenValidationError) diff --git a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h index 6653a47c..69fc55c1 100644 --- a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h +++ b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h @@ -9,10 +9,11 @@ // #import "MASService.h" - #import "MASConstantsPrivate.h" + #import "MASAuthValidationOperation.h" +typedef NSURLRequest* (^MASSessionDataTaskHTTPRedirectBlock)(NSURLSession *_Nonnull session, NSURLSessionTask *_Nonnull task, NSURLResponse * _Nonnull response, NSURLRequest *_Nonnull request); @interface MASNetworkingService : MASService @@ -26,6 +27,12 @@ @property (nonatomic, assign, readonly) MASGatewayMonitoringStatus monitoringStatus; +/** + Http redirection block. Set this block only if you want to handle the redirection coming from the original NSURLRequest. + */ +@property (nonatomic) MASSessionDataTaskHTTPRedirectBlock httpRedirectionBlock; + + /** Constructs, if not exist, the shared operation that validates current session's registration and authentication status diff --git a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.m b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.m index 209a8a61..d016e392 100644 --- a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.m +++ b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.m @@ -11,7 +11,6 @@ #import "MASNetworkingService.h" #import "MASAccessService.h" -#import "MASConstantsPrivate.h" #import "MASConfigurationService.h" #import "MASLocationService.h" #import "MASModelService.h" @@ -603,9 +602,9 @@ - (MASSessionDataTaskCompletionBlock)sessionDataTaskCompletionBlockWithEndPoint: // // Remove slave client_id and client_secret from keychain // - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeClientId]; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeClientSecret]; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeClientExpiration]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyClientId]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyClientSecret]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyClientExpiration]; // // Remove access_token from keychain @@ -657,6 +656,7 @@ - (MASSessionDataTaskCompletionBlock)sessionDataTaskCompletionBlockWithEndPoint: } + - (BOOL)isMAGEndpoint:(NSString *)endpoint { BOOL isMAGEndpoint = NO; @@ -1273,6 +1273,11 @@ - (void)httpRequest:(NSString *)httpMethod endPoint:(NSString *)endPoint paramet // // Construct MASSessionDataTaskOperation with request, and completion block to handle any responsive re-authentication or re-registration. // + if(self.httpRedirectionBlock) + { + [_sessionManager setSessionDidReceiveHTTPRedirectBlock:self.httpRedirectionBlock]; + } + MASSessionDataTaskOperation *operation = [_sessionManager dataOperationWithRequest:request completionHandler:[self sessionDataTaskCompletionBlockWithEndPoint:endPoint parameters:parameterInfo @@ -1283,6 +1288,7 @@ - (void)httpRequest:(NSString *)httpMethod endPoint:(NSString *)endPoint paramet isPublic:isPublic completionBlock:blockCompletion]]; + if (![self isMAGEndpoint:endPoint]) { // diff --git a/MASFoundation/Classes/_private_/services/network/internal/MASSessionDataTaskOperation.m b/MASFoundation/Classes/_private_/services/network/internal/MASSessionDataTaskOperation.m index 371b3e13..0329c917 100644 --- a/MASFoundation/Classes/_private_/services/network/internal/MASSessionDataTaskOperation.m +++ b/MASFoundation/Classes/_private_/services/network/internal/MASSessionDataTaskOperation.m @@ -75,9 +75,9 @@ - (void)start { NSMutableDictionary *mutableHeader = [self.request.headerInfo mutableCopy]; - if (![[self.request.headerInfo allKeys] containsObject:MASMagIdentifierRequestResponseKey] && [MASDevice currentDevice].isRegistered && [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier]) + if (![[self.request.headerInfo allKeys] containsObject:MASMagIdentifierRequestResponseKey] && [MASDevice currentDevice].isRegistered && [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]) { - [mutableHeader setObject:[[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier] forKey:MASMagIdentifierRequestResponseKey]; + [mutableHeader setObject:[[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier] forKey:MASMagIdentifierRequestResponseKey]; } if (![[self.request.headerInfo allKeys] containsObject:MASAuthorizationRequestResponseKey] && [MASAccessService sharedService].currentAccessObj.accessToken) diff --git a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h index ad42a64c..139d8155 100644 --- a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h +++ b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h @@ -150,4 +150,12 @@ typedef void (^MASNetworkSessionDidFinishEventsForBackgroundURLSessionBlock)(NSU - (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential **credential))block; + +/** + Set code block of session level redirection for the current NSURLRequest object. + + @param block http redirection code block. + */ +- (void)setSessionDidReceiveHTTPRedirectBlock:(NSURLRequest* (^)(NSURLSession *session,NSURLSessionTask *task, NSURLResponse* response,NSURLRequest *request))block; + @end diff --git a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.m b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.m index 52f37c81..f35e4139 100644 --- a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.m +++ b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.m @@ -17,6 +17,7 @@ @interface MASURLSessionManager () 0) + NSMutableData *certificateData = [NSMutableData data]; + + for (NSData *cert in certs) + { + [certificateData appendData:cert]; + [certificateData appendData:[@"\n" dataUsingEncoding:NSUTF8StringEncoding]]; + } + + if (certificateData) { - NSData *certificateData = certs[0]; - - //DLog(@"\n\nServer Certificate class is: %@\n\n and value: %@\n\n", [[certificateData class] debugDescription], certificateData); - - if(certificateData) - { - clientCert = [MASFile fileWithName:[NSString stringWithFormat:@"%@.%@", gatewayIdentifier, MASCertificate] contents:certificateData]; - [clientCert save]; - } + clientCert = [MASFile fileWithName:[NSString stringWithFormat:@"%@.%@", gatewayIdentifier, MASCertificate] contents:certificateData]; + [clientCert save]; } } @@ -477,7 +478,7 @@ - (MASFile *)getPrivateKey // // Retrieve privateKeyBits from keychain. // - NSString *privateKeyBits = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypePrivateKeyBits]; + NSString *privateKeyBits = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyPrivateKeyBits]; if (privateKeyBits) { @@ -496,22 +497,22 @@ - (MASFile *)getPrivateKey - (void)removeAllFiles { MASFile *privateKey = [self getPrivateKey]; - MASFile *clientCert = [self getClientCertificate]; - MASFile *signedCert = [self getSignedCertificate]; + MASFile *serverCert = [self getServerCertificate]; + MASFile *deviceClientCert = [self getDeviceClientCertificate]; if ([privateKey filePath]) { [MASFile removeItemAtFilePath:[privateKey filePath]]; } - if ([clientCert filePath]) + if ([serverCert filePath]) { - [MASFile removeItemAtFilePath:[clientCert filePath]]; + [MASFile removeItemAtFilePath:[serverCert filePath]]; } - if ([signedCert filePath]) + if ([deviceClientCert filePath]) { - [MASFile removeItemAtFilePath:[signedCert filePath]]; + [MASFile removeItemAtFilePath:[deviceClientCert filePath]]; } } diff --git a/MASFoundation/Classes/models/AuthCredentials/MASAuthCredentialsAuthorizationCode.m b/MASFoundation/Classes/models/AuthCredentials/MASAuthCredentialsAuthorizationCode.m index bc75b7f9..277d3cf1 100644 --- a/MASFoundation/Classes/models/AuthCredentials/MASAuthCredentialsAuthorizationCode.m +++ b/MASFoundation/Classes/models/AuthCredentials/MASAuthCredentialsAuthorizationCode.m @@ -142,13 +142,13 @@ - (NSDictionary *)getParameters MASAccessService *accessService = [MASAccessService sharedService]; // ClientId - NSString *clientId = [accessService getAccessValueStringWithType:MASAccessValueTypeClientId]; + NSString *clientId = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; if (clientId) { parameterInfo[MASClientIdentifierRequestResponseKey] = clientId; } - NSString *clientSecret = [accessService getAccessValueStringWithType:MASAccessValueTypeClientSecret]; + NSString *clientSecret = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientSecret]; if (clientSecret) { parameterInfo[MASClientSecretRequestResponseKey] = clientSecret; diff --git a/MASFoundation/Classes/models/AuthCredentials/MASAuthCredentialsJWT.m b/MASFoundation/Classes/models/AuthCredentials/MASAuthCredentialsJWT.m index 54d45503..93777227 100644 --- a/MASFoundation/Classes/models/AuthCredentials/MASAuthCredentialsJWT.m +++ b/MASFoundation/Classes/models/AuthCredentials/MASAuthCredentialsJWT.m @@ -49,7 +49,7 @@ - (instancetype)initPrivateWithJWT:(NSString *)jwt tokenType:(NSString *)tokenTy } _canRegisterDevice = YES; - _isReuseable = YES; + _isReuseable = NO; } return self; @@ -79,8 +79,8 @@ - (void)loginWithCredential:(MASCompletionErrorBlock)completion // If there is an error from the server complaining about invalid token, // invalidate local id_token and id_token_type and revalidate the user's session. // - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeIdToken]; - [[MASAccessService sharedService] setAccessValueString:nil withAccessValueType:MASAccessValueTypeIdTokenType]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyIdToken]; + [[MASAccessService sharedService] setAccessValueString:nil storageKey:MASKeychainStorageKeyIdTokenType]; [[MASAccessService sharedService].currentAccessObj refresh]; } diff --git a/MASFoundation/Classes/models/MASApplication.m b/MASFoundation/Classes/models/MASApplication.m index 15d7d480..43923b77 100644 --- a/MASFoundation/Classes/models/MASApplication.m +++ b/MASFoundation/Classes/models/MASApplication.m @@ -108,9 +108,9 @@ - (BOOL)isRegistered // MASAccessService *accessService = [MASAccessService sharedService]; - NSNumber *clientExpiration = [accessService getAccessValueNumberWithType:MASAccessValueTypeClientExpiration]; - NSString *clientId = [accessService getAccessValueStringWithType:MASAccessValueTypeClientId]; - NSString *clientSecret = [accessService getAccessValueStringWithType:MASAccessValueTypeClientSecret]; + NSNumber *clientExpiration = [accessService getAccessValueNumberWithStorageKey:MASKeychainStorageKeyClientExpiration]; + NSString *clientId = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; + NSString *clientSecret = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientSecret]; _isRegistered = (clientExpiration && clientId && clientSecret && !self.isExpired); return _isRegistered; diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h new file mode 100644 index 00000000..235634cf --- /dev/null +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h @@ -0,0 +1,38 @@ +// +// MASBrowserBasedAuthentication.h +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import +#import "MASConstants.h" + +/** + MASBrowserBasedAuthentication class is a helper class to utilize SFSafariViewController to launch a customized login template. + * This class will get the redirection to receive the authorization code to perform login. + */ +@interface MASBrowserBasedAuthentication : NSObject + +# pragma mark - Browser Based Authentication + +/** + * Retrieve the shared MASBrowserBasedAuthentication singleton. + * + * @return Returns the shared MASBrowserBasedAuthentication singleton. + */ ++ (instancetype)sharedInstance; + + + +/** + * Method to load the browser with a URL that loads a templatized login page. + * + * @param webLoginBlock completion MASCompletionErrorBlock that receives the results. + */ +- (void)loadWebLoginTemplate:(MASAuthCredentialsBlock)webLoginBlock; + +@end diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m new file mode 100644 index 00000000..8a9b792b --- /dev/null +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m @@ -0,0 +1,302 @@ +// +// MASBrowserBasedAuthentication.m +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import "MASAccessService.h" +#import "MASAuthorizationResponse.h" +#import "MASBrowserBasedAuthentication.h" +#import "MASConfigurationService.h" +#import "MASGetURLRequest.h" +#import "MASModelService.h" +#import "UIAlertController+MAS.h" +#import + +@interface MASBrowserBasedAuthentication () +{ + +} + +@property (nonatomic) SFSafariViewController *safariViewController; +@property (nonatomic) MASAuthCredentialsBlock webLoginCallBack; + +@end + +@implementation MASBrowserBasedAuthentication + +# pragma mark - Shared Service + ++ (instancetype)sharedInstance +{ + static id sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^ + { + sharedInstance = [[MASBrowserBasedAuthentication alloc] init]; + }); + + return sharedInstance; +} + + +- (void)loadWebLoginTemplate:(MASAuthCredentialsBlock)webLoginBlock +{ + self.webLoginCallBack = webLoginBlock; + MASModelService* service = [MASModelService sharedService]; + [[MASAuthorizationResponse sharedInstance] setDelegate:self]; + __block MASBrowserBasedAuthentication *blockSelf = self; + + // + // Try to register so that all the essential things are set up in that API call and we get a valid URL. If Application is already registered the API returns without doing any work. + // + [service registerApplication:^(BOOL completed, NSError *error) { + [blockSelf getURLForWebLogin]; + }]; +} + + +- (void)getURLForWebLogin +{ + // + // Headers + // + MASIMutableOrderedDictionary *headerInfo = [MASIMutableOrderedDictionary new]; + + // + // Parameters + // + MASIMutableOrderedDictionary *parameterInfo = [MASIMutableOrderedDictionary new]; + + // ClientId + parameterInfo[MASClientKeyRequestResponseKey] = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; + + // RedirectUri + parameterInfo[MASRedirectUriRequestResponseKey] = [[MASApplication currentApplication].redirectUri absoluteString]; + + // Scope + NSString *scope = [MASApplication currentApplication].scopeAsString; + + // + // Workaround - msso_register scope should NOT be used to retrieve authenticationProviders when it is going to be used to "authenticate" + // msso_register scope should only contain for device registration with authorizationCode. + // When the authroizationCode was granted with msso_register scope and used to retrieve the tokens, it will FAIL with unknown error from the server. + // + if (scope && [[MASDevice currentDevice] isRegistered]) + { + scope = [scope replaceStringWithRegexPattern:@"\\bmsso_register\\b" withString:@""]; + } + + // + // If sso is disabled, manually remove msso scope, as it will create id_token with msso scope + // + if (scope && ![MASConfiguration currentConfiguration].ssoEnabled) + { + scope = [scope replaceStringWithRegexPattern:@"\\bmsso\\b" withString:@""]; + } + + parameterInfo[MASScopeRequestResponseKey] = scope; + + // ResponseType + parameterInfo[MASRequestResponseTypeRequestResponseKey] = @"code"; + + // Display + parameterInfo[MASDisplayRequestResponseKey] = @"template"; + + // PKCE Support - generate code verifier + [[MASAccessService sharedService].currentAccessObj generateCodeVerifier]; + + // PKCE Support - generate state + [[MASAccessService sharedService].currentAccessObj generatePKCEState]; + + // Retrieve code verifier + NSString *codeVerifier = [[MASAccessService sharedService].currentAccessObj retrieveCodeVerifier]; + + // Retrieve state + NSString *pkceState = [[MASAccessService sharedService].currentAccessObj retrievePKCEState]; + + if (codeVerifier) + { + // SHA256 the code verifier and encode it with base64url + NSString *codeChallenge = [NSString base64URLWithNSData:[codeVerifier sha256Data]]; + + if (codeChallenge) + { + parameterInfo[MASPKCECodeChallengeRequestResponseKey] = codeChallenge; + // + // code_challenge_method should be S256 if the code challenge is hashed; + // + // Otherwise, make code_challenge = code_verifier, and send code_challenge_method as plan, MASPKCECodeChallengeMethodPlainKey + // + parameterInfo[MASPKCECodeChallengeMethodRequestResponseKey] = MASPKCECodeChallengeMethodSHA256Key; + + parameterInfo[MASPKCEStateRequestResponseKey] = pkceState; + } + } + + //Put the mag-identifier in the url as query parameter for the device to be identified + NSString* magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]; + + if(magIdentifier && magIdentifier.length > 0) + { + parameterInfo[MASMagIdentifierRequestResponseKey] = magIdentifier; + } + + // + // Endpoint + // + NSString *endPoint = [MASConfiguration currentConfiguration].authorizationEndpointPath; + + // + // preserve the redirection block that was set earlier + // + MASSessionDataTaskHTTPRedirectBlock previousRedirectionBlock = [[MASNetworkingService sharedService] httpRedirectionBlock]; + [[MASNetworkingService sharedService] setHttpRedirectionBlock:[self getRedirectionBlock]]; + __block MASBrowserBasedAuthentication *blockSelf = self; + + // + // This get request would result in a redirection which contains the actual URL to be loaded into browser and hence this would be canceled after the redirection + // + [[MASNetworkingService sharedService] getFrom:endPoint withParameters:parameterInfo andHeaders:headerInfo requestType:MASRequestResponseTypeWwwFormUrlEncoded responseType:MASRequestResponseTypeWwwFormUrlEncoded completion:^(NSDictionary* response, NSError* error){ + + // + // We expect this API to be cancelled in the redirection and hence the only acceptable error here is cancel.Any other error could mean an error for authenticaion itself. Hence cancel authorization. + // + if(error.code != NSURLErrorCancelled) + { + DLog(@"error occured in BBA error info: %@",error); + blockSelf.webLoginCallBack(nil, YES, nil); + return; + } + + [[MASNetworkingService sharedService] setHttpRedirectionBlock:previousRedirectionBlock]; + }]; +} + +- (MASSessionDataTaskHTTPRedirectBlock)getRedirectionBlock +{ + __block MASBrowserBasedAuthentication *blockSelf = self; + MASSessionDataTaskHTTPRedirectBlock redirectionBlock = ^(NSURLSession *session, NSURLSessionTask *task, NSURLResponse * response, NSURLRequest *request){ + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + if(httpResponse.statusCode == 302 && [self isBBARedirection:task.originalRequest]) + { + DLog(@"all headers %@",httpResponse.allHeaderFields); + NSString* locationURL = [httpResponse.allHeaderFields objectForKey:@"Location"]; + NSURL* redirectURL = [NSURL URLWithString:locationURL]; + [task cancel]; + + if(![blockSelf redirectURLHasErrors:redirectURL]) + { + [blockSelf launchBrowserWithURL:redirectURL]; + } + else{ + blockSelf.webLoginCallBack(nil, YES, nil); + } + } + return request; + }; + + return redirectionBlock; +} + +- (BOOL)isBBARedirection:(NSURLRequest*)request +{ + if([request.URL.absoluteString containsString:[MASConfiguration currentConfiguration].authorizationEndpointPath] && [request.URL.absoluteString containsString:@"display=template"]) + { + return YES; + } + + return NO; +} + + +- (BOOL)redirectURLHasErrors :(NSURL*)redirectURL +{ + NSString* redirectURLString = redirectURL.absoluteString; + if([redirectURLString containsString:@"x-ca-err"] && [redirectURLString containsString:@"error"] && [redirectURLString containsString:@"error_description"]) + { + return YES; + } + return NO; +} + + +- (void)launchBrowserWithURL:(NSURL*)templatizedURL +{ + __block MASBrowserBasedAuthentication *blockSelf = self; + __weak __typeof__(self) weakSelf = self; + blockSelf.safariViewController = [[SFSafariViewController alloc] initWithURL:templatizedURL]; + blockSelf.safariViewController.delegate = weakSelf; + + dispatch_async(dispatch_get_main_queue(), ^{ + [UIAlertController rootViewController].modalTransitionStyle = UIModalTransitionStyleCoverVertical; + + [[UIAlertController rootViewController] presentViewController:blockSelf.safariViewController animated:YES + completion:^{ + + DLog(@"Successfully displayed login template"); + }]; + + return; + }); +} + + +#pragma mark - SafariViewController Delegates + +- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller +{ + self.webLoginCallBack(nil, YES, ^(BOOL completed, NSError* error){ + if(error) + { + DLog(@"Browser cancel clicked"); + } + }); +} + + +#pragma mark - Authorization Response delegate + +- (void)didReceiveAuthorizationCode:(NSString *)code +{ + MASAuthCredentialsAuthorizationCode *authCredentials = [MASAuthCredentialsAuthorizationCode initWithAuthorizationCode:code]; + [[MASNetworkingService sharedService] setHttpRedirectionBlock:nil]; + + self.webLoginCallBack(authCredentials, NO, ^(BOOL completed, NSError* error){ + // + // In either success or error case dismiss the browser and just log the status. The caller would pass the error state/success back to user. + // + if(error) + { + DLog(@"successfully logged in"); + } + DLog(@"successfully logged in"); + [self dismissBrowser]; + }); +} + + +- (void)didReceiveError:(NSError *)error +{ + self.webLoginCallBack(nil, YES, ^(BOOL completed, NSError* error){ + if(error) + { + DLog(@"Did not receive Authorization code"); + } + }); +} + +#pragma mark - UI + +- (void)dismissBrowser +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIAlertController rootViewController] dismissViewControllerAnimated:YES completion:nil]; + }); +} + +@end diff --git a/MASFoundation/Classes/models/MASClaims.m b/MASFoundation/Classes/models/MASClaims.m index 2b5d550b..54557475 100644 --- a/MASFoundation/Classes/models/MASClaims.m +++ b/MASFoundation/Classes/models/MASClaims.m @@ -68,8 +68,8 @@ - (id)initPrivate // // Prepare iss // - NSString *magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier]; - NSString *clientId = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeClientId]; + NSString *magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]; + NSString *clientId = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; if (magIdentifier && clientId) { diff --git a/MASFoundation/Classes/models/MASConfiguration.h b/MASFoundation/Classes/models/MASConfiguration.h index 51d544be..8d4eafd8 100644 --- a/MASFoundation/Classes/models/MASConfiguration.h +++ b/MASFoundation/Classes/models/MASConfiguration.h @@ -174,13 +174,17 @@ # pragma mark - Security Configuration /** - Sets security measure for SSL pinning, and SSL validation for specified host in MASSecurityConfiguration object + Sets security measure for SSL pinning, and SSL validation for specified host in MASSecurityConfiguration object. + + @remark MASSecurityConfiguration must have valid host in NSURL object with port number (port number is mandatory), at least one pinning information (either certificates, or public key hashes), or trust public PKI. If public PKI is not trusted, and no pinning information is provided, it will fail to store the security configuration object, and eventually fail on evaluating SSL for requests. @warning Upon SDK initialization, [MASConfiguration currentConfiguration].gatewayUrl's MASSecurityConfiguration object will be overwritten. If primary gateway's security configuration has to be modified, ensure to set security configuration after SDK initialization. - @param securityConfiguration MASSecurityConfiguration object with host, and security measure configuration values. - */ -+ (void)setSecurityConfiguration:(MASSecurityConfiguration *_Nonnull)securityConfiguration; + @param securityConfiguration MASSecurityConfiguration object with host, and security measure configuration values + @param error NSError object reference to notify any error occurred while validating MASSecurityConfiguration + @return YES if security configuration was successfully set + */ ++ (BOOL)setSecurityConfiguration:(MASSecurityConfiguration *_Nonnull)securityConfiguration error:(NSError *__nullable __autoreleasing *__nullable)error; @@ -352,4 +356,19 @@ + (NSError *_Nullable)validateJSONConfiguration:(NSDictionary *_Nonnull)configuration; + +///-------------------------------------- +/// @name Deprecated +///-------------------------------------- + +# pragma mark - Deprecated + +/** + Sets security measure for SSL pinning, and SSL validation for specified host in MASSecurityConfiguration object + + @warning Upon SDK initialization, [MASConfiguration currentConfiguration].gatewayUrl's MASSecurityConfiguration object will be overwritten. If primary gateway's security configuration has to be modified, ensure to set security configuration after SDK initialization. + @param securityConfiguration MASSecurityConfiguration object with host, and security measure configuration values. + */ ++ (void)setSecurityConfiguration:(MASSecurityConfiguration *_Nonnull)securityConfiguration DEPRECATED_MSG_ATTRIBUTE("[MASConfiguration setSecurityConfiguration:] is deprecated. Use [MASConfiguration setSecurityConfiguration:error:] instead for better handling of error cases."); + @end diff --git a/MASFoundation/Classes/models/MASConfiguration.m b/MASFoundation/Classes/models/MASConfiguration.m index edd665b7..d9705c15 100644 --- a/MASFoundation/Classes/models/MASConfiguration.m +++ b/MASFoundation/Classes/models/MASConfiguration.m @@ -100,7 +100,7 @@ static NSString *const MASClientInitializeEndpoint = @"client_credential_init_endpoint_path"; // string static NSString *const MASDeviceListEndpoint = @"device_list_endpoint_path"; // string static NSString *const MASDeviceRegisterEndpoint = @"device_register_endpoint_path"; // string -static NSString *const MASDeviceRegisterClientEndpoint = @"device_register_client_endpoint_path"; // string +static NSString *const MASDeviceRegisterClientEndpoint = @"device_client_register_endpoint_path"; // string static NSString *const MASDeviceRenewEndpoint = @"device_renew_endpoint_path"; // string static NSString *const MASDeviceRemoveEndpoint = @"device_remove_endpoint_path"; // string static NSString *const MASEnterpriseBrowserEndpoint = @"enterprise_browser_endpoint_path"; // string @@ -166,10 +166,16 @@ -(id)valueForKeyPathWithIndexes:(NSString*)fullPath @end +@interface MASConfiguration () + +@property (strong, nonatomic) NSMutableDictionary *endpointKeysToPaths; + +@end + + @implementation MASConfiguration static NSDictionary *_configurationInfo_; -static NSMutableDictionary *_endpointKeysToPaths_; static float _systemVersionNumber_; @@ -195,7 +201,7 @@ - (id)init - (id)initPrivate { self = [super init]; - if(self) + if (self) { } @@ -206,7 +212,7 @@ - (id)initPrivate - (id)initWithConfigurationInfo:(NSDictionary *)info { - if(self = [super init]) + if (self = [super init]) { _configurationInfo_ = info; @@ -226,26 +232,35 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info // // If the dictionary already exists ignore the call // - if(_endpointKeysToPaths_) return; + if (_endpointKeysToPaths) + { + return; + } // // Create the dictionary // - _endpointKeysToPaths_ = [NSMutableDictionary new]; + _endpointKeysToPaths = [NSMutableDictionary new]; // // OAuth Endpoints // NSDictionary *oauthInfo = _configurationInfo_[MASOAuthConfigurationKey]; - if(oauthInfo) + if (oauthInfo) { // System Endpoints NSDictionary *endpointsInfo = oauthInfo[MASSystemEndpointsConfigurationKey]; - if(endpointsInfo) [_endpointKeysToPaths_ addEntriesFromDictionary:endpointsInfo]; + if (endpointsInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + } // Protected Endpoints endpointsInfo = oauthInfo[MASProtectedEndpointsConfigurationKey]; - if(endpointsInfo) [_endpointKeysToPaths_ addEntriesFromDictionary:endpointsInfo]; + if (endpointsInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + } } @@ -253,22 +268,28 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info // MAG Endpoints // NSDictionary *magInfo = _configurationInfo_[MASMAGConfigurationKey]; - if(magInfo) + if (magInfo) { // System Endpoints NSDictionary *endpointsInfo = magInfo[MASSystemEndpointsConfigurationKey]; - if(endpointsInfo) [_endpointKeysToPaths_ addEntriesFromDictionary:endpointsInfo]; + if (endpointsInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + } // Protected Endpoints endpointsInfo = magInfo[MASProtectedEndpointsConfigurationKey]; - if(endpointsInfo) [_endpointKeysToPaths_ addEntriesFromDictionary:endpointsInfo]; + if (endpointsInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + } } // // MAS Endpoints // NSDictionary *masInfo = _configurationInfo_[MASConfigurationKey]; - if(masInfo) + if (masInfo) { // // currently scim-path is configured as String, maybe later when it comes as dictionary change it @@ -276,16 +297,16 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info //scim-path NSString *scimPathInfo = masInfo[MASScimPathEndpoint]; - if(scimPathInfo) + if (scimPathInfo) { - [_endpointKeysToPaths_ addEntriesFromDictionary:@{MASScimPathEndpoint : scimPathInfo}]; + [_endpointKeysToPaths addEntriesFromDictionary:@{MASScimPathEndpoint : scimPathInfo}]; } //storage-path NSString *storagePathInfo = masInfo[MASStoragePathEndpoint]; - if(scimPathInfo) + if (scimPathInfo) { - [_endpointKeysToPaths_ addEntriesFromDictionary:@{MASStoragePathEndpoint : storagePathInfo}]; + [_endpointKeysToPaths addEntriesFromDictionary:@{MASStoragePathEndpoint : storagePathInfo}]; } } @@ -293,18 +314,20 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info // Custom Endpoints // NSDictionary *customInfo = _configurationInfo_[MASCustomConfigurationKey]; - if(customInfo) [_endpointKeysToPaths_ addEntriesFromDictionary:customInfo]; - + if (customInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:customInfo]; + } // // Temporary Hardcoded Endpoints // - _endpointKeysToPaths_[MASDeviceRegisterClientEndpoint] = @"/connect/device/register/client"; + _endpointKeysToPaths[MASDeviceRegisterClientEndpoint] = @"/connect/device/register/client"; - _endpointKeysToPaths_[MASUsersLDAPEndpoint] = @"/scim/ldap/v2/users"; - _endpointKeysToPaths_[MASUserGroupsLDAPEndpoint] = @"/scim/ldap/v2/groups"; - _endpointKeysToPaths_[MASUsersMSADEndpoint] = @"/scim/msad/v2/users"; - _endpointKeysToPaths_[MASUserGroupsMSADEndpoint] = @"/scim/msad/v2/groups"; + _endpointKeysToPaths[MASUsersLDAPEndpoint] = @"/scim/ldap/v2/users"; + _endpointKeysToPaths[MASUserGroupsLDAPEndpoint] = @"/scim/ldap/v2/groups"; + _endpointKeysToPaths[MASUsersMSADEndpoint] = @"/scim/msad/v2/users"; + _endpointKeysToPaths[MASUserGroupsMSADEndpoint] = @"/scim/msad/v2/groups"; } @@ -316,7 +339,7 @@ + (MASConfiguration *)instanceFromStorage // Attempt to retrieve from keychain // NSData *data = [[MASIKeyChainStore keyChainStoreWithService:[MASConfiguration currentConfiguration].gatewayUrl.absoluteString] dataForKey:[MASConfiguration.class description]]; - if(data) + if (data) { configuration = (MASConfiguration *)[NSKeyedUnarchiver unarchiveObjectWithData:data]; } @@ -331,11 +354,11 @@ - (void)saveToStorage // Save to the keychain // NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self]; - if(data) + if (data) { NSError *error; [[MASIKeyChainStore keyChainStoreWithService:[MASConfiguration currentConfiguration].gatewayUrl.absoluteString] setData:data forKey:[MASConfiguration.class description] error:&error]; - if(error) + if (error) { DLog(@"Error attempting to save data: %@", [error localizedDescription]); } @@ -359,13 +382,16 @@ - (void)encodeWithCoder:(NSCoder *)aCoder MASKeyChainService *keyChainService = [MASKeyChainService keyChainService]; // Configuration - if(_configurationInfo_) [keyChainService setConfiguration:_configurationInfo_]; + if (_configurationInfo_) + { + [keyChainService setConfiguration:_configurationInfo_]; + } } - (id)initWithCoder:(NSCoder *)aDecoder { - if(self = [super init]) + if (self = [super init]) { MASKeyChainService *keyChainService = [MASKeyChainService keyChainService]; @@ -380,9 +406,38 @@ - (id)initWithCoder:(NSCoder *)aDecoder } -+ (void)setSecurityConfiguration:(MASSecurityConfiguration *)securityConfiguration ++ (BOOL)setSecurityConfiguration:(MASSecurityConfiguration *)securityConfiguration error:(NSError **)error { + // + // Validate the NSURL host for security configuration. + // + if (!securityConfiguration.host || !securityConfiguration.host.port) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeConfigurationInvalidHostForSecurityConfiguration errorDomain:MASFoundationErrorDomainLocal]; + } + + return NO; + } + + // + // Validate pinning information for the security configuration. + // At least one pinning information (certificates or public key hashes) should be defined, or public PKI should be trusted. + // + if (!securityConfiguration.trustPublicPKI && (!securityConfiguration.certificates || [securityConfiguration.certificates count]== 0) && (!securityConfiguration.publicKeyHashes || [securityConfiguration.publicKeyHashes count] == 0)) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeConfigurationInvalidPinningInfoForSecurityConfiguration errorDomain:MASFoundationErrorDomainLocal]; + } + + return NO; + } + [MASConfigurationService setSecurityConfiguration:securityConfiguration]; + + return YES; } @@ -547,7 +602,7 @@ - (NSString *)gatewayHostName error:nil]; NSUInteger numberOfMatches = [regexToValidateIP numberOfMatchesInString:gatewayInfo[MASGatewayHostNameKey] options:0 range:NSMakeRange(0, [gatewayInfo[MASGatewayHostNameKey] length])]; - if(_systemVersionNumber_ < 9.0 && numberOfMatches != 1) + if (_systemVersionNumber_ < 9.0 && numberOfMatches != 1) { if (![MASDevice currentDevice].isRegistered) { @@ -600,7 +655,7 @@ - (NSURL *)gatewayUrl - (NSString *)endpointPathForKey:(NSString *)endpointKey { - NSString *endpointPath = _endpointKeysToPaths_[endpointKey]; + NSString *endpointPath = _endpointKeysToPaths[endpointKey]; return endpointPath; } @@ -610,97 +665,97 @@ - (NSString *)endpointPathForKey:(NSString *)endpointKey - (NSString *)scimPathEndpointPath { - return _endpointKeysToPaths_[MASScimPathEndpoint]; + return _endpointKeysToPaths[MASScimPathEndpoint]; } - (NSString *)storagePathEndpointPath { - return _endpointKeysToPaths_[MASStoragePathEndpoint]; + return _endpointKeysToPaths[MASStoragePathEndpoint]; } - (NSString *)authorizationEndpointPath { - return _endpointKeysToPaths_[MASAuthorizationEndpoint]; + return _endpointKeysToPaths[MASAuthorizationEndpoint]; } - (NSString *)clientInitializeEndpointPath { - return _endpointKeysToPaths_[MASClientInitializeEndpoint]; + return _endpointKeysToPaths[MASClientInitializeEndpoint]; } - (NSString *)authenticateOTPEndpointPath { - return _endpointKeysToPaths_[MASAuthenticateOTPEndpoint]; + return _endpointKeysToPaths[MASAuthenticateOTPEndpoint]; } - (NSString *)deviceListAllEndpointPath { - return _endpointKeysToPaths_[MASDeviceListEndpoint]; + return _endpointKeysToPaths[MASDeviceListEndpoint]; } - (NSString *)deviceRegisterEndpointPath { - return _endpointKeysToPaths_[MASDeviceRegisterEndpoint]; + return _endpointKeysToPaths[MASDeviceRegisterEndpoint]; } - (NSString *)deviceRegisterClientEndpointPath { - return _endpointKeysToPaths_[MASDeviceRegisterClientEndpoint]; + return _endpointKeysToPaths[MASDeviceRegisterClientEndpoint]; } - (NSString *)deviceRenewEndpointPath { - return _endpointKeysToPaths_[MASDeviceRenewEndpoint]; + return _endpointKeysToPaths[MASDeviceRenewEndpoint]; } - (NSString *)deviceRemoveEndpointPath { - return _endpointKeysToPaths_[MASDeviceRemoveEndpoint]; + return _endpointKeysToPaths[MASDeviceRemoveEndpoint]; } - (NSString *)enterpriseBrowserEndpointPath { - return _endpointKeysToPaths_[MASEnterpriseBrowserEndpoint]; + return _endpointKeysToPaths[MASEnterpriseBrowserEndpoint]; } - (NSString *)tokenEndpointPath { - return _endpointKeysToPaths_[MASTokenEndpoint]; + return _endpointKeysToPaths[MASTokenEndpoint]; } - (NSString *)tokenRevokeEndpointPath { - return _endpointKeysToPaths_[MASTokenRevokeEndpoint]; + return _endpointKeysToPaths[MASTokenRevokeEndpoint]; } - (NSString *)userInfoEndpointPath { - return _endpointKeysToPaths_[MASUserInfoEndpoint]; + return _endpointKeysToPaths[MASUserInfoEndpoint]; } - (NSString *)userSessionLogoutEndpointPath { - return _endpointKeysToPaths_[MASUserSessionLogoutEndpoint]; + return _endpointKeysToPaths[MASUserSessionLogoutEndpoint]; } - (NSString *)userSessionStatusEndpointPath { - return _endpointKeysToPaths_[MASUserSessionStatusEndpoint]; + return _endpointKeysToPaths[MASUserSessionStatusEndpoint]; } @@ -768,7 +823,7 @@ - (BOOL)enabledTrustedPublicPKI - (BOOL)ssoEnabled { MASAccessService *accessService = [MASAccessService sharedService]; - NSString *ssoEnabledString = [accessService getAccessValueStringWithType:MASAccessValueTypeMSSOEnabled]; + NSString *ssoEnabledString = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyMSSOEnabled]; if (ssoEnabledString) { @@ -787,7 +842,7 @@ - (void)setSsoEnabled:(BOOL)ssoEnabled { MASAccessService *accessService = [MASAccessService sharedService]; - [accessService setAccessValueString:(ssoEnabled ? @"true":@"false") withAccessValueType:MASAccessValueTypeMSSOEnabled]; + [accessService setAccessValueString:(ssoEnabled ? @"true":@"false") storageKey:MASKeychainStorageKeyMSSOEnabled]; } @@ -876,9 +931,9 @@ - (NSString *)debugDescription NSMutableString *endpoints = [[NSMutableString alloc] initWithString:@"\n\n {\n"]; NSString *keyToEndpoint; - for(NSString *endpointKey in _endpointKeysToPaths_) + for (NSString *endpointKey in _endpointKeysToPaths) { - keyToEndpoint = [NSString stringWithFormat:@" %@ = %@\n", endpointKey, _endpointKeysToPaths_[endpointKey]]; + keyToEndpoint = [NSString stringWithFormat:@" %@ = %@\n", endpointKey, _endpointKeysToPaths[endpointKey]]; [endpoints appendString:keyToEndpoint]; } [endpoints appendString:@" }"]; @@ -898,13 +953,13 @@ - (NSString *)debugDescription - (NSDictionary *)defaultApplicationClientInfo { NSMutableArray *applicationClientInfoFound = [NSMutableArray new]; - for(NSDictionary *info in self.applicationClients) + for (NSDictionary *info in self.applicationClients) { [applicationClientInfoFound addObject:info]; } // Should there be two or more allowed in the list that meet that criteria? Can it happen? - if(applicationClientInfoFound.count > 1) + if (applicationClientInfoFound.count > 1) { DLog(@"Warning: found %ld iOS clients that are enabled, just choosing first in the list", (long)applicationClientInfoFound.count); @@ -975,4 +1030,12 @@ - (NSArray *)generateCertificatesFromPEM:(NSArray *)certificatesAsPEM return certificatesAsDER; } + +# pragma mark - Deprecated + ++ (void)setSecurityConfiguration:(MASSecurityConfiguration *)securityConfiguration +{ + [self setSecurityConfiguration:securityConfiguration error:nil]; +} + @end diff --git a/MASFoundation/Classes/models/MASDevice.m b/MASFoundation/Classes/models/MASDevice.m index 645399ce..2c1c1414 100644 --- a/MASFoundation/Classes/models/MASDevice.m +++ b/MASFoundation/Classes/models/MASDevice.m @@ -50,15 +50,26 @@ + (void)setProximityLoginDelegate:(id)delegate - (BOOL)isRegistered { + _isRegistered = NO; + // // Obtain key chain items to determine registration status // MASAccessService *accessService = [MASAccessService sharedService]; - NSString *magIdentifier = [accessService getAccessValueStringWithType:MASAccessValueTypeMAGIdentifier]; - NSData *certificateData = [accessService getAccessValueCertificateWithType:MASAccessValueTypeSignedPublicCertificate]; - - _isRegistered = (magIdentifier && certificateData); + NSString *vendorIdFromKeychain = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyDeviceVendorId]; + NSString *vendorIdCurrent = [MASDevice deviceVendorId]; + + // + // Check if the vendorId in Keychain macth with current vendorId + // + if ([vendorIdCurrent isEqualToString:vendorIdFromKeychain]) + { + NSString *magIdentifier = [accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]; + NSData *certificateData = [accessService getAccessValueCertificateWithStorageKey:MASKeychainStorageKeySignedPublicCertificate]; + + _isRegistered = (magIdentifier && certificateData); + } return _isRegistered; } @@ -119,10 +130,14 @@ - (void)resetLocally // re-establish URL session // [[MASNetworkingService sharedService] establishURLSession]; + + // + // Post the did reset locally notification + // + [[NSNotificationCenter defaultCenter] postNotificationName:MASDeviceDidResetLocallyNotification object:self]; } - # pragma mark - Lifecycle - (id)init @@ -200,7 +215,7 @@ - (void)encodeWithCoder:(NSCoder *)aCoder - (id)initWithCoder:(NSCoder *)aDecoder { - if(self = [super initWithCoder:aDecoder]) + if (self = [super initWithCoder:aDecoder]) { [self setValue:[aDecoder decodeObjectForKey:MASDeviceIdentifierPropertyKey] forKey:@"identifier"]; [self setValue:[aDecoder decodeObjectForKey:MASDeviceNamePropertyKey] forKey:@"name"]; diff --git a/MASFoundation/Classes/models/MASSharedStorage.h b/MASFoundation/Classes/models/MASSharedStorage.h new file mode 100644 index 00000000..7b68d72c --- /dev/null +++ b/MASFoundation/Classes/models/MASSharedStorage.h @@ -0,0 +1,87 @@ +// +// MASSharedStorage.h +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import + + +/** + MASSharedStorage class is designed for developers to write, read, and delete NSString or NSData data into shared keychain storage, + so that multiple applications with same keychain sharing group in the same device can share data between applications. + + @warning *Important:* MASSharedStorage will not be available if MASFoundation framework is not initialized; the framework should be initialized prior to write/read/delete any data into MASSharedStorage. + */ +@interface MASSharedStorage : MASObject + + + +///-------------------------------------- +/// @name Public +///-------------------------------------- + +# pragma mark - Public + + +/** + Finds NSString data stored with the key from shared keychain storage. + + @param key NSString of the key used to store the NSString data + @param error NSError object reference that would notify if there was any error while retrieving the data + @return NSString of data found with the key + */ ++ (NSString *_Nullable)findStringUsingKey:(NSString *_Nonnull)key error:(NSError * __nullable __autoreleasing * __nullable)error; + + + +/** + Finds NSData object stored with the key from shared keychain storage. + + @param key NSString of the key used to store the NSData object + @param error NSError object reference that would notify if there was any error while retrieving the data + @return NSData of data found with the key + */ ++ (NSData *_Nullable)findDataUsingKey:(NSString *_Nonnull)key error:(NSError * __nullable __autoreleasing * __nullable)error; + + + +/** + Saves NSString data with the specified key into shared keychain storage. + Save method can also be used to delete the data from the shared keychain storage by passing nil in string parameter with the key. + + @param string NSString data to be stored + @param key NSString of the key used to store the NSString data + @param error NSError object reference that would notify if there was any error while storing the data + @return BOOL result of saving operation + */ ++ (BOOL)saveString:(NSString *_Nonnull)string key:(NSString *_Nonnull)key error:(NSError * __nullable __autoreleasing * __nullable)error; + + + +/** + Saves NSData object with the specified key into shared keychain storage. + Save method can also be used to delete the data from the shared keychain storage by passing nil in data parameter with the key. + + @param data NSData object to be stored + @param key NSString of the key used to store the NSData object + @param error NSError object reference that would notify if there was any error while storing the data + @return BOOL result of saving operation + */ ++ (BOOL)saveData:(NSData *_Nonnull)data key:(NSString *_Nonnull)key error:(NSError * __nullable __autoreleasing * __nullable)error; + + + +/** + Deletes any data type with the specified key from shared keychain storage. + + @param key NSString of the key used to store the data + @param error NSError object reference that would notify if there was any error while deleting the data + */ ++ (void)deleteForKey:(NSString *_Nonnull)key error:(NSError * __nullable __autoreleasing * __nullable)error; + +@end diff --git a/MASFoundation/Classes/models/MASSharedStorage.m b/MASFoundation/Classes/models/MASSharedStorage.m new file mode 100644 index 00000000..84a652e8 --- /dev/null +++ b/MASFoundation/Classes/models/MASSharedStorage.m @@ -0,0 +1,264 @@ +// +// MASSharedStorage.m +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import "MASSharedStorage.h" + +#import "MASAccessService.h" +#import "MASConstantsPrivate.h" + +@implementation MASSharedStorage + ++ (NSString *)findStringUsingKey:(NSString *)key error:(NSError **)error +{ + // + // Check if SDK was initialized + // + if ([MAS MASState] != MASStateDidStart) + { + if (error) + { + *error = [NSError errorMASIsNotStarted]; + } + + return nil; + } + + // + // Check for data key + // + if (key == nil || [key length] <= 0) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeSharedStorageNotNilKey errorDomain:MASFoundationErrorDomainLocal]; + } + + return nil; + } + + // + // Retrieve NSString from shared keychain storage + // + NSError *operationError = nil; + NSString *resultString = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:[NSString stringWithFormat:@"%@.%@", MASSharedStorageCustomPrefix, key] error:&operationError]; + + // + // If an error occurred while keychain operation, convert it into MASFoundationErrorDomainLocal error object + // + if (operationError) + { + NSError *thisError = [NSError errorWithDomain:MASFoundationErrorDomainLocal code:operationError.code userInfo:@{NSLocalizedDescriptionKey : operationError.localizedDescription}]; + + if (error) + { + *error = thisError; + } + } + + return resultString; +} + + ++ (NSData *)findDataUsingKey:(NSString *)key error:(NSError **)error +{ + // + // Check if SDK was initialized + // + if ([MAS MASState] != MASStateDidStart) + { + if (error) + { + *error = [NSError errorMASIsNotStarted]; + } + + return nil; + } + + // + // Check for data key + // + if (key == nil || [key length] <= 0) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeSharedStorageNotNilKey errorDomain:MASFoundationErrorDomainLocal]; + } + + return nil; + } + + // + // Retrieve NSData from shared keychain storage + // + NSError *operationError = nil; + NSData *resultData = [[MASAccessService sharedService] getAccessValueDataWithStorageKey:[NSString stringWithFormat:@"%@.%@", MASSharedStorageCustomPrefix, key] error:&operationError]; + + // + // If an error occurred while keychain operation, convert it into MASFoundationErrorDomainLocal error object + // + if (operationError) + { + NSError *thisError = [NSError errorWithDomain:MASFoundationErrorDomainLocal code:operationError.code userInfo:@{NSLocalizedDescriptionKey : operationError.localizedDescription}]; + + if (error) + { + *error = thisError; + } + } + + return resultData; +} + + ++ (BOOL)saveString:(NSString *)string key:(NSString *)key error:(NSError **)error +{ + // + // Check if SDK was initialized + // + if ([MAS MASState] != MASStateDidStart) + { + if (error) + { + *error = [NSError errorMASIsNotStarted]; + } + + return NO; + } + + // + // Check for data key + // + if (key == nil || [key length] <= 0) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeSharedStorageNotNilKey errorDomain:MASFoundationErrorDomainLocal]; + } + + return NO; + } + + // + // Store NSString into shared keychain storage + // + NSError *operationError = nil; + BOOL result = [[MASAccessService sharedService] setAccessValueString:string storageKey:[NSString stringWithFormat:@"%@.%@", MASSharedStorageCustomPrefix, key] error:&operationError]; + + // + // If an error occurred while keychain operation, convert it into MASFoundationErrorDomainLocal error object + // + if (operationError) + { + NSError *thisError = [NSError errorWithDomain:MASFoundationErrorDomainLocal code:operationError.code userInfo:@{NSLocalizedDescriptionKey : operationError.localizedDescription}]; + + if (error) + { + *error = thisError; + } + } + + return result; +} + + ++ (BOOL)saveData:(NSData *)data key:(NSString *)key error:(NSError **)error +{ + // + // Check if SDK was initialized + // + if ([MAS MASState] != MASStateDidStart) + { + if (error) + { + *error = [NSError errorMASIsNotStarted]; + } + + return NO; + } + + // + // Check for data key + // + if (key == nil || [key length] <= 0) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeSharedStorageNotNilKey errorDomain:MASFoundationErrorDomainLocal]; + } + + return NO; + } + + NSError *operationError = nil; + BOOL result = [[MASAccessService sharedService] setAccessValueData:data storageKey:[NSString stringWithFormat:@"%@.%@", MASSharedStorageCustomPrefix, key] error:&operationError]; + + // + // If an error occurred while keychain operation, convert it into MASFoundationErrorDomainLocal error object + // + if (operationError) + { + NSError *thisError = [NSError errorWithDomain:MASFoundationErrorDomainLocal code:operationError.code userInfo:@{NSLocalizedDescriptionKey : operationError.localizedDescription}]; + + if (error) + { + *error = thisError; + } + } + + return result; +} + + ++ (void)deleteForKey:(NSString *_Nonnull)key error:(NSError * __nullable __autoreleasing * __nullable)error +{ + // + // Check if SDK was initialized + // + if ([MAS MASState] != MASStateDidStart) + { + if (error) + { + *error = [NSError errorMASIsNotStarted]; + } + + return; + } + + // + // Check for data key + // + if (key == nil || [key length] <= 0) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeSharedStorageNotNilKey errorDomain:MASFoundationErrorDomainLocal]; + } + + return; + } + + NSError *operationError = nil; + [[MASAccessService sharedService] deleteForStorageKey:[NSString stringWithFormat:@"%@.%@", MASSharedStorageCustomPrefix, key] error:&operationError]; + + // + // If an error occurred while keychain operation, convert it into MASFoundationErrorDomainLocal error object + // + if (operationError) + { + NSError *thisError = [NSError errorWithDomain:MASFoundationErrorDomainLocal code:operationError.code userInfo:@{NSLocalizedDescriptionKey : operationError.localizedDescription}]; + + if (error) + { + *error = thisError; + } + } +} + +@end diff --git a/MASFoundation/Classes/models/MASUser.h b/MASFoundation/Classes/models/MASUser.h index ff7c6507..78f5c497 100644 --- a/MASFoundation/Classes/models/MASUser.h +++ b/MASFoundation/Classes/models/MASUser.h @@ -261,6 +261,16 @@ +/** + Authenticate a user by launching a Browser which in turn loads a URL (templatized). + + @param completion The MASCompletionErrorBlock block that receives the results. On a successful completion, the user + available via [MASUser currentUser] has been updated with the new information. + */ ++(void)initializeBrowserBasedAuthenticationWithCompletion:(MASCompletionErrorBlock _Nullable)completion; + + + /** * Requesting userInfo for the MASUser object. * This method will retrieve additional information on the MASUser object. diff --git a/MASFoundation/Classes/models/MASUser.m b/MASFoundation/Classes/models/MASUser.m index da2b3d3b..34eaded7 100644 --- a/MASFoundation/Classes/models/MASUser.m +++ b/MASFoundation/Classes/models/MASUser.m @@ -42,7 +42,7 @@ + (MASUser *)currentUser + (NSString *_Nullable)authCredentialsType { - NSString *authCredentialsType = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeCurrentAuthCredentialsGrantType]; + NSString *authCredentialsType = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyCurrentAuthCredentialsGrantType]; return authCredentialsType; } @@ -142,7 +142,7 @@ - (BOOL)isCurrentUser // // Get currently authenticated user's object id to make sure that isCurrentUser flag can be determined properly for other users // - NSString *currentlyAuthenticatedUserObjectId = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeAuthenticatedUserObjectId]; + NSString *currentlyAuthenticatedUserObjectId = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyAuthenticatedUserObjectId]; return [self.objectId isEqualToString:currentlyAuthenticatedUserObjectId]; } @@ -154,7 +154,7 @@ - (BOOL)isAuthenticated // // Get currently authenticated user's object id to make sure that isAuthenticated flag can be determined properly for other users // - NSString *currentlyAuthenticatedUserObjectId = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeAuthenticatedUserObjectId]; + NSString *currentlyAuthenticatedUserObjectId = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyAuthenticatedUserObjectId]; // // if the user status is not MASUserStatusNotLoggedIn, @@ -169,7 +169,7 @@ - (BOOL)isSessionLocked // // Get currently authenticated user's object id to make sure that isAuthenticated flag can be determined properly for other users // - NSString *currentlyAuthenticatedUserObjectId = [[MASAccessService sharedService] getAccessValueStringWithType:MASAccessValueTypeAuthenticatedUserObjectId]; + NSString *currentlyAuthenticatedUserObjectId = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyAuthenticatedUserObjectId]; if ([self.objectId isEqualToString:currentlyAuthenticatedUserObjectId]) { @@ -250,6 +250,24 @@ + (void)loginWithAuthCredentials:(MASAuthCredentials *_Nonnull)authCredentials c } ++(void)initializeBrowserBasedAuthenticationWithCompletion:(MASCompletionErrorBlock _Nullable)completion +{ + if(![MASModelService browserBasedAuthentication]) + { + if(completion) completion(NO, [NSError errorBrowserBasedAuthenticaionNotEnabled]); + return; + } + + if ([MASUser currentUser] && [MASUser currentUser].isAuthenticated) + { + if(completion) completion(NO, [NSError errorUserAlreadyAuthenticated]); + + return; + } + + [[MASModelService sharedService] validateCurrentUserSession:completion]; +} + - (void)requestUserInfoWithCompletion:(MASUserResponseErrorBlock)completion { [[MASModelService sharedService] requestUserInfoWithCompletion:completion]; @@ -287,7 +305,7 @@ - (void)logoutWithCompletion:(MASCompletionErrorBlock)completion // // Detect if there is id_token // - if([accessService getAccessValueStringWithType:MASAccessValueTypeIdToken]) + if ([accessService getAccessValueStringWithStorageKey:MASKeychainStorageKeyIdToken]) { [[MASModelService sharedService] logOutDeviceAndClearLocalAccessToken:YES completion:completion]; } diff --git a/MASFoundation/Classes/models/Network/MASRequest.h b/MASFoundation/Classes/models/Network/MASRequest.h new file mode 100644 index 00000000..5b493627 --- /dev/null +++ b/MASFoundation/Classes/models/Network/MASRequest.h @@ -0,0 +1,150 @@ +// +// MASRequest.h +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import "MASRequestBuilder.h" + +/** + MASRequest class is an object created by MASRequestBuilder. It contains all necessary information to invoke an API. + The class cannot be constructed or changed directly, only through MASRequestBuilder. + */ +@interface MASRequest : MASObject + + +///-------------------------------------- +/// @name Properties +///-------------------------------------- + +# pragma mark - Properties + +/** + NSString value of the HTTP Method (GET, POST, PUT, DELETE). + */ +@property (nonatomic, strong, readonly) NSString * _Nonnull httpMethod; + + +/** + BOOL value that determines whether or not to include credentials of primary gateway in the request. + */ +@property (assign, readonly) BOOL isPublic; + + +/** + BOOL value that determines whether or not digitally sign the request parameters with JWT signature. + */ +@property (assign, readonly) BOOL sign; + + +/** + NSString value of the specific end point path fragment to append to the base Gateway URL. endPoint value can also be defined as full URL format; in this case, + SDK must be configured to add add the external host as a trusted source using MASSecurityConfiguration object. + */ +@property (nonatomic, strong, nullable, readonly) NSString *endPoint; + + +/** + NSData value of private key. + */ +@property (nonatomic, strong, nullable, readonly) NSData *privateKey; + + +/** + NSDictionary of type/value parameters to put into the header of a request. + */ +@property (nonatomic, strong, nullable, readonly) NSDictionary *header; + + +/** + NSDictionary of type/value parameters to put into the body of a request. + */ +@property (nonatomic, strong, nullable, readonly) NSDictionary *body; + + +/** + NSDictionary of type/value parameters to put into the URL of a request. + */ +@property (nonatomic, strong, nullable, readonly) NSDictionary *query; + + +/** + MASRequestResponseType value that specifies what type formatting is required for request body. + */ +@property (assign, readonly) MASRequestResponseType requestType; + + +/** + MASRequestResponseType value that specifies what type formatting is required for response body. + */ +@property (assign, readonly) MASRequestResponseType responseType; + + +# pragma mark - Public + + +/** + Initialize MASRequest using MASRequestBuilder block and defining the request method as a HTTP DELETE call. This type of HTTP Method type + places its parameters within the NSURL itself as an HTTP query extension. + + @discussion default values for designated initializer are: isPublic: NO, sign: NO, requestType:MASRequestResponseTypeJson, responseType:MASRequestResponseTypeJson. + @param block MASRequestBuilder block containing all paramters to build the request. + @return MASRequestBuilder object + */ ++ (instancetype _Nullable)deleteFrom:(void (^_Nonnull)(MASRequestBuilder* _Nonnull builder))block; + + + +/** + Initialize MASRequest using MASRequestBuilder block and defining the request method as a HTTP GET call. This type of HTTP Method type + places its parameters within the NSURL itself as an HTTP query extension. + + @discussion default values for designated initializer are: isPublic: NO, sign: NO, requestType:MASRequestResponseTypeJson, responseType:MASRequestResponseTypeJson. + @param block MASRequestBuilder block containing all paramters to build the request. + @return MASRequestBuilder object + */ ++ (instancetype _Nullable)getFrom:(void (^_Nonnull)(MASRequestBuilder* _Nonnull builder))block; + + + +/** + Initialize MASRequest using MASRequestBuilder block and defining the request method as a HTTP PATCH call. This type of HTTP Method type + places its parameters within the HTTP body in www-form-url-encoded format. + + @discussion default values for designated initializer are: isPublic: NO, sign: NO, requestType:MASRequestResponseTypeJson, responseType:MASRequestResponseTypeJson. + @param block MASRequestBuilder block containing all paramters to build the request. + @return MASRequestBuilder object + */ ++ (instancetype _Nullable)patchTo:(void (^_Nonnull)(MASRequestBuilder* _Nonnull builder))block; + + + +/** + Initialize MASRequest using MASRequestBuilder block and defining the request method as a HTTP POST call. This type of HTTP Method type + places its parameters within the HTTP body in www-form-url-encoded format. + + @discussion default values for designated initializer are: isPublic: NO, sign: NO, requestType:MASRequestResponseTypeJson, responseType:MASRequestResponseTypeJson. + @param block MASRequestBuilder block containing all paramters to build the request. + @return MASRequestBuilder object + */ ++ (instancetype _Nullable)postTo:(void (^_Nonnull)(MASRequestBuilder* _Nonnull builder))block; + + + +/** + Initialize MASRequest using MASRequestBuilder block and defining the request method as a HTTP PUT call. This type of HTTP Method type + places its parameters within the HTTP body in www-form-url-encoded format. + + @discussion default values for designated initializer are: isPublic: NO, sign: NO, requestType:MASRequestResponseTypeJson, responseType:MASRequestResponseTypeJson. + @param block MASRequestBuilder block containing all paramters to build the request. + @return MASRequestBuilder object + */ ++ (instancetype _Nullable)putTo:(void (^_Nonnull)(MASRequestBuilder* _Nonnull builder))block; + + + +@end diff --git a/MASFoundation/Classes/models/Network/MASRequest.m b/MASFoundation/Classes/models/Network/MASRequest.m new file mode 100644 index 00000000..c63179d8 --- /dev/null +++ b/MASFoundation/Classes/models/Network/MASRequest.m @@ -0,0 +1,71 @@ +// +// MASRequest.m +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import "MASRequest.h" + +@interface MASRequest () + +@property (nonatomic, readwrite) NSString *endPoint; +@property (nonatomic, readwrite) NSString *httpMethod; +@property (nonatomic, readwrite) NSData *privateKey; +@property (nonatomic, readwrite) NSDictionary *header; +@property (nonatomic, readwrite) NSDictionary *body; +@property (nonatomic, readwrite) NSDictionary *query; +@property (assign, readwrite) BOOL isPublic; +@property (assign, readwrite) BOOL sign; +@property (assign, readwrite) MASRequestResponseType requestType; +@property (assign, readwrite) MASRequestResponseType responseType; + +@end + +@implementation MASRequest + + ++ (instancetype)deleteFrom:(void (^)(MASRequestBuilder *builder))block { + + MASRequestBuilder *builder = [[MASRequestBuilder alloc] initWithHTTPMethod:@"DELETE"]; + block(builder); + return [builder build]; +} + + ++ (instancetype)getFrom:(void (^)(MASRequestBuilder *builder))block { + + MASRequestBuilder *builder = [[MASRequestBuilder alloc] initWithHTTPMethod:@"GET"]; + block(builder); + return [builder build]; +} + + ++ (instancetype)patchTo:(void (^)(MASRequestBuilder *builder))block { + + MASRequestBuilder *builder = [[MASRequestBuilder alloc] initWithHTTPMethod:@"PATCH"]; + block(builder); + return [builder build]; +} + + ++ (instancetype)postTo:(void (^)(MASRequestBuilder *builder))block { + + MASRequestBuilder *builder = [[MASRequestBuilder alloc] initWithHTTPMethod:@"POST"]; + block(builder); + return [builder build]; +} + + ++ (instancetype)putTo:(void (^)(MASRequestBuilder *builder))block { + + MASRequestBuilder *builder = [[MASRequestBuilder alloc] initWithHTTPMethod:@"PUT"]; + block(builder); + return [builder build]; +} + + +@end diff --git a/MASFoundation/Classes/models/Network/MASRequestBuilder.h b/MASFoundation/Classes/models/Network/MASRequestBuilder.h new file mode 100644 index 00000000..368ab55f --- /dev/null +++ b/MASFoundation/Classes/models/Network/MASRequestBuilder.h @@ -0,0 +1,194 @@ +// +// MASRequestBuilder.h +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import "MASClaims.h" + +@class MASRequest; + +/** + MASRequestBuilder class is an object that allows developers to progressively build a request as needed. + The class is mainly responsible to receive parameters and create a MASRequest object. + + Default configuration value for designated initializer, [[MASRequestBuilder alloc] initWithHTTPMethod:], would be: + isPublic: NO, + sign: NO, + requestType:MASRequestResponseTypeJson, + responseType:MASRequestResponseTypeJson. + */ +@interface MASRequestBuilder : MASObject + + +///-------------------------------------- +/// @name Properties +///-------------------------------------- + +# pragma mark - Properties + + +/** + NSString value of the HTTP Method (GET, POST, PUT, DELETE). + */ +@property (nonatomic, strong, readonly) NSString * _Nonnull httpMethod; + + +/** + BOOL value that determines whether or not to include credentials of primary gateway in the request. + */ +@property (assign) BOOL isPublic; + + +/** + BOOL value that determines whether or not digitally sign the request parameters with JWT signature. + */ +@property (assign, readonly) BOOL sign; + + +/** + NSString value of the target endpoint. + */ +@property (nonatomic, strong, nullable) NSString *endPoint; + + +/** + MASClaims object containing claims for JWT. + */ +@property (nonatomic, strong, nullable, readonly) MASClaims *claims; + + +/** + NSData value of private key. + */ +@property (nonatomic, strong, nullable, readonly) NSData *privateKey; + + +/** + NSDictionary of type/value parameters to put into the header of a request. + */ +@property (nonatomic, strong, nullable) NSDictionary *header; + + +/** + NSDictionary of type/value parameters to put into the body of a request. + */ +@property (nonatomic, strong, nullable) NSDictionary *body; + + +/** + NSDictionary of type/value parameters to put into the URL of a request. + */ +@property (nonatomic, strong, nullable) NSDictionary *query; + + +/** + MASRequestResponseType value that specifies what type formatting is required for request body. + */ +@property (assign) MASRequestResponseType requestType; + + +/** + MASRequestResponseType value that specifies what type formatting is required for response body. + */ +@property (assign) MASRequestResponseType responseType; + + +///-------------------------------------- +/// @name Lifecycle +///-------------------------------------- + +# pragma mark - Lifecycle + + +/** + Designated initializer for MASRequestBuilder. + + @discussion default values for designated initializer are: isPublic: NO, sign: NO, requestType:MASRequestResponseTypeJson, responseType:MASRequestResponseTypeJson. + @param method NSString of the HTTP Method (GET, POST, PUT, DELETE) + @return MASRequestBuilder object + */ +- (instancetype _Nonnull)initWithHTTPMethod:(NSString *_Nonnull)method NS_DESIGNATED_INITIALIZER; + + + +///-------------------------------------- +/// @name Public +///-------------------------------------- + +# pragma mark - Public + + +/** + Create a MASRequest object using the parameters from MASRequestBuider + + @return MASRequest object + */ +- (MASRequest *_Nullable)build; + + + +/** + Set to sign the body of request using default private key from device registration against primary gateway. + + @param error NSError error reference object that returns any error occurred during JWT signature. + */ +- (void)setSignWithError:(NSError *__nullable __autoreleasing *__nullable)error; + + + +/** + Set to sign the request with a MASClaims object using default private key from device registration against primary gateway. + + @param claims MASClaims object containing claims for JWT + @param error NSError error reference object that returns any error occurred during JWT signature. + */ +- (void)setSignWithClaims:(MASClaims *_Nonnull)claims error:(NSError *__nullable __autoreleasing *__nullable)error; + + + +/** + Set to sign the request with a MASClaims object using custom private key in NSData format. + + @param privateKey Custom private key in NSData format signed using RS256 algorithm. + @param error NSError error reference object that returns any error occurred during JWT signature. + */ +- (void)setSignWithClaims:(MASClaims *_Nonnull)claims privateKey:(NSData *_Nonnull)privateKey error:(NSError *__nullable __autoreleasing *__nullable)error; + + + +/** + Append parameter into the header of a request. + + @param key NSString containing name/type of the parameter. + @param value NSString containing value of the parameter. + */ +- (void)setHeaderParameter:(NSString *_Nonnull)key value:(NSString *_Nonnull)value; + + + +/** + Append parameter into the body of a request. + + @param key NSString containing name/type of the parameter. + @param value NSString containing value of the parameter. + */ +- (void)setBodyParameter:(NSString *_Nonnull)key value:(NSString *_Nonnull)value; + + + +/** + Append parameter into the URL of a request. + + @param key NSString containing name/type of the parameter. + @param value NSString containing value of the parameter. + */ +- (void)setQueryParameter:(NSString *_Nonnull)key value:(NSString *_Nonnull)value; + + + +@end diff --git a/MASFoundation/Classes/models/Network/MASRequestBuilder.m b/MASFoundation/Classes/models/Network/MASRequestBuilder.m new file mode 100644 index 00000000..d5531630 --- /dev/null +++ b/MASFoundation/Classes/models/Network/MASRequestBuilder.m @@ -0,0 +1,149 @@ +// +// MASRequestBuilder.m +// MASFoundation +// +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +#import "MASRequestBuilder.h" + +#import "MASRequest+MASPrivate.h" + +@interface MASRequestBuilder () + +@property (nonatomic, strong, readwrite) NSString *httpMethod; +@property (assign, readwrite) BOOL sign; +@property (nonatomic, strong, readwrite) MASClaims *claims; +@property (nonatomic, strong, readwrite) NSData *privateKey; +@end + +@implementation MASRequestBuilder + + +# pragma mark - Lifecycle + + +- (instancetype)initWithHTTPMethod:(NSString *)method +{ + self = [super init]; + + if (self) { + self.httpMethod = method; + self.isPublic = NO; + self.sign = NO; + self.requestType = MASRequestResponseTypeJson; + self.responseType = MASRequestResponseTypeJson; + } + + return self; +} + + +# pragma mark - Public + + +- (MASRequest *)build +{ + return [[MASRequest alloc] initWithBuilder:self]; +} + + +- (void)setSignWithError:(NSError *__nullable __autoreleasing *__nullable)error +{ + self.sign = TRUE; + + // + // create a new MASClaims and set the body content + // + MASClaims *claims = [MASClaims claims]; + claims.content = self.body; + claims.contentType = @"application/json"; + self.claims = claims; + + NSString *jwt = [MAS signWithClaims:claims error:error]; + + // + // injects JWT claims into the payload + // + if (!*error) + { + [self setBody:@{@"jwt":jwt}]; + } + +} + +- (void)setSignWithClaims:(MASClaims *)claims error:(NSError *__nullable __autoreleasing *__nullable)error +{ + self.sign = TRUE; + self.claims = claims; + + NSString *jwt = [MAS signWithClaims:claims error:error]; + + // + // injects JWT claims into the payload + // + if (!*error) + { + [self setBody:@{@"jwt":jwt}]; + } +} + + +- (void)setSignWithClaims:(MASClaims *)claims privateKey:(NSData *)privateKey error:(NSError *__nullable __autoreleasing *__nullable)error +{ + self.sign = TRUE; + self.claims = claims; + self.privateKey = privateKey; + + NSString *jwt = [MAS signWithClaims:claims privateKey:self.privateKey error:error]; + + // + // injects JWT claims into the payload + // + if (!*error) + { + [self setBody:@{@"jwt":jwt}]; + } +} + + +- (void)setHeaderParameter:(NSString *)key value:(NSString *)value +{ + if(self.header) + { + [self.header setValue:value forKey:key]; + } + else { + self.header = [[NSDictionary alloc] initWithObjectsAndKeys:value,key, nil]; + } +} + + +- (void)setBodyParameter:(NSString *)key value:(NSString *)value +{ + if(self.body) + { + [self.body setValue:value forKey:key]; + } + else { + self.body = [[NSDictionary alloc] initWithObjectsAndKeys:value,key, nil]; + } +} + + +- (void)setQueryParameter:(NSString *)key value:(NSString *)value +{ + if(self.query) + { + [self.query setValue:value forKey:key]; + } + else { + self.query = [[NSDictionary alloc] initWithObjectsAndKeys:value,key, nil]; + } +} + + +@end diff --git a/MASFoundation/Info.plist b/MASFoundation/Info.plist index 033da143..6c0ca926 100644 --- a/MASFoundation/Info.plist +++ b/MASFoundation/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.5 + 1.6 CFBundleSignature ???? CFBundleVersion diff --git a/MASFoundation/MASFoundation.h b/MASFoundation/MASFoundation.h index 15882b5e..10a69f8c 100644 --- a/MASFoundation/MASFoundation.h +++ b/MASFoundation/MASFoundation.h @@ -47,10 +47,13 @@ FOUNDATION_EXPORT const unsigned char MASFoundationVersionString[]; #import #import #import -#import -#import #import #import +#import +#import +#import +#import +#import // // AuthCredentials Models diff --git a/README.md b/README.md index 635b7ca0..81fc427a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -MASFoundation is the core iOS framework of the Mobile SDK, which is part of [CA Mobile App Services][mas.ca.com]. MASFoundation handles the communication and authentication layer of the Mobile SDK, making it easy for developers to establish a secure connection (TLS, Mutual SSL) to any CA Mobile API Gateway (MAG). +MASFoundation is the core iOS framework of the iOS Mobile SDK, which is part of CA Mobile API Gateway. MASFoundation handles the communication and authentication layer of the iOS Mobile SDK, making it easy for developers to establish a secure connection (TLS, Mutual SSL) to any CA Mobile API Gateway (MAG). ## Features @@ -15,15 +15,15 @@ The MASFoundation framework has the following features: + OTP - One Time Password + PKCE - Proof Key for Code Exchange + SSL Pinning with certificate, public key, or public key hash + + Fingerprint Sessions Lock - Support phone unlocking using fingerprint recognition - Dynamic SDK Configuration - Enterprise Browser - Geo Location ## Get Started +- Check out our [documentation][docs] for sample code, video tutorials, and more. - [Download MASFoundation][download] -- Read the ["Getting Started" guide][get-started] or watch some [video tutorials][videos] -- Check out our [documentation][docs] for more details and sample codes ## Communication @@ -72,9 +72,7 @@ For manual install, you add the Mobile SDK to your Xcode project. Note that you ## Set Up Project and Start the SDK -The following ***video*** describes how to set up the project and start the Mobile SDK. - -[![IMAGE ALT TEXT](http://img.youtube.com/vi/h95MF55Uuuw/0.jpg)](http://www.youtube.com/watch?v=h95MF55Uuuw "Starting the SDK") +To start your project, see [developer site](https://mas.ca.com/docs) After your project is properly configured, you must start the SDK to establish a secure connection with the backend services. The startup process includes: initialize necessary services for library (such as geo-location, BLE, and network services), and load configuration.