diff --git a/README.md b/README.md index c868119..481807f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Authentication framework and extensions for Hummingbird server framework. -Includes Authenticator middleware setup, bearer, basic authentication extraction from your Request headers, Bcrypt encryption for passwords. +Includes authentication and session middleware, bearer, basic authentication extraction from your Request headers, Bcrypt encryption for passwords. ## Documentation diff --git a/Sources/HummingbirdAuth/Authenticator/AuthRequestContext.swift b/Sources/HummingbirdAuth/Authenticator/AuthRequestContext.swift index 31f2d60..aff451c 100644 --- a/Sources/HummingbirdAuth/Authenticator/AuthRequestContext.swift +++ b/Sources/HummingbirdAuth/Authenticator/AuthRequestContext.swift @@ -18,19 +18,19 @@ import NIOCore /// Protocol that all request contexts should conform to if they want to support /// authentication middleware -public protocol HBAuthRequestContext: HBRequestContext { +public protocol AuthRequestContext: RequestContext { /// Login cache - var auth: HBLoginCache { get set } + var auth: LoginCache { get set } } /// Implementation of a basic request context that supports everything the Hummingbird library needs -public struct HBBasicAuthRequestContext: HBAuthRequestContext { +public struct BasicAuthRequestContext: AuthRequestContext { /// core context - public var coreContext: HBCoreRequestContext + public var coreContext: CoreRequestContext /// Login cache - public var auth: HBLoginCache + public var auth: LoginCache - /// Initialize an `HBRequestContext` + /// Initialize an `RequestContext` /// - Parameters: /// - applicationContext: Context from Application that instigated the request /// - channel: Channel that generated this request diff --git a/Sources/HummingbirdAuth/Authenticator/Authenticator.swift b/Sources/HummingbirdAuth/Authenticator/Authenticator.swift index f5a6460..b4b343d 100644 --- a/Sources/HummingbirdAuth/Authenticator/Authenticator.swift +++ b/Sources/HummingbirdAuth/Authenticator/Authenticator.swift @@ -15,8 +15,8 @@ import Hummingbird import NIOCore -/// Protocol for objects that can be returned by an `HBAuthenticator`. -public protocol HBAuthenticatable: Sendable {} +/// Protocol for objects that can be returned by an `AuthenticatorMiddleware`. +public protocol Authenticatable: Sendable {} /// Protocol for a middleware that checks if a request is authenticated. /// @@ -26,15 +26,15 @@ public protocol HBAuthenticatable: Sendable {} /// run then throw an error. /// /// To use an authenticator middleware it is required that your request context conform to -/// ``HBAuthRequestContext`` so the middleware can attach authentication data to -/// ``HBAuthRequestContext/auth``. +/// ``AuthRequestContext`` so the middleware can attach authentication data to +/// ``AuthRequestContext/auth``. /// /// A simple username, password authenticator could be implemented as follows. If the /// authenticator is successful it returns a `User` struct, otherwise it returns `nil`. /// /// ```swift -/// struct BasicAuthenticator: HBAuthenticator { -/// func authenticate(request: HBRequest, context: Context) async throws -> User? { +/// struct BasicAuthenticator: AuthenticatorMiddleware { +/// func authenticate(request: Request, context: Context) async throws -> User? { /// // Basic authentication info in the "Authorization" header, is accessible /// // via request.headers.basic /// guard let basic = request.headers.basic else { return nil } @@ -55,20 +55,20 @@ public protocol HBAuthenticatable: Sendable {} /// } /// } /// ``` -public protocol HBAuthenticator: HBMiddlewareProtocol where Context: HBAuthRequestContext { +public protocol AuthenticatorMiddleware: RouterMiddleware where Context: AuthRequestContext { /// type to be authenticated - associatedtype Value: HBAuthenticatable + associatedtype Value: Authenticatable /// Called by middleware to see if request can authenticate. /// /// Should return an authenticatable object if authenticated, return nil is not authenticated /// but want the request to be passed onto the next middleware or the router, or throw an error /// if the request should not proceed any further - func authenticate(request: HBRequest, context: Context) async throws -> Value? + func authenticate(request: Request, context: Context) async throws -> Value? } -extension HBAuthenticator { +extension AuthenticatorMiddleware { /// Calls `authenticate` and if it returns a valid authenticatable object `login` with this object - public func handle(_ request: HBRequest, context: Context, next: (HBRequest, Context) async throws -> HBResponse) async throws -> HBResponse { + public func handle(_ request: Request, context: Context, next: (Request, Context) async throws -> Response) async throws -> Response { if let authenticated = try await authenticate(request: request, context: context) { var context = context context.auth.login(authenticated) diff --git a/Sources/HummingbirdAuth/Authenticator/LoginCache.swift b/Sources/HummingbirdAuth/Authenticator/LoginCache.swift index 420e2bd..621c06f 100644 --- a/Sources/HummingbirdAuth/Authenticator/LoginCache.swift +++ b/Sources/HummingbirdAuth/Authenticator/LoginCache.swift @@ -14,43 +14,43 @@ import Hummingbird -public struct HBLoginCache: Sendable { +public struct LoginCache: Sendable { public init() { self.cache = [:] } /// Login with authenticatable object. Add object to cache /// - Parameter auth: authentication details - public mutating func login(_ auth: Auth) { + public mutating func login(_ auth: Auth) { self.cache = [ObjectIdentifier(Auth.self): auth] } /// Logout authenticatable object. Removes object from cache /// - Parameter auth: authentication type - public mutating func logout(_: Auth.Type) { + public mutating func logout(_: Auth.Type) { self.cache[ObjectIdentifier(Auth.self)] = nil } /// Return authenticated type /// - Parameter auth: Type required - public func get(_: Auth.Type) -> Auth? { + public func get(_: Auth.Type) -> Auth? { return self.cache[ObjectIdentifier(Auth.self)] as? Auth } /// Require authenticated type /// - Parameter auth: Type required - public func require(_: Auth.Type) throws -> Auth { + public func require(_: Auth.Type) throws -> Auth { guard let auth = get(Auth.self) else { - throw HBHTTPError(.unauthorized) + throw HTTPError(.unauthorized) } return auth } /// Return if cache is authenticated with type /// - Parameter auth: Authentication type - public func has(_: Auth.Type) -> Bool { + public func has(_: Auth.Type) -> Bool { return self.cache[ObjectIdentifier(Auth.self)] != nil } - var cache: [ObjectIdentifier: HBAuthenticatable] + var cache: [ObjectIdentifier: Authenticatable] } diff --git a/Sources/HummingbirdAuth/Deprecated.swift b/Sources/HummingbirdAuth/Deprecated.swift new file mode 100644 index 0000000..a8590f6 --- /dev/null +++ b/Sources/HummingbirdAuth/Deprecated.swift @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Hummingbird server framework project +// +// Copyright (c) 2024 the Hummingbird authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +// Below is a list of deprecated symbols with the "HB" prefix. These are available +// temporarily to ease transition from the old symbols that included the "HB" +// prefix to the new ones. +// +// This file will be removed before we do a 2.0 release + +@_documentation(visibility: internal) @available(*, deprecated, renamed: "AuthRequestContext") +public typealias HBAuthRequestContext = AuthRequestContext +@_documentation(visibility: internal) @available(*, deprecated, renamed: "BasicAuthRequestContext") +public typealias HBBasicAuthRequestContext = BasicAuthRequestContext +@_documentation(visibility: internal) @available(*, deprecated, renamed: "LoginCache") +public typealias HBLoginCache = LoginCache + +@_documentation(visibility: internal) @available(*, deprecated, renamed: "Authenticatable") +public typealias HBAuthenticatable = Authenticatable +@_documentation(visibility: internal) @available(*, deprecated, renamed: "AuthenticatorMiddleware") +public typealias HBAuthenticator = AuthenticatorMiddleware +@_documentation(visibility: internal) @available(*, deprecated, renamed: "SessionMiddleware") +public typealias HBSessionAuthenticator = SessionMiddleware +@_documentation(visibility: internal) @available(*, deprecated, renamed: "SessionStorage") +public typealias HBSessionStorage = SessionStorage diff --git a/Sources/HummingbirdAuth/Middleware/IsAuthenticateMiddleware.swift b/Sources/HummingbirdAuth/Middleware/IsAuthenticateMiddleware.swift index 4e57a1e..9ae64f6 100644 --- a/Sources/HummingbirdAuth/Middleware/IsAuthenticateMiddleware.swift +++ b/Sources/HummingbirdAuth/Middleware/IsAuthenticateMiddleware.swift @@ -15,10 +15,10 @@ import Hummingbird /// Middleware returning 404 for unauthenticated requests -public struct IsAuthenticatedMiddleware: HBMiddlewareProtocol { +public struct IsAuthenticatedMiddleware: RouterMiddleware { public init(_: Auth.Type) {} - public func handle(_ request: HBRequest, context: Context, next: (HBRequest, Context) async throws -> HBResponse) async throws -> HBResponse { guard context.auth.has(Auth.self) else { throw HBHTTPError(.unauthorized) } + public func handle(_ request: Request, context: Context, next: (Request, Context) async throws -> Response) async throws -> Response { guard context.auth.has(Auth.self) else { throw HTTPError(.unauthorized) } return try await next(request, context) } } diff --git a/Sources/HummingbirdAuth/OTP/OTP.swift b/Sources/HummingbirdAuth/OTP/OTP.swift index 49505c6..44d7bff 100644 --- a/Sources/HummingbirdAuth/OTP/OTP.swift +++ b/Sources/HummingbirdAuth/OTP/OTP.swift @@ -2,7 +2,7 @@ // // This source file is part of the Hummingbird server framework project // -// Copyright (c) 2021-2021 the Hummingbird authors +// Copyright (c) 2021-2024 the Hummingbird authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -41,7 +41,7 @@ protocol OTP { } extension OTP { - /// Create Authenticator URL for OTP generator + /// Create authenticator URL for OTP generator /// /// - Parameters: /// - algorithmName: Name of algorithm @@ -104,7 +104,7 @@ public struct HOTP: OTP, Sendable { /// Initialize HOTP /// - /// If you are using the Google Authenticator you should choose the default values for length and hashFunction + /// If you are using the Google AuthenticatorMiddleware you should choose the default values for length and hashFunction /// /// - Parameters: /// - secret: Secret known by client and server @@ -124,9 +124,9 @@ public struct HOTP: OTP, Sendable { self.compute(message: counter.bigEndian.bytes) } - /// Create Authenticator URL for HOTP generator + /// Create AuthenticatorMiddleware URL for HOTP generator /// - /// OTP is used commonly with authenticator apps on the phone. The Authenticator apps require your + /// OTP is used commonly with authenticator apps on the phone. The AuthenticatorMiddleware apps require your /// secret to be Base32 encoded when you supply it. You can either supply the base32 encoded secret /// to be copied into the authenticator app or generate a QR Code to be scanned. This generates the /// URL you should create your QR Code from. @@ -159,7 +159,7 @@ public struct TOTP: OTP, Sendable { /// Initialize TOTP /// - /// If you are using the Google Authenticator you should choose the default values for length, timeStep and hashFunction + /// If you are using the Google AuthenticatorMiddleware you should choose the default values for length, timeStep and hashFunction /// /// - Parameters: /// - secret: Secret known by client and server @@ -184,9 +184,9 @@ public struct TOTP: OTP, Sendable { return self.compute(message: value.bigEndian.bytes) } - /// Create Authenticator URL for TOTP generator + /// Create AuthenticatorMiddleware URL for TOTP generator /// - /// OTP is used commonly with authenticator apps on the phone. The Authenticator apps require your + /// OTP is used commonly with authenticator apps on the phone. The AuthenticatorMiddleware apps require your /// secret to be Base32 encoded when you supply it. You can either supply the base32 encoded secret /// to be copied into the authenticator app or generate a QR Code to be scanned. This generates the /// URL you should create your QR Code from. diff --git a/Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift b/Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift index af3aa07..998999c 100644 --- a/Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift +++ b/Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift @@ -15,25 +15,25 @@ import Hummingbird /// Session authenticator -public protocol HBSessionAuthenticator: HBAuthenticator { +public protocol SessionMiddleware: AuthenticatorMiddleware { /// authenticable value associatedtype Value = Value /// session object associatedtype Session: Codable /// container for session objects - var sessionStorage: HBSessionStorage { get } + var sessionStorage: SessionStorage { get } /// Convert Session object into authenticated user /// - Parameters: /// - from: session /// - request: request being processed /// - Returns: Future holding optional authenticated user - func getValue(from: Session, request: HBRequest, context: Context) async throws -> Value? + func getValue(from: Session, request: Request, context: Context) async throws -> Value? } -extension HBSessionAuthenticator { - public func authenticate(request: HBRequest, context: Context) async throws -> Value? { +extension SessionMiddleware { + public func authenticate(request: Request, context: Context) async throws -> Value? { guard let session: Session = try await self.sessionStorage.load(request: request) else { return nil } return try await getValue(from: session, request: request, context: context) } diff --git a/Sources/HummingbirdAuth/Sessions/SessionStorage.swift b/Sources/HummingbirdAuth/Sessions/SessionStorage.swift index e56e777..cbb31e1 100644 --- a/Sources/HummingbirdAuth/Sessions/SessionStorage.swift +++ b/Sources/HummingbirdAuth/Sessions/SessionStorage.swift @@ -16,8 +16,8 @@ import ExtrasBase64 import Hummingbird /// Stores session data -public struct HBSessionStorage: Sendable { - /// HBSessionStorage Errors +public struct SessionStorage: Sendable { + /// SessionStorage Errors public struct Error: Swift.Error, Equatable { enum ErrorType { case sessionDoesNotExist @@ -35,7 +35,7 @@ public struct HBSessionStorage: Sendable { let sessionCookie: String /// Initialize session storage - public init(_ storage: any HBPersistDriver, sessionCookie: String = "SESSION_ID") { + public init(_ storage: any PersistDriver, sessionCookie: String = "SESSION_ID") { self.storage = storage self.sessionCookie = sessionCookie } @@ -44,17 +44,17 @@ public struct HBSessionStorage: Sendable { /// /// Saving a new session will create a new session id and returns a cookie setting /// the session id. You need to then return a response including this cookie. You - /// can either create an ``HummingbirdCore/HBResponse`` directly or use ``Hummingbird/HBEditedResponse`` to + /// can either create an ``HummingbirdCore/Response`` directly or use ``Hummingbird/EditedResponse`` to /// generate the response from another type. /// ```swift /// let cookie = try await sessionStorage.save(session: session, expiresIn: .seconds(600)) - /// var response = HBEditedResponse(response: responseGenerator) + /// var response = EditedResponse(response: responseGenerator) /// response.setCookie(cookie) /// return response /// ``` /// If you know a session already exists it is preferable to use - /// ``HBSessionStorage/update(session:expiresIn:request:)``. - public func save(session: some Codable, expiresIn: Duration) async throws -> HBCookie { + /// ``SessionStorage/update(session:expiresIn:request:)``. + public func save(session: some Codable, expiresIn: Duration) async throws -> Cookie { let sessionId = Self.createSessionId() // prefix with "hbs." try await self.storage.set( @@ -68,7 +68,7 @@ public struct HBSessionStorage: Sendable { /// update existing session /// /// If session does not exist then a `sessionDoesNotExist` error will be thrown - public func update(session: some Codable, expiresIn: Duration, request: HBRequest) async throws { + public func update(session: some Codable, expiresIn: Duration, request: Request) async throws { guard let sessionId = self.getId(request: request) else { throw Error.sessionDoesNotExist } @@ -81,7 +81,7 @@ public struct HBSessionStorage: Sendable { } /// load session - public func load(as: Session.Type = Session.self, request: HBRequest) async throws -> Session? { + public func load(as: Session.Type = Session.self, request: Request) async throws -> Session? { guard let sessionId = getId(request: request) else { return nil } // prefix with "hbs." return try await self.storage.get( @@ -91,7 +91,7 @@ public struct HBSessionStorage: Sendable { } /// delete session - public func delete(request: HBRequest) async throws { + public func delete(request: Request) async throws { guard let sessionId = getId(request: request) else { return } // prefix with "hbs." return try await self.storage.remove( @@ -100,16 +100,16 @@ public struct HBSessionStorage: Sendable { } /// Get session id gets id from request - func getId(request: HBRequest) -> String? { + func getId(request: Request) -> String? { guard let sessionCookie = request.cookies[self.sessionCookie]?.value else { return nil } return String(sessionCookie) } /// set session id on response - func setId(_ id: String, request: HBRequest) { + func setId(_ id: String, request: Request) { /* precondition( request.extensions.get(\.response) != nil, - "Saving a session involves editing the response via HBRequest.response which cannot be done outside of a route without the .editResponse option set" + "Saving a session involves editing the response via Request.response which cannot be done outside of a route without the .editResponse option set" ) switch self.sessionID { case .cookie(let cookie): @@ -125,8 +125,8 @@ public struct HBSessionStorage: Sendable { return String(base64Encoding: bytes) } - // This is wrapped in an unsafe storage wrapper because I cannot conform `HBPersistDriver` + // This is wrapped in an unsafe storage wrapper because I cannot conform `PersistDriver` // to `Sendable` at this point because Redis and Fluent types do not currently conform to // `Sendable` when it should be possible for this to be the case. - let storage: any HBPersistDriver + let storage: any PersistDriver } diff --git a/Sources/HummingbirdAuthTesting/TestClient+Auth.swift b/Sources/HummingbirdAuthTesting/TestClient+Auth.swift index 5210fc9..caa2d63 100644 --- a/Sources/HummingbirdAuthTesting/TestClient+Auth.swift +++ b/Sources/HummingbirdAuthTesting/TestClient+Auth.swift @@ -18,7 +18,7 @@ import HummingbirdTesting import XCTest /// Used to generate various authentication types for Testing framework -public struct HBTestAuthentication: Equatable { +public struct TestAuthentication: Equatable { /// create basic authentication test public static func basic(username: String, password: String) -> Self { return .init(value: .basic(username: username, password: password)) @@ -71,7 +71,7 @@ public struct HBTestAuthentication: Equatable { private let value: Internal } -extension HBTestClientProtocol { +extension TestClientProtocol { /// Send request with authentication and call test callback on the response returned /// /// - Parameters: @@ -86,9 +86,9 @@ extension HBTestClientProtocol { uri: String, method: HTTPRequest.Method, headers: HTTPFields = [:], - auth: HBTestAuthentication, + auth: TestAuthentication, body: ByteBuffer? = nil, - testCallback: @escaping (HBTestResponse) throws -> Return + testCallback: @escaping (TestResponse) throws -> Return ) async throws -> Return { let request = auth.apply(uri: uri, method: method, headers: headers, body: body) return try await self.execute( diff --git a/Tests/HummingbirdAuthTests/AuthTests.swift b/Tests/HummingbirdAuthTests/AuthTests.swift index 31e2c3c..ab484da 100644 --- a/Tests/HummingbirdAuthTests/AuthTests.swift +++ b/Tests/HummingbirdAuthTests/AuthTests.swift @@ -50,11 +50,11 @@ final class AuthTests: XCTestCase { } func testBearer() async throws { - let router = HBRouter(context: HBBasicAuthRequestContext.self) + let router = Router(context: BasicAuthRequestContext.self) router.get { request, _ -> String? in return request.headers.bearer?.token } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in try await client.execute(uri: "/", method: .get, auth: .bearer("1234567890")) { response in let body = try XCTUnwrap(response.body) @@ -67,11 +67,11 @@ final class AuthTests: XCTestCase { } func testBasic() async throws { - let router = HBRouter(context: HBBasicAuthRequestContext.self) + let router = Router(context: BasicAuthRequestContext.self) router.get { request, _ -> String? in return request.headers.basic.map { "\($0.username):\($0.password)" } } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in try await client.execute(uri: "/", method: .get, auth: .basic(username: "adam", password: "password")) { response in let body = try XCTUnwrap(response.body) @@ -81,10 +81,10 @@ final class AuthTests: XCTestCase { } func testBcryptThread() async throws { - let persist = HBMemoryPersistDriver() - let router = HBRouter(context: HBBasicAuthRequestContext.self) + let persist = MemoryPersistDriver() + let router = Router(context: BasicAuthRequestContext.self) router.put { request, _ -> HTTPResponse.Status in - guard let basic = request.headers.basic else { throw HBHTTPError(.unauthorized) } + guard let basic = request.headers.basic else { throw HTTPError(.unauthorized) } let hash = try await NIOThreadPool.singleton.runIfActive { Bcrypt.hash(basic.password) } @@ -92,8 +92,8 @@ final class AuthTests: XCTestCase { return .ok } router.post { request, _ -> HTTPResponse.Status in - guard let basic = request.headers.basic else { throw HBHTTPError(.unauthorized) } - guard let hash = try await persist.get(key: basic.username, as: String.self) else { throw HBHTTPError(.unauthorized) } + guard let basic = request.headers.basic else { throw HTTPError(.unauthorized) } + guard let hash = try await persist.get(key: basic.username, as: String.self) else { throw HTTPError(.unauthorized) } let verified = try await NIOThreadPool.singleton.runIfActive { Bcrypt.verify(basic.password, hash: hash) } @@ -103,7 +103,7 @@ final class AuthTests: XCTestCase { return .unauthorized } } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in try await client.execute(uri: "/", method: .put, auth: .basic(username: "testuser", password: "testpassword123")) { response in XCTAssertEqual(response.status, .ok) @@ -115,10 +115,10 @@ final class AuthTests: XCTestCase { } func testAuth() async throws { - struct User: HBAuthenticatable { + struct User: Authenticatable { let name: String } - let router = HBRouter(context: HBBasicAuthRequestContext.self) + let router = Router(context: BasicAuthRequestContext.self) router.get { _, context -> HTTPResponse.Status in var context = context context.auth.login(User(name: "Test")) @@ -129,7 +129,7 @@ final class AuthTests: XCTestCase { XCTAssertNil(context.auth.get(User.self)) return .accepted } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in try await client.execute(uri: "/", method: .get) { response in @@ -139,21 +139,21 @@ final class AuthTests: XCTestCase { } func testLogin() async throws { - struct User: HBAuthenticatable { + struct User: Authenticatable { let name: String } - struct HBTestAuthenticator: HBAuthenticator { - func authenticate(request: HBRequest, context: Context) async throws -> User? { + struct TestAuthenticator: AuthenticatorMiddleware { + func authenticate(request: Request, context: Context) async throws -> User? { User(name: "Adam") } } - let router = HBRouter(context: HBBasicAuthRequestContext.self) - router.middlewares.add(HBTestAuthenticator()) + let router = Router(context: BasicAuthRequestContext.self) + router.middlewares.add(TestAuthenticator()) router.get { _, context -> HTTPResponse.Status in guard context.auth.has(User.self) else { return .unauthorized } return .ok } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in try await client.execute(uri: "/", method: .get) { response in @@ -163,17 +163,17 @@ final class AuthTests: XCTestCase { } func testIsAuthenticatedMiddleware() async throws { - struct User: HBAuthenticatable { + struct User: Authenticatable { let name: String } - struct HBTestAuthenticator: HBAuthenticator { - func authenticate(request: HBRequest, context: Context) async throws -> User? { + struct TestAuthenticator: AuthenticatorMiddleware { + func authenticate(request: Request, context: Context) async throws -> User? { User(name: "Adam") } } - let router = HBRouter(context: HBBasicAuthRequestContext.self) + let router = Router(context: BasicAuthRequestContext.self) router.group() - .add(middleware: HBTestAuthenticator()) + .add(middleware: TestAuthenticator()) .add(middleware: IsAuthenticatedMiddleware(User.self)) .get("authenticated") { _, _ -> HTTPResponse.Status in return .ok @@ -183,7 +183,7 @@ final class AuthTests: XCTestCase { .get("unauthenticated") { _, _ -> HTTPResponse.Status in return .ok } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in try await client.execute(uri: "/authenticated", method: .get) { response in @@ -196,23 +196,23 @@ final class AuthTests: XCTestCase { } func testSessionAuthenticator() async throws { - struct User: HBAuthenticatable { + struct User: Authenticatable { let name: String } - struct MySessionAuthenticator: HBSessionAuthenticator { - let sessionStorage: HBSessionStorage + struct MySessionAuthenticator: SessionMiddleware { + let sessionStorage: SessionStorage - func getValue(from session: Int, request: HBRequest, context: Context) async throws -> User? { + func getValue(from session: Int, request: Request, context: Context) async throws -> User? { return User(name: "Adam") } } - let router = HBRouter(context: HBBasicAuthRequestContext.self) - let persist = HBMemoryPersistDriver() - let sessions = HBSessionStorage(persist) + let router = Router(context: BasicAuthRequestContext.self) + let persist = MemoryPersistDriver() + let sessions = SessionStorage(persist) - router.put("session") { _, _ -> HBResponse in + router.put("session") { _, _ -> Response in let cookie = try await sessions.save(session: 1, expiresIn: .seconds(60)) - var response = HBResponse(status: .ok) + var response = Response(status: .ok) response.setCookie(cookie) return response } @@ -222,7 +222,7 @@ final class AuthTests: XCTestCase { _ = try context.auth.require(User.self) return .ok } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in let responseCookies = try await client.execute(uri: "/session", method: .put) { response -> String? in diff --git a/Tests/HummingbirdAuthTests/SessionTests.swift b/Tests/HummingbirdAuthTests/SessionTests.swift index be76426..59f67ae 100644 --- a/Tests/HummingbirdAuthTests/SessionTests.swift +++ b/Tests/HummingbirdAuthTests/SessionTests.swift @@ -21,21 +21,21 @@ import XCTest final class SessionTests: XCTestCase { func testSessionAuthenticator() async throws { - struct User: HBAuthenticatable { + struct User: Authenticatable { let name: String } - struct MySessionAuthenticator: HBSessionAuthenticator { - let sessionStorage: HBSessionStorage - func getValue(from session: Int, request: HBRequest, context: Context) async throws -> User? { + struct MySessionAuthenticator: SessionMiddleware { + let sessionStorage: SessionStorage + func getValue(from session: Int, request: Request, context: Context) async throws -> User? { return User(name: "Adam") } } - let router = HBRouter(context: HBBasicAuthRequestContext.self) - let persist = HBMemoryPersistDriver() - let sessions = HBSessionStorage(persist) - router.put("session") { _, _ -> HBResponse in + let router = Router(context: BasicAuthRequestContext.self) + let persist = MemoryPersistDriver() + let sessions = SessionStorage(persist) + router.put("session") { _, _ -> Response in let cookie = try await sessions.save(session: 1, expiresIn: .seconds(300)) - var response = HBResponse(status: .ok) + var response = Response(status: .ok) response.setCookie(cookie) return response } @@ -45,7 +45,7 @@ final class SessionTests: XCTestCase { _ = try context.auth.require(User.self) return .ok } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in let responseCookies = try await client.execute(uri: "/session", method: .put) { response -> String? in @@ -64,26 +64,26 @@ final class SessionTests: XCTestCase { let name: String } - let router = HBRouter(context: HBBasicAuthRequestContext.self) - let persist = HBMemoryPersistDriver() - let sessions = HBSessionStorage(persist) - router.post("save") { request, _ -> HBResponse in - guard let name = request.uri.queryParameters.get("name") else { throw HBHTTPError(.badRequest) } + let router = Router(context: BasicAuthRequestContext.self) + let persist = MemoryPersistDriver() + let sessions = SessionStorage(persist) + router.post("save") { request, _ -> Response in + guard let name = request.uri.queryParameters.get("name") else { throw HTTPError(.badRequest) } let cookie = try await sessions.save(session: User(name: name), expiresIn: .seconds(600)) - var response = HBResponse(status: .ok) + var response = Response(status: .ok) response.setCookie(cookie) return response } router.post("update") { request, _ -> HTTPResponse.Status in - guard let name = request.uri.queryParameters.get("name") else { throw HBHTTPError(.badRequest) } + guard let name = request.uri.queryParameters.get("name") else { throw HTTPError(.badRequest) } try await sessions.update(session: User(name: name), expiresIn: .seconds(600), request: request) return .ok } router.get("name") { request, _ -> String in - guard let user = try await sessions.load(as: User.self, request: request) else { throw HBHTTPError(.unauthorized) } + guard let user = try await sessions.load(as: User.self, request: request) else { throw HTTPError(.unauthorized) } return user.name } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in let cookies = try await client.execute(uri: "/save?name=john", method: .post) { response -> String? in @@ -105,9 +105,9 @@ final class SessionTests: XCTestCase { } func testSessionUpdateError() async throws { - let router = HBRouter(context: HBBasicAuthRequestContext.self) - let persist = HBMemoryPersistDriver() - let sessions = HBSessionStorage(persist) + let router = Router(context: BasicAuthRequestContext.self) + let persist = MemoryPersistDriver() + let sessions = SessionStorage(persist) router.post("update") { request, _ -> HTTPResponse.Status in do { @@ -117,7 +117,7 @@ final class SessionTests: XCTestCase { return .badRequest } } - let app = HBApplication(responder: router.buildResponder()) + let app = Application(responder: router.buildResponder()) try await app.test(.router) { client in try await client.execute(uri: "/update", method: .post) { response in