feat: token introspection, api clients and auth method private_key_jwt (#1276)

* introspect

* testingapplication key

* date

* client keys

* fix client keys

* fix client keys

* access tokens only for users

* AuthMethodPrivateKeyJWT

* client keys

* set introspection info correctly

* managae apis

* update oidc pkg

* cleanup

* merge msater

* set current sequence in migration

* set current sequence in migration

* set current sequence in migration

* Apply suggestions from code review

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* DeleteAuthNKeysByObjectID

* ensure authn keys uptodate

* update oidc version

* merge master

* merge master

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
Livio Amstutz
2021-02-17 15:31:47 +01:00
committed by GitHub
parent 39eb172804
commit 744185449e
64 changed files with 2275 additions and 836 deletions

View File

@@ -2,9 +2,10 @@ package auth
import (
"github.com/caos/logging"
"github.com/golang/protobuf/ptypes"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/pkg/grpc/auth"
"github.com/golang/protobuf/ptypes"
)
func machineViewFromModel(machine *usr_model.MachineView) *auth.MachineView {
@@ -16,36 +17,3 @@ func machineViewFromModel(machine *usr_model.MachineView) *auth.MachineView {
LastKeyAdded: lastKeyAdded,
}
}
func machineKeyViewsFromModel(keys ...*usr_model.MachineKeyView) []*auth.MachineKeyView {
keyViews := make([]*auth.MachineKeyView, len(keys))
for i, key := range keys {
keyViews[i] = machineKeyViewFromModel(key)
}
return keyViews
}
func machineKeyViewFromModel(key *usr_model.MachineKeyView) *auth.MachineKeyView {
creationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-gluk7").OnError(err).Debug("unable to parse timestamp")
expirationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-gluk7").OnError(err).Debug("unable to parse timestamp")
return &auth.MachineKeyView{
Id: key.ID,
CreationDate: creationDate,
ExpirationDate: expirationDate,
Sequence: key.Sequence,
Type: machineKeyTypeFromModel(key.Type),
}
}
func machineKeyTypeFromModel(typ usr_model.MachineKeyType) auth.MachineKeyType {
switch typ {
case usr_model.MachineKeyTypeJSON:
return auth.MachineKeyType_MACHINEKEY_JSON
default:
return auth.MachineKeyType_MACHINEKEY_UNSPECIFIED
}
}

View File

@@ -31,6 +31,13 @@ func (s *Server) CreateOIDCApplication(ctx context.Context, in *management.OIDCA
}
return appFromModel(app), nil
}
func (s *Server) CreateAPIApplication(ctx context.Context, in *management.APIApplicationCreate) (*management.Application, error) {
app, err := s.project.AddApplication(ctx, apiAppCreateToModel(in))
if err != nil {
return nil, err
}
return appFromModel(app), nil
}
func (s *Server) UpdateApplication(ctx context.Context, in *management.ApplicationUpdate) (*management.Application, error) {
app, err := s.project.ChangeApplication(ctx, appUpdateToModel(in))
if err != nil {
@@ -66,6 +73,14 @@ func (s *Server) UpdateApplicationOIDCConfig(ctx context.Context, in *management
return oidcConfigFromModel(config), nil
}
func (s *Server) UpdateApplicationAPIConfig(ctx context.Context, in *management.APIConfigUpdate) (*management.APIConfig, error) {
config, err := s.project.ChangeAPIConfig(ctx, apiConfigUpdateToModel(in))
if err != nil {
return nil, err
}
return apiConfigFromModel(config), nil
}
func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, in *management.ApplicationID) (*management.ClientSecret, error) {
config, err := s.project.ChangeOIDConfigSecret(ctx, in.ProjectId, in.Id)
if err != nil {
@@ -74,6 +89,14 @@ func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, in *management.
return &management.ClientSecret{ClientSecret: config.ClientSecretString}, nil
}
func (s *Server) RegenerateAPIClientSecret(ctx context.Context, in *management.ApplicationID) (*management.ClientSecret, error) {
config, err := s.project.ChangeAPIConfigSecret(ctx, in.ProjectId, in.Id)
if err != nil {
return nil, err
}
return &management.ClientSecret{ClientSecret: config.ClientSecretString}, nil
}
func (s *Server) ApplicationChanges(ctx context.Context, changesRequest *management.ChangeRequest) (*management.Changes, error) {
response, err := s.project.ApplicationChanges(ctx, changesRequest.Id, changesRequest.SecId, changesRequest.SequenceOffset, changesRequest.Limit, changesRequest.Asc)
if err != nil {
@@ -81,3 +104,32 @@ func (s *Server) ApplicationChanges(ctx context.Context, changesRequest *managem
}
return appChangesToResponse(response, changesRequest.GetSequenceOffset(), changesRequest.GetLimit()), nil
}
func (s *Server) SearchClientKeys(ctx context.Context, req *management.ClientKeySearchRequest) (*management.ClientKeySearchResponse, error) {
result, err := s.project.SearchClientKeys(ctx, clientKeySearchRequestToModel(req))
if err != nil {
return nil, err
}
return clientKeySearchResponseFromModel(result), nil
}
func (s *Server) GetClientKey(ctx context.Context, req *management.ClientKeyIDRequest) (*management.ClientKeyView, error) {
key, err := s.project.GetClientKey(ctx, req.ProjectId, req.ApplicationId, req.KeyId)
if err != nil {
return nil, err
}
return clientKeyViewFromModel(key), nil
}
func (s *Server) AddClientKey(ctx context.Context, req *management.AddClientKeyRequest) (*management.AddClientKeyResponse, error) {
key, err := s.project.AddClientKey(ctx, addClientKeyToModel(req))
if err != nil {
return nil, err
}
return addClientKeyFromModel(key), nil
}
func (s *Server) DeleteClientKey(ctx context.Context, req *management.ClientKeyIDRequest) (*empty.Empty, error) {
err := s.project.RemoveClientKey(ctx, req.ProjectId, req.ApplicationId, req.KeyId)
return &empty.Empty{}, err
}

View File

@@ -2,6 +2,7 @@ package management
import (
"encoding/json"
"time"
"github.com/caos/logging"
"github.com/golang/protobuf/ptypes"
@@ -10,6 +11,7 @@ import (
"google.golang.org/protobuf/types/known/structpb"
"github.com/caos/zitadel/internal/eventstore/models"
key_model "github.com/caos/zitadel/internal/key/model"
"github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/pkg/grpc/management"
@@ -40,6 +42,11 @@ func appConfigFromModel(app *proj_model.Application) management.AppConfig {
OidcConfig: oidcConfigFromModel(app.OIDCConfig),
}
}
if app.Type == proj_model.AppTypeAPI {
return &management.Application_ApiConfig{
ApiConfig: apiConfigFromModel(app.APIConfig),
}
}
return nil
}
@@ -65,6 +72,14 @@ func oidcConfigFromModel(config *proj_model.OIDCConfig) *management.OIDCConfig {
}
}
func apiConfigFromModel(config *proj_model.APIConfig) *management.APIConfig {
return &management.APIConfig{
ClientId: config.ClientID,
ClientSecret: config.ClientSecretString,
AuthMethodType: apiAuthMethodTypeFromModel(config.AuthMethodType),
}
}
func oidcConfigFromApplicationViewModel(app *proj_model.ApplicationView) *management.OIDCConfig {
return &management.OIDCConfig{
RedirectUris: app.OIDCRedirectUris,
@@ -120,6 +135,19 @@ func oidcAppCreateToModel(app *management.OIDCApplicationCreate) *proj_model.App
}
}
func apiAppCreateToModel(app *management.APIApplicationCreate) *proj_model.Application {
return &proj_model.Application{
ObjectRoot: models.ObjectRoot{
AggregateID: app.ProjectId,
},
Name: app.Name,
Type: proj_model.AppTypeAPI,
APIConfig: &proj_model.APIConfig{
AuthMethodType: apiAuthMethodTypeToModel(app.AuthMethodType),
},
}
}
func appUpdateToModel(app *management.ApplicationUpdate) *proj_model.Application {
return &proj_model.Application{
ObjectRoot: models.ObjectRoot{
@@ -151,6 +179,16 @@ func oidcConfigUpdateToModel(app *management.OIDCConfigUpdate) *proj_model.OIDCC
}
}
func apiConfigUpdateToModel(app *management.APIConfigUpdate) *proj_model.APIConfig {
return &proj_model.APIConfig{
ObjectRoot: models.ObjectRoot{
AggregateID: app.ProjectId,
},
AppID: app.ApplicationId,
AuthMethodType: apiAuthMethodTypeToModel(app.AuthMethodType),
}
}
func applicationSearchRequestsToModel(request *management.ApplicationSearchRequest) *proj_model.ApplicationSearchRequest {
return &proj_model.ApplicationSearchRequest{
Offset: request.Offset,
@@ -354,11 +392,24 @@ func oidcAuthMethodTypeToModel(authType management.OIDCAuthMethodType) proj_mode
return proj_model.OIDCAuthMethodTypePost
case management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE:
return proj_model.OIDCAuthMethodTypeNone
case management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT:
return proj_model.OIDCAuthMethodTypePrivateKeyJWT
default:
return proj_model.OIDCAuthMethodTypeBasic
}
}
func apiAuthMethodTypeToModel(authType management.APIAuthMethodType) proj_model.APIAuthMethodType {
switch authType {
case management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC:
return proj_model.APIAuthMethodTypeBasic
case management.APIAuthMethodType_APIAUTHMETHODTYPE_PRIVATE_KEY_JWT:
return proj_model.APIAuthMethodTypePrivateKeyJWT
default:
return proj_model.APIAuthMethodTypeBasic
}
}
func oidcAuthMethodTypeFromModel(authType proj_model.OIDCAuthMethodType) management.OIDCAuthMethodType {
switch authType {
case proj_model.OIDCAuthMethodTypeBasic:
@@ -367,11 +418,24 @@ func oidcAuthMethodTypeFromModel(authType proj_model.OIDCAuthMethodType) managem
return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_POST
case proj_model.OIDCAuthMethodTypeNone:
return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE
case proj_model.OIDCAuthMethodTypePrivateKeyJWT:
return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT
default:
return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_BASIC
}
}
func apiAuthMethodTypeFromModel(authType proj_model.APIAuthMethodType) management.APIAuthMethodType {
switch authType {
case proj_model.APIAuthMethodTypeBasic:
return management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC
case proj_model.APIAuthMethodTypePrivateKeyJWT:
return management.APIAuthMethodType_APIAUTHMETHODTYPE_PRIVATE_KEY_JWT
default:
return management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC
}
}
func oidcTokenTypeToModel(tokenType management.OIDCTokenType) proj_model.OIDCTokenType {
switch tokenType {
case management.OIDCTokenType_OIDCTokenType_Bearer:
@@ -432,3 +496,126 @@ func appChangesToMgtAPI(changes *proj_model.ApplicationChanges) (_ []*management
return result
}
func clientKeyViewsFromModel(keys ...*key_model.AuthNKeyView) []*management.ClientKeyView {
keyViews := make([]*management.ClientKeyView, len(keys))
for i, key := range keys {
keyViews[i] = clientKeyViewFromModel(key)
}
return keyViews
}
func clientKeyViewFromModel(key *key_model.AuthNKeyView) *management.ClientKeyView {
creationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-DAs2t").OnError(err).Debug("unable to parse timestamp")
expirationDate, err := ptypes.TimestampProto(key.ExpirationDate)
logging.Log("MANAG-BDgh4").OnError(err).Debug("unable to parse timestamp")
return &management.ClientKeyView{
Id: key.ID,
CreationDate: creationDate,
ExpirationDate: expirationDate,
Sequence: key.Sequence,
Type: authNKeyTypeFromModel(key.Type),
}
}
func addClientKeyToModel(key *management.AddClientKeyRequest) *proj_model.ClientKey {
expirationDate := time.Time{}
if key.ExpirationDate != nil {
var err error
expirationDate, err = ptypes.Timestamp(key.ExpirationDate)
logging.Log("MANAG-Dgt42").OnError(err).Debug("unable to parse expiration date")
}
return &proj_model.ClientKey{
ExpirationDate: expirationDate,
Type: authNKeyTypeToModel(key.Type),
ApplicationID: key.ApplicationId,
ObjectRoot: models.ObjectRoot{AggregateID: key.ProjectId},
}
}
func addClientKeyFromModel(key *proj_model.ClientKey) *management.AddClientKeyResponse {
creationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-FBzz4").OnError(err).Debug("unable to parse cretaion date")
expirationDate, err := ptypes.TimestampProto(key.ExpirationDate)
logging.Log("MANAG-sag21").OnError(err).Debug("unable to parse cretaion date")
detail, err := json.Marshal(struct {
Type string `json:"type"`
KeyID string `json:"keyId"`
Key string `json:"key"`
AppID string `json:"appId"`
ClientID string `json:"clientID"`
}{
Type: "application",
KeyID: key.KeyID,
Key: string(key.PrivateKey),
AppID: key.ApplicationID,
ClientID: key.ClientID,
})
logging.Log("MANAG-adt42").OnError(err).Warn("unable to marshall key")
return &management.AddClientKeyResponse{
Id: key.KeyID,
CreationDate: creationDate,
ExpirationDate: expirationDate,
Sequence: key.Sequence,
KeyDetails: detail,
Type: authNKeyTypeFromModel(key.Type),
}
}
func authNKeyTypeToModel(typ management.AuthNKeyType) key_model.AuthNKeyType {
switch typ {
case management.AuthNKeyType_AUTHNKEY_JSON:
return key_model.AuthNKeyTypeJSON
default:
return key_model.AuthNKeyTypeNONE
}
}
func authNKeyTypeFromModel(typ key_model.AuthNKeyType) management.AuthNKeyType {
switch typ {
case key_model.AuthNKeyTypeJSON:
return management.AuthNKeyType_AUTHNKEY_JSON
default:
return management.AuthNKeyType_AUTHNKEY_UNSPECIFIED
}
}
func clientKeySearchRequestToModel(req *management.ClientKeySearchRequest) *key_model.AuthNKeySearchRequest {
return &key_model.AuthNKeySearchRequest{
Offset: req.Offset,
Limit: req.Limit,
Asc: req.Asc,
Queries: []*key_model.AuthNKeySearchQuery{
{
Key: key_model.AuthNKeyObjectType,
Method: model.SearchMethodEquals,
Value: key_model.AuthNKeyObjectTypeApplication,
}, {
Key: key_model.AuthNKeyObjectID,
Method: model.SearchMethodEquals,
Value: req.ApplicationId,
},
},
}
}
func clientKeySearchResponseFromModel(req *key_model.AuthNKeySearchResponse) *management.ClientKeySearchResponse {
viewTimestamp, err := ptypes.TimestampProto(req.Timestamp)
logging.Log("MANAG-Sk9ds").OnError(err).Debug("unable to parse cretaion date")
return &management.ClientKeySearchResponse{
Offset: req.Offset,
Limit: req.Limit,
TotalResult: req.TotalResult,
ProcessedSequence: req.Sequence,
ViewTimestamp: viewTimestamp,
Result: clientKeyViewsFromModel(req.Result...),
}
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore/models"
key_model "github.com/caos/zitadel/internal/key/model"
"github.com/caos/zitadel/internal/model"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/pkg/grpc/management"
@@ -43,7 +44,7 @@ func machineViewFromModel(machine *usr_model.MachineView) *management.MachineVie
}
}
func machineKeyViewsFromModel(keys ...*usr_model.MachineKeyView) []*management.MachineKeyView {
func authnKeyViewsFromModel(keys ...*key_model.AuthNKeyView) []*management.MachineKeyView {
keyViews := make([]*management.MachineKeyView, len(keys))
for i, key := range keys {
keyViews[i] = machineKeyViewFromModel(key)
@@ -51,7 +52,7 @@ func machineKeyViewsFromModel(keys ...*usr_model.MachineKeyView) []*management.M
return keyViews
}
func machineKeyViewFromModel(key *usr_model.MachineKeyView) *management.MachineKeyView {
func machineKeyViewFromModel(key *key_model.AuthNKeyView) *management.MachineKeyView {
creationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-gluk7").OnError(err).Debug("unable to parse timestamp")
@@ -112,32 +113,36 @@ func addMachineKeyFromModel(key *usr_model.MachineKey) *management.AddMachineKey
}
}
func machineKeyTypeToModel(typ management.MachineKeyType) usr_model.MachineKeyType {
func machineKeyTypeToModel(typ management.MachineKeyType) key_model.AuthNKeyType {
switch typ {
case management.MachineKeyType_MACHINEKEY_JSON:
return usr_model.MachineKeyTypeJSON
return key_model.AuthNKeyTypeJSON
default:
return usr_model.MachineKeyTypeNONE
return key_model.AuthNKeyTypeNONE
}
}
func machineKeyTypeFromModel(typ usr_model.MachineKeyType) management.MachineKeyType {
func machineKeyTypeFromModel(typ key_model.AuthNKeyType) management.MachineKeyType {
switch typ {
case usr_model.MachineKeyTypeJSON:
case key_model.AuthNKeyTypeJSON:
return management.MachineKeyType_MACHINEKEY_JSON
default:
return management.MachineKeyType_MACHINEKEY_UNSPECIFIED
}
}
func machineKeySearchRequestToModel(req *management.MachineKeySearchRequest) *usr_model.MachineKeySearchRequest {
return &usr_model.MachineKeySearchRequest{
func machineKeySearchRequestToModel(req *management.MachineKeySearchRequest) *key_model.AuthNKeySearchRequest {
return &key_model.AuthNKeySearchRequest{
Offset: req.Offset,
Limit: req.Limit,
Asc: req.Asc,
Queries: []*usr_model.MachineKeySearchQuery{
Queries: []*key_model.AuthNKeySearchQuery{
{
Key: usr_model.MachineKeyKeyUserID,
Key: key_model.AuthNKeyObjectType,
Method: model.SearchMethodEquals,
Value: key_model.AuthNKeyObjectTypeUser,
}, {
Key: key_model.AuthNKeyObjectID,
Method: model.SearchMethodEquals,
Value: req.UserId,
},
@@ -145,7 +150,7 @@ func machineKeySearchRequestToModel(req *management.MachineKeySearchRequest) *us
}
}
func machineKeySearchResponseFromModel(req *usr_model.MachineKeySearchResponse) *management.MachineKeySearchResponse {
func machineKeySearchResponseFromModel(req *key_model.AuthNKeySearchResponse) *management.MachineKeySearchResponse {
viewTimestamp, err := ptypes.TimestampProto(req.Timestamp)
logging.Log("MANAG-Sk9ds").OnError(err).Debug("unable to parse cretaion date")
@@ -155,6 +160,6 @@ func machineKeySearchResponseFromModel(req *usr_model.MachineKeySearchResponse)
TotalResult: req.TotalResult,
ProcessedSequence: req.Sequence,
ViewTimestamp: viewTimestamp,
Result: machineKeyViewsFromModel(req.Result...),
Result: authnKeyViewsFromModel(req.Result...),
}
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/auth_request/model"
authreq_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model"
@@ -55,13 +56,17 @@ func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Cl
}
func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (_ *jose.JSONWebKey, err error) {
return o.GetKeyByIDAndIssuer(ctx, keyID, userID)
}
func (o *OPStorage) GetKeyByIDAndIssuer(ctx context.Context, keyID, issuer string) (_ *jose.JSONWebKey, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
key, err := o.repo.MachineKeyByID(ctx, keyID)
if err != nil {
return nil, err
}
if key.UserID != userID {
if key.AuthIdentifier != issuer {
return nil, errors.ThrowPermissionDenied(nil, "OIDC-24jm3", "key from different user")
}
publicKey, err := crypto.BytesToPublicKey(key.PublicKey)
@@ -75,6 +80,29 @@ func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID strin
}, nil
}
func (o *OPStorage) ValidateJWTProfileScopes(ctx context.Context, subject string, scopes oidc.Scopes) (oidc.Scopes, error) {
user, err := o.repo.UserByID(ctx, subject)
if err != nil {
return nil, err
}
for i := len(scopes) - 1; i >= 0; i-- {
scope := scopes[i]
if strings.HasPrefix(scope, authreq_model.OrgDomainPrimaryScope) {
var orgID string
org, err := o.repo.OrgByPrimaryDomain(strings.TrimPrefix(scope, authreq_model.OrgDomainPrimaryScope))
if err == nil {
orgID = org.ID
}
if orgID != user.ResourceOwner {
scopes[i] = scopes[len(scopes)-1]
scopes[len(scopes)-1] = ""
scopes = scopes[:len(scopes)-1]
}
}
}
return scopes, nil
}
func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -85,33 +113,32 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr
return o.repo.AuthorizeOIDCApplication(ctx, id, secret)
}
func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID, subject, origin string) (_ oidc.UserInfo, err error) {
func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.UserInfoSetter, tokenID, subject, origin string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
token, err := o.repo.TokenByID(ctx, subject, tokenID)
if err != nil {
return nil, errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
if token.ApplicationID != "" {
app, err := o.repo.ApplicationByClientID(ctx, token.ApplicationID)
if err != nil {
return nil, err
return err
}
if origin != "" && !http.IsOriginAllowed(app.OriginAllowList, origin) {
return nil, errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed")
return errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed")
}
}
return o.GetUserinfoFromScopes(ctx, token.UserID, token.ApplicationID, token.Scopes)
return o.SetUserinfoFromScopes(ctx, userInfo, token.UserID, token.ApplicationID, token.Scopes)
}
func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID, applicationID string, scopes []string) (_ oidc.UserInfo, err error) {
func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo oidc.UserInfoSetter, userID, applicationID string, scopes []string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
user, err := o.repo.UserByID(ctx, userID)
if err != nil {
return nil, err
return err
}
userInfo := oidc.NewUserInfo()
roles := make([]string, 0)
for _, scope := range scopes {
switch scope {
@@ -160,17 +187,40 @@ func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID, applicati
}
if len(roles) == 0 || applicationID == "" {
return userInfo, nil
return nil
}
projectRoles, err := o.assertRoles(ctx, userID, applicationID, roles)
if err != nil {
return nil, err
return err
}
if len(projectRoles) > 0 {
userInfo.AppendClaims(ClaimProjectRoles, projectRoles)
}
return userInfo, nil
return nil
}
func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection oidc.IntrospectionResponse, tokenID, subject, clientID string) error {
token, err := o.repo.TokenByID(ctx, subject, tokenID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
app, err := o.repo.ApplicationByClientID(ctx, clientID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found")
}
for _, aud := range token.Audience {
if aud == clientID || aud == app.ProjectID {
err := o.SetUserinfoFromScopes(ctx, introspection, token.UserID, clientID, token.Scopes)
if err != nil {
return err
}
introspection.SetScopes(token.Scopes)
introspection.SetClientID(token.ApplicationID)
return nil
}
}
return errors.ThrowPermissionDenied(nil, "OIDC-sdg3G", "token is not valid for this client")
}
func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (claims map[string]interface{}, err error) {

View File

@@ -1,13 +1,13 @@
package oidc
import (
authreq_model "github.com/caos/zitadel/internal/auth_request/model"
"strings"
"time"
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/op"
authreq_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/project/model"
)
@@ -37,7 +37,7 @@ func (c *Client) ApplicationType() op.ApplicationType {
return op.ApplicationType(c.OIDCApplicationType)
}
func (c *Client) AuthMethod() op.AuthMethod {
func (c *Client) AuthMethod() oidc.AuthMethod {
return authMethodToOIDC(c.OIDCAuthMethodType)
}
@@ -129,16 +129,18 @@ func accessTokenTypeToOIDC(tokenType model.OIDCTokenType) op.AccessTokenType {
}
}
func authMethodToOIDC(authType model.OIDCAuthMethodType) op.AuthMethod {
func authMethodToOIDC(authType model.OIDCAuthMethodType) oidc.AuthMethod {
switch authType {
case model.OIDCAuthMethodTypeBasic:
return op.AuthMethodBasic
return oidc.AuthMethodBasic
case model.OIDCAuthMethodTypePost:
return op.AuthMethodPost
return oidc.AuthMethodPost
case model.OIDCAuthMethodTypeNone:
return op.AuthMethodNone
return oidc.AuthMethodNone
case model.OIDCAuthMethodTypePrivateKeyJWT:
return oidc.AuthMethodPrivateKeyJWT
default:
return op.AuthMethodBasic
return oidc.AuthMethodBasic
}
}

View File

@@ -2,9 +2,10 @@ package oidc
import (
"context"
"github.com/caos/zitadel/internal/telemetry/metrics"
"time"
"github.com/caos/zitadel/internal/telemetry/metrics"
"github.com/caos/logging"
"github.com/caos/oidc/pkg/op"
@@ -32,11 +33,12 @@ type StorageConfig struct {
}
type EndpointConfig struct {
Auth *Endpoint
Token *Endpoint
Userinfo *Endpoint
EndSession *Endpoint
Keys *Endpoint
Auth *Endpoint
Token *Endpoint
Introspection *Endpoint
Userinfo *Endpoint
EndSession *Endpoint
Keys *Endpoint
}
type Endpoint struct {
@@ -70,6 +72,7 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Re
),
op.WithCustomAuthEndpoint(op.NewEndpointWithURL(config.Endpoints.Auth.Path, config.Endpoints.Auth.URL)),
op.WithCustomTokenEndpoint(op.NewEndpointWithURL(config.Endpoints.Token.Path, config.Endpoints.Token.URL)),
op.WithCustomIntrospectionEndpoint(op.NewEndpointWithURL(config.Endpoints.Introspection.Path, config.Endpoints.Introspection.URL)),
op.WithCustomUserinfoEndpoint(op.NewEndpointWithURL(config.Endpoints.Userinfo.Path, config.Endpoints.Userinfo.URL)),
op.WithCustomEndSessionEndpoint(op.NewEndpointWithURL(config.Endpoints.EndSession.Path, config.Endpoints.EndSession.URL)),
op.WithCustomKeysEndpoint(op.NewEndpointWithURL(config.Endpoints.Keys.Path, config.Endpoints.Keys.URL)),