-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add session authenticator * comments * Add configurable session id storage * formatting * Have separate storage for session management * Use branch main of hummingbird * Use 1.0.0-alpha branches * swift format * fix tests * Moved session tests,add header test
- Loading branch information
1 parent
7d5df79
commit 77aff53
Showing
10 changed files
with
513 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
Sources/HummingbirdAuth/AsyncAwaitSupport/AsyncSessionAuthenticator.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Hummingbird server framework project | ||
// | ||
// Copyright (c) 2021-2021 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#if compiler(>=5.5) && canImport(_Concurrency) | ||
|
||
import Hummingbird | ||
import NIOCore | ||
|
||
/// Async version of session authenticator. | ||
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) | ||
public protocol HBAsyncSessionAuthenticator: HBAsyncAuthenticator { | ||
associatedtype Value = Value | ||
associatedtype Session: Codable | ||
|
||
/// Convert Session object into authenticated user | ||
/// - Parameters: | ||
/// - from: session | ||
/// - request: request being processed | ||
/// - Returns: optional authenticated user | ||
func getValue(from: Session, request: HBRequest) async throws -> Value? | ||
} | ||
|
||
extension HBAsyncSessionAuthenticator { | ||
public func authenticate(request: HBRequest) async throws -> Value? { | ||
let session: Session? = try await request.session.load() | ||
guard let session = session else { | ||
return nil | ||
} | ||
return try await getValue(from: session, request: request) | ||
} | ||
} | ||
|
||
#endif // compiler(>=5.5) && canImport(_Concurrency) |
48 changes: 48 additions & 0 deletions
48
Sources/HummingbirdAuth/AsyncAwaitSupport/Request+session+async.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Hummingbird server framework project | ||
// | ||
// Copyright (c) 2021-2022 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#if compiler(>=5.5) && canImport(_Concurrency) | ||
|
||
import ExtrasBase64 | ||
import Foundation | ||
import Hummingbird | ||
|
||
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) | ||
extension SessionManager { | ||
/// save session | ||
public func save<Session: Codable>(session: Session, expiresIn: TimeAmount) async throws { | ||
let sessionId = Self.createSessionId() | ||
// prefix with "hbs." | ||
try await self.request.application.sessionStorage.driver.set( | ||
key: "hbs.\(sessionId)", | ||
value: session, | ||
expires: expiresIn, | ||
request: self.request | ||
).get() | ||
setId(sessionId) | ||
} | ||
|
||
/// load session | ||
public func load<Session: Codable>(as: Session.Type = Session.self) async throws -> Session? { | ||
guard let sessionId = getId() else { return nil } | ||
// prefix with "hbs." | ||
return try await self.request.application.sessionStorage.driver.get( | ||
key: "hbs.\(sessionId)", | ||
as: Session.self, | ||
request: self.request | ||
).get() | ||
} | ||
} | ||
|
||
#endif // compiler(>=5.5) && canImport(_Concurrency) |
48 changes: 48 additions & 0 deletions
48
Sources/HummingbirdAuth/Sessions/Application+session.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Hummingbird server framework project | ||
// | ||
// Copyright (c) 2021-2022 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
import Hummingbird | ||
|
||
extension HBApplication { | ||
/// Accessor for session storage | ||
public var sessionStorage: Persist { | ||
self.extensions.get( | ||
\.sessionStorage, | ||
error: "To use session storage you need to set it up with `HBApplication.addSessions`." | ||
) | ||
} | ||
|
||
/// Add session management to `HBApplication`. | ||
/// - Parameters: | ||
/// - storage: Factory struct that will create the persist driver for session storage | ||
/// - sessionID: Where session id is stored in request/response | ||
public func addSessions( | ||
using storage: HBPersistDriverFactory, | ||
sessionID: SessionManager.SessionIDStorage = .cookie("HB_SESSION_ID") | ||
) { | ||
SessionManager.sessionID = sessionID | ||
self.extensions.set(\.sessionStorage, value: .init(storage, application: self)) { persist in | ||
persist.driver.shutdown() | ||
} | ||
} | ||
|
||
/// Add session management to `HBApplication` using default persist memory driver | ||
/// - Parameter sessionID: Where session id is stored in request/response | ||
public func addSessions( | ||
sessionID: SessionManager.SessionIDStorage = .cookie("HB_SESSION_ID") | ||
) { | ||
SessionManager.sessionID = sessionID | ||
self.extensions.set(\.sessionStorage, value: self.persist) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Hummingbird server framework project | ||
// | ||
// Copyright (c) 2021-2022 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
import ExtrasBase64 | ||
import Foundation | ||
import Hummingbird | ||
import HummingbirdFoundation | ||
|
||
/// Manage session ids and associated data | ||
public struct SessionManager { | ||
internal static var sessionID: SessionIDStorage = .cookie("SESSION_ID") | ||
|
||
// enum defining where to store a session id | ||
public enum SessionIDStorage { | ||
case cookie(String) | ||
case header(String) | ||
} | ||
|
||
/// save session | ||
public func save<Session: Codable>(session: Session, expiresIn: TimeAmount) -> EventLoopFuture<Void> { | ||
let sessionId = Self.createSessionId() | ||
// prefix with "hbs." | ||
return self.request.application.sessionStorage.driver.set( | ||
key: "hbs.\(sessionId)", | ||
value: session, | ||
expires: expiresIn, | ||
request: self.request | ||
).map { _ in setId(sessionId) } | ||
} | ||
|
||
/// load session | ||
public func load<Session: Codable>(as: Session.Type = Session.self) -> EventLoopFuture<Session?> { | ||
guard let sessionId = getId() else { return self.request.success(nil) } | ||
// prefix with "hbs." | ||
return self.request.application.sessionStorage.driver.get( | ||
key: "hbs.\(sessionId)", | ||
as: Session.self, | ||
request: self.request | ||
) | ||
} | ||
|
||
/// Get session id gets id from request | ||
public func getId() -> String? { | ||
switch Self.sessionID { | ||
case .cookie(let cookie): | ||
guard let sessionCookie = request.cookies[cookie]?.value else { return nil } | ||
return String(sessionCookie) | ||
case .header(let header): | ||
guard let sessionHeader = request.headers[header].first else { return nil } | ||
return sessionHeader | ||
} | ||
} | ||
|
||
/// set session id on response | ||
public func setId(_ id: String) { | ||
switch Self.sessionID { | ||
case .cookie(let cookie): | ||
self.request.response.setCookie(.init(name: cookie, value: id)) | ||
case .header(let header): | ||
self.request.response.headers.replaceOrAdd(name: header, value: id) | ||
} | ||
} | ||
|
||
/// create a session id | ||
public static func createSessionId() -> String { | ||
let bytes: [UInt8] = (0..<32).map { _ in UInt8.random(in: 0...255) } | ||
return String(base64Encoding: bytes) | ||
} | ||
|
||
let request: HBRequest | ||
} | ||
|
||
extension HBRequest { | ||
/// access session info | ||
public var session: SessionManager { return .init(request: self) } | ||
} |
43 changes: 43 additions & 0 deletions
43
Sources/HummingbirdAuth/Sessions/SessionAuthenticator.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Hummingbird server framework project | ||
// | ||
// Copyright (c) 2021-2022 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
import Hummingbird | ||
|
||
/// Session authenticator | ||
public protocol HBSessionAuthenticator: HBAuthenticator { | ||
/// authenticable value | ||
associatedtype Value = Value | ||
/// session object | ||
associatedtype Session: Codable | ||
|
||
/// 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) -> EventLoopFuture<Value?> | ||
} | ||
|
||
extension HBSessionAuthenticator { | ||
public func authenticate(request: HBRequest) -> EventLoopFuture<Value?> { | ||
return request.session.load().flatMap { (session: Session?) in | ||
// check if session exists. | ||
guard let session = session else { | ||
return request.success(nil) | ||
} | ||
// find authenticated user from session | ||
return getValue(from: session, request: request) | ||
} | ||
} | ||
} |
Oops, something went wrong.