Skip to content
This repository has been archived by the owner on Oct 29, 2024. It is now read-only.

Refactor Scope Validation and OAuth Models, Update DiscoveryDocument Protocol #17

Merged
merged 18 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
13d006e
Refactor scope validation in token handlers and client validator (#11)
vamsii777 Jan 10, 2024
a1c9df6
Refactor OAuth models to use structs instead of classes
vamsii777 Jan 11, 2024
79b3c1a
Refactor OAuthResourceServer struct
vamsii777 Jan 11, 2024
396e95d
Update DiscoveryDocument protocol to make certain properties optional…
vamsii777 Jan 20, 2024
ea87141
Refactor OAuthUser struct and add Address struct (#14)
vamsii777 Jan 20, 2024
b6fab1e
Add environment parameter to UserInfoHandler constructor (#14)
vamsii777 Jan 20, 2024
c5ddbfe
Add key rotation and deletion methods to KeyManagementService (#14)
vamsii777 Jan 20, 2024
3eed523
Add keyType parameter to storeKey method
vamsii777 Jan 20, 2024
b2f156b
Refactor KeyManagementService protocol to support storing different t…
vamsii777 Jan 20, 2024
11e853d
Refactor KeyManagementService protocol to store RSA key as string
vamsii777 Jan 20, 2024
6994801
Refactor key management service and JWT signer service
vamsii777 Jan 20, 2024
68d1f10
Refactor DiscoveryDocument and OAuthDiscoveryDocument structs (#14)
vamsii777 Jan 20, 2024
be9e6c9
Update KeyManagementService protocol to support async/await
vamsii777 Jan 20, 2024
26038f5
Refactor JwksHandler to use async/await
vamsii777 Jan 20, 2024
f636ef3
Update makeJWTSigner function to support async
vamsii777 Jan 20, 2024
4156cf3
Refactor token generation to use async/await
vamsii777 Jan 20, 2024
3bc4d51
Refactor token handlers to use async/await
vamsii777 Jan 20, 2024
1baab86
Update scopes property from [String]? to String? in AccessToken and R…
vamsii777 Feb 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/VaporOAuth/Models/OAuthClient.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Vapor

public final class OAuthClient: Extendable {
public struct OAuthClient {
public let clientID: String
public let redirectURIs: [String]?
public let clientSecret: String?
Expand Down
2 changes: 1 addition & 1 deletion Sources/VaporOAuth/Models/OAuthCode.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

public final class OAuthCode {
public struct OAuthCode {
public let codeID: String
public let clientID: String
public let redirectURI: String
Expand Down
9 changes: 1 addition & 8 deletions Sources/VaporOAuth/Models/OAuthDeviceCode.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
//
// OAuthDeviceCode.swift
//
//
// Created by Vamsi Madduluri on 24/08/23.
//

import Foundation

public final class OAuthDeviceCode {
public struct OAuthDeviceCode {
public let deviceCodeID: String
public let userCode: String
public let clientID: String
Expand Down
124 changes: 58 additions & 66 deletions Sources/VaporOAuth/Models/OAuthDiscoveryDocument.swift
Original file line number Diff line number Diff line change
@@ -1,70 +1,46 @@
import Vapor

public final class OAuthDiscoveryDocument: Content {
public let issuer: String
public let authorizationEndpoint: String
public let tokenEndpoint: String
public let userInfoEndpoint: String
public let revocationEndpoint: String
public let introspectionEndpoint: String
public let jwksURI: String
public let registrationEndpoint: String
public let scopesSupported: [String]
public let responseTypesSupported: [String]
public let grantTypesSupported: [String]
public let tokenEndpointAuthMethodsSupported: [String]
public let tokenEndpointAuthSigningAlgValuesSupported: [String]
public let serviceDocumentation: String
public let uiLocalesSupported: [String]
public let opPolicyURI: String
public let opTosURI: String
public let subjectTypesSupported: [String]
public let claimsSupported: [String]

public struct OAuthDiscoveryDocument: Content {

public var issuer: String?
public var authorizationEndpoint: String?
public var tokenEndpoint: String?
public var userInfoEndpoint: String?
public var revocationEndpoint: String?
public var introspectionEndpoint: String?
public var jwksURI: String?
public var registrationEndpoint: String?
public var scopesSupported: [String]?
public var responseTypesSupported: [String]?
public var responseModesSupported: [String]?
public var grantTypesSupported: [String]?
public var acrValuesSupported: [String]?
public var idTokenEncryptionAlgValuesSupported: [String]?
public var idTokenEncryptionEncValuesSupported: [String]?
public var userinfoSigningAlgValuesSupported: [String]?
public var userinfoEncryptionAlgValuesSupported: [String]?
public var userinfoEncryptionEncValuesSupported: [String]?
public var requestObjectSigningAlgValuesSupported: [String]?
public var requestObjectEncryptionAlgValuesSupported: [String]?
public var requestObjectEncryptionEncValuesSupported: [String]?
public var tokenEndpointAuthMethodsSupported: [String]?
public var tokenEndpointAuthSigningAlgValuesSupported: [String]?
public var displayValuesSupported: [String]?
public var claimTypesSupported: [String]?
public var claimsSupported: [String]?
public var serviceDocumentation: String?
public var claimsLocalesSupported: [String]?
public var uiLocalesSupported: [String]?
public var claimsParameterSupported: Bool?
public var requestParameterSupported: Bool?
public var requestUriParameterSupported: Bool?
public var requireRequestUriRegistration: Bool?
public var opPolicyURI: String?
public var opTosURI: String?
public var extend: [String: Any] = [:]

public init(
issuer: String,
authorizationEndpoint: String,
tokenEndpoint: String,
userInfoEndpoint: String,
revocationEndpoint: String,
introspectionEndpoint: String,
jwksURI: String,
registrationEndpoint: String,
scopesSupported: [String],
responseTypesSupported: [String],
grantTypesSupported: [String],
tokenEndpointAuthMethodsSupported: [String],
tokenEndpointAuthSigningAlgValuesSupported: [String],
serviceDocumentation: String,
uiLocalesSupported: [String],
opPolicyURI: String,
opTosURI: String,
subjectTypesSupported: [String],
claimsSupported: [String]
) {
self.issuer = issuer
self.authorizationEndpoint = authorizationEndpoint
self.tokenEndpoint = tokenEndpoint
self.userInfoEndpoint = userInfoEndpoint
self.revocationEndpoint = revocationEndpoint
self.introspectionEndpoint = introspectionEndpoint
self.jwksURI = jwksURI
self.registrationEndpoint = registrationEndpoint
self.scopesSupported = scopesSupported
self.responseTypesSupported = responseTypesSupported
self.grantTypesSupported = grantTypesSupported
self.tokenEndpointAuthMethodsSupported = tokenEndpointAuthMethodsSupported
self.tokenEndpointAuthSigningAlgValuesSupported = tokenEndpointAuthSigningAlgValuesSupported
self.serviceDocumentation = serviceDocumentation
self.uiLocalesSupported = uiLocalesSupported
self.opPolicyURI = opPolicyURI
self.opTosURI = opTosURI
self.subjectTypesSupported = subjectTypesSupported
self.claimsSupported = claimsSupported
}




// Exclude 'extend' property from encoding
private enum CodingKeys: String, CodingKey {
case issuer
Expand All @@ -77,14 +53,30 @@ public final class OAuthDiscoveryDocument: Content {
case registrationEndpoint
case scopesSupported
case responseTypesSupported
case responseModesSupported
case grantTypesSupported
case acrValuesSupported
case idTokenEncryptionAlgValuesSupported
case idTokenEncryptionEncValuesSupported
case userinfoSigningAlgValuesSupported
case userinfoEncryptionAlgValuesSupported
case userinfoEncryptionEncValuesSupported
case requestObjectSigningAlgValuesSupported
case requestObjectEncryptionAlgValuesSupported
case requestObjectEncryptionEncValuesSupported
case tokenEndpointAuthMethodsSupported
case tokenEndpointAuthSigningAlgValuesSupported
case displayValuesSupported
case claimTypesSupported
case claimsSupported
case serviceDocumentation
case claimsLocalesSupported
case uiLocalesSupported
case claimsParameterSupported
case requestParameterSupported
case requestUriParameterSupported
case requireRequestUriRegistration
case opPolicyURI
case opTosURI
case subjectTypesSupported
case claimsSupported
}
}
2 changes: 1 addition & 1 deletion Sources/VaporOAuth/Models/OAuthResourceServer.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Vapor

public final class OAuthResourceServer: Extendable {
public struct OAuthResourceServer {
public let username: String
public let password: String
public var extend: Vapor.Extend = .init()
Expand Down
43 changes: 35 additions & 8 deletions Sources/VaporOAuth/Models/OAuthUser.swift
Original file line number Diff line number Diff line change
@@ -1,52 +1,79 @@
import Vapor

public final class OAuthUser: Authenticatable, Content {

public struct OAuthUser: Authenticatable, Content {
public var id: String?
public let username: String
public let emailAddress: String?
public var password: String

// OpenID Connect specific attributes
public var name: String?
public var givenName: String?
public var familyName: String?
public var middleName: String?
public var nickname: String?
public var preferredUserName: String?
public var profile: String?
public var picture: String?
public var website: String?
public var emailVerified: Bool?
public var gender: String?
public var birthdate: String?
public var zoneinfo: String?
public var locale: String?
public var phoneNumber: String?
public var phoneNumberVerified: Bool?
public var address: Address?
public var extend: [String: String]?
public var updatedAt: Date?

public init(userID: String? = nil, username: String, emailAddress: String?, password: String,
name: String? = nil, givenName: String? = nil, familyName: String? = nil, middleName: String? = nil,
nickname: String? = nil, profile: String? = nil, picture: String? = nil, website: String? = nil,
gender: String? = nil, birthdate: String? = nil, zoneinfo: String? = nil, locale: String? = nil,
phoneNumber: String? = nil, extend: [String: String]? = nil, updatedAt: Date? = nil) {
nickname: String? = nil, preferredUserName: String? = nil, profile: String? = nil, picture: String? = nil,
website: String? = nil, emailVerified: Bool? = nil, gender: String? = nil, birthdate: String? = nil,
zoneinfo: String? = nil, locale: String? = nil, phoneNumber: String? = nil, phoneNumberVerified: Bool? = nil,
address: Address? = nil, extend: [String: String]? = nil, updatedAt: Date? = nil) {
self.id = userID
self.username = username
self.emailAddress = emailAddress
self.password = password
self.id = userID
self.name = name
self.givenName = givenName
self.familyName = familyName
self.middleName = middleName
self.nickname = nickname
self.preferredUserName = preferredUserName
self.profile = profile
self.picture = picture
self.website = website
self.emailVerified = emailVerified
self.gender = gender
self.birthdate = birthdate
self.zoneinfo = zoneinfo
self.locale = locale
self.phoneNumber = phoneNumber
self.phoneNumberVerified = phoneNumberVerified
self.address = address
self.extend = extend
self.updatedAt = updatedAt
}
}

public struct Address: Content {
public var formatted: String?
public var streetAddress: String?
public var locality: String?
public var region: String?
public var postalCode: String?
public var country: String?

public init(formatted: String? = nil, streetAddress: String? = nil, locality: String? = nil,
region: String? = nil, postalCode: String? = nil, country: String? = nil) {
self.formatted = formatted
self.streetAddress = streetAddress
self.locality = locality
self.region = region
self.postalCode = postalCode
self.country = country
}
}
2 changes: 1 addition & 1 deletion Sources/VaporOAuth/Models/Tokens/AccessToken.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public protocol AccessToken: JWTPayload {
var jti: String { get }
var clientID: String { get }
var userID: String? { get }
var scopes: [String]? { get }
var scopes: String? { get }
var expiryTime: Date { get }
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/VaporOAuth/Models/Tokens/RefreshToken.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public protocol RefreshToken: JWTPayload {
var jti: String { get set }
var clientID: String { get set }
var userID: String? { get set }
var scopes: [String]? { get set }
var scopes: String? { get set }
var exp: Date { get }
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/VaporOAuth/OAuth2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public struct OAuth2: LifecycleHandler {
clientValidator: clientValidator
)

let userInfoHandler = UserInfoHandler(jwtSignerService: jwtSignerService, userManager: userManager)
let userInfoHandler = UserInfoHandler(jwtSignerService: jwtSignerService, userManager: userManager, environment: app.environment)

let resourceServerAuthenticator = ResourceServerAuthenticator(resourceServerRetriever: resourceServerRetriever)

Expand Down
55 changes: 36 additions & 19 deletions Sources/VaporOAuth/Protocols/DiscoveryDocument.swift
Original file line number Diff line number Diff line change
@@ -1,25 +1,42 @@
import Foundation

public protocol DiscoveryDocument: Sendable {
var issuer: String { get }
var authorizationEndpoint: String { get }
var tokenEndpoint: String { get }
var userInfoEndpoint: String { get }
var revocationEndpoint: String { get }
var introspectionEndpoint: String { get }
var jwksURI: String { get }
var registrationEndpoint: String { get }
var scopesSupported: [String] { get }
var responseTypesSupported: [String] { get }
var grantTypesSupported: [String] { get }
var tokenEndpointAuthMethodsSupported: [String] { get }
var tokenEndpointAuthSigningAlgValuesSupported: [String] { get }
var serviceDocumentation: String { get }
var uiLocalesSupported: [String] { get }
var opPolicyURI: String { get }
var opTosURI: String { get }
var issuer: String? { get }
var authorizationEndpoint: String? { get }
var tokenEndpoint: String? { get }
var userInfoEndpoint: String? { get }
var revocationEndpoint: String? { get }
var introspectionEndpoint: String? { get }
var jwksURI: String? { get }
var registrationEndpoint: String? { get }
var scopesSupported: [String]? { get }
var responseTypesSupported: [String]? { get }
var responseModesSupported: [String]? { get }
var grantTypesSupported: [String]? { get }
var acrValuesSupported: [String]? { get }
var idTokenEncryptionAlgValuesSupported: [String]? { get }
var idTokenEncryptionEncValuesSupported: [String]? { get }
var userinfoSigningAlgValuesSupported: [String]? { get }
var userinfoEncryptionAlgValuesSupported: [String]? { get }
var userinfoEncryptionEncValuesSupported: [String]? { get }
var requestObjectSigningAlgValuesSupported: [String]? { get }
var requestObjectEncryptionAlgValuesSupported: [String]? { get }
var requestObjectEncryptionEncValuesSupported: [String]? { get }
var tokenEndpointAuthMethodsSupported: [String]? { get }
var tokenEndpointAuthSigningAlgValuesSupported: [String]? { get }
var displayValuesSupported: [String]? { get }
var claimTypesSupported: [String]? { get }
var claimsSupported: [String]? { get }
var serviceDocumentation: String? { get }
var claimsLocalesSupported: [String]? { get }
var uiLocalesSupported: [String]? { get }
var claimsParameterSupported: Bool? { get }
var requestParameterSupported: Bool? { get }
var requestUriParameterSupported: Bool? { get }
var requireRequestUriRegistration: Bool? { get }
var opPolicyURI: String? { get }
var opTosURI: String? { get }
var extend: [String: Any] { get set }
var resourceServerRetriever: ResourceServerRetriever? { get }
var subjectTypesSupported: [String] { get }
var claimsSupported: [String] { get }
var subjectTypesSupported: [String]? { get } // Made optional to align with OAuthDiscoveryDocument
}
Loading