mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-10 19:02:26 +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:
@@ -8,7 +8,9 @@ import (
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
key_model "github.com/caos/zitadel/internal/key/model"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
@@ -30,6 +32,7 @@ type OIDCConfig struct {
|
||||
IDTokenRoleAssertion bool `json:"idTokenRoleAssertion,omitempty"`
|
||||
IDTokenUserinfoAssertion bool `json:"idTokenUserinfoAssertion,omitempty"`
|
||||
ClockSkew time.Duration `json:"clockSkew,omitempty"`
|
||||
ClientKeys []*ClientKey `json:"-"`
|
||||
}
|
||||
|
||||
func (c *OIDCConfig) Changes(changed *OIDCConfig) map[string]interface{} {
|
||||
@@ -134,6 +137,7 @@ func OIDCConfigToModel(config *OIDCConfig) *model.OIDCConfig {
|
||||
IDTokenRoleAssertion: config.IDTokenRoleAssertion,
|
||||
IDTokenUserinfoAssertion: config.IDTokenUserinfoAssertion,
|
||||
ClockSkew: config.ClockSkew,
|
||||
ClientKeys: ClientKeysToModel(config.ClientKeys),
|
||||
}
|
||||
oidcConfig.FillCompliance()
|
||||
return oidcConfig
|
||||
@@ -161,7 +165,50 @@ func (p *Project) appendChangeOIDCConfigEvent(event *es_models.Event) error {
|
||||
}
|
||||
|
||||
if i, a := GetApplication(p.Applications, config.AppID); a != nil {
|
||||
p.Applications[i].OIDCConfig.setData(event)
|
||||
return p.Applications[i].OIDCConfig.setData(event)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendAddClientKeyEvent(event *es_models.Event) error {
|
||||
key := new(ClientKey)
|
||||
err := key.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i, a := GetApplication(p.Applications, key.ApplicationID); a != nil {
|
||||
if a.OIDCConfig != nil {
|
||||
p.Applications[i].OIDCConfig.ClientKeys = append(p.Applications[i].OIDCConfig.ClientKeys, key)
|
||||
}
|
||||
if a.APIConfig != nil {
|
||||
p.Applications[i].APIConfig.ClientKeys = append(p.Applications[i].APIConfig.ClientKeys, key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendRemoveClientKeyEvent(event *es_models.Event) error {
|
||||
key := new(ClientKey)
|
||||
err := key.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, a := GetApplication(p.Applications, key.ApplicationID); a != nil {
|
||||
if a.OIDCConfig != nil {
|
||||
if j, k := GetClientKey(p.Applications[i].OIDCConfig.ClientKeys, key.KeyID); k != nil {
|
||||
p.Applications[i].OIDCConfig.ClientKeys[j] = p.Applications[i].OIDCConfig.ClientKeys[len(p.Applications[i].OIDCConfig.ClientKeys)-1]
|
||||
p.Applications[i].OIDCConfig.ClientKeys[len(p.Applications[i].OIDCConfig.ClientKeys)-1] = nil
|
||||
p.Applications[i].OIDCConfig.ClientKeys = p.Applications[i].OIDCConfig.ClientKeys[:len(p.Applications[i].OIDCConfig.ClientKeys)-1]
|
||||
}
|
||||
}
|
||||
if a.APIConfig != nil {
|
||||
if j, k := GetClientKey(p.Applications[i].APIConfig.ClientKeys, key.KeyID); k != nil {
|
||||
p.Applications[i].APIConfig.ClientKeys[j] = p.Applications[i].APIConfig.ClientKeys[len(p.Applications[i].APIConfig.ClientKeys)-1]
|
||||
p.Applications[i].APIConfig.ClientKeys[len(p.Applications[i].APIConfig.ClientKeys)-1] = nil
|
||||
p.Applications[i].APIConfig.ClientKeys = p.Applications[i].APIConfig.ClientKeys[:len(p.Applications[i].APIConfig.ClientKeys)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -174,3 +221,100 @@ func (o *OIDCConfig) setData(event *es_models.Event) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetClientKey(keys []*ClientKey, id string) (int, *ClientKey) {
|
||||
for i, k := range keys {
|
||||
if k.KeyID == id {
|
||||
return i, k
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
type ClientKey struct {
|
||||
es_models.ObjectRoot `json:"-"`
|
||||
ApplicationID string `json:"applicationId,omitempty"`
|
||||
ClientID string `json:"clientId,omitempty"`
|
||||
KeyID string `json:"keyId,omitempty"`
|
||||
Type int32 `json:"type,omitempty"`
|
||||
ExpirationDate time.Time `json:"expirationDate,omitempty"`
|
||||
PublicKey []byte `json:"publicKey,omitempty"`
|
||||
privateKey []byte
|
||||
}
|
||||
|
||||
func (key *ClientKey) SetData(event *es_models.Event) error {
|
||||
key.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, key); err != nil {
|
||||
logging.Log("EVEN-SADdg").WithError(err).Error("could not unmarshal event data")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (key *ClientKey) AppendEvents(events ...*es_models.Event) error {
|
||||
for _, event := range events {
|
||||
err := key.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (key *ClientKey) AppendEvent(event *es_models.Event) (err error) {
|
||||
key.ObjectRoot.AppendEvent(event)
|
||||
switch event.Type {
|
||||
case ClientKeyAdded:
|
||||
err = json.Unmarshal(event.Data, key)
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "MODEL-Fetg3", "Errors.Internal")
|
||||
}
|
||||
case ClientKeyRemoved:
|
||||
key.ExpirationDate = event.CreationDate
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ClientKeyFromModel(key *model.ClientKey) *ClientKey {
|
||||
return &ClientKey{
|
||||
ObjectRoot: key.ObjectRoot,
|
||||
ExpirationDate: key.ExpirationDate,
|
||||
ApplicationID: key.ApplicationID,
|
||||
ClientID: key.ClientID,
|
||||
KeyID: key.KeyID,
|
||||
Type: int32(key.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func ClientKeysToModel(keys []*ClientKey) []*model.ClientKey {
|
||||
clientKeys := make([]*model.ClientKey, len(keys))
|
||||
for i, key := range keys {
|
||||
clientKeys[i] = ClientKeyToModel(key)
|
||||
}
|
||||
return clientKeys
|
||||
}
|
||||
|
||||
func ClientKeyToModel(key *ClientKey) *model.ClientKey {
|
||||
return &model.ClientKey{
|
||||
ObjectRoot: key.ObjectRoot,
|
||||
ExpirationDate: key.ExpirationDate,
|
||||
ApplicationID: key.ApplicationID,
|
||||
ClientID: key.ClientID,
|
||||
KeyID: key.KeyID,
|
||||
PrivateKey: key.privateKey,
|
||||
Type: key_model.AuthNKeyType(key.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func (key *ClientKey) GenerateClientKeyPair(keySize int) error {
|
||||
privateKey, publicKey, err := crypto.GenerateKeyPair(keySize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key.PublicKey, err = crypto.PublicKeyToBytes(publicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key.privateKey = crypto.PrivateKeyToBytes(privateKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user