Skip to content

Commit

Permalink
feat: Store device secret in keychain
Browse files Browse the repository at this point in the history
  • Loading branch information
jjlangholtz committed May 5, 2022
1 parent a572e44 commit 85ade2a
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 8 deletions.
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export const createConfig = async({
endSessionRedirectUri,
discoveryUri,
scopes,
keychainService = 'Okta',
keychainAccessGroup = 'com.okta.mobile-sdk.shared',
requireHardwareBackedKeyStore,
androidChromeTabColor,
httpConnectionTimeout,
Expand Down Expand Up @@ -110,6 +112,8 @@ export const createConfig = async({
endSessionRedirectUri,
discoveryUri,
scopes,
keychainService,
keychainAccessGroup,
userAgentTemplate,
httpConnectionTimeout,
);
Expand Down
47 changes: 46 additions & 1 deletion ios/OktaSdkBridge/OktaSdkBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,38 @@ extension OktaOidcStateManager: StateManagerProtocol {

}

// MARK: - DeviceSecretKeychain

class DeviceSecretKeychain {
var service: String
var accessGroup: String

init(service: String, accessGroup: String) {
self.service = service
self.accessGroup = accessGroup
}

func save(_ tokens: [String: String]) {
let query: [String: Any] = [
(kSecClass as String): kSecClassGenericPassword,
(kSecAttrService as String): service,
(kSecAttrAccessGroup as String): self.accessGroup]
SecItemDelete(query as CFDictionary)

for (kind, value) in tokens {
let attributes: [String: Any] = [
(kSecClass as String): kSecClassGenericPassword,
(kSecAttrService as String): service,
(kSecAttrAccessGroup as String): self.accessGroup,
(kSecAttrAccount as String): "Okta-\(kind)",
(kSecValueData as String): value.data(using: .utf8)!
]

SecItemAdd(attributes as CFDictionary, nil)
}
}
}

// MARK: - OktaSdkBridge

@objc(OktaSdkBridge)
Expand All @@ -70,10 +102,11 @@ class OktaSdkBridge: RCTEventEmitter {
}

var oktaOidc: OktaOidcProtocol?

override var methodQueue: DispatchQueue { .main }

private var requestTimeout: Int?
private var deviceSecretKeychain: DeviceSecretKeychain?

func presentedViewController() -> UIViewController? {
RCTPresentedViewController()
Expand All @@ -85,6 +118,8 @@ class OktaSdkBridge: RCTEventEmitter {
endSessionRedirectUri: String,
discoveryUri: String,
scopes: String,
keychainService: String,
keychainAccessGroup: String,
userAgentTemplate: String,
requestTimeout: Int,
promiseResolver: RCTPromiseResolveBlock,
Expand All @@ -105,6 +140,7 @@ class OktaSdkBridge: RCTEventEmitter {

oktaOidc = try OktaOidc(configuration: config)
self.requestTimeout = requestTimeout
self.deviceSecretKeychain = DeviceSecretKeychain(service: keychainService, accessGroup: keychainAccessGroup)

promiseResolver(true)
} catch let error {
Expand Down Expand Up @@ -311,6 +347,15 @@ class OktaSdkBridge: RCTEventEmitter {
}

currStateManager.writeToSecureStorage()

// Only use the DeviceSecretKeychain if the response includes a "device_secret" field
if let deviceSecret = currStateManager.authState.lastTokenResponse!.additionalParameters!["device_secret"] as? String {
self.deviceSecretKeychain!.save([
"id_token": currStateManager.idToken!,
"device_secret": deviceSecret
])
}

let dic = [
OktaSdkConstant.RESOLVE_TYPE_KEY: OktaSdkConstant.AUTHORIZED,
OktaSdkConstant.ACCESS_TOKEN_KEY: stateManager?.accessToken
Expand Down
2 changes: 2 additions & 0 deletions ios/OktaSdkBridge/ReactNativeOktaSdkBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ @interface RCT_EXTERN_MODULE(OktaSdkBridge, RCTEventEmitter)
endSessionRedirectUri:(NSString *)endSessionRedirectUri
discoveryUri:(NSString *)discoveryUri
scopes:(NSString *)scopes
keychainService:(NSString *)keychainService
keychainAccessGroup:(NSString *)keychainAccessGroup
userAgentTemplate:(NSString *)userAgentTemplate
requestTimeout:(NSInteger)requestTimeout
promiseResolver:(RCTPromiseResolveBlock *)promiseResolver
Expand Down
14 changes: 7 additions & 7 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ PODS:
- ReactCommon/turbomodule/core (= 0.66.1)
- fmt (6.2.1)
- glog (0.3.5)
- OktaOidc (3.11.0):
- OktaOidc/AppAuth (= 3.11.0)
- OktaOidc/Okta (= 3.11.0)
- OktaOidc/AppAuth (3.11.0)
- OktaOidc/Okta (3.11.0):
- OktaOidc (3.11.1):
- OktaOidc/AppAuth (= 3.11.1)
- OktaOidc/Okta (= 3.11.1)
- OktaOidc/AppAuth (3.11.1)
- OktaOidc/Okta (3.11.1):
- OktaOidc/AppAuth
- RCT-Folly (2021.06.28.00-v2):
- boost
Expand Down Expand Up @@ -391,7 +391,7 @@ SPEC CHECKSUMS:
FBReactNativeSpec: 74c869e2cffa2ffec685cd1bac6788c021da6005
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 5337263514dd6f09803962437687240c5dc39aa4
OktaOidc: 7a6a9a827722b26fded69c9715e606f5abc3a3a7
OktaOidc: 94d65a417fefbdd92441a6e8b8347e2db2ea885a
RCT-Folly: a21c126816d8025b547704b777a2ba552f3d9fa9
RCTRequired: 3cc065b52aa18db729268b9bd78a2feffb4d0f91
RCTTypeSafety: 3c4fc37d5dea452d2ef17324db5504ec2f05083a
Expand Down Expand Up @@ -420,4 +420,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: f13ca5f6cbb443c84939aa83a099c537f97121fa

COCOAPODS: 1.11.2
COCOAPODS: 1.11.3
9 changes: 9 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,23 @@ describe('OktaReactNative', () => {
Platform.OS = 'ios';
Platform.Version = '1.0.0';
const processedScope = config.scopes.join(' ');

config = {
...config,
keychainService: 'Test',
keychainAccessGroup: 'com.example.SharedItems',
}
createConfig(config);

expect(mockCreateConfig).toHaveBeenCalledTimes(1);
expect(mockCreateConfig).toHaveBeenCalledWith(
config.clientId,
config.redirectUri,
config.endSessionRedirectUri,
config.discoveryUri,
processedScope,
config.keychainService,
config.keychainAccessGroup,
`okta-react-native/${version} $UPSTREAM_SDK react-native/${reactNativeVersion} ios/1.0.0`,
defaultTimeouts.httpConnectionTimeout,
);
Expand Down
2 changes: 2 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export namespace Okta {
endSessionRedirectUri: string;
discoveryUri: string;
scopes: string[];
keychainService?: string;
keychainAccessGroup?: string;
requireHardwareBackedKeyStore: boolean;
androidChromeTabColor?: string;
httpConnectionTimeout?: number;
Expand Down
2 changes: 2 additions & 0 deletions types/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ expectType<Promise<boolean>>(OktaSDK.createConfig({
endSessionRedirectUri: '{endSessionRedirectUri}',
discoveryUri: '{discoveryUri}',
scopes: ['scope1', 'scope2'],
keychainService: 'Test';
keychainAccessGroup: 'com.example.SharedItems';
requireHardwareBackedKeyStore: false,
androidChromeTabColor: '#00000',
httpConnectionTimeout: 15,
Expand Down

0 comments on commit 85ade2a

Please sign in to comment.