From 93b8d7a1ff590ea873f854635eb7c99a7111d91b Mon Sep 17 00:00:00 2001 From: Jaap Wijnen Date: Thu, 14 Mar 2024 11:46:29 +0100 Subject: [PATCH 1/2] update to jwt-kit v5 --- .../Configuration/OAuth/OAuthPayload.swift | 2 +- .../OAuth/OAuthServiceAccount.swift | 50 ++++++++++--------- Package.swift | 4 +- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/Core/Sources/Configuration/OAuth/OAuthPayload.swift b/Core/Sources/Configuration/OAuth/OAuthPayload.swift index e7cd1da..cdff2fc 100644 --- a/Core/Sources/Configuration/OAuth/OAuthPayload.swift +++ b/Core/Sources/Configuration/OAuth/OAuthPayload.swift @@ -23,7 +23,7 @@ public struct OAuthPayload: JWTPayload { /// Using to nominate the account you want access to on the domain from a service account var sub: String? - public func verify(using signer: JWTSigner) throws { + public func verify(using algorithm: any JWTAlgorithm) async throws { try exp.verifyNotExpired() } } diff --git a/Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift b/Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift index 27918be..3e60f29 100644 --- a/Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift +++ b/Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift @@ -31,40 +31,44 @@ public class OAuthServiceAccount: OAuthRefreshable { // Google Documentation for this approach: https://developers.google.com/identity/protocols/OAuth2ServiceAccount public func refresh() -> EventLoopFuture { - do { - let headers: HTTPHeaders = ["Content-Type": "application/x-www-form-urlencoded"] - let token = try generateJWT() + let headers: HTTPHeaders = ["Content-Type": "application/x-www-form-urlencoded"] + + return generateJWT(on: self.eventLoop).flatMapThrowing { (token: String) -> HTTPClient.Request in let body: HTTPClient.Body = .string("grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=\(token)" - .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "") - let request = try HTTPClient.Request(url: GoogleOAuthTokenUrl, method: .POST, headers: headers, body: body) + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "") - return httpClient.execute(request: request, eventLoop: .delegate(on: self.eventLoop)).flatMap { response in - - guard var byteBuffer = response.body, - let responseData = byteBuffer.readData(length: byteBuffer.readableBytes), - response.status == .ok else { - return self.eventLoop.makeFailedFuture(OauthRefreshError.noResponse(response.status)) - } - - do { - return self.eventLoop.makeSucceededFuture(try self.decoder.decode(OAuthAccessToken.self, from: responseData)) - } catch { - return self.eventLoop.makeFailedFuture(error) - } + return try HTTPClient.Request(url: GoogleOAuthTokenUrl, method: .POST, headers: headers, body: body) + }.flatMap { request in + return self.httpClient.execute(request: request, eventLoop: .delegate(on: self.eventLoop)) + }.flatMap { (response: HTTPClient.Response) in + guard var byteBuffer = response.body, + let responseData = byteBuffer.readData(length: byteBuffer.readableBytes), + response.status == .ok else { + return self.eventLoop.makeFailedFuture(OauthRefreshError.noResponse(response.status)) } - } catch { - return self.eventLoop.makeFailedFuture(error) + do { + return self.eventLoop.makeSucceededFuture(try self.decoder.decode(OAuthAccessToken.self, from: responseData)) + } catch { + return self.eventLoop.makeFailedFuture(error) + } } } - private func generateJWT() throws -> String { + private func generateJWT(on eventLoop: EventLoop) -> EventLoopFuture { let payload = OAuthPayload(iss: IssuerClaim(value: credentials.clientEmail), scope: scope, aud: AudienceClaim(value: GoogleOAuthTokenAudience), exp: ExpirationClaim(value: Date().addingTimeInterval(3600)), iat: IssuedAtClaim(value: Date()), sub: subscription) - let privateKey = try RSAKey.private(pem: credentials.privateKey.data(using: .utf8, allowLossyConversion: true) ?? Data()) - return try JWTSigner.rs256(key: privateKey).sign(payload) + + let privateKey: Insecure.RSA.PrivateKey + do { + privateKey = try Insecure.RSA.PrivateKey(pem: credentials.privateKey.data(using: .utf8, allowLossyConversion: true) ?? Data()) + } catch { + return eventLoop.makeFailedFuture(error) + } + + return eventLoop.makeFutureWithTask { try await JWTKeyCollection().addRS256(key: privateKey).sign(payload) } } } diff --git a/Package.swift b/Package.swift index 2b85514..e04d4f6 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ let package = Package( name: "google-cloud-kit", platforms: [ .macOS(.v13), - .iOS(.v13) + .iOS(.v16) ], products: [ .library( @@ -51,7 +51,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.18.0"), - .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0") + .package(url: "https://github.com/vapor/jwt-kit.git", from: "5.0.0-beta.1") ], targets: [ .target( From b7fcf5dc59fdaf70f461ac73f09ac9c0f5adfaa6 Mon Sep 17 00:00:00 2001 From: Tim <0xtimc@gmail.com> Date: Fri, 20 Dec 2024 18:13:50 +0000 Subject: [PATCH 2/2] Update for release --- Core/Sources/Configuration/OAuth/OAuthPayload.swift | 2 +- Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift | 4 +++- Package.swift | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/Sources/Configuration/OAuth/OAuthPayload.swift b/Core/Sources/Configuration/OAuth/OAuthPayload.swift index cdff2fc..451539b 100644 --- a/Core/Sources/Configuration/OAuth/OAuthPayload.swift +++ b/Core/Sources/Configuration/OAuth/OAuthPayload.swift @@ -23,7 +23,7 @@ public struct OAuthPayload: JWTPayload { /// Using to nominate the account you want access to on the domain from a service account var sub: String? - public func verify(using algorithm: any JWTAlgorithm) async throws { + public func verify(using algorithm: some JWTAlgorithm) async throws { try exp.verifyNotExpired() } } diff --git a/Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift b/Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift index 3e60f29..1ee82e4 100644 --- a/Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift +++ b/Core/Sources/Configuration/OAuth/OAuthServiceAccount.swift @@ -69,6 +69,8 @@ public class OAuthServiceAccount: OAuthRefreshable { return eventLoop.makeFailedFuture(error) } - return eventLoop.makeFutureWithTask { try await JWTKeyCollection().addRS256(key: privateKey).sign(payload) } + return eventLoop.makeFutureWithTask { + try await JWTKeyCollection().add(rsa: privateKey, digestAlgorithm: .sha256).sign(payload) + } } } diff --git a/Package.swift b/Package.swift index e04d4f6..bbd619d 100644 --- a/Package.swift +++ b/Package.swift @@ -51,7 +51,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.18.0"), - .package(url: "https://github.com/vapor/jwt-kit.git", from: "5.0.0-beta.1") + .package(url: "https://github.com/vapor/jwt-kit.git", from: "5.0.0") ], targets: [ .target(