Merge branch 'master' into signingkey
This commit is contained in:
commit
b2f23dc5b7
20 changed files with 240 additions and 134 deletions
|
@ -121,7 +121,7 @@ func ValidateAuthReqScopes(client Client, scopes []string) ([]string, error) {
|
|||
scope == oidc.ScopePhone ||
|
||||
scope == oidc.ScopeAddress ||
|
||||
scope == oidc.ScopeOfflineAccess) &&
|
||||
!utils.Contains(client.AllowedScopes(), scope) {
|
||||
!client.IsScopeAllowed(scope) {
|
||||
scopes[i] = scopes[len(scopes)-1]
|
||||
scopes[len(scopes)-1] = ""
|
||||
scopes = scopes[:len(scopes)-1]
|
||||
|
|
|
@ -34,9 +34,11 @@ type Client interface {
|
|||
AccessTokenType() AccessTokenType
|
||||
IDTokenLifetime() time.Duration
|
||||
DevMode() bool
|
||||
AllowedScopes() []string
|
||||
AssertAdditionalIdTokenScopes() bool
|
||||
AssertAdditionalAccessTokenScopes() bool
|
||||
RestrictAdditionalIdTokenScopes() func(scopes []string) []string
|
||||
RestrictAdditionalAccessTokenScopes() func(scopes []string) []string
|
||||
IsScopeAllowed(scope string) bool
|
||||
IDTokenUserinfoClaimsAssertion() bool
|
||||
ClockSkew() time.Duration
|
||||
}
|
||||
|
||||
func ContainsResponseType(types []oidc.ResponseType, responseType oidc.ResponseType) bool {
|
||||
|
|
|
@ -19,6 +19,8 @@ type Configuration interface {
|
|||
|
||||
AuthMethodPostSupported() bool
|
||||
CodeMethodS256Supported() bool
|
||||
GrantTypeTokenExchangeSupported() bool
|
||||
GrantTypeJWTAuthorizationSupported() bool
|
||||
}
|
||||
|
||||
func ValidateIssuer(issuer string) error {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -26,7 +26,7 @@ func NewClientExpectAny(t *testing.T, appType op.ApplicationType) op.Client {
|
|||
func(id string) string {
|
||||
return "login?id=" + id
|
||||
})
|
||||
m.EXPECT().AllowedScopes().AnyTimes().Return(nil)
|
||||
m.EXPECT().IsScopeAllowed(gomock.Any()).AnyTimes().Return(false)
|
||||
return c
|
||||
}
|
||||
|
||||
|
|
|
@ -49,20 +49,6 @@ func (mr *MockClientMockRecorder) AccessTokenType() *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessTokenType", reflect.TypeOf((*MockClient)(nil).AccessTokenType))
|
||||
}
|
||||
|
||||
// AllowedScopes mocks base method
|
||||
func (m *MockClient) AllowedScopes() []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AllowedScopes")
|
||||
ret0, _ := ret[0].([]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AllowedScopes indicates an expected call of AllowedScopes
|
||||
func (mr *MockClientMockRecorder) AllowedScopes() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllowedScopes", reflect.TypeOf((*MockClient)(nil).AllowedScopes))
|
||||
}
|
||||
|
||||
// ApplicationType mocks base method
|
||||
func (m *MockClient) ApplicationType() op.ApplicationType {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -77,34 +63,6 @@ func (mr *MockClientMockRecorder) ApplicationType() *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplicationType", reflect.TypeOf((*MockClient)(nil).ApplicationType))
|
||||
}
|
||||
|
||||
// AssertAdditionalAccessTokenScopes mocks base method
|
||||
func (m *MockClient) AssertAdditionalAccessTokenScopes() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AssertAdditionalAccessTokenScopes")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AssertAdditionalAccessTokenScopes indicates an expected call of AssertAdditionalAccessTokenScopes
|
||||
func (mr *MockClientMockRecorder) AssertAdditionalAccessTokenScopes() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssertAdditionalAccessTokenScopes", reflect.TypeOf((*MockClient)(nil).AssertAdditionalAccessTokenScopes))
|
||||
}
|
||||
|
||||
// AssertAdditionalIdTokenScopes mocks base method
|
||||
func (m *MockClient) AssertAdditionalIdTokenScopes() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AssertAdditionalIdTokenScopes")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AssertAdditionalIdTokenScopes indicates an expected call of AssertAdditionalIdTokenScopes
|
||||
func (mr *MockClientMockRecorder) AssertAdditionalIdTokenScopes() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssertAdditionalIdTokenScopes", reflect.TypeOf((*MockClient)(nil).AssertAdditionalIdTokenScopes))
|
||||
}
|
||||
|
||||
// AuthMethod mocks base method
|
||||
func (m *MockClient) AuthMethod() op.AuthMethod {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -119,6 +77,20 @@ func (mr *MockClientMockRecorder) AuthMethod() *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethod", reflect.TypeOf((*MockClient)(nil).AuthMethod))
|
||||
}
|
||||
|
||||
// ClockSkew mocks base method
|
||||
func (m *MockClient) ClockSkew() time.Duration {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ClockSkew")
|
||||
ret0, _ := ret[0].(time.Duration)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ClockSkew indicates an expected call of ClockSkew
|
||||
func (mr *MockClientMockRecorder) ClockSkew() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClockSkew", reflect.TypeOf((*MockClient)(nil).ClockSkew))
|
||||
}
|
||||
|
||||
// DevMode mocks base method
|
||||
func (m *MockClient) DevMode() bool {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -161,6 +133,34 @@ func (mr *MockClientMockRecorder) IDTokenLifetime() *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDTokenLifetime", reflect.TypeOf((*MockClient)(nil).IDTokenLifetime))
|
||||
}
|
||||
|
||||
// IDTokenUserinfoClaimsAssertion mocks base method
|
||||
func (m *MockClient) IDTokenUserinfoClaimsAssertion() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IDTokenUserinfoClaimsAssertion")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IDTokenUserinfoClaimsAssertion indicates an expected call of IDTokenUserinfoClaimsAssertion
|
||||
func (mr *MockClientMockRecorder) IDTokenUserinfoClaimsAssertion() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDTokenUserinfoClaimsAssertion", reflect.TypeOf((*MockClient)(nil).IDTokenUserinfoClaimsAssertion))
|
||||
}
|
||||
|
||||
// IsScopeAllowed mocks base method
|
||||
func (m *MockClient) IsScopeAllowed(arg0 string) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsScopeAllowed", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsScopeAllowed indicates an expected call of IsScopeAllowed
|
||||
func (mr *MockClientMockRecorder) IsScopeAllowed(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsScopeAllowed", reflect.TypeOf((*MockClient)(nil).IsScopeAllowed), arg0)
|
||||
}
|
||||
|
||||
// LoginURL mocks base method
|
||||
func (m *MockClient) LoginURL(arg0 string) string {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -216,3 +216,31 @@ func (mr *MockClientMockRecorder) ResponseTypes() *gomock.Call {
|
|||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResponseTypes", reflect.TypeOf((*MockClient)(nil).ResponseTypes))
|
||||
}
|
||||
|
||||
// RestrictAdditionalAccessTokenScopes mocks base method
|
||||
func (m *MockClient) RestrictAdditionalAccessTokenScopes() func([]string) []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RestrictAdditionalAccessTokenScopes")
|
||||
ret0, _ := ret[0].(func([]string) []string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RestrictAdditionalAccessTokenScopes indicates an expected call of RestrictAdditionalAccessTokenScopes
|
||||
func (mr *MockClientMockRecorder) RestrictAdditionalAccessTokenScopes() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RestrictAdditionalAccessTokenScopes", reflect.TypeOf((*MockClient)(nil).RestrictAdditionalAccessTokenScopes))
|
||||
}
|
||||
|
||||
// RestrictAdditionalIdTokenScopes mocks base method
|
||||
func (m *MockClient) RestrictAdditionalIdTokenScopes() func([]string) []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RestrictAdditionalIdTokenScopes")
|
||||
ret0, _ := ret[0].(func([]string) []string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RestrictAdditionalIdTokenScopes indicates an expected call of RestrictAdditionalIdTokenScopes
|
||||
func (mr *MockClientMockRecorder) RestrictAdditionalIdTokenScopes() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RestrictAdditionalIdTokenScopes", reflect.TypeOf((*MockClient)(nil).RestrictAdditionalIdTokenScopes))
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -156,9 +156,24 @@ func (c *ConfClient) DevMode() bool {
|
|||
func (c *ConfClient) AllowedScopes() []string {
|
||||
return nil
|
||||
}
|
||||
func (c *ConfClient) AssertAdditionalIdTokenScopes() bool {
|
||||
func (c *ConfClient) RestrictAdditionalIdTokenScopes() func(scopes []string) []string {
|
||||
return func(scopes []string) []string {
|
||||
return scopes
|
||||
}
|
||||
}
|
||||
func (c *ConfClient) RestrictAdditionalAccessTokenScopes() func(scopes []string) []string {
|
||||
return func(scopes []string) []string {
|
||||
return scopes
|
||||
}
|
||||
}
|
||||
func (c *ConfClient) IsScopeAllowed(scope string) bool {
|
||||
return false
|
||||
}
|
||||
func (c *ConfClient) AssertAdditionalAccessTokenScopes() bool {
|
||||
|
||||
func (c *ConfClient) IDTokenUserinfoClaimsAssertion() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *ConfClient) ClockSkew() time.Duration {
|
||||
return 0
|
||||
}
|
||||
|
|
20
pkg/op/op.go
20
pkg/op/op.go
|
@ -49,7 +49,6 @@ type OpenIDProvider interface {
|
|||
Decoder() utils.Decoder
|
||||
Encoder() utils.Encoder
|
||||
IDTokenHintVerifier() IDTokenHintVerifier
|
||||
JWTProfileVerifier() JWTProfileVerifier
|
||||
AccessTokenVerifier() AccessTokenVerifier
|
||||
Crypto() Crypto
|
||||
DefaultLogoutRedirectURI() string
|
||||
|
@ -76,7 +75,7 @@ func CreateRouter(o OpenIDProvider, interceptors ...HttpInterceptor) *mux.Router
|
|||
router.HandleFunc(readinessEndpoint, readyHandler(o.Probes()))
|
||||
router.HandleFunc(oidc.DiscoveryEndpoint, discoveryHandler(o, o.Signer()))
|
||||
router.Handle(o.AuthorizationEndpoint().Relative(), intercept(authorizeHandler(o)))
|
||||
router.Handle(o.AuthorizationEndpoint().Relative()+"/{id}", intercept(authorizeCallbackHandler(o)))
|
||||
router.NewRoute().Path(o.AuthorizationEndpoint().Relative()+"/callback").Queries("id", "{id}").Handler(intercept(authorizeCallbackHandler(o)))
|
||||
router.Handle(o.TokenEndpoint().Relative(), intercept(tokenHandler(o)))
|
||||
router.HandleFunc(o.UserinfoEndpoint().Relative(), userinfoHandler(o))
|
||||
router.Handle(o.EndSessionEndpoint().Relative(), intercept(endSessionHandler(o)))
|
||||
|
@ -89,15 +88,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 {
|
||||
|
@ -195,6 +185,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
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ func CreateTokenResponse(ctx context.Context, authReq AuthRequest, client Client
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
idToken, err := CreateIDToken(ctx, creator.Issuer(), authReq, client.IDTokenLifetime(), accessToken, code, creator.Storage(), creator.Signer(), client.AssertAdditionalIdTokenScopes())
|
||||
idToken, err := CreateIDToken(ctx, creator.Issuer(), authReq, client.IDTokenLifetime(), accessToken, code, creator.Storage(), creator.Signer(), client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func CreateAccessToken(ctx context.Context, tokenRequest TokenRequest, accessTok
|
|||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
validity = exp.Sub(time.Now().UTC())
|
||||
validity = exp.Add(client.ClockSkew()).Sub(time.Now().UTC())
|
||||
if accessTokenType == AccessTokenTypeJWT {
|
||||
token, err = CreateJWT(ctx, creator.Issuer(), tokenRequest, exp, id, creator.Signer(), client, creator.Storage())
|
||||
return
|
||||
|
@ -83,9 +83,10 @@ func CreateBearerToken(tokenID, subject string, crypto Crypto) (string, error) {
|
|||
}
|
||||
|
||||
func CreateJWT(ctx context.Context, issuer string, tokenRequest TokenRequest, exp time.Time, id string, signer Signer, client Client, storage Storage) (string, error) {
|
||||
claims := oidc.NewAccessTokenClaims(issuer, tokenRequest.GetSubject(), tokenRequest.GetAudience(), exp, id)
|
||||
if client != nil && client.AssertAdditionalAccessTokenScopes() {
|
||||
privateClaims, err := storage.GetPrivateClaimsFromScopes(ctx, tokenRequest.GetSubject(), client.GetID(), removeUserinfoScopes(tokenRequest.GetScopes()))
|
||||
claims := oidc.NewAccessTokenClaims(issuer, tokenRequest.GetSubject(), tokenRequest.GetAudience(), exp, id, client.GetID(), client.ClockSkew())
|
||||
if client != nil {
|
||||
restrictedScopes := client.RestrictAdditionalAccessTokenScopes()(tokenRequest.GetScopes())
|
||||
privateClaims, err := storage.GetPrivateClaimsFromScopes(ctx, tokenRequest.GetSubject(), client.GetID(), removeUserinfoScopes(restrictedScopes))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -94,21 +95,19 @@ func CreateJWT(ctx context.Context, issuer string, tokenRequest TokenRequest, ex
|
|||
return utils.Sign(claims, signer.Signer())
|
||||
}
|
||||
|
||||
func CreateIDToken(ctx context.Context, issuer string, authReq AuthRequest, validity time.Duration, accessToken, code string, storage Storage, signer Signer, additonalScopes bool) (string, error) {
|
||||
exp := time.Now().UTC().Add(validity)
|
||||
claims := oidc.NewIDTokenClaims(issuer, authReq.GetSubject(), authReq.GetAudience(), exp, authReq.GetAuthTime(), authReq.GetNonce(), authReq.GetACR(), authReq.GetAMR(), authReq.GetClientID())
|
||||
scopes := authReq.GetScopes()
|
||||
|
||||
func CreateIDToken(ctx context.Context, issuer string, authReq AuthRequest, validity time.Duration, accessToken, code string, storage Storage, signer Signer, client Client) (string, error) {
|
||||
exp := time.Now().UTC().Add(client.ClockSkew()).Add(validity)
|
||||
claims := oidc.NewIDTokenClaims(issuer, authReq.GetSubject(), authReq.GetAudience(), exp, authReq.GetAuthTime(), authReq.GetNonce(), authReq.GetACR(), authReq.GetAMR(), authReq.GetClientID(), client.ClockSkew())
|
||||
scopes := client.RestrictAdditionalIdTokenScopes()(authReq.GetScopes())
|
||||
if accessToken != "" {
|
||||
atHash, err := oidc.ClaimHash(accessToken, signer.SignatureAlgorithm())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
claims.SetAccessTokenHash(atHash)
|
||||
scopes = removeUserinfoScopes(scopes)
|
||||
}
|
||||
if !additonalScopes {
|
||||
scopes = removeAdditionalScopes(scopes)
|
||||
if !client.IDTokenUserinfoClaimsAssertion() {
|
||||
scopes = removeUserinfoScopes(scopes)
|
||||
}
|
||||
}
|
||||
if len(scopes) > 0 {
|
||||
userInfo, err := storage.GetUserinfoFromScopes(ctx, authReq.GetSubject(), authReq.GetClientID(), scopes)
|
||||
|
@ -142,19 +141,3 @@ func removeUserinfoScopes(scopes []string) []string {
|
|||
}
|
||||
return scopes
|
||||
}
|
||||
|
||||
func removeAdditionalScopes(scopes []string) []string {
|
||||
for i := len(scopes) - 1; i >= 0; i-- {
|
||||
if !(scopes[i] == oidc.ScopeOpenID ||
|
||||
scopes[i] == oidc.ScopeProfile ||
|
||||
scopes[i] == oidc.ScopeEmail ||
|
||||
scopes[i] == oidc.ScopeAddress ||
|
||||
scopes[i] == oidc.ScopePhone) {
|
||||
|
||||
scopes[i] = scopes[len(scopes)-1]
|
||||
scopes[len(scopes)-1] = ""
|
||||
scopes = scopes[:len(scopes)-1]
|
||||
}
|
||||
}
|
||||
return scopes
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/oidc/grants/tokenexchange"
|
||||
|
@ -17,6 +18,12 @@ type Exchanger interface {
|
|||
Signer() Signer
|
||||
Crypto() Crypto
|
||||
AuthMethodPostSupported() bool
|
||||
GrantTypeTokenExchangeSupported() bool
|
||||
GrantTypeJWTAuthorizationSupported() bool
|
||||
}
|
||||
|
||||
type JWTAuthorizationGrantExchanger interface {
|
||||
Exchanger
|
||||
JWTProfileVerifier() JWTProfileVerifier
|
||||
}
|
||||
|
||||
|
@ -27,17 +34,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"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,9 +85,14 @@ func ParseAccessTokenRequest(r *http.Request, decoder utils.Decoder) (*oidc.Acce
|
|||
}
|
||||
clientID, clientSecret, ok := r.BasicAuth()
|
||||
if ok {
|
||||
tokenReq.ClientID = clientID
|
||||
tokenReq.ClientSecret = clientSecret
|
||||
|
||||
tokenReq.ClientID, err = url.QueryUnescape(clientID)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidRequest("invalid basic auth header")
|
||||
}
|
||||
tokenReq.ClientSecret, err = url.QueryUnescape(clientSecret)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidRequest("invalid basic auth header")
|
||||
}
|
||||
}
|
||||
return tokenReq, nil
|
||||
}
|
||||
|
@ -106,7 +121,7 @@ func AuthorizeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exc
|
|||
return authReq, client, err
|
||||
}
|
||||
if client.AuthMethod() == AuthMethodPost && !exchanger.AuthMethodPostSupported() {
|
||||
return nil, nil, errors.New("basic not supported")
|
||||
return nil, nil, errors.New("auth_method post not supported")
|
||||
}
|
||||
err = AuthorizeClientIDSecret(ctx, tokenReq.ClientID, tokenReq.ClientSecret, exchanger.Storage())
|
||||
if err != nil {
|
||||
|
@ -137,7 +152,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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue