From 52f09a7d1407804238f3a7dd6b1b54c20b980f29 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Sun, 10 Mar 2024 12:20:23 +0000 Subject: [PATCH 1/3] Remove "HB" prefix --- Package.swift | 2 +- .../Authenticator/AuthRequestContext.swift | 12 ++-- .../Authenticator/Authenticator.swift | 22 +++--- .../Authenticator/LoginCache.swift | 16 ++--- Sources/HummingbirdAuth/Deprecated.swift | 35 ++++++++++ .../Middleware/IsAuthenticateMiddleware.swift | 4 +- .../Sessions/SessionAuthenticator.swift | 10 +-- .../Sessions/SessionStorage.swift | 30 ++++---- .../TestClient+Auth.swift | 8 +-- Tests/HummingbirdAuthTests/AuthTests.swift | 70 +++++++++---------- Tests/HummingbirdAuthTests/SessionTests.swift | 46 ++++++------ 11 files changed, 145 insertions(+), 110 deletions(-) create mode 100644 Sources/HummingbirdAuth/Deprecated.swift diff --git a/Package.swift b/Package.swift index df1e71c..1fa4553 100644 --- a/Package.swift +++ b/Package.swift @@ -11,7 +11,7 @@ let package = Package( .library(name: "HummingbirdAuthTesting", targets: ["HummingbirdAuthTesting"]), ], dependencies: [ - .package(url: "https://github.com/hummingbird-project/hummingbird.git", branch: "main"), + .package(url: "https://github.com/hummingbird-project/hummingbird.git", branch: "remove-hb-prefix"), .package(url: "https://github.com/apple/swift-crypto.git", "1.0.0"..<"4.0.0"), .package(url: "https://github.com/apple/swift-nio.git", from: "2.63.0"), .package(url: "https://github.com/swift-extras/swift-extras-base64.git", .upToNextMinor(from: "0.7.0")), 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..8f4a5a9 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 `Authenticator`. +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: Authenticator { +/// 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 Authenticator: 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 Authenticator { /// 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..9573ac5 --- /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: "Authenticator") +public typealias HBAuthenticator = Authenticator +@_documentation(visibility: internal) @available(*, deprecated, renamed: "SessionAuthenticator") +public typealias HBSessionAuthenticator = SessionAuthenticator +@_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/Sessions/SessionAuthenticator.swift b/Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift index af3aa07..2694e9a 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 SessionAuthenticator: Authenticator { /// 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 SessionAuthenticator { + 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..bfed2da 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: Authenticator { + 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: Authenticator { + 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: SessionAuthenticator { + 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..cdebac6 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: SessionAuthenticator { + 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 From 69f5b0c6cbd601b827191bedf7ee35031c4d5467 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Mon, 11 Mar 2024 09:20:23 +0000 Subject: [PATCH 2/3] Use main --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 1fa4553..df1e71c 100644 --- a/Package.swift +++ b/Package.swift @@ -11,7 +11,7 @@ let package = Package( .library(name: "HummingbirdAuthTesting", targets: ["HummingbirdAuthTesting"]), ], dependencies: [ - .package(url: "https://github.com/hummingbird-project/hummingbird.git", branch: "remove-hb-prefix"), + .package(url: "https://github.com/hummingbird-project/hummingbird.git", branch: "main"), .package(url: "https://github.com/apple/swift-crypto.git", "1.0.0"..<"4.0.0"), .package(url: "https://github.com/apple/swift-nio.git", from: "2.63.0"), .package(url: "https://github.com/swift-extras/swift-extras-base64.git", .upToNextMinor(from: "0.7.0")), From 0ddac0624b5e1f1f4533f9403f80a46ba08b53d8 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Mon, 11 Mar 2024 15:26:06 +0000 Subject: [PATCH 3/3] Renaming symbols --- README.md | 2 +- .../Authenticator/Authenticator.swift | 8 ++++---- Sources/HummingbirdAuth/Deprecated.swift | 8 ++++---- Sources/HummingbirdAuth/OTP/OTP.swift | 16 ++++++++-------- .../Sessions/SessionAuthenticator.swift | 4 ++-- Tests/HummingbirdAuthTests/AuthTests.swift | 6 +++--- Tests/HummingbirdAuthTests/SessionTests.swift | 2 +- 7 files changed, 23 insertions(+), 23 deletions(-) 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/Authenticator.swift b/Sources/HummingbirdAuth/Authenticator/Authenticator.swift index 8f4a5a9..b4b343d 100644 --- a/Sources/HummingbirdAuth/Authenticator/Authenticator.swift +++ b/Sources/HummingbirdAuth/Authenticator/Authenticator.swift @@ -15,7 +15,7 @@ import Hummingbird import NIOCore -/// Protocol for objects that can be returned by an `Authenticator`. +/// 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. @@ -33,7 +33,7 @@ public protocol Authenticatable: Sendable {} /// authenticator is successful it returns a `User` struct, otherwise it returns `nil`. /// /// ```swift -/// struct BasicAuthenticator: Authenticator { +/// 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 @@ -55,7 +55,7 @@ public protocol Authenticatable: Sendable {} /// } /// } /// ``` -public protocol Authenticator: RouterMiddleware where Context: AuthRequestContext { +public protocol AuthenticatorMiddleware: RouterMiddleware where Context: AuthRequestContext { /// type to be authenticated associatedtype Value: Authenticatable /// Called by middleware to see if request can authenticate. @@ -66,7 +66,7 @@ public protocol Authenticator: RouterMiddleware where Context: AuthRequestContex func authenticate(request: Request, context: Context) async throws -> Value? } -extension Authenticator { +extension AuthenticatorMiddleware { /// Calls `authenticate` and if it returns a valid authenticatable object `login` with this object 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) { diff --git a/Sources/HummingbirdAuth/Deprecated.swift b/Sources/HummingbirdAuth/Deprecated.swift index 9573ac5..a8590f6 100644 --- a/Sources/HummingbirdAuth/Deprecated.swift +++ b/Sources/HummingbirdAuth/Deprecated.swift @@ -27,9 +27,9 @@ public typealias HBLoginCache = LoginCache @_documentation(visibility: internal) @available(*, deprecated, renamed: "Authenticatable") public typealias HBAuthenticatable = Authenticatable -@_documentation(visibility: internal) @available(*, deprecated, renamed: "Authenticator") -public typealias HBAuthenticator = Authenticator -@_documentation(visibility: internal) @available(*, deprecated, renamed: "SessionAuthenticator") -public typealias HBSessionAuthenticator = SessionAuthenticator +@_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/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 2694e9a..998999c 100644 --- a/Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift +++ b/Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift @@ -15,7 +15,7 @@ import Hummingbird /// Session authenticator -public protocol SessionAuthenticator: Authenticator { +public protocol SessionMiddleware: AuthenticatorMiddleware { /// authenticable value associatedtype Value = Value /// session object @@ -32,7 +32,7 @@ public protocol SessionAuthenticator: Authenticator { func getValue(from: Session, request: Request, context: Context) async throws -> Value? } -extension SessionAuthenticator { +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/Tests/HummingbirdAuthTests/AuthTests.swift b/Tests/HummingbirdAuthTests/AuthTests.swift index bfed2da..ab484da 100644 --- a/Tests/HummingbirdAuthTests/AuthTests.swift +++ b/Tests/HummingbirdAuthTests/AuthTests.swift @@ -142,7 +142,7 @@ final class AuthTests: XCTestCase { struct User: Authenticatable { let name: String } - struct TestAuthenticator: Authenticator { + struct TestAuthenticator: AuthenticatorMiddleware { func authenticate(request: Request, context: Context) async throws -> User? { User(name: "Adam") } @@ -166,7 +166,7 @@ final class AuthTests: XCTestCase { struct User: Authenticatable { let name: String } - struct TestAuthenticator: Authenticator { + struct TestAuthenticator: AuthenticatorMiddleware { func authenticate(request: Request, context: Context) async throws -> User? { User(name: "Adam") } @@ -199,7 +199,7 @@ final class AuthTests: XCTestCase { struct User: Authenticatable { let name: String } - struct MySessionAuthenticator: SessionAuthenticator { + struct MySessionAuthenticator: SessionMiddleware { let sessionStorage: SessionStorage func getValue(from session: Int, request: Request, context: Context) async throws -> User? { diff --git a/Tests/HummingbirdAuthTests/SessionTests.swift b/Tests/HummingbirdAuthTests/SessionTests.swift index cdebac6..59f67ae 100644 --- a/Tests/HummingbirdAuthTests/SessionTests.swift +++ b/Tests/HummingbirdAuthTests/SessionTests.swift @@ -24,7 +24,7 @@ final class SessionTests: XCTestCase { struct User: Authenticatable { let name: String } - struct MySessionAuthenticator: SessionAuthenticator { + struct MySessionAuthenticator: SessionMiddleware { let sessionStorage: SessionStorage func getValue(from session: Int, request: Request, context: Context) async throws -> User? { return User(name: "Adam")