Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove "HB" prefix #35

Merged
merged 3 commits into from Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Expand Up @@ -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")),
Expand Down
12 changes: 6 additions & 6 deletions Sources/HummingbirdAuth/Authenticator/AuthRequestContext.swift
Expand Up @@ -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
Expand Down
22 changes: 11 additions & 11 deletions Sources/HummingbirdAuth/Authenticator/Authenticator.swift
Expand Up @@ -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.
///
Expand All @@ -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<Context: HBAuthRequestContext>(request: HBRequest, context: Context) async throws -> User? {
/// struct BasicAuthenticator: Authenticator {
/// func authenticate<Context: AuthRequestContext>(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 }
Expand All @@ -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)
Expand Down
16 changes: 8 additions & 8 deletions Sources/HummingbirdAuth/Authenticator/LoginCache.swift
Expand Up @@ -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: HBAuthenticatable>(_ auth: Auth) {
public mutating func login<Auth: Authenticatable>(_ auth: Auth) {
self.cache = [ObjectIdentifier(Auth.self): auth]
}

/// Logout authenticatable object. Removes object from cache
/// - Parameter auth: authentication type
public mutating func logout<Auth: HBAuthenticatable>(_: Auth.Type) {
public mutating func logout<Auth: Authenticatable>(_: Auth.Type) {
self.cache[ObjectIdentifier(Auth.self)] = nil
}

/// Return authenticated type
/// - Parameter auth: Type required
public func get<Auth: HBAuthenticatable>(_: Auth.Type) -> Auth? {
public func get<Auth: Authenticatable>(_: Auth.Type) -> Auth? {
return self.cache[ObjectIdentifier(Auth.self)] as? Auth
}

/// Require authenticated type
/// - Parameter auth: Type required
public func require<Auth: HBAuthenticatable>(_: Auth.Type) throws -> Auth {
public func require<Auth: Authenticatable>(_: 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: HBAuthenticatable>(_: Auth.Type) -> Bool {
public func has<Auth: Authenticatable>(_: Auth.Type) -> Bool {
return self.cache[ObjectIdentifier(Auth.self)] != nil
}

var cache: [ObjectIdentifier: HBAuthenticatable]
var cache: [ObjectIdentifier: Authenticatable]
}
35 changes: 35 additions & 0 deletions 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
Expand Up @@ -15,10 +15,10 @@
import Hummingbird

/// Middleware returning 404 for unauthenticated requests
public struct IsAuthenticatedMiddleware<Auth: HBAuthenticatable, Context: HBAuthRequestContext>: HBMiddlewareProtocol {
public struct IsAuthenticatedMiddleware<Auth: Authenticatable, Context: AuthRequestContext>: 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)
}
}
10 changes: 5 additions & 5 deletions Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift
Expand Up @@ -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)
}
Expand Down
30 changes: 15 additions & 15 deletions Sources/HummingbirdAuth/Sessions/SessionStorage.swift
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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(
Expand All @@ -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
}
Expand All @@ -81,7 +81,7 @@ public struct HBSessionStorage: Sendable {
}

/// load session
public func load<Session: Codable>(as: Session.Type = Session.self, request: HBRequest) async throws -> Session? {
public func load<Session: Codable>(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(
Expand All @@ -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(
Expand All @@ -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):
Expand All @@ -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
}
8 changes: 4 additions & 4 deletions Sources/HummingbirdAuthTesting/TestClient+Auth.swift
Expand Up @@ -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))
Expand Down Expand Up @@ -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:
Expand All @@ -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(
Expand Down