Skip to content

Commit

Permalink
Merge pull request #20 from vapor/signer-access-through-config
Browse files Browse the repository at this point in the history
Signer access through config
  • Loading branch information
tanner0101 committed Sep 13, 2017
2 parents 22897dc + ea600c3 commit 6485a7e
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 91 deletions.
55 changes: 55 additions & 0 deletions Sources/JWTProvider/Config+JWT.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import JWT
import Vapor

// MARK: Signer map access

private let jwtSignersKey = "jwt-provider:signers"

extension Config {
public internal(set) var signers: SignerMap? {
get { return storage[jwtSignersKey] as? SignerMap }
set { storage[jwtSignersKey] = newValue }
}

/// Returns the JWT signers
/// or throws an error if not properly configured
public func assertSigners() throws -> SignerMap {
guard let signers = self.signers else {
throw JWTProviderError.noJWTSigner
}

return signers
}

/// Returns the JWT signer with the supplied identifier key
public func assertSigner(kid: String) throws -> Signer {
let signers = try assertSigners()
guard let signer = signers[kid] else {
throw JWTProviderError.noJWTSigner
}
return signer
}
}

// MARK: JSON Web Key Set (JWKS) URL access

private let jwtJWKSURLKey = "jwt-provider:jwks-url"

extension Config {

/// Returns the JWKS URL
public internal(set) var jwksURL: String? {
get { return storage[jwtJWKSURLKey] as? String }
set { storage[jwtJWKSURLKey] = newValue }
}

/// Returns the JWKS URL
/// or throws an error if not properly configured
public func assertJWKSURL() throws -> String {
guard let jwksURL = jwksURL else {
throw JWTProviderError.noJWTSigner
}

return jwksURL
}
}
34 changes: 34 additions & 0 deletions Sources/JWTProvider/Deprecated/Droplet+legacySigner.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import JWT
import Vapor

extension Droplet {

/// Returns the JWT signer
@available(*, deprecated, message: "Use signers instead.")
public internal(set) var signer: Signer? {
get { return signers?.legacySigner }
set {
if let signer = newValue {
if signers != nil {
signers?.legacySigner = signer
} else {
signers = SignerMap(legacySigner: signer)
}
} else {
signers?.legacySigner = nil
}
}
}

/// Returns the main JWT signer
/// or throws an error if not properly configured
public func assertSigner() throws -> Signer {
// NB. duplicated code from `signer` is necessary
// to prevent deprecation warning
guard let signer = signers?.legacySigner else {
throw JWTProviderError.noJWTSigner
}

return signer
}
}
20 changes: 20 additions & 0 deletions Sources/JWTProvider/Deprecated/Provider+legacySigner.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import JWT
import Vapor

extension Provider {
@available(*, deprecated, message: "Use signers instead.")
public var signer: Signer {
if let legacySigner = signers?.legacySigner {
return legacySigner
} else if let signer = signers?.first?.value {
return signer
} else {
fatalError("Trying to access a legacy signer when none has been specified.")
}
}

@available(*, deprecated, message: "Use init(signers: SignerMap) instead.")
public convenience init(signer: Signer) {
self.init(signers: SignerMap(legacySigner: signer))
}
}
18 changes: 18 additions & 0 deletions Sources/JWTProvider/Deprecated/SignerMap+legacySigner.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import JWT

private let jwtLegacySignerKey = "jwt-providers:legacy-signer"

internal extension Dictionary where Key == String, Value == Signer {
internal init(legacySigner: Signer) {
self = [jwtLegacySignerKey: legacySigner]
}

var legacySigner: Signer? {
get {
return self[jwtLegacySignerKey]
}
set {
self[jwtLegacySignerKey] = newValue
}
}
}
73 changes: 20 additions & 53 deletions Sources/JWTProvider/Droplet+JWT.swift
Original file line number Diff line number Diff line change
@@ -1,81 +1,48 @@
import Vapor
// `Signer`s used to be stored on the `Droplet`'s storage.
// They have since been moved to `Config` to enable access
// to signers in `Configinitializable` objects
// (eg. `Providers`).
// This file makes sure the `Signer`s can still be accessed
// through from the Droplet.

import JWT
import Vapor

let jwtLegacySignerKey = "jwt-providers:legacy-signer"
// MARK: Signer map access (via Config)

extension Droplet {
@available(*, deprecated, message: "Use signers instead.")
public internal(set) var signer: Signer? {
get { return self.signers?[jwtLegacySignerKey] }
set {
if let signer = newValue {

if self.signers != nil {
self.signers?[jwtLegacySignerKey] = signer
} else {
self.signers = [jwtLegacySignerKey: signer]
}
} else {
self.signers?[jwtLegacySignerKey] = nil
}
}
}

/// Returns the JWT signer
/// or throws an error if not properly configured
@available(*, deprecated, message: "Use assertSigner(kid:) or assertSigners() instead.")
public func assertSigner() throws -> Signer {
guard let signer = self.signer else {
throw JWTProviderError.noJWTSigner
}

return signer
}
}

private let jwtSignersKey = "jwt-provider:signers"

extension Droplet {
/// Returns the JWT signers
public internal(set) var signers: SignerMap? {
get { return storage[jwtSignersKey] as? SignerMap }
set { storage[jwtSignersKey] = newValue }
get { return config.signers }
set { config.signers = newValue }
}

/// Returns the JWT signers
/// or throws an error if not properly configured
public func assertSigners() throws -> SignerMap {
guard let signers = self.signers else {
throw JWTProviderError.noJWTSigner
}

return signers
return try config.assertSigners()
}

/// Returns the JWT signer with the supplied identifier key
public func assertSigner(kid: String) throws -> Signer {
let signers = try assertSigners()
guard let signer = signers[kid] else {
throw JWTProviderError.noJWTSigner
}
return signer
return try config.assertSigner(kid: kid)
}
}

private let jwtJWKSURLKey = "jwt-provider:jwks-url"
// MARK: JSON Web Key Set (JWKS) URL access (via Config)

extension Droplet {

/// Returns the JWKS URL
public internal(set) var jwksURL: String? {
get { return storage[jwtJWKSURLKey] as? String }
set { storage[jwtJWKSURLKey] = newValue }
get { return config.jwksURL }
set { config.jwksURL = newValue }
}

/// Returns the JWKS URL
/// or throws an error if not properly configured
public func assertJWKSURL() throws -> String {
guard let jwksURL = self.jwksURL else {
throw JWTProviderError.noJWTSigner
}

return jwksURL
return try config.assertJWKSURL()
}
}
4 changes: 2 additions & 2 deletions Sources/JWTProvider/PayloadAuthenticationMiddleware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public final class PayloadAuthenticationMiddleware<U: PayloadAuthenticatable>: M
_ claims: [Claim] = [],
_ userType: U.Type = U.self
) {
self.signers = [jwtLegacySignerKey: signer]
self.signers = SignerMap(legacySigner: signer)
self.claims = claims
self.jwksURL = nil
self.clientFactory = nil
Expand Down Expand Up @@ -81,7 +81,7 @@ public final class PayloadAuthenticationMiddleware<U: PayloadAuthenticatable>: M
// based on kid
private func signer(for jwt: JWT) throws -> Signer {

if let legacySigner = self.signers[jwtLegacySignerKey] {
if let legacySigner = signers.legacySigner {
// Legacy signer, ignore any kid
return legacySigner
}
Expand Down
39 changes: 7 additions & 32 deletions Sources/JWTProvider/Provider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,14 @@ import JWT
/// Adds required JWT objects to your application
/// like token Signers
public final class Provider: Vapor.Provider {

public static let repositoryName = "jwt-provider"

@available(*, deprecated, message: "Use signers instead.")
public var signer: Signer {

if let legacySigner = self.signers?[jwtLegacySignerKey] {
return legacySigner
} else if let signer = self.signers?.first?.value {
return signer
} else {
fatalError("Trying to access a legacy signer when none has been specified.")
}
}

public let signers: SignerMap?

public let jwksURL: String?

@available(*, deprecated, message: "Use init(signers: SignerMap) instead.")
public init(signer: Signer) {
self.signers = [jwtLegacySignerKey: signer]
self.jwksURL = nil
}
public let signers: SignerMap?

public init(signers: SignerMap) {
self.signers = signers
self.jwksURL = nil
self.signers = signers
}

public init(jwksURL: String) {
Expand All @@ -55,17 +35,12 @@ public final class Provider: Vapor.Provider {
}
}

public func boot(_ config: Config) throws { }

/// Called to prepare the Droplet.
public func boot(_ drop: Droplet) {
drop.signers = self.signers
drop.jwksURL = self.jwksURL
public func boot(_ config: Config) throws {
config.signers = signers
config.jwksURL = jwksURL
}

/// Called before the Droplet begins serving
/// which is @noreturn.
public func beforeRun(_ drop: Droplet) {
public func boot(_ drop: Droplet) throws { }

}
public func beforeRun(_ drop: Droplet) { }
}
1 change: 0 additions & 1 deletion Sources/JWTProvider/SignerFactory.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Foundation
import JWT

public protocol SignerFactory {
Expand Down
4 changes: 2 additions & 2 deletions Sources/JWTProvider/SignerMap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public extension Dictionary where Key == String, Value == Signer {
throw SignerMapError.missingKey("keys")
}

var map = [String: Signer]()
var map = SignerMap()

for key in keys {

Expand Down Expand Up @@ -50,7 +50,7 @@ public extension Dictionary where Key == String, Value == Signer {
// Legacy
let signer = try JWTConfigSignerFactory(signerConfig: signerConfig).makeSigner()

self = [jwtLegacySignerKey: signer]
self = SignerMap(legacySigner: signer)

} else {
return nil
Expand Down
2 changes: 1 addition & 1 deletion Tests/JWTProviderTests/ProviderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ProviderTests: XCTestCase {
let drop = try Droplet(config: config, middleware: [])

XCTAssertNotNil(drop.signers)
XCTAssertNotNil(drop.signers?[jwtLegacySignerKey])
XCTAssertNotNil(drop.signers?.legacySigner)
XCTAssertNil(drop.jwksURL)
}

Expand Down

0 comments on commit 6485a7e

Please sign in to comment.