diff --git a/pkg/oidc/token_request.go b/pkg/oidc/token_request.go index e80d28a4..1312b189 100644 --- a/pkg/oidc/token_request.go +++ b/pkg/oidc/token_request.go @@ -9,8 +9,12 @@ import ( const ( //GrantTypeCode defines the grant_type `authorization_code` used for the Token Request in the Authorization Code Flow GrantTypeCode GrantType = "authorization_code" - //GrantTypeBearer define the grant_type `urn:ietf:params:oauth:grant-type:jwt-bearer` used for the JWT Authorization Grant + + //GrantTypeBearer defines the grant_type `urn:ietf:params:oauth:grant-type:jwt-bearer` used for the JWT Authorization Grant GrantTypeBearer GrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer" + + //GrantTypeTokenExchange defines the grant_type `urn:ietf:params:oauth:grant-type:token-exchange` used for the OAuth Token Exchange Grant + GrantTypeTokenExchange GrantType = "urn:ietf:params:oauth:grant-type:token-exchange" ) type GrantType string diff --git a/pkg/op/config.go b/pkg/op/config.go index d64c0ee4..a2b831e9 100644 --- a/pkg/op/config.go +++ b/pkg/op/config.go @@ -19,6 +19,8 @@ type Configuration interface { AuthMethodPostSupported() bool CodeMethodS256Supported() bool + GrantTypeTokenExchangeSupported() bool + GrantTypeJWTAuthorizationSupported() bool } func ValidateIssuer(issuer string) error { diff --git a/pkg/op/discovery.go b/pkg/op/discovery.go index 76110907..4bc12722 100644 --- a/pkg/op/discovery.go +++ b/pkg/op/discovery.go @@ -52,22 +52,23 @@ func Scopes(c Configuration) []string { func ResponseTypes(c Configuration) []string { return []string{ - "code", - "id_token", - // "code token", - // "code id_token", - "id_token token", - // "code id_token token" - } + string(oidc.ResponseTypeCode), + string(oidc.ResponseTypeIDTokenOnly), + string(oidc.ResponseTypeIDToken), + } //TODO: ok for now, check later if dynamic needed } func GrantTypes(c Configuration) []string { - return []string{ - "client_credentials", - "authorization_code", - // "password", - "urn:ietf:params:oauth:grant-type:token-exchange", + grantTypes := []string{ + string(oidc.GrantTypeCode), + } + if c.GrantTypeTokenExchangeSupported() { + grantTypes = append(grantTypes, string(oidc.GrantTypeTokenExchange)) + } + if c.GrantTypeJWTAuthorizationSupported() { + grantTypes = append(grantTypes, string(oidc.GrantTypeBearer)) } + return grantTypes } func SupportedClaims(c Configuration) []string { diff --git a/pkg/op/mock/configuration.mock.go b/pkg/op/mock/configuration.mock.go index 88e9aa71..ece747c4 100644 --- a/pkg/op/mock/configuration.mock.go +++ b/pkg/op/mock/configuration.mock.go @@ -89,6 +89,34 @@ func (mr *MockConfigurationMockRecorder) EndSessionEndpoint() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EndSessionEndpoint", reflect.TypeOf((*MockConfiguration)(nil).EndSessionEndpoint)) } +// GrantTypeJWTAuthorizationSupported mocks base method +func (m *MockConfiguration) GrantTypeJWTAuthorizationSupported() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrantTypeJWTAuthorizationSupported") + ret0, _ := ret[0].(bool) + return ret0 +} + +// GrantTypeJWTAuthorizationSupported indicates an expected call of GrantTypeJWTAuthorizationSupported +func (mr *MockConfigurationMockRecorder) GrantTypeJWTAuthorizationSupported() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeJWTAuthorizationSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeJWTAuthorizationSupported)) +} + +// GrantTypeTokenExchangeSupported mocks base method +func (m *MockConfiguration) GrantTypeTokenExchangeSupported() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrantTypeTokenExchangeSupported") + ret0, _ := ret[0].(bool) + return ret0 +} + +// GrantTypeTokenExchangeSupported indicates an expected call of GrantTypeTokenExchangeSupported +func (mr *MockConfigurationMockRecorder) GrantTypeTokenExchangeSupported() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeTokenExchangeSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeTokenExchangeSupported)) +} + // Issuer mocks base method func (m *MockConfiguration) Issuer() string { m.ctrl.T.Helper() diff --git a/pkg/op/op.go b/pkg/op/op.go index bba7a140..3d2fe41e 100644 --- a/pkg/op/op.go +++ b/pkg/op/op.go @@ -50,7 +50,6 @@ type OpenIDProvider interface { Decoder() utils.Decoder Encoder() utils.Encoder IDTokenHintVerifier() IDTokenHintVerifier - JWTProfileVerifier() JWTProfileVerifier AccessTokenVerifier() AccessTokenVerifier Crypto() Crypto DefaultLogoutRedirectURI() string @@ -90,15 +89,6 @@ type Config struct { CryptoKey [32]byte DefaultLogoutRedirectURI string CodeMethodS256 bool - - //TODO: add to config after updating Configuration interface for DiscoveryConfig - // ScopesSupported: oidc.SupportedScopes, - // ResponseTypesSupported: responseTypes, - // GrantTypesSupported: oidc.SupportedGrantTypes, - // ClaimsSupported: oidc.SupportedClaims, - // IdTokenSigningAlgValuesSupported: []string{keys.SigningAlgorithm}, - // SubjectTypesSupported: []string{"public"}, - // TokenEndpointAuthMethodsSupported: } type endpoints struct { @@ -196,6 +186,14 @@ func (o *openidProvider) CodeMethodS256Supported() bool { return o.config.CodeMethodS256 } +func (o *openidProvider) GrantTypeTokenExchangeSupported() bool { + return false +} + +func (o *openidProvider) GrantTypeJWTAuthorizationSupported() bool { + return true +} + func (o *openidProvider) Storage() Storage { return o.storage } diff --git a/pkg/op/tokenrequest.go b/pkg/op/tokenrequest.go index cba70f35..d4142215 100644 --- a/pkg/op/tokenrequest.go +++ b/pkg/op/tokenrequest.go @@ -17,6 +17,12 @@ type Exchanger interface { Signer() Signer Crypto() Crypto AuthMethodPostSupported() bool + GrantTypeTokenExchangeSupported() bool + GrantTypeJWTAuthorizationSupported() bool +} + +type JWTAuthorizationGrantExchanger interface { + Exchanger JWTProfileVerifier() JWTProfileVerifier } @@ -27,17 +33,20 @@ func tokenHandler(exchanger Exchanger) func(w http.ResponseWriter, r *http.Reque CodeExchange(w, r, exchanger) return case string(oidc.GrantTypeBearer): - JWTProfile(w, r, exchanger) - return - case "exchange": - TokenExchange(w, r, exchanger) + if ex, ok := exchanger.(JWTAuthorizationGrantExchanger); ok && exchanger.GrantTypeJWTAuthorizationSupported() { + JWTProfile(w, r, ex) + return + } + case string(oidc.GrantTypeTokenExchange): + if exchanger.GrantTypeTokenExchangeSupported() { + TokenExchange(w, r, exchanger) + return + } case "": RequestError(w, r, ErrInvalidRequest("grant_type missing")) return - default: - RequestError(w, r, ErrInvalidRequest("grant_type not supported")) - return } + RequestError(w, r, ErrInvalidRequest("grant_type not supported")) } } @@ -137,7 +146,7 @@ func AuthorizeCodeChallenge(ctx context.Context, tokenReq *oidc.AccessTokenReque return authReq, nil } -func JWTProfile(w http.ResponseWriter, r *http.Request, exchanger Exchanger) { +func JWTProfile(w http.ResponseWriter, r *http.Request, exchanger JWTAuthorizationGrantExchanger) { profileRequest, err := ParseJWTProfileRequest(r, exchanger.Decoder()) if err != nil { RequestError(w, r, err)