mirror of
https://github.com/zitadel/zitadel.git
synced 2025-10-19 07:33:54 +00:00
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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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...),
|
||||
}
|
||||
}
|
||||
|
@@ -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...),
|
||||
}
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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)),
|
||||
|
Reference in New Issue
Block a user