Skip to content

Commit

Permalink
Updated Credentials Manager
Browse files Browse the repository at this point in the history
Renamed Touch Internals -> BioAuthentication
Deprecated enableTouchAuth method -> enableBiometricAuth for clarity
Expand README Docs
Update Circle CI Xcode Version
SwiftLint Corrections
  • Loading branch information
cocojoe committed Dec 20, 2017
1 parent 092bc40 commit c94d77e
Show file tree
Hide file tree
Showing 16 changed files with 78 additions and 50 deletions.
16 changes: 8 additions & 8 deletions Auth0.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
5B5E93F91EC45C22002A37F9 /* CredentialsManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5E93F81EC45C22002A37F9 /* CredentialsManagerError.swift */; };
5B6269E71E3F702000305093 /* NativeAuthSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6269E51E3F700000305093 /* NativeAuthSpec.swift */; };
5B6269EA1E3F9E5200305093 /* AuthProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6269E91E3F9E5200305093 /* AuthProvider.swift */; };
5B9262C01ECF0CA800F4F6D3 /* TouchAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9262BF1ECF0CA800F4F6D3 /* TouchAuthentication.swift */; };
5B9262C31ECF0CC200F4F6D3 /* TouchAuthenticationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9262C11ECF0CBA00F4F6D3 /* TouchAuthenticationSpec.swift */; };
5B9262C01ECF0CA800F4F6D3 /* BioAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9262BF1ECF0CA800F4F6D3 /* BioAuthentication.swift */; };
5B9262C31ECF0CC200F4F6D3 /* BioAuthenticationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9262C11ECF0CBA00F4F6D3 /* BioAuthenticationSpec.swift */; };
5BD4A9CE1DEC6EFA00D6D7AE /* ResponseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD4A9CD1DEC6EFA00D6D7AE /* ResponseType.swift */; };
5BE65DCA1F7270DE00CADD3B /* Auth0.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5F06DD781CC448B10011842B /* Auth0.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5BEDE1571EC1FBBE0007300D /* SilentSafariViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BEDE1561EC1FBBE0007300D /* SilentSafariViewController.swift */; };
Expand Down Expand Up @@ -328,8 +328,8 @@
5B5E93F81EC45C22002A37F9 /* CredentialsManagerError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialsManagerError.swift; sourceTree = "<group>"; };
5B6269E51E3F700000305093 /* NativeAuthSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NativeAuthSpec.swift; path = Auth0Tests/NativeAuthSpec.swift; sourceTree = SOURCE_ROOT; };
5B6269E91E3F9E5200305093 /* AuthProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AuthProvider.swift; path = Auth0/AuthProvider.swift; sourceTree = SOURCE_ROOT; };
5B9262BF1ECF0CA800F4F6D3 /* TouchAuthentication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchAuthentication.swift; sourceTree = "<group>"; };
5B9262C11ECF0CBA00F4F6D3 /* TouchAuthenticationSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TouchAuthenticationSpec.swift; path = Auth0Tests/TouchAuthenticationSpec.swift; sourceTree = SOURCE_ROOT; };
5B9262BF1ECF0CA800F4F6D3 /* BioAuthentication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BioAuthentication.swift; sourceTree = "<group>"; };
5B9262C11ECF0CBA00F4F6D3 /* BioAuthenticationSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BioAuthenticationSpec.swift; path = Auth0Tests/BioAuthenticationSpec.swift; sourceTree = SOURCE_ROOT; };
5B9A54411E49E3AE004B5454 /* Auth0.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Auth0.plist; sourceTree = SOURCE_ROOT; };
5BD4A9CD1DEC6EFA00D6D7AE /* ResponseType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ResponseType.swift; path = Auth0/ResponseType.swift; sourceTree = SOURCE_ROOT; };
5BEDE1561EC1FBBE0007300D /* SilentSafariViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SilentSafariViewController.swift; path = Auth0/SilentSafariViewController.swift; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -535,7 +535,7 @@
isa = PBXGroup;
children = (
5B1748731EF2D3A40060E653 /* Date.swift */,
5B9262BF1ECF0CA800F4F6D3 /* TouchAuthentication.swift */,
5B9262BF1ECF0CA800F4F6D3 /* BioAuthentication.swift */,
5BEDE1891EC21B040007300D /* CredentialsManager.swift */,
5B5E93F81EC45C22002A37F9 /* CredentialsManagerError.swift */,
);
Expand Down Expand Up @@ -747,7 +747,7 @@
5FBBF0331CC95FA40024D2AF /* Utils */ = {
isa = PBXGroup;
children = (
5B9262C11ECF0CBA00F4F6D3 /* TouchAuthenticationSpec.swift */,
5B9262C11ECF0CBA00F4F6D3 /* BioAuthenticationSpec.swift */,
5BEDE1931EC3331A0007300D /* CredentialsManagerSpec.swift */,
5FBBF0371CC964BC0024D2AF /* Matchers.swift */,
5FBBF03A1CC96AA70024D2AF /* Responses.swift */,
Expand Down Expand Up @@ -1353,7 +1353,7 @@
5FDE87651D8A424700EA27DC /* Profile.swift in Sources */,
5FE2F8B21CCEAED8003628F4 /* Requestable.swift in Sources */,
5F7504F51D8C3F2900E3BA1C /* NSError+Helper.swift in Sources */,
5B9262C01ECF0CA800F4F6D3 /* TouchAuthentication.swift in Sources */,
5B9262C01ECF0CA800F4F6D3 /* BioAuthentication.swift in Sources */,
5FADB60C1CED7E0800D4BB50 /* UserPatchAttributes.swift in Sources */,
5FCAB1791D09124D00331C84 /* NSURL+Auth0.swift in Sources */,
5F74CB401CEFD5E600226823 /* JSONObjectPayload.swift in Sources */,
Expand Down Expand Up @@ -1422,7 +1422,7 @@
5FCAB16A1D07AC3500331C84 /* ChallengeGeneratorSpec.swift in Sources */,
5FADB60F1CED7E5200D4BB50 /* UserPatchAttributesSpec.swift in Sources */,
5FA250541D4A85A200C544FA /* WebAuthErrorSpec.swift in Sources */,
5B9262C31ECF0CC200F4F6D3 /* TouchAuthenticationSpec.swift in Sources */,
5B9262C31ECF0CC200F4F6D3 /* BioAuthenticationSpec.swift in Sources */,
5FBBF0381CC964BC0024D2AF /* Matchers.swift in Sources */,
5F93BC0B1CC6B0DE0031519F /* Auth0Spec.swift in Sources */,
5FE2F8A61CCA9C17003628F4 /* CredentialsSpec.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Auth0/Auth0Authentication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ struct Auth0Authentication: Authentication {
return Request(session: session, url: oauthToken, method: "POST", handle: noBody, payload: payload, logger: self.logger, telemetry: self.telemetry)
}

func delegation(withParameters parameters: [String : Any]) -> Request<[String : Any], AuthenticationError> {
func delegation(withParameters parameters: [String: Any]) -> Request<[String: Any], AuthenticationError> {
var payload: [String: Any] = [
"client_id": self.clientId,
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer"
Expand Down
2 changes: 1 addition & 1 deletion Auth0/AuthenticationError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ extension AuthenticationError: CustomNSError {
public static let infoKey = "com.auth0.authentication.error.info"
public static var errorDomain: String { return "com.auth0.authentication" }
public var errorCode: Int { return 1 }
public var errorUserInfo: [String : Any] {
public var errorUserInfo: [String: Any] {
return [
NSLocalizedDescriptionKey: self.description,
AuthenticationError.infoKey: self
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// TouchAuthentication.swift
// BioAuthentication.swift
//
// Copyright (c) 2017 Auth0 (http://auth0.com)
//
Expand All @@ -23,7 +23,7 @@
import Foundation
import LocalAuthentication

struct TouchAuthentication {
struct BioAuthentication {

private let authContext: LAContext

Expand All @@ -50,7 +50,7 @@ struct TouchAuthentication {
self.fallbackTitle = fallbackTitle
}

func requireTouch(callback: @escaping (Error?) -> Void) {
func validateBiometric(callback: @escaping (Error?) -> Void) {
self.authContext.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: self.title) {
guard $1 == nil else { return callback($1) }
callback($0 ? nil : LAError(LAError.authenticationFailed))
Expand Down
28 changes: 20 additions & 8 deletions Auth0/CredentialsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public struct CredentialsManager {
private let storage = A0SimpleKeychain()
private let storeKey = "credentials"
private let authentication: Authentication
private var touchAuth: TouchAuthentication?
private var bioAuth: BioAuthentication?

/// Creates a new CredentialsManager instance
///
Expand All @@ -40,14 +40,25 @@ public struct CredentialsManager {
self.authentication = authentication
}

/// Enable TouchID Authentication for additional securtity during credentials retrieval.
/// Enable Face ID / Touch ID Authentication for additional securtity during credentials retrieval.
///
/// - Parameters:
/// - title: main message to display in TouchID prompt
/// - cancelTitle: cancel message to display in TouchID prompt (iOS 10+)
/// - fallbackTitle: fallback message to display in TouchID prompt after a failed match
@available(*, deprecated, message: "see enableBioAuth(withTitle title:, cancelTitle:, fallbackTitle:)")
public mutating func enableTouchAuth(withTitle title: String, cancelTitle: String? = nil, fallbackTitle: String? = nil) {
self.touchAuth = TouchAuthentication(authContext: LAContext(), title: title, cancelTitle: cancelTitle, fallbackTitle: fallbackTitle)
self.bioAuth = BioAuthentication(authContext: LAContext(), title: title, cancelTitle: cancelTitle, fallbackTitle: fallbackTitle)
}

/// Enable Device Biometric Authentication for additional securtity during credentials retrieval.
///
/// - Parameters:
/// - title: main message to display in TouchID prompt
/// - cancelTitle: cancel message to display in TouchID prompt (iOS 10+)
/// - fallbackTitle: fallback message to display in TouchID prompt after a failed match
public mutating func enableBiometricAuth(withTitle title: String, cancelTitle: String? = nil, fallbackTitle: String? = nil) {
self.bioAuth = BioAuthentication(authContext: LAContext(), title: title, cancelTitle: cancelTitle, fallbackTitle: fallbackTitle)
}

/// Store credentials instance in keychain
Expand All @@ -70,7 +81,7 @@ public struct CredentialsManager {
/// - Returns: if there are valid and non-expired credentials stored
public func hasValid() -> Bool {
guard
let data = self.storage.data(forKey:self.storeKey),
let data = self.storage.data(forKey: self.storeKey),
let credentials = NSKeyedUnarchiver.unarchiveObject(with: data) as? Credentials,
credentials.accessToken != nil,
let expiresIn = credentials.expiresIn
Expand All @@ -96,9 +107,10 @@ public struct CredentialsManager {
/// - Important: This method only works for a refresh token obtained after auth with OAuth 2.0 API Authorization.
/// - Note: [Auth0 Refresh Tokens Docs](https://auth0.com/docs/tokens/refresh-token)
public func credentials(withScope scope: String? = nil, callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
if let touchAuth = self.touchAuth {
guard touchAuth.available else { return callback(.touchFailed(LAError(LAError.touchIDNotAvailable)), nil) }
touchAuth.requireTouch {
guard self.hasValid() else { return callback(.noCredentials, nil) }
if let bioAuth = self.bioAuth {
guard bioAuth.available else { return callback(.touchFailed(LAError(LAError.touchIDNotAvailable)), nil) }
bioAuth.validateBiometric {
guard $0 == nil else {
return callback(.touchFailed($0!), nil)
}
Expand All @@ -111,7 +123,7 @@ public struct CredentialsManager {

private func retrieveCredentials(withScope scope: String? = nil, callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
guard
let data = self.storage.data(forKey:self.storeKey),
let data = self.storage.data(forKey: self.storeKey),
let credentials = NSKeyedUnarchiver.unarchiveObject(with: data) as? Credentials
else { return callback(.noCredentials, nil) }
guard let expiresIn = credentials.expiresIn else { return callback(.noCredentials, nil) }
Expand Down
2 changes: 1 addition & 1 deletion Auth0/Identity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class Identity: NSObject, JSONObjectPayload {
self.accessTokenSecret = accessTokenSecret
}

@objc convenience public required init?(json: [String : Any]) {
@objc convenience public required init?(json: [String: Any]) {

guard
let identifier = json["user_id"] as? String,
Expand Down
2 changes: 1 addition & 1 deletion Auth0/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct DefaultLogger: Logger {
request.allHTTPHeaderFields?.forEach { key, value in output.log(message: "\(key): \(value)") }
if let data = request.httpBody, let string = String(data: data, encoding: .utf8) {
output.newLine()
output.log(message:string)
output.log(message: string)
}
output.newLine()
}
Expand Down
2 changes: 1 addition & 1 deletion Auth0/ManagementError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ extension ManagementError: CustomNSError {
public static let infoKey = "com.auth0.management.error.info"
public static var errorDomain: String { return "com.auth0.management" }
public var errorCode: Int { return 1 }
public var errorUserInfo: [String : Any] {
public var errorUserInfo: [String: Any] {
return [
NSLocalizedDescriptionKey: self.description,
ManagementError.infoKey: self
Expand Down
12 changes: 6 additions & 6 deletions Auth0/OAuth2Grant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protocol OAuth2Grant {

struct ImplicitGrant: OAuth2Grant {

let defaults: [String : String]
let defaults: [String: String]
let responseType: [ResponseType]

init(responseType: [ResponseType] = [.token], nonce: String? = nil) {
Expand All @@ -42,7 +42,7 @@ struct ImplicitGrant: OAuth2Grant {
}
}

func credentials(from values: [String : String], callback: @escaping (Result<Credentials>) -> Void) {
func credentials(from values: [String: String], callback: @escaping (Result<Credentials>) -> Void) {
guard validate(responseType: self.responseType, token: values["id_token"], nonce: self.defaults["nonce"]) else {
return callback(.failure(error: WebAuthError.invalidIdTokenNonce))
}
Expand All @@ -51,10 +51,10 @@ struct ImplicitGrant: OAuth2Grant {
return callback(.failure(error: WebAuthError.missingAccessToken))
}

callback(.success(result: Credentials(json: values as [String : Any])))
callback(.success(result: Credentials(json: values as [String: Any])))
}

func values(fromComponents components: URLComponents) -> [String : String] {
func values(fromComponents components: URLComponents) -> [String: String] {
return components.a0_fragmentValues
}

Expand All @@ -64,7 +64,7 @@ struct PKCE: OAuth2Grant {

let authentication: Authentication
let redirectURL: URL
let defaults: [String : String]
let defaults: [String: String]
let verifier: String
let responseType: [ResponseType]

Expand Down Expand Up @@ -114,7 +114,7 @@ struct PKCE: OAuth2Grant {
}
}

func values(fromComponents components: URLComponents) -> [String : String] {
func values(fromComponents components: URLComponents) -> [String: String] {
var items = components.a0_fragmentValues
components.a0_queryValues.forEach { items[$0] = $1 }
return items
Expand Down
2 changes: 1 addition & 1 deletion Auth0/SafariAuthenticationCallback.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class SafariAuthenticationSessionCallback: AuthTransaction {
self.authSession?.start()
}

func resume(_ url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
func resume(_ url: URL, options: [UIApplicationOpenURLOptionsKey: Any]) -> Bool {
self.callback(true)
return true
}
Expand Down
2 changes: 1 addition & 1 deletion Auth0/WebAuthError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public enum WebAuthError: CustomNSError {
}
}

public var errorUserInfo: [String : Any] {
public var errorUserInfo: [String: Any] {
switch self {
case .userCancelled:
return [
Expand Down
2 changes: 1 addition & 1 deletion Auth0/_ObjectiveManagementAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public class _ObjectiveManagementAPI: NSObject {
@objc(unlinkUserWithIdentifier:provider:fromUserId:callback:)
public func unlink(identifier: String, provider: String, fromUserId userId: String, callback: @escaping (NSError?, [[String: Any]]?) -> Void) {
self.users
.unlink(identityId: identifier, provider: provider, fromUserId:userId)
.unlink(identityId: identifier, provider: provider, fromUserId: userId)
.start { result in
switch result {
case .success(let payload):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// TouchAuthenticationSpec.swift
// BioAuthenticationSpec.swift
//
// Copyright (c) 2016 Auth0 (http://auth0.com)
//
Expand Down Expand Up @@ -27,41 +27,41 @@ import LocalAuthentication

@testable import Auth0

class TouchAuthenticationSpec: QuickSpec {
class BioAuthenticationSpec: QuickSpec {

override func spec() {

var mockContext: MockLAContext!
var touchAuthentication: TouchAuthentication!
var bioAuthentication: BioAuthentication!

beforeEach {
mockContext = MockLAContext()
touchAuthentication = TouchAuthentication(authContext: mockContext, title: "Touch Auth")
bioAuthentication = BioAuthentication(authContext: mockContext, title: "Touch Auth")
}

describe("touch availablility") {

it("touch should be enabled") {
expect(touchAuthentication.available).to(beTrue())
expect(bioAuthentication.available).to(beTrue())
}

it("touch should be disabled") {
mockContext.enabled = false
expect(touchAuthentication.available).to(beFalse())
expect(bioAuthentication.available).to(beFalse())
}
}

describe("setters") {

if #available(iOS 10, *) {
it("should set cancel title") {
touchAuthentication.cancelTitle = "cancel title"
bioAuthentication.cancelTitle = "cancel title"
expect(mockContext.localizedCancelTitle) == "cancel title"
}
}

it("should set fallback title") {
touchAuthentication.fallbackTitle = "fallback title"
bioAuthentication.fallbackTitle = "fallback title"
expect(mockContext.localizedFallbackTitle) == "fallback title"
}
}
Expand All @@ -74,21 +74,21 @@ class TouchAuthenticationSpec: QuickSpec {
}

it("should authenticate") {
touchAuthentication.requireTouch { error = $0 }
bioAuthentication.validateBiometric { error = $0 }
expect(error).toEventually(beNil())
}

it("should return error on touch authentication") {
let touchError = LAError(.appCancel)
mockContext.replyError = touchError
touchAuthentication.requireTouch { error = $0 }
bioAuthentication.validateBiometric { error = $0 }
expect(error).toEventually(matchError(touchError))
}

it("should return authenticationFailed error if no policy success") {
let touchError = LAError(.authenticationFailed)
mockContext.replySuccess = false
touchAuthentication.requireTouch { error = $0 }
bioAuthentication.validateBiometric { error = $0 }
expect(error).toEventually(matchError(touchError))
}

Expand Down
Loading

0 comments on commit c94d77e

Please sign in to comment.