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...),
}
}