introspect and client assertion
This commit is contained in:
parent
a1a21f0d59
commit
50ab51bb46
15 changed files with 171 additions and 60 deletions
|
@ -184,22 +184,22 @@ func (s *AuthStorage) GetClientByClientID(_ context.Context, id string) (op.Clie
|
||||||
return nil, errors.New("not found")
|
return nil, errors.New("not found")
|
||||||
}
|
}
|
||||||
var appType op.ApplicationType
|
var appType op.ApplicationType
|
||||||
var authMethod op.AuthMethod
|
var authMethod oidc.AuthMethod
|
||||||
var accessTokenType op.AccessTokenType
|
var accessTokenType op.AccessTokenType
|
||||||
var responseTypes []oidc.ResponseType
|
var responseTypes []oidc.ResponseType
|
||||||
if id == "web" {
|
if id == "web" {
|
||||||
appType = op.ApplicationTypeWeb
|
appType = op.ApplicationTypeWeb
|
||||||
authMethod = op.AuthMethodBasic
|
authMethod = oidc.AuthMethodBasic
|
||||||
accessTokenType = op.AccessTokenTypeBearer
|
accessTokenType = op.AccessTokenTypeBearer
|
||||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
||||||
} else if id == "native" {
|
} else if id == "native" {
|
||||||
appType = op.ApplicationTypeNative
|
appType = op.ApplicationTypeNative
|
||||||
authMethod = op.AuthMethodNone
|
authMethod = oidc.AuthMethodNone
|
||||||
accessTokenType = op.AccessTokenTypeBearer
|
accessTokenType = op.AccessTokenTypeBearer
|
||||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
||||||
} else {
|
} else {
|
||||||
appType = op.ApplicationTypeUserAgent
|
appType = op.ApplicationTypeUserAgent
|
||||||
authMethod = op.AuthMethodNone
|
authMethod = oidc.AuthMethodNone
|
||||||
accessTokenType = op.AccessTokenTypeJWT
|
accessTokenType = op.AccessTokenTypeJWT
|
||||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken, oidc.ResponseTypeIDTokenOnly}
|
responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken, oidc.ResponseTypeIDTokenOnly}
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ func (s *AuthStorage) GetPrivateClaimsFromScopes(_ context.Context, _, _ string,
|
||||||
|
|
||||||
type ConfClient struct {
|
type ConfClient struct {
|
||||||
applicationType op.ApplicationType
|
applicationType op.ApplicationType
|
||||||
authMethod op.AuthMethod
|
authMethod oidc.AuthMethod
|
||||||
responseTypes []oidc.ResponseType
|
responseTypes []oidc.ResponseType
|
||||||
ID string
|
ID string
|
||||||
accessTokenType op.AccessTokenType
|
accessTokenType op.AccessTokenType
|
||||||
|
@ -262,7 +262,7 @@ func (c *ConfClient) ApplicationType() op.ApplicationType {
|
||||||
return c.applicationType
|
return c.applicationType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) AuthMethod() op.AuthMethod {
|
func (c *ConfClient) AuthMethod() oidc.AuthMethod {
|
||||||
return c.authMethod
|
return c.authMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,16 @@ type DiscoveryConfiguration struct {
|
||||||
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
|
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
|
||||||
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
|
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
|
||||||
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"`
|
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"`
|
||||||
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
|
TokenEndpointAuthMethodsSupported []AuthMethod `json:"token_endpoint_auth_methods_supported,omitempty"`
|
||||||
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
|
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
|
||||||
ClaimsSupported []string `json:"claims_supported,omitempty"`
|
ClaimsSupported []string `json:"claims_supported,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AuthMethod string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuthMethodBasic AuthMethod = "client_secret_basic"
|
||||||
|
AuthMethodPost AuthMethod = "client_secret_post"
|
||||||
|
AuthMethodNone AuthMethod = "none"
|
||||||
|
AuthMethodPrivateKeyJWT AuthMethod = "private_key_jwt"
|
||||||
|
)
|
||||||
|
|
|
@ -209,7 +209,7 @@ func (i *introspectionResponse) MarshalJSON() ([]byte, error) {
|
||||||
*Alias
|
*Alias
|
||||||
Locale interface{} `json:"locale,omitempty"`
|
Locale interface{} `json:"locale,omitempty"`
|
||||||
UpdatedAt int64 `json:"updated_at,omitempty"`
|
UpdatedAt int64 `json:"updated_at,omitempty"`
|
||||||
PreferredUsername string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
}{
|
}{
|
||||||
Alias: (*Alias)(i),
|
Alias: (*Alias)(i),
|
||||||
}
|
}
|
||||||
|
@ -219,8 +219,7 @@ func (i *introspectionResponse) MarshalJSON() ([]byte, error) {
|
||||||
if !time.Time(i.UpdatedAt).IsZero() {
|
if !time.Time(i.UpdatedAt).IsZero() {
|
||||||
a.UpdatedAt = time.Time(i.UpdatedAt).Unix()
|
a.UpdatedAt = time.Time(i.UpdatedAt).Unix()
|
||||||
}
|
}
|
||||||
a.PreferredUsername = i.PreferredUsername
|
a.Username = i.PreferredUsername
|
||||||
i.PreferredUsername = ""
|
|
||||||
|
|
||||||
b, err := json.Marshal(a)
|
b, err := json.Marshal(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,6 +15,10 @@ const (
|
||||||
|
|
||||||
//GrantTypeTokenExchange defines the grant_type `urn:ietf:params:oauth:grant-type:token-exchange` used for the OAuth Token Exchange Grant
|
//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"
|
GrantTypeTokenExchange GrantType = "urn:ietf:params:oauth:grant-type:token-exchange"
|
||||||
|
|
||||||
|
//ClientAssertionTypeJWTAssertion defines the client_assertion_type `urn:ietf:params:oauth:client-assertion-type:jwt-bearer`
|
||||||
|
//used for the OAuth JWT Profile Client Authentication
|
||||||
|
ClientAssertionTypeJWTAssertion = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GrantType string
|
type GrantType string
|
||||||
|
@ -32,6 +36,8 @@ type AccessTokenRequest struct {
|
||||||
ClientID string `schema:"client_id"`
|
ClientID string `schema:"client_id"`
|
||||||
ClientSecret string `schema:"client_secret"`
|
ClientSecret string `schema:"client_secret"`
|
||||||
CodeVerifier string `schema:"code_verifier"`
|
CodeVerifier string `schema:"code_verifier"`
|
||||||
|
ClientAssertion string `schema:"client_assertion"`
|
||||||
|
ClientAssertionType string `schema:"client_assertion_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AccessTokenRequest) GrantType() GrantType {
|
func (a *AccessTokenRequest) GrantType() GrantType {
|
||||||
|
|
|
@ -28,7 +28,7 @@ type Client interface {
|
||||||
RedirectURIs() []string
|
RedirectURIs() []string
|
||||||
PostLogoutRedirectURIs() []string
|
PostLogoutRedirectURIs() []string
|
||||||
ApplicationType() ApplicationType
|
ApplicationType() ApplicationType
|
||||||
AuthMethod() AuthMethod
|
AuthMethod() oidc.AuthMethod
|
||||||
ResponseTypes() []oidc.ResponseType
|
ResponseTypes() []oidc.ResponseType
|
||||||
LoginURL(string) string
|
LoginURL(string) string
|
||||||
AccessTokenType() AccessTokenType
|
AccessTokenType() AccessTokenType
|
||||||
|
|
|
@ -20,6 +20,7 @@ type Configuration interface {
|
||||||
|
|
||||||
AuthMethodPostSupported() bool
|
AuthMethodPostSupported() bool
|
||||||
CodeMethodS256Supported() bool
|
CodeMethodS256Supported() bool
|
||||||
|
AuthMethodPrivateKeyJWTSupported() bool
|
||||||
GrantTypeTokenExchangeSupported() bool
|
GrantTypeTokenExchangeSupported() bool
|
||||||
GrantTypeJWTAuthorizationSupported() bool
|
GrantTypeJWTAuthorizationSupported() bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,12 +108,16 @@ func SubjectTypes(c Configuration) []string {
|
||||||
return []string{"public"} //TODO: config
|
return []string{"public"} //TODO: config
|
||||||
}
|
}
|
||||||
|
|
||||||
func AuthMethods(c Configuration) []string {
|
func AuthMethods(c Configuration) []oidc.AuthMethod {
|
||||||
authMethods := []string{
|
authMethods := []oidc.AuthMethod{
|
||||||
string(AuthMethodBasic),
|
oidc.AuthMethodNone,
|
||||||
|
oidc.AuthMethodBasic,
|
||||||
}
|
}
|
||||||
if c.AuthMethodPostSupported() {
|
if c.AuthMethodPostSupported() {
|
||||||
authMethods = append(authMethods, string(AuthMethodPost))
|
authMethods = append(authMethods, oidc.AuthMethodPost)
|
||||||
|
}
|
||||||
|
if c.AuthMethodPrivateKeyJWTSupported() {
|
||||||
|
authMethods = append(authMethods, oidc.AuthMethodPrivateKeyJWT)
|
||||||
}
|
}
|
||||||
return authMethods
|
return authMethods
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,10 +64,10 @@ func (mr *MockClientMockRecorder) ApplicationType() *gomock.Call {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthMethod mocks base method
|
// AuthMethod mocks base method
|
||||||
func (m *MockClient) AuthMethod() op.AuthMethod {
|
func (m *MockClient) AuthMethod() oidc.AuthMethod {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "AuthMethod")
|
ret := m.ctrl.Call(m, "AuthMethod")
|
||||||
ret0, _ := ret[0].(op.AuthMethod)
|
ret0, _ := ret[0].(oidc.AuthMethod)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,20 @@ func (mr *MockConfigurationMockRecorder) AuthMethodPostSupported() *gomock.Call
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethodPostSupported", reflect.TypeOf((*MockConfiguration)(nil).AuthMethodPostSupported))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethodPostSupported", reflect.TypeOf((*MockConfiguration)(nil).AuthMethodPostSupported))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthMethodPrivateKeyJWTSupported mocks base method
|
||||||
|
func (m *MockConfiguration) AuthMethodPrivateKeyJWTSupported() bool {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AuthMethodPrivateKeyJWTSupported")
|
||||||
|
ret0, _ := ret[0].(bool)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthMethodPrivateKeyJWTSupported indicates an expected call of AuthMethodPrivateKeyJWTSupported
|
||||||
|
func (mr *MockConfigurationMockRecorder) AuthMethodPrivateKeyJWTSupported() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethodPrivateKeyJWTSupported", reflect.TypeOf((*MockConfiguration)(nil).AuthMethodPrivateKeyJWTSupported))
|
||||||
|
}
|
||||||
|
|
||||||
// AuthorizationEndpoint mocks base method
|
// AuthorizationEndpoint mocks base method
|
||||||
func (m *MockConfiguration) AuthorizationEndpoint() op.Endpoint {
|
func (m *MockConfiguration) AuthorizationEndpoint() op.Endpoint {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -117,6 +131,20 @@ func (mr *MockConfigurationMockRecorder) GrantTypeTokenExchangeSupported() *gomo
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeTokenExchangeSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeTokenExchangeSupported))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeTokenExchangeSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeTokenExchangeSupported))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IntrospectionEndpoint mocks base method
|
||||||
|
func (m *MockConfiguration) IntrospectionEndpoint() op.Endpoint {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "IntrospectionEndpoint")
|
||||||
|
ret0, _ := ret[0].(op.Endpoint)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntrospectionEndpoint indicates an expected call of IntrospectionEndpoint
|
||||||
|
func (mr *MockConfigurationMockRecorder) IntrospectionEndpoint() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntrospectionEndpoint", reflect.TypeOf((*MockConfiguration)(nil).IntrospectionEndpoint))
|
||||||
|
}
|
||||||
|
|
||||||
// Issuer mocks base method
|
// Issuer mocks base method
|
||||||
func (m *MockConfiguration) Issuer() string {
|
func (m *MockConfiguration) Issuer() string {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
@ -270,6 +270,34 @@ func (mr *MockStorageMockRecorder) SaveNewKeyPair(arg0 interface{}) *gomock.Call
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveNewKeyPair", reflect.TypeOf((*MockStorage)(nil).SaveNewKeyPair), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveNewKeyPair", reflect.TypeOf((*MockStorage)(nil).SaveNewKeyPair), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetUserinfoFromScopes mocks base method
|
||||||
|
func (m *MockStorage) SetUserinfoFromScopes(arg0 context.Context, arg1 oidc.UserInfoSetter, arg2, arg3 string, arg4 []string) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "SetUserinfoFromScopes", arg0, arg1, arg2, arg3, arg4)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserinfoFromScopes indicates an expected call of SetUserinfoFromScopes
|
||||||
|
func (mr *MockStorageMockRecorder) SetUserinfoFromScopes(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserinfoFromScopes", reflect.TypeOf((*MockStorage)(nil).SetUserinfoFromScopes), arg0, arg1, arg2, arg3, arg4)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserinfoFromToken mocks base method
|
||||||
|
func (m *MockStorage) SetUserinfoFromToken(arg0 context.Context, arg1 oidc.UserInfoSetter, arg2, arg3, arg4 string) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "SetUserinfoFromToken", arg0, arg1, arg2, arg3, arg4)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserinfoFromToken indicates an expected call of SetUserinfoFromToken
|
||||||
|
func (mr *MockStorageMockRecorder) SetUserinfoFromToken(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserinfoFromToken", reflect.TypeOf((*MockStorage)(nil).SetUserinfoFromToken), arg0, arg1, arg2, arg3, arg4)
|
||||||
|
}
|
||||||
|
|
||||||
// TerminateSession mocks base method
|
// TerminateSession mocks base method
|
||||||
func (m *MockStorage) TerminateSession(arg0 context.Context, arg1, arg2 string) error {
|
func (m *MockStorage) TerminateSession(arg0 context.Context, arg1, arg2 string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
@ -65,23 +65,23 @@ func ExpectValidClientID(s op.Storage) {
|
||||||
mockS.EXPECT().GetClientByClientID(gomock.Any(), gomock.Any()).DoAndReturn(
|
mockS.EXPECT().GetClientByClientID(gomock.Any(), gomock.Any()).DoAndReturn(
|
||||||
func(_ context.Context, id string) (op.Client, error) {
|
func(_ context.Context, id string) (op.Client, error) {
|
||||||
var appType op.ApplicationType
|
var appType op.ApplicationType
|
||||||
var authMethod op.AuthMethod
|
var authMethod oidc.AuthMethod
|
||||||
var accessTokenType op.AccessTokenType
|
var accessTokenType op.AccessTokenType
|
||||||
var responseTypes []oidc.ResponseType
|
var responseTypes []oidc.ResponseType
|
||||||
switch id {
|
switch id {
|
||||||
case "web_client":
|
case "web_client":
|
||||||
appType = op.ApplicationTypeWeb
|
appType = op.ApplicationTypeWeb
|
||||||
authMethod = op.AuthMethodBasic
|
authMethod = oidc.AuthMethodBasic
|
||||||
accessTokenType = op.AccessTokenTypeBearer
|
accessTokenType = op.AccessTokenTypeBearer
|
||||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
||||||
case "native_client":
|
case "native_client":
|
||||||
appType = op.ApplicationTypeNative
|
appType = op.ApplicationTypeNative
|
||||||
authMethod = op.AuthMethodNone
|
authMethod = oidc.AuthMethodNone
|
||||||
accessTokenType = op.AccessTokenTypeBearer
|
accessTokenType = op.AccessTokenTypeBearer
|
||||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
||||||
case "useragent_client":
|
case "useragent_client":
|
||||||
appType = op.ApplicationTypeUserAgent
|
appType = op.ApplicationTypeUserAgent
|
||||||
authMethod = op.AuthMethodBasic
|
authMethod = oidc.AuthMethodBasic
|
||||||
accessTokenType = op.AccessTokenTypeJWT
|
accessTokenType = op.AccessTokenTypeJWT
|
||||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken}
|
responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func ExpectSigningKey(s op.Storage) {
|
||||||
type ConfClient struct {
|
type ConfClient struct {
|
||||||
id string
|
id string
|
||||||
appType op.ApplicationType
|
appType op.ApplicationType
|
||||||
authMethod op.AuthMethod
|
authMethod oidc.AuthMethod
|
||||||
accessTokenType op.AccessTokenType
|
accessTokenType op.AccessTokenType
|
||||||
responseTypes []oidc.ResponseType
|
responseTypes []oidc.ResponseType
|
||||||
devMode bool
|
devMode bool
|
||||||
|
@ -145,7 +145,7 @@ func (c *ConfClient) ApplicationType() op.ApplicationType {
|
||||||
return c.appType
|
return c.appType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) AuthMethod() op.AuthMethod {
|
func (c *ConfClient) AuthMethod() oidc.AuthMethod {
|
||||||
return c.authMethod
|
return c.authMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ const (
|
||||||
AuthMethodBasic AuthMethod = "client_secret_basic"
|
AuthMethodBasic AuthMethod = "client_secret_basic"
|
||||||
AuthMethodPost AuthMethod = "client_secret_post"
|
AuthMethodPost AuthMethod = "client_secret_post"
|
||||||
AuthMethodNone AuthMethod = "none"
|
AuthMethodNone AuthMethod = "none"
|
||||||
|
AuthMethodPrivateKeyJWT AuthMethod = "private_key_jwt"
|
||||||
|
|
||||||
CodeMethodS256 = "S256"
|
CodeMethodS256 = "S256"
|
||||||
)
|
)
|
||||||
|
@ -90,6 +91,7 @@ type Config struct {
|
||||||
CryptoKey [32]byte
|
CryptoKey [32]byte
|
||||||
DefaultLogoutRedirectURI string
|
DefaultLogoutRedirectURI string
|
||||||
CodeMethodS256 bool
|
CodeMethodS256 bool
|
||||||
|
AuthMethodPrivateKeyJWT bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type endpoints struct {
|
type endpoints struct {
|
||||||
|
@ -191,6 +193,10 @@ func (o *openidProvider) CodeMethodS256Supported() bool {
|
||||||
return o.config.CodeMethodS256
|
return o.config.CodeMethodS256
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *openidProvider) AuthMethodPrivateKeyJWTSupported() bool {
|
||||||
|
return o.config.AuthMethodPrivateKeyJWT
|
||||||
|
}
|
||||||
|
|
||||||
func (o *openidProvider) GrantTypeTokenExchangeSupported() bool {
|
func (o *openidProvider) GrantTypeTokenExchangeSupported() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ type OPStorage interface {
|
||||||
SetUserinfoFromToken(ctx context.Context, userinfo oidc.UserInfoSetter, tokenID, subject, origin string) error
|
SetUserinfoFromToken(ctx context.Context, userinfo oidc.UserInfoSetter, tokenID, subject, origin string) error
|
||||||
GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (map[string]interface{}, error)
|
GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (map[string]interface{}, error)
|
||||||
GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (*jose.JSONWebKey, error)
|
GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (*jose.JSONWebKey, error)
|
||||||
|
//ValidateJWTProfileScopes(ctx context.Context, userID string, scope oidc.Scopes) (oidc.Scopes, error)
|
||||||
|
|
||||||
//deprecated: use GetUserinfoFromScopes instead
|
//deprecated: use GetUserinfoFromScopes instead
|
||||||
GetUserinfoFromScopes(ctx context.Context, userID, clientID string, scopes []string) (oidc.UserInfo, error)
|
GetUserinfoFromScopes(ctx context.Context, userID, clientID string, scopes []string) (oidc.UserInfo, error)
|
||||||
|
|
|
@ -18,6 +18,7 @@ type Exchanger interface {
|
||||||
Signer() Signer
|
Signer() Signer
|
||||||
Crypto() Crypto
|
Crypto() Crypto
|
||||||
AuthMethodPostSupported() bool
|
AuthMethodPostSupported() bool
|
||||||
|
AuthMethodPrivateKeyJWTSupported() bool
|
||||||
GrantTypeTokenExchangeSupported() bool
|
GrantTypeTokenExchangeSupported() bool
|
||||||
GrantTypeJWTAuthorizationSupported() bool
|
GrantTypeJWTAuthorizationSupported() bool
|
||||||
}
|
}
|
||||||
|
@ -112,18 +113,30 @@ func ValidateAccessTokenRequest(ctx context.Context, tokenReq *oidc.AccessTokenR
|
||||||
}
|
}
|
||||||
|
|
||||||
func AuthorizeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (AuthRequest, Client, error) {
|
func AuthorizeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (AuthRequest, Client, error) {
|
||||||
|
if tokenReq.ClientAssertionType == oidc.ClientAssertionTypeJWTAssertion {
|
||||||
|
jwtExchanger, ok := exchanger.(JWTAuthorizationGrantExchanger)
|
||||||
|
if !ok || !exchanger.AuthMethodPrivateKeyJWTSupported() {
|
||||||
|
return nil, nil, errors.New("auth_method private_key_jwt not supported")
|
||||||
|
}
|
||||||
|
return AuthorizePrivateJWTKey(ctx, tokenReq, jwtExchanger)
|
||||||
|
}
|
||||||
client, err := exchanger.Storage().GetClientByClientID(ctx, tokenReq.ClientID)
|
client, err := exchanger.Storage().GetClientByClientID(ctx, tokenReq.ClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if client.AuthMethod() == AuthMethodNone {
|
if client.AuthMethod() == oidc.AuthMethodNone {
|
||||||
authReq, err := AuthorizeCodeChallenge(ctx, tokenReq, exchanger)
|
authReq, err := AuthorizeCodeChallenge(ctx, tokenReq, exchanger)
|
||||||
return authReq, client, err
|
return authReq, client, err
|
||||||
}
|
}
|
||||||
if client.AuthMethod() == AuthMethodPost && !exchanger.AuthMethodPostSupported() {
|
if client.AuthMethod() == oidc.AuthMethodPost && !exchanger.AuthMethodPostSupported() {
|
||||||
return nil, nil, errors.New("auth_method post not supported")
|
return nil, nil, errors.New("auth_method post not supported")
|
||||||
}
|
}
|
||||||
err = AuthorizeClientIDSecret(ctx, tokenReq.ClientID, tokenReq.ClientSecret, exchanger.Storage())
|
authReq, err := AuthorizeClientIDSecret(ctx, tokenReq.ClientID, tokenReq.ClientSecret, tokenReq.Code, exchanger.Storage())
|
||||||
|
return authReq, client, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func AuthorizePrivateJWTKey(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger JWTAuthorizationGrantExchanger) (AuthRequest, Client, error) {
|
||||||
|
jwtReq, err := VerifyJWTAssertion(ctx, tokenReq.ClientAssertion, exchanger.JWTProfileVerifier())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -131,11 +144,26 @@ func AuthorizeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exc
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, ErrInvalidRequest("invalid code")
|
return nil, nil, ErrInvalidRequest("invalid code")
|
||||||
}
|
}
|
||||||
|
client, err := exchanger.Storage().GetClientByClientID(ctx, jwtReq.Issuer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if client.AuthMethod() != oidc.AuthMethodPrivateKeyJWT {
|
||||||
|
return nil, nil, ErrInvalidRequest("invalid_client")
|
||||||
|
}
|
||||||
return authReq, client, nil
|
return authReq, client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string, storage OPStorage) error {
|
func AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret, code string, storage Storage) (AuthRequest, error) {
|
||||||
return storage.AuthorizeClientIDSecret(ctx, clientID, clientSecret)
|
err := storage.AuthorizeClientIDSecret(ctx, clientID, clientSecret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authReq, err := storage.AuthRequestByCode(ctx, code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrInvalidRequest("invalid code")
|
||||||
|
}
|
||||||
|
return authReq, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AuthorizeCodeChallenge(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (AuthRequest, error) {
|
func AuthorizeCodeChallenge(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (AuthRequest, error) {
|
||||||
|
@ -158,12 +186,15 @@ func JWTProfile(w http.ResponseWriter, r *http.Request, exchanger JWTAuthorizati
|
||||||
RequestError(w, r, err)
|
RequestError(w, r, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenRequest, err := VerifyJWTAssertion(r.Context(), profileRequest, exchanger.JWTProfileVerifier())
|
tokenRequest, err := VerifyJWTAssertion(r.Context(), profileRequest.Assertion, exchanger.JWTProfileVerifier())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RequestError(w, r, err)
|
RequestError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: filter scopes
|
||||||
|
tokenRequest.Scopes = profileRequest.Scope
|
||||||
|
|
||||||
resp, err := CreateJWTTokenResponse(r.Context(), tokenRequest, exchanger)
|
resp, err := CreateJWTTokenResponse(r.Context(), tokenRequest, exchanger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RequestError(w, r, err)
|
RequestError(w, r, err)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"gopkg.in/square/go-jose.v2"
|
"gopkg.in/square/go-jose.v2"
|
||||||
|
|
||||||
"github.com/caos/oidc/pkg/oidc"
|
"github.com/caos/oidc/pkg/oidc"
|
||||||
"github.com/caos/oidc/pkg/oidc/grants/tokenexchange"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type JWTProfileVerifier interface {
|
type JWTProfileVerifier interface {
|
||||||
|
@ -48,9 +47,9 @@ func (v *jwtProfileVerifier) Offset() time.Duration {
|
||||||
return v.offset
|
return v.offset
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyJWTAssertion(ctx context.Context, profileRequest *tokenexchange.JWTProfileRequest, v JWTProfileVerifier) (*oidc.JWTTokenRequest, error) {
|
func VerifyJWTAssertion(ctx context.Context, assertion string, v JWTProfileVerifier) (*oidc.JWTTokenRequest, error) {
|
||||||
request := new(oidc.JWTTokenRequest)
|
request := new(oidc.JWTTokenRequest)
|
||||||
payload, err := oidc.ParseToken(profileRequest.Assertion, request)
|
payload, err := oidc.ParseToken(assertion, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -73,10 +72,9 @@ func VerifyJWTAssertion(ctx context.Context, profileRequest *tokenexchange.JWTPr
|
||||||
|
|
||||||
keySet := &jwtProfileKeySet{v.Storage(), request.Subject}
|
keySet := &jwtProfileKeySet{v.Storage(), request.Subject}
|
||||||
|
|
||||||
if err = oidc.CheckSignature(ctx, profileRequest.Assertion, payload, request, nil, keySet); err != nil {
|
if err = oidc.CheckSignature(ctx, assertion, payload, request, nil, keySet); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
request.Scopes = profileRequest.Scope
|
|
||||||
return request, nil
|
return request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue