From a6574d510bc5c30b698cdc844d932ab211fe29bb Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 02:39:26 +0000 Subject: [PATCH] refactor: Make internal validators throwing --- Sources/Claims.swift | 37 ++++++++++++++++--------------------- Sources/Decode.swift | 13 ++++++------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/Sources/Claims.swift b/Sources/Claims.swift index 2b3f33d..61c7f65 100644 --- a/Sources/Claims.swift +++ b/Sources/Claims.swift @@ -1,53 +1,48 @@ import Foundation -func validateClaims(_ payload:Payload, audience:String?, issuer:String?) -> InvalidToken? { - return validateIssuer(payload, issuer: issuer) ?? validateAudience(payload, audience: audience) ?? - validateDate(payload, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") ?? - validateDate(payload, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") ?? - validateDate(payload, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") +func validateClaims(_ payload:Payload, audience:String?, issuer:String?) throws { + try validateIssuer(payload, issuer: issuer) + try validateAudience(payload, audience: audience) + try validateDate(payload, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") + try validateDate(payload, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") + try validateDate(payload, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") } -func validateAudience(_ payload:Payload, audience:String?) -> InvalidToken? { +func validateAudience(_ payload:Payload, audience:String?) throws { if let audience = audience { if let aud = payload["aud"] as? [String] { if !aud.contains(audience) { - return .invalidAudience + throw InvalidToken.invalidAudience } } else if let aud = payload["aud"] as? String { if aud != audience { - return .invalidAudience + throw InvalidToken.invalidAudience } } else { - return .decodeError("Invalid audience claim, must be a string or an array of strings") + throw InvalidToken.decodeError("Invalid audience claim, must be a string or an array of strings") } } - - return nil } -func validateIssuer(_ payload:Payload, issuer:String?) -> InvalidToken? { +func validateIssuer(_ payload:Payload, issuer:String?) throws { if let issuer = issuer { if let iss = payload["iss"] as? String { if iss != issuer { - return .invalidIssuer + throw InvalidToken.invalidIssuer } } else { - return .invalidIssuer + throw InvalidToken.invalidIssuer } } - - return nil } -func validateDate(_ payload:Payload, key:String, comparison:ComparisonResult, failure:InvalidToken, decodeError:String) -> InvalidToken? { +func validateDate(_ payload:Payload, key:String, comparison:ComparisonResult, failure:InvalidToken, decodeError:String) throws { if let timestamp = payload[key] as? TimeInterval ?? (payload[key] as? NSString)?.doubleValue as TimeInterval? { let date = Date(timeIntervalSince1970: timestamp) if date.compare(Date()) == comparison { - return failure + throw failure } } else if payload[key] != nil { - return .decodeError(decodeError) + throw InvalidToken.decodeError(decodeError) } - - return nil } diff --git a/Sources/Decode.swift b/Sources/Decode.swift index 4ec9642..5533e74 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -51,9 +51,8 @@ public func decode(_ jwt:String, algorithms:[Algorithm], verify:Bool = true, aud switch load(jwt) { case let .success(header, payload, signature, signatureInput): if verify { - if let failure = validateClaims(payload, audience: audience, issuer: issuer) ?? verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) { - throw failure - } + try validateClaims(payload, audience: audience, issuer: issuer) + try verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) } return payload @@ -115,17 +114,17 @@ func load(_ jwt:String) -> LoadResult { // MARK: Signature Verification -func verifySignature(_ algorithms:[Algorithm], header:Payload, signingInput:String, signature:Data) -> InvalidToken? { +func verifySignature(_ algorithms:[Algorithm], header:Payload, signingInput:String, signature:Data) throws { if let alg = header["alg"] as? String { let matchingAlgorithms = algorithms.filter { algorithm in algorithm.description == alg } let results = matchingAlgorithms.map { algorithm in algorithm.verify(signingInput, signature: signature) } let successes = results.filter { $0 } if successes.count > 0 { - return nil + return } - return .invalidAlgorithm + throw InvalidToken.invalidAlgorithm } - return .decodeError("Missing Algorithm") + throw InvalidToken.decodeError("Missing Algorithm") }