From 66b357f194dfff476d6b8c8487b47b456bd23edc Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 5 Apr 2015 00:35:02 +0100 Subject: [PATCH] [verify] Support iat claims --- JWT/JWT.swift | 16 ++++++++++++++-- JWTTests/JWTTests.swift | 23 ++++++++++++++++++++++- README.md | 1 + 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/JWT/JWT.swift b/JWT/JWT.swift index 90e54c5..0e5de7e 100644 --- a/JWT/JWT.swift +++ b/JWT/JWT.swift @@ -7,6 +7,7 @@ public enum InvalidToken : Printable { case InvalidIssuer case ExpiredSignature case ImmatureSignature + case InvalidIssuedAt public var description:String { switch self { @@ -18,6 +19,8 @@ public enum InvalidToken : Printable { return "Expired Signature" case .ImmatureSignature: return "The token is not yet valid (not before claim)" + case .InvalidIssuedAt: + return "Issued at claim (iat) is in the future" } } } @@ -129,13 +132,22 @@ func validateClaims(payload:Payload, audience:String?, issuer:String?) -> Invali } if let nbf = payload["nbf"] as? NSTimeInterval { - let expiary = NSDate(timeIntervalSince1970: nbf) - if expiary.compare(NSDate()) == .OrderedDescending { + let date = NSDate(timeIntervalSince1970: nbf) + if date.compare(NSDate()) == .OrderedDescending { return .ImmatureSignature } } else if let nbf:AnyObject = payload["nbf"] { return .DecodeError("Not before claim (nbf) must be an integer") } + if let iat = payload["iat"] as? NSTimeInterval { + let date = NSDate(timeIntervalSince1970: iat) + if date.compare(NSDate()) == .OrderedDescending { + return .InvalidIssuedAt + } + } else if let iat:AnyObject = payload["iat"] { + return .DecodeError("Issued at claim (iat) must be an integer") + } + return nil } diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index ff03617..c04a015 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -78,6 +78,27 @@ class JWTDecodeTests : XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" assertFailure(decode(jwt)) } + + // MARK: Issued at claim + + func testIssuedAtClaimInThePast() { + let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.hXBPQvdi9G5Kb5ySZUzAukYsP9wyBF172eTP9gNF9sg" + assertSuccess(decode(jwt)) { payload in + XCTAssertEqual(payload as NSDictionary, ["iat": 1428189720]) + } + } + + func testIssuedAtClaimInTheFuture() { + // If this just started failing, hello 2024! + let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" + assertFailure(decode(jwt)) + } + + func testInvalidIssuedAtClaim() { + // If this just started failing, hello 2024! + let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOlsxNzI4MTg4NDkxXX0.ND7QMWtLkXDXH38OaXM3SQgLo3Z5TNgF_pcfWHV_alQ" + assertDecodeError(decode(jwt), "Issued at claim (iat) must be an integer") + } } // MARK: Helpers @@ -114,7 +135,7 @@ func assertDecodeError(result:DecodeResult, error:String) { XCTFail("Incorrect decode error \(decodeError) != \(error)") } default: - XCTFail("Failure for the wrong reason") + XCTFail("Failure for the wrong reason \(failure)") } } } diff --git a/README.md b/README.md index 2d86d5b..1df360d 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E - Issuer (`iss`) Claim - Expiration Time (`exp`) Claim - Not Before (`nbf`) Claim +- Issued At (`iat`) Claim ## License