mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 10:49:25 +00:00
feat(saml): implementation of saml for ZITADEL v2 (#3618)
This commit is contained in:
@@ -33,6 +33,7 @@ type App struct {
|
||||
Name string
|
||||
|
||||
OIDCConfig *OIDCApp
|
||||
SAMLConfig *SAMLApp
|
||||
APIConfig *APIApp
|
||||
}
|
||||
|
||||
@@ -56,6 +57,12 @@ type OIDCApp struct {
|
||||
AllowedOrigins database.StringArray
|
||||
}
|
||||
|
||||
type SAMLApp struct {
|
||||
Metadata []byte
|
||||
MetadataURL string
|
||||
EntityID string
|
||||
}
|
||||
|
||||
type APIApp struct {
|
||||
ClientID string
|
||||
AuthMethodType domain.APIAuthMethodType
|
||||
@@ -116,6 +123,28 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
appSAMLConfigsTable = table{
|
||||
name: projection.AppSAMLTable,
|
||||
}
|
||||
AppSAMLConfigColumnAppID = Column{
|
||||
name: projection.AppSAMLConfigColumnAppID,
|
||||
table: appSAMLConfigsTable,
|
||||
}
|
||||
AppSAMLConfigColumnEntityID = Column{
|
||||
name: projection.AppSAMLConfigColumnEntityID,
|
||||
table: appSAMLConfigsTable,
|
||||
}
|
||||
AppSAMLConfigColumnMetadata = Column{
|
||||
name: projection.AppSAMLConfigColumnMetadata,
|
||||
table: appSAMLConfigsTable,
|
||||
}
|
||||
AppSAMLConfigColumnMetadataURL = Column{
|
||||
name: projection.AppSAMLConfigColumnMetadataURL,
|
||||
table: appSAMLConfigsTable,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
appAPIConfigsTable = table{
|
||||
name: projection.AppAPITable,
|
||||
@@ -225,6 +254,54 @@ func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bo
|
||||
return scan(row)
|
||||
}
|
||||
|
||||
func (q *Queries) AppByID(ctx context.Context, appID string) (*App, error) {
|
||||
stmt, scan := prepareAppQuery()
|
||||
query, args, err := stmt.Where(
|
||||
sq.Eq{
|
||||
AppColumnID.identifier(): appID,
|
||||
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
},
|
||||
).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-immt9", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
row := q.client.QueryRowContext(ctx, query, args...)
|
||||
return scan(row)
|
||||
}
|
||||
|
||||
func (q *Queries) AppBySAMLEntityID(ctx context.Context, entityID string) (*App, error) {
|
||||
stmt, scan := prepareAppQuery()
|
||||
query, args, err := stmt.Where(
|
||||
sq.Eq{
|
||||
AppSAMLConfigColumnEntityID.identifier(): entityID,
|
||||
},
|
||||
).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-JgUop", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
row := q.client.QueryRowContext(ctx, query, args...)
|
||||
return scan(row)
|
||||
}
|
||||
|
||||
func (q *Queries) ProjectByClientID(ctx context.Context, appID string) (*Project, error) {
|
||||
stmt, scan := prepareProjectByAppQuery()
|
||||
query, args, err := stmt.Where(
|
||||
sq.Or{
|
||||
sq.Eq{AppOIDCConfigColumnClientID.identifier(): appID},
|
||||
sq.Eq{AppAPIConfigColumnClientID.identifier(): appID},
|
||||
sq.Eq{AppSAMLConfigColumnAppID.identifier(): appID},
|
||||
},
|
||||
).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-XhJi3", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
row := q.client.QueryRowContext(ctx, query, args...)
|
||||
return scan(row)
|
||||
}
|
||||
|
||||
func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string) (string, error) {
|
||||
stmt, scan := prepareProjectIDByAppQuery()
|
||||
query, args, err := stmt.Where(
|
||||
@@ -249,6 +326,7 @@ func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string) (stri
|
||||
sq.Or{
|
||||
sq.Eq{AppOIDCConfigColumnClientID.identifier(): appID},
|
||||
sq.Eq{AppAPIConfigColumnClientID.identifier(): appID},
|
||||
sq.Eq{AppSAMLConfigColumnAppID.identifier(): appID},
|
||||
},
|
||||
},
|
||||
).ToSql()
|
||||
@@ -389,15 +467,22 @@ func prepareAppQuery() (sq.SelectBuilder, func(*sql.Row) (*App, error)) {
|
||||
AppOIDCConfigColumnIDTokenUserinfoAssertion.identifier(),
|
||||
AppOIDCConfigColumnClockSkew.identifier(),
|
||||
AppOIDCConfigColumnAdditionalOrigins.identifier(),
|
||||
|
||||
AppSAMLConfigColumnAppID.identifier(),
|
||||
AppSAMLConfigColumnEntityID.identifier(),
|
||||
AppSAMLConfigColumnMetadata.identifier(),
|
||||
AppSAMLConfigColumnMetadataURL.identifier(),
|
||||
).From(appsTable.identifier()).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID)).
|
||||
PlaceholderFormat(sq.Dollar), func(row *sql.Row) (*App, error) {
|
||||
app := new(App)
|
||||
|
||||
var (
|
||||
apiConfig = sqlAPIConfig{}
|
||||
oidcConfig = sqlOIDCConfig{}
|
||||
samlConfig = sqlSAMLConfig{}
|
||||
)
|
||||
|
||||
err := row.Scan(
|
||||
@@ -430,6 +515,11 @@ func prepareAppQuery() (sq.SelectBuilder, func(*sql.Row) (*App, error)) {
|
||||
&oidcConfig.iDTokenUserinfoAssertion,
|
||||
&oidcConfig.clockSkew,
|
||||
&oidcConfig.additionalOrigins,
|
||||
|
||||
&samlConfig.appID,
|
||||
&samlConfig.entityID,
|
||||
&samlConfig.metadata,
|
||||
&samlConfig.metadataURL,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@@ -441,6 +531,7 @@ func prepareAppQuery() (sq.SelectBuilder, func(*sql.Row) (*App, error)) {
|
||||
|
||||
apiConfig.set(app)
|
||||
oidcConfig.set(app)
|
||||
samlConfig.set(app)
|
||||
|
||||
return app, nil
|
||||
}
|
||||
@@ -452,6 +543,7 @@ func prepareProjectIDByAppQuery() (sq.SelectBuilder, func(*sql.Row) (projectID s
|
||||
).From(appsTable.identifier()).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID)).
|
||||
PlaceholderFormat(sq.Dollar), func(row *sql.Row) (projectID string, err error) {
|
||||
err = row.Scan(
|
||||
&projectID,
|
||||
@@ -485,6 +577,7 @@ func prepareProjectByAppQuery() (sq.SelectBuilder, func(*sql.Row) (*Project, err
|
||||
Join(join(AppColumnProjectID, ProjectColumnID)).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*Project, error) {
|
||||
p := new(Project)
|
||||
@@ -542,10 +635,16 @@ func prepareAppsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Apps, error)) {
|
||||
AppOIDCConfigColumnIDTokenUserinfoAssertion.identifier(),
|
||||
AppOIDCConfigColumnClockSkew.identifier(),
|
||||
AppOIDCConfigColumnAdditionalOrigins.identifier(),
|
||||
|
||||
AppSAMLConfigColumnAppID.identifier(),
|
||||
AppSAMLConfigColumnEntityID.identifier(),
|
||||
AppSAMLConfigColumnMetadata.identifier(),
|
||||
AppSAMLConfigColumnMetadataURL.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(appsTable.identifier()).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID)).
|
||||
PlaceholderFormat(sq.Dollar), func(row *sql.Rows) (*Apps, error) {
|
||||
apps := &Apps{Apps: []*App{}}
|
||||
|
||||
@@ -554,6 +653,7 @@ func prepareAppsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Apps, error)) {
|
||||
var (
|
||||
apiConfig = sqlAPIConfig{}
|
||||
oidcConfig = sqlOIDCConfig{}
|
||||
samlConfig = sqlSAMLConfig{}
|
||||
)
|
||||
|
||||
err := row.Scan(
|
||||
@@ -586,6 +686,12 @@ func prepareAppsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Apps, error)) {
|
||||
&oidcConfig.iDTokenUserinfoAssertion,
|
||||
&oidcConfig.clockSkew,
|
||||
&oidcConfig.additionalOrigins,
|
||||
|
||||
&samlConfig.appID,
|
||||
&samlConfig.entityID,
|
||||
&samlConfig.metadata,
|
||||
&samlConfig.metadataURL,
|
||||
|
||||
&apps.Count,
|
||||
)
|
||||
|
||||
@@ -595,6 +701,7 @@ func prepareAppsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Apps, error)) {
|
||||
|
||||
apiConfig.set(app)
|
||||
oidcConfig.set(app)
|
||||
samlConfig.set(app)
|
||||
|
||||
apps.Apps = append(apps.Apps, app)
|
||||
}
|
||||
@@ -681,6 +788,24 @@ func (c sqlOIDCConfig) set(app *App) {
|
||||
logging.LogWithFields("app", app.ID).OnError(err).Warn("unable to set allowed origins")
|
||||
}
|
||||
|
||||
type sqlSAMLConfig struct {
|
||||
appID sql.NullString
|
||||
entityID sql.NullString
|
||||
metadataURL sql.NullString
|
||||
metadata []byte
|
||||
}
|
||||
|
||||
func (c sqlSAMLConfig) set(app *App) {
|
||||
if !c.appID.Valid {
|
||||
return
|
||||
}
|
||||
app.SAMLConfig = &SAMLApp{
|
||||
MetadataURL: c.metadataURL.String,
|
||||
Metadata: c.metadata,
|
||||
EntityID: c.entityID.String,
|
||||
}
|
||||
}
|
||||
|
||||
type sqlAPIConfig struct {
|
||||
appID sql.NullString
|
||||
clientID sql.NullString
|
||||
|
@@ -15,80 +15,93 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
expectedAppQuery = regexp.QuoteMeta(`SELECT projections.apps2.id,` +
|
||||
` projections.apps2.name,` +
|
||||
` projections.apps2.project_id,` +
|
||||
` projections.apps2.creation_date,` +
|
||||
` projections.apps2.change_date,` +
|
||||
` projections.apps2.resource_owner,` +
|
||||
` projections.apps2.state,` +
|
||||
` projections.apps2.sequence,` +
|
||||
expectedAppQuery = regexp.QuoteMeta(`SELECT projections.apps3.id,` +
|
||||
` projections.apps3.name,` +
|
||||
` projections.apps3.project_id,` +
|
||||
` projections.apps3.creation_date,` +
|
||||
` projections.apps3.change_date,` +
|
||||
` projections.apps3.resource_owner,` +
|
||||
` projections.apps3.state,` +
|
||||
` projections.apps3.sequence,` +
|
||||
// api config
|
||||
` projections.apps2_api_configs.app_id,` +
|
||||
` projections.apps2_api_configs.client_id,` +
|
||||
` projections.apps2_api_configs.auth_method,` +
|
||||
` projections.apps3_api_configs.app_id,` +
|
||||
` projections.apps3_api_configs.client_id,` +
|
||||
` projections.apps3_api_configs.auth_method,` +
|
||||
// oidc config
|
||||
` projections.apps2_oidc_configs.app_id,` +
|
||||
` projections.apps2_oidc_configs.version,` +
|
||||
` projections.apps2_oidc_configs.client_id,` +
|
||||
` projections.apps2_oidc_configs.redirect_uris,` +
|
||||
` projections.apps2_oidc_configs.response_types,` +
|
||||
` projections.apps2_oidc_configs.grant_types,` +
|
||||
` projections.apps2_oidc_configs.application_type,` +
|
||||
` projections.apps2_oidc_configs.auth_method_type,` +
|
||||
` projections.apps2_oidc_configs.post_logout_redirect_uris,` +
|
||||
` projections.apps2_oidc_configs.is_dev_mode,` +
|
||||
` projections.apps2_oidc_configs.access_token_type,` +
|
||||
` projections.apps2_oidc_configs.access_token_role_assertion,` +
|
||||
` projections.apps2_oidc_configs.id_token_role_assertion,` +
|
||||
` projections.apps2_oidc_configs.id_token_userinfo_assertion,` +
|
||||
` projections.apps2_oidc_configs.clock_skew,` +
|
||||
` projections.apps2_oidc_configs.additional_origins` +
|
||||
` FROM projections.apps2` +
|
||||
` LEFT JOIN projections.apps2_api_configs ON projections.apps2.id = projections.apps2_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps2_oidc_configs ON projections.apps2.id = projections.apps2_oidc_configs.app_id`)
|
||||
expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps2.id,` +
|
||||
` projections.apps2.name,` +
|
||||
` projections.apps2.project_id,` +
|
||||
` projections.apps2.creation_date,` +
|
||||
` projections.apps2.change_date,` +
|
||||
` projections.apps2.resource_owner,` +
|
||||
` projections.apps2.state,` +
|
||||
` projections.apps2.sequence,` +
|
||||
` projections.apps3_oidc_configs.app_id,` +
|
||||
` projections.apps3_oidc_configs.version,` +
|
||||
` projections.apps3_oidc_configs.client_id,` +
|
||||
` projections.apps3_oidc_configs.redirect_uris,` +
|
||||
` projections.apps3_oidc_configs.response_types,` +
|
||||
` projections.apps3_oidc_configs.grant_types,` +
|
||||
` projections.apps3_oidc_configs.application_type,` +
|
||||
` projections.apps3_oidc_configs.auth_method_type,` +
|
||||
` projections.apps3_oidc_configs.post_logout_redirect_uris,` +
|
||||
` projections.apps3_oidc_configs.is_dev_mode,` +
|
||||
` projections.apps3_oidc_configs.access_token_type,` +
|
||||
` projections.apps3_oidc_configs.access_token_role_assertion,` +
|
||||
` projections.apps3_oidc_configs.id_token_role_assertion,` +
|
||||
` projections.apps3_oidc_configs.id_token_userinfo_assertion,` +
|
||||
` projections.apps3_oidc_configs.clock_skew,` +
|
||||
` projections.apps3_oidc_configs.additional_origins,` +
|
||||
//saml config
|
||||
` projections.apps3_saml_configs.app_id,` +
|
||||
` projections.apps3_saml_configs.entity_id,` +
|
||||
` projections.apps3_saml_configs.metadata,` +
|
||||
` projections.apps3_saml_configs.metadata_url` +
|
||||
` FROM projections.apps3` +
|
||||
` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_saml_configs ON projections.apps3.id = projections.apps3_saml_configs.app_id`)
|
||||
expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps3.id,` +
|
||||
` projections.apps3.name,` +
|
||||
` projections.apps3.project_id,` +
|
||||
` projections.apps3.creation_date,` +
|
||||
` projections.apps3.change_date,` +
|
||||
` projections.apps3.resource_owner,` +
|
||||
` projections.apps3.state,` +
|
||||
` projections.apps3.sequence,` +
|
||||
// api config
|
||||
` projections.apps2_api_configs.app_id,` +
|
||||
` projections.apps2_api_configs.client_id,` +
|
||||
` projections.apps2_api_configs.auth_method,` +
|
||||
` projections.apps3_api_configs.app_id,` +
|
||||
` projections.apps3_api_configs.client_id,` +
|
||||
` projections.apps3_api_configs.auth_method,` +
|
||||
// oidc config
|
||||
` projections.apps2_oidc_configs.app_id,` +
|
||||
` projections.apps2_oidc_configs.version,` +
|
||||
` projections.apps2_oidc_configs.client_id,` +
|
||||
` projections.apps2_oidc_configs.redirect_uris,` +
|
||||
` projections.apps2_oidc_configs.response_types,` +
|
||||
` projections.apps2_oidc_configs.grant_types,` +
|
||||
` projections.apps2_oidc_configs.application_type,` +
|
||||
` projections.apps2_oidc_configs.auth_method_type,` +
|
||||
` projections.apps2_oidc_configs.post_logout_redirect_uris,` +
|
||||
` projections.apps2_oidc_configs.is_dev_mode,` +
|
||||
` projections.apps2_oidc_configs.access_token_type,` +
|
||||
` projections.apps2_oidc_configs.access_token_role_assertion,` +
|
||||
` projections.apps2_oidc_configs.id_token_role_assertion,` +
|
||||
` projections.apps2_oidc_configs.id_token_userinfo_assertion,` +
|
||||
` projections.apps2_oidc_configs.clock_skew,` +
|
||||
` projections.apps2_oidc_configs.additional_origins,` +
|
||||
` projections.apps3_oidc_configs.app_id,` +
|
||||
` projections.apps3_oidc_configs.version,` +
|
||||
` projections.apps3_oidc_configs.client_id,` +
|
||||
` projections.apps3_oidc_configs.redirect_uris,` +
|
||||
` projections.apps3_oidc_configs.response_types,` +
|
||||
` projections.apps3_oidc_configs.grant_types,` +
|
||||
` projections.apps3_oidc_configs.application_type,` +
|
||||
` projections.apps3_oidc_configs.auth_method_type,` +
|
||||
` projections.apps3_oidc_configs.post_logout_redirect_uris,` +
|
||||
` projections.apps3_oidc_configs.is_dev_mode,` +
|
||||
` projections.apps3_oidc_configs.access_token_type,` +
|
||||
` projections.apps3_oidc_configs.access_token_role_assertion,` +
|
||||
` projections.apps3_oidc_configs.id_token_role_assertion,` +
|
||||
` projections.apps3_oidc_configs.id_token_userinfo_assertion,` +
|
||||
` projections.apps3_oidc_configs.clock_skew,` +
|
||||
` projections.apps3_oidc_configs.additional_origins,` +
|
||||
//saml config
|
||||
` projections.apps3_saml_configs.app_id,` +
|
||||
` projections.apps3_saml_configs.entity_id,` +
|
||||
` projections.apps3_saml_configs.metadata,` +
|
||||
` projections.apps3_saml_configs.metadata_url,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.apps2` +
|
||||
` LEFT JOIN projections.apps2_api_configs ON projections.apps2.id = projections.apps2_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps2_oidc_configs ON projections.apps2.id = projections.apps2_oidc_configs.app_id`)
|
||||
expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps2_api_configs.client_id,` +
|
||||
` projections.apps2_oidc_configs.client_id` +
|
||||
` FROM projections.apps2` +
|
||||
` LEFT JOIN projections.apps2_api_configs ON projections.apps2.id = projections.apps2_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps2_oidc_configs ON projections.apps2.id = projections.apps2_oidc_configs.app_id`)
|
||||
expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps2.project_id` +
|
||||
` FROM projections.apps2` +
|
||||
` LEFT JOIN projections.apps2_api_configs ON projections.apps2.id = projections.apps2_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps2_oidc_configs ON projections.apps2.id = projections.apps2_oidc_configs.app_id`)
|
||||
` FROM projections.apps3` +
|
||||
` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_saml_configs ON projections.apps3.id = projections.apps3_saml_configs.app_id`)
|
||||
expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps3_api_configs.client_id,` +
|
||||
` projections.apps3_oidc_configs.client_id` +
|
||||
` FROM projections.apps3` +
|
||||
` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id`)
|
||||
expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps3.project_id` +
|
||||
` FROM projections.apps3` +
|
||||
` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_saml_configs ON projections.apps3.id = projections.apps3_saml_configs.app_id`)
|
||||
expectedProjectByAppQuery = regexp.QuoteMeta(`SELECT projections.projects2.id,` +
|
||||
` projections.projects2.creation_date,` +
|
||||
` projections.projects2.change_date,` +
|
||||
@@ -101,9 +114,10 @@ var (
|
||||
` projections.projects2.has_project_check,` +
|
||||
` projections.projects2.private_labeling_setting` +
|
||||
` FROM projections.projects2` +
|
||||
` JOIN projections.apps2 ON projections.projects2.id = projections.apps2.project_id` +
|
||||
` LEFT JOIN projections.apps2_api_configs ON projections.apps2.id = projections.apps2_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps2_oidc_configs ON projections.apps2.id = projections.apps2_oidc_configs.app_id`)
|
||||
` JOIN projections.apps3 ON projections.projects2.id = projections.apps3.project_id` +
|
||||
` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id` +
|
||||
` LEFT JOIN projections.apps3_saml_configs ON projections.apps3.id = projections.apps3_saml_configs.app_id`)
|
||||
|
||||
appCols = database.StringArray{
|
||||
"id",
|
||||
@@ -135,6 +149,11 @@ var (
|
||||
"id_token_userinfo_assertion",
|
||||
"clock_skew",
|
||||
"additional_origins",
|
||||
//saml config
|
||||
"app_id",
|
||||
"entity_id",
|
||||
"metadata",
|
||||
"metadata_url",
|
||||
}
|
||||
appsCols = append(appCols, "count")
|
||||
)
|
||||
@@ -200,6 +219,11 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -260,6 +284,11 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -285,6 +314,75 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "prepareAppsQuery saml app",
|
||||
prepare: prepareAppsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
expectedAppsQuery,
|
||||
appsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"app-id",
|
||||
"app-name",
|
||||
"project-id",
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.AppStateActive,
|
||||
uint64(20211109),
|
||||
// api config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// oidc config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml config
|
||||
"app-id",
|
||||
"https://test.com/saml/metadata",
|
||||
[]byte("<?xml version=\"1.0\"?>\n<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n validUntil=\"2022-08-26T14:08:16Z\"\n cacheDuration=\"PT604800S\"\n entityID=\"https://test.com/saml/metadata\">\n <md:SPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"false\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>\n <md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n Location=\"https://test.com/saml/acs\"\n index=\"1\" />\n \n </md:SPSSODescriptor>\n</md:EntityDescriptor>"),
|
||||
"https://test.com/saml/metadata",
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &Apps{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 1,
|
||||
},
|
||||
Apps: []*App{
|
||||
{
|
||||
ID: "app-id",
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.AppStateActive,
|
||||
Sequence: 20211109,
|
||||
Name: "app-name",
|
||||
ProjectID: "project-id",
|
||||
SAMLConfig: &SAMLApp{
|
||||
Metadata: []byte("<?xml version=\"1.0\"?>\n<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n validUntil=\"2022-08-26T14:08:16Z\"\n cacheDuration=\"PT604800S\"\n entityID=\"https://test.com/saml/metadata\">\n <md:SPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"false\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>\n <md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n Location=\"https://test.com/saml/acs\"\n index=\"1\" />\n \n </md:SPSSODescriptor>\n</md:EntityDescriptor>"),
|
||||
MetadataURL: "https://test.com/saml/metadata",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareAppsQuery oidc app",
|
||||
@@ -324,6 +422,11 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -403,6 +506,11 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -482,6 +590,11 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -561,6 +674,11 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -640,6 +758,11 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -719,6 +842,11 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"api-app-id",
|
||||
@@ -750,13 +878,54 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"saml-app-id",
|
||||
"app-name",
|
||||
"project-id",
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.AppStateActive,
|
||||
uint64(20211109),
|
||||
// api config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// oidc config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml config
|
||||
"saml-app-id",
|
||||
"https://test.com/saml/metadata",
|
||||
[]byte("<?xml version=\"1.0\"?>\n<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n validUntil=\"2022-08-26T14:08:16Z\"\n cacheDuration=\"PT604800S\"\n entityID=\"https://test.com/saml/metadata\">\n <md:SPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"false\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>\n <md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n Location=\"https://test.com/saml/acs\"\n index=\"1\" />\n \n </md:SPSSODescriptor>\n</md:EntityDescriptor>"),
|
||||
"https://test.com/saml/metadata",
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &Apps{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 2,
|
||||
Count: 3,
|
||||
},
|
||||
Apps: []*App{
|
||||
{
|
||||
@@ -802,6 +971,21 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "saml-app-id",
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.AppStateActive,
|
||||
Sequence: 20211109,
|
||||
Name: "app-name",
|
||||
ProjectID: "project-id",
|
||||
SAMLConfig: &SAMLApp{
|
||||
Metadata: []byte("<?xml version=\"1.0\"?>\n<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n validUntil=\"2022-08-26T14:08:16Z\"\n cacheDuration=\"PT604800S\"\n entityID=\"https://test.com/saml/metadata\">\n <md:SPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"false\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>\n <md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n Location=\"https://test.com/saml/acs\"\n index=\"1\" />\n \n </md:SPSSODescriptor>\n</md:EntityDescriptor>"),
|
||||
MetadataURL: "https://test.com/saml/metadata",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -896,6 +1080,11 @@ func Test_AppPrepare(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -948,6 +1137,11 @@ func Test_AppPrepare(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -1005,6 +1199,11 @@ func Test_AppPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -1038,6 +1237,68 @@ func Test_AppPrepare(t *testing.T) {
|
||||
AllowedOrigins: database.StringArray{"https://redirect.to", "additional.origin"},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "prepareAppQuery saml app",
|
||||
prepare: prepareAppQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
expectedAppQuery,
|
||||
appCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"app-id",
|
||||
"app-name",
|
||||
"project-id",
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.AppStateActive,
|
||||
uint64(20211109),
|
||||
// api config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// oidc config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml config
|
||||
"app-id",
|
||||
"https://test.com/saml/metadata",
|
||||
[]byte("<?xml version=\"1.0\"?>\n<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n validUntil=\"2022-08-26T14:08:16Z\"\n cacheDuration=\"PT604800S\"\n entityID=\"https://test.com/saml/metadata\">\n <md:SPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"false\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>\n <md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n Location=\"https://test.com/saml/acs\"\n index=\"1\" />\n \n </md:SPSSODescriptor>\n</md:EntityDescriptor>"),
|
||||
"https://test.com/saml/metadata",
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &App{
|
||||
ID: "app-id",
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.AppStateActive,
|
||||
Sequence: 20211109,
|
||||
Name: "app-name",
|
||||
ProjectID: "project-id",
|
||||
SAMLConfig: &SAMLApp{
|
||||
Metadata: []byte("<?xml version=\"1.0\"?>\n<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n validUntil=\"2022-08-26T14:08:16Z\"\n cacheDuration=\"PT604800S\"\n entityID=\"https://test.com/saml/metadata\">\n <md:SPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"false\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>\n <md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n Location=\"https://test.com/saml/acs\"\n index=\"1\" />\n \n </md:SPSSODescriptor>\n</md:EntityDescriptor>"),
|
||||
MetadataURL: "https://test.com/saml/metadata",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareAppQuery oidc app IsDevMode inactive",
|
||||
@@ -1077,6 +1338,11 @@ func Test_AppPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -1149,6 +1415,11 @@ func Test_AppPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -1221,6 +1492,11 @@ func Test_AppPrepare(t *testing.T) {
|
||||
true,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -1293,6 +1569,11 @@ func Test_AppPrepare(t *testing.T) {
|
||||
false,
|
||||
1 * time.Second,
|
||||
database.StringArray{"additional.origin"},
|
||||
// saml config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
|
156
internal/query/certificate.go
Normal file
156
internal/query/certificate.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
)
|
||||
|
||||
type Certificate interface {
|
||||
Key
|
||||
Expiry() time.Time
|
||||
Key() *crypto.CryptoValue
|
||||
Certificate() []byte
|
||||
}
|
||||
|
||||
type Certificates struct {
|
||||
SearchResponse
|
||||
Certificates []Certificate
|
||||
}
|
||||
|
||||
type rsaCertificate struct {
|
||||
key
|
||||
expiry time.Time
|
||||
privateKey *crypto.CryptoValue
|
||||
certificate []byte
|
||||
}
|
||||
|
||||
func (c *rsaCertificate) Expiry() time.Time {
|
||||
return c.expiry
|
||||
}
|
||||
|
||||
func (c *rsaCertificate) Key() *crypto.CryptoValue {
|
||||
return c.privateKey
|
||||
}
|
||||
|
||||
func (c *rsaCertificate) Certificate() []byte {
|
||||
return c.certificate
|
||||
}
|
||||
|
||||
var (
|
||||
certificateTable = table{
|
||||
name: projection.CertificateTable,
|
||||
}
|
||||
CertificateColID = Column{
|
||||
name: projection.CertificateColumnID,
|
||||
table: certificateTable,
|
||||
}
|
||||
CertificateColExpiry = Column{
|
||||
name: projection.CertificateColumnExpiry,
|
||||
table: certificateTable,
|
||||
}
|
||||
CertificateColCertificate = Column{
|
||||
name: projection.CertificateColumnCertificate,
|
||||
table: certificateTable,
|
||||
}
|
||||
)
|
||||
|
||||
func (q *Queries) ActiveCertificates(ctx context.Context, t time.Time, usage domain.KeyUsage) (*Certificates, error) {
|
||||
query, scan := prepareCertificateQuery()
|
||||
if t.IsZero() {
|
||||
t = time.Now()
|
||||
}
|
||||
stmt, args, err := query.Where(
|
||||
sq.And{
|
||||
sq.Eq{
|
||||
KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
KeyColUse.identifier(): usage,
|
||||
},
|
||||
sq.Gt{
|
||||
CertificateColExpiry.identifier(): t,
|
||||
},
|
||||
sq.Gt{
|
||||
KeyPrivateColExpiry.identifier(): t,
|
||||
},
|
||||
}).OrderBy(KeyPrivateColExpiry.identifier()).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-SDfkg", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
rows, err := q.client.QueryContext(ctx, stmt, args...)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-Sgan4", "Errors.Internal")
|
||||
}
|
||||
keys, err := scan(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys.LatestSequence, err = q.latestSequence(ctx, keyTable)
|
||||
if !errors.IsNotFound(err) {
|
||||
return keys, err
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func prepareCertificateQuery() (sq.SelectBuilder, func(*sql.Rows) (*Certificates, error)) {
|
||||
return sq.Select(
|
||||
KeyColID.identifier(),
|
||||
KeyColCreationDate.identifier(),
|
||||
KeyColChangeDate.identifier(),
|
||||
KeyColSequence.identifier(),
|
||||
KeyColResourceOwner.identifier(),
|
||||
KeyColAlgorithm.identifier(),
|
||||
KeyColUse.identifier(),
|
||||
CertificateColExpiry.identifier(),
|
||||
CertificateColCertificate.identifier(),
|
||||
KeyPrivateColKey.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(keyTable.identifier()).
|
||||
LeftJoin(join(CertificateColID, KeyColID)).
|
||||
LeftJoin(join(KeyPrivateColID, KeyColID)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*Certificates, error) {
|
||||
certificates := make([]Certificate, 0)
|
||||
var count uint64
|
||||
for rows.Next() {
|
||||
k := new(rsaCertificate)
|
||||
err := rows.Scan(
|
||||
&k.id,
|
||||
&k.creationDate,
|
||||
&k.changeDate,
|
||||
&k.sequence,
|
||||
&k.resourceOwner,
|
||||
&k.algorithm,
|
||||
&k.use,
|
||||
&k.expiry,
|
||||
&k.certificate,
|
||||
&k.privateKey,
|
||||
&count,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certificates = append(certificates, k)
|
||||
}
|
||||
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-rKd6k", "Errors.Query.CloseRows")
|
||||
}
|
||||
|
||||
return &Certificates{
|
||||
Certificates: certificates,
|
||||
SearchResponse: SearchResponse{
|
||||
Count: count,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
169
internal/query/certificate_test.go
Normal file
169
internal/query/certificate_test.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
func Test_CertificatePrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
err checkErr
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
prepare interface{}
|
||||
want want
|
||||
object interface{}
|
||||
}{
|
||||
{
|
||||
name: "prepareCertificateQuery no result",
|
||||
prepare: prepareCertificateQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_certificate.expiry,`+
|
||||
` projections.keys3_certificate.certificate,`+
|
||||
` projections.keys3_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_certificate ON projections.keys3.id = projections.keys3_certificate.id`+
|
||||
` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !errs.IsNotFound(err) {
|
||||
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: &Certificates{Certificates: []Certificate{}},
|
||||
},
|
||||
{
|
||||
name: "prepareCertificateQuery found",
|
||||
prepare: prepareCertificateQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_certificate.expiry,`+
|
||||
` projections.keys3_certificate.certificate,`+
|
||||
` projections.keys3_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_certificate ON projections.keys3.id = projections.keys3_certificate.id`+
|
||||
` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"resource_owner",
|
||||
"algorithm",
|
||||
"use",
|
||||
"expiry",
|
||||
"certificate",
|
||||
"key",
|
||||
"count",
|
||||
},
|
||||
[][]driver.Value{
|
||||
{
|
||||
"key-id",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
"ro",
|
||||
"",
|
||||
1,
|
||||
testNow,
|
||||
[]byte(`privateKey`),
|
||||
[]byte(`{"Algorithm": "enc", "Crypted": "cHJpdmF0ZUtleQ==", "CryptoType": 0, "KeyID": "id"}`),
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &Certificates{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 1,
|
||||
},
|
||||
Certificates: []Certificate{
|
||||
&rsaCertificate{
|
||||
key: key{
|
||||
id: "key-id",
|
||||
creationDate: testNow,
|
||||
changeDate: testNow,
|
||||
sequence: 20211109,
|
||||
resourceOwner: "ro",
|
||||
algorithm: "",
|
||||
use: domain.KeyUsageSAMLMetadataSigning,
|
||||
},
|
||||
expiry: testNow,
|
||||
certificate: []byte("privateKey"),
|
||||
privateKey: &crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("privateKey"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareCertificateQuery sql err",
|
||||
prepare: prepareCertificateQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_certificate.expiry,`+
|
||||
` projections.keys3_certificate.certificate,`+
|
||||
` projections.keys3_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_certificate ON projections.keys3.id = projections.keys3_certificate.id`+
|
||||
` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !errors.Is(err, sql.ErrConnDone) {
|
||||
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
})
|
||||
}
|
||||
}
|
@@ -200,7 +200,10 @@ func (q *Queries) ActivePublicKeys(ctx context.Context, t time.Time) (*PublicKey
|
||||
return nil, err
|
||||
}
|
||||
keys.LatestSequence, err = q.latestSequence(ctx, keyTable)
|
||||
return keys, err
|
||||
if !errors.IsNotFound(err) {
|
||||
return keys, err
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (q *Queries) ActivePrivateSigningKey(ctx context.Context, t time.Time) (*PrivateKeys, error) {
|
||||
|
@@ -31,18 +31,18 @@ func Test_KeyPrepares(t *testing.T) {
|
||||
prepare: preparePublicKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.keys2.id,`+
|
||||
` projections.keys2.creation_date,`+
|
||||
` projections.keys2.change_date,`+
|
||||
` projections.keys2.sequence,`+
|
||||
` projections.keys2.resource_owner,`+
|
||||
` projections.keys2.algorithm,`+
|
||||
` projections.keys2.use,`+
|
||||
` projections.keys2_public.expiry,`+
|
||||
` projections.keys2_public.key,`+
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_public.expiry,`+
|
||||
` projections.keys3_public.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys2`+
|
||||
` LEFT JOIN projections.keys2_public ON projections.keys2.id = projections.keys2_public.id`),
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_public ON projections.keys3.id = projections.keys3_public.id`),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@@ -60,18 +60,18 @@ func Test_KeyPrepares(t *testing.T) {
|
||||
prepare: preparePublicKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.keys2.id,`+
|
||||
` projections.keys2.creation_date,`+
|
||||
` projections.keys2.change_date,`+
|
||||
` projections.keys2.sequence,`+
|
||||
` projections.keys2.resource_owner,`+
|
||||
` projections.keys2.algorithm,`+
|
||||
` projections.keys2.use,`+
|
||||
` projections.keys2_public.expiry,`+
|
||||
` projections.keys2_public.key,`+
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_public.expiry,`+
|
||||
` projections.keys3_public.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys2`+
|
||||
` LEFT JOIN projections.keys2_public ON projections.keys2.id = projections.keys2_public.id`),
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_public ON projections.keys3.id = projections.keys3_public.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@@ -128,18 +128,18 @@ func Test_KeyPrepares(t *testing.T) {
|
||||
prepare: preparePublicKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.keys2.id,`+
|
||||
` projections.keys2.creation_date,`+
|
||||
` projections.keys2.change_date,`+
|
||||
` projections.keys2.sequence,`+
|
||||
` projections.keys2.resource_owner,`+
|
||||
` projections.keys2.algorithm,`+
|
||||
` projections.keys2.use,`+
|
||||
` projections.keys2_public.expiry,`+
|
||||
` projections.keys2_public.key,`+
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_public.expiry,`+
|
||||
` projections.keys3_public.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys2`+
|
||||
` LEFT JOIN projections.keys2_public ON projections.keys2.id = projections.keys2_public.id`),
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_public ON projections.keys3.id = projections.keys3_public.id`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@@ -156,18 +156,18 @@ func Test_KeyPrepares(t *testing.T) {
|
||||
prepare: preparePrivateKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.keys2.id,`+
|
||||
` projections.keys2.creation_date,`+
|
||||
` projections.keys2.change_date,`+
|
||||
` projections.keys2.sequence,`+
|
||||
` projections.keys2.resource_owner,`+
|
||||
` projections.keys2.algorithm,`+
|
||||
` projections.keys2.use,`+
|
||||
` projections.keys2_private.expiry,`+
|
||||
` projections.keys2_private.key,`+
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_private.expiry,`+
|
||||
` projections.keys3_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys2`+
|
||||
` LEFT JOIN projections.keys2_private ON projections.keys2.id = projections.keys2_private.id`),
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@@ -185,18 +185,18 @@ func Test_KeyPrepares(t *testing.T) {
|
||||
prepare: preparePrivateKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.keys2.id,`+
|
||||
` projections.keys2.creation_date,`+
|
||||
` projections.keys2.change_date,`+
|
||||
` projections.keys2.sequence,`+
|
||||
` projections.keys2.resource_owner,`+
|
||||
` projections.keys2.algorithm,`+
|
||||
` projections.keys2.use,`+
|
||||
` projections.keys2_private.expiry,`+
|
||||
` projections.keys2_private.key,`+
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_private.expiry,`+
|
||||
` projections.keys3_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys2`+
|
||||
` LEFT JOIN projections.keys2_private ON projections.keys2.id = projections.keys2_private.id`),
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@@ -255,18 +255,18 @@ func Test_KeyPrepares(t *testing.T) {
|
||||
prepare: preparePrivateKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.keys2.id,`+
|
||||
` projections.keys2.creation_date,`+
|
||||
` projections.keys2.change_date,`+
|
||||
` projections.keys2.sequence,`+
|
||||
` projections.keys2.resource_owner,`+
|
||||
` projections.keys2.algorithm,`+
|
||||
` projections.keys2.use,`+
|
||||
` projections.keys2_private.expiry,`+
|
||||
` projections.keys2_private.key,`+
|
||||
regexp.QuoteMeta(`SELECT projections.keys3.id,`+
|
||||
` projections.keys3.creation_date,`+
|
||||
` projections.keys3.change_date,`+
|
||||
` projections.keys3.sequence,`+
|
||||
` projections.keys3.resource_owner,`+
|
||||
` projections.keys3.algorithm,`+
|
||||
` projections.keys3.use,`+
|
||||
` projections.keys3_private.expiry,`+
|
||||
` projections.keys3_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys2`+
|
||||
` LEFT JOIN projections.keys2_private ON projections.keys2.id = projections.keys2_private.id`),
|
||||
` FROM projections.keys3`+
|
||||
` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
|
@@ -13,9 +13,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
AppProjectionTable = "projections.apps2"
|
||||
AppProjectionTable = "projections.apps3"
|
||||
AppAPITable = AppProjectionTable + "_" + appAPITableSuffix
|
||||
AppOIDCTable = AppProjectionTable + "_" + appOIDCTableSuffix
|
||||
AppSAMLTable = AppProjectionTable + "_" + appSAMLTableSuffix
|
||||
|
||||
AppColumnID = "id"
|
||||
AppColumnName = "name"
|
||||
@@ -53,6 +54,13 @@ const (
|
||||
AppOIDCConfigColumnIDTokenUserinfoAssertion = "id_token_userinfo_assertion"
|
||||
AppOIDCConfigColumnClockSkew = "clock_skew"
|
||||
AppOIDCConfigColumnAdditionalOrigins = "additional_origins"
|
||||
|
||||
appSAMLTableSuffix = "saml_configs"
|
||||
AppSAMLConfigColumnAppID = "app_id"
|
||||
AppSAMLConfigColumnInstanceID = "instance_id"
|
||||
AppSAMLConfigColumnEntityID = "entity_id"
|
||||
AppSAMLConfigColumnMetadata = "metadata"
|
||||
AppSAMLConfigColumnMetadataURL = "metadata_url"
|
||||
)
|
||||
|
||||
type appProjection struct {
|
||||
@@ -116,6 +124,18 @@ func newAppProjection(ctx context.Context, config crdb.StatementHandlerConfig) *
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_oidc_ref_apps")),
|
||||
crdb.WithIndex(crdb.NewIndex("oidc_client_id_idx", []string{AppOIDCConfigColumnClientID})),
|
||||
),
|
||||
crdb.NewSuffixedTable([]*crdb.Column{
|
||||
crdb.NewColumn(AppSAMLConfigColumnAppID, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(AppSAMLConfigColumnInstanceID, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(AppSAMLConfigColumnEntityID, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(AppSAMLConfigColumnMetadata, crdb.ColumnTypeBytes),
|
||||
crdb.NewColumn(AppSAMLConfigColumnMetadataURL, crdb.ColumnTypeText),
|
||||
},
|
||||
crdb.NewPrimaryKey(AppSAMLConfigColumnInstanceID, AppSAMLConfigColumnAppID),
|
||||
appSAMLTableSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_saml_ref_apps")),
|
||||
crdb.WithIndex(crdb.NewIndex("saml_entity_id_idx", []string{AppSAMLConfigColumnEntityID})),
|
||||
),
|
||||
)
|
||||
p.StatementHandler = crdb.NewStatementHandler(ctx, config)
|
||||
return p
|
||||
@@ -174,6 +194,14 @@ func (p *appProjection) reducers() []handler.AggregateReducer {
|
||||
Event: project.OIDCConfigSecretChangedType,
|
||||
Reduce: p.reduceOIDCConfigSecretChanged,
|
||||
},
|
||||
{
|
||||
Event: project.SAMLConfigAddedType,
|
||||
Reduce: p.reduceSAMLConfigAdded,
|
||||
},
|
||||
{
|
||||
Event: project.SAMLConfigChangedType,
|
||||
Reduce: p.reduceSAMLConfigChanged,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -535,3 +563,77 @@ func (p *appProjection) reduceOIDCConfigSecretChanged(event eventstore.Event) (*
|
||||
),
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *appProjection) reduceSAMLConfigAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, ok := event.(*project.SAMLConfigAddedEvent)
|
||||
if !ok {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "HANDL-GMHU1", "reduce.wrong.event.type")
|
||||
}
|
||||
return crdb.NewMultiStatement(
|
||||
e,
|
||||
crdb.AddCreateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(AppSAMLConfigColumnAppID, e.AppID),
|
||||
handler.NewCol(AppSAMLConfigColumnInstanceID, e.Aggregate().InstanceID),
|
||||
handler.NewCol(AppSAMLConfigColumnEntityID, e.EntityID),
|
||||
handler.NewCol(AppSAMLConfigColumnMetadata, e.Metadata),
|
||||
handler.NewCol(AppSAMLConfigColumnMetadataURL, e.MetadataURL),
|
||||
},
|
||||
crdb.WithTableSuffix(appSAMLTableSuffix),
|
||||
),
|
||||
crdb.AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(AppColumnChangeDate, e.CreationDate()),
|
||||
handler.NewCol(AppColumnSequence, e.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(AppColumnID, e.AppID),
|
||||
handler.NewCond(AppColumnInstanceID, e.Aggregate().InstanceID),
|
||||
},
|
||||
),
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *appProjection) reduceSAMLConfigChanged(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, ok := event.(*project.SAMLConfigChangedEvent)
|
||||
if !ok {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "HANDL-GMHU2", "reduce.wrong.event.type")
|
||||
}
|
||||
|
||||
cols := make([]handler.Column, 0, 3)
|
||||
if e.Metadata != nil {
|
||||
cols = append(cols, handler.NewCol(AppSAMLConfigColumnMetadata, e.Metadata))
|
||||
}
|
||||
if e.MetadataURL != nil {
|
||||
cols = append(cols, handler.NewCol(AppSAMLConfigColumnMetadataURL, *e.MetadataURL))
|
||||
}
|
||||
if e.EntityID != "" {
|
||||
cols = append(cols, handler.NewCol(AppSAMLConfigColumnEntityID, e.EntityID))
|
||||
}
|
||||
|
||||
if len(cols) == 0 {
|
||||
return crdb.NewNoOpStatement(e), nil
|
||||
}
|
||||
|
||||
return crdb.NewMultiStatement(
|
||||
e,
|
||||
crdb.AddUpdateStatement(
|
||||
cols,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(AppSAMLConfigColumnAppID, e.AppID),
|
||||
handler.NewCond(AppSAMLConfigColumnInstanceID, e.Aggregate().InstanceID),
|
||||
},
|
||||
crdb.WithTableSuffix(appSAMLTableSuffix),
|
||||
),
|
||||
crdb.AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(AppColumnChangeDate, e.CreationDate()),
|
||||
handler.NewCol(AppColumnSequence, e.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(AppColumnID, e.AppID),
|
||||
handler.NewCond(AppColumnInstanceID, e.Aggregate().InstanceID),
|
||||
},
|
||||
),
|
||||
), nil
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.apps2 (id, name, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
||||
expectedStmt: "INSERT INTO projections.apps3 (id, name, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
||||
expectedArgs: []interface{}{
|
||||
"app-id",
|
||||
"my-app",
|
||||
@@ -82,7 +82,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
"my-app",
|
||||
anyArg{},
|
||||
@@ -115,7 +115,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
domain.AppStateInactive,
|
||||
anyArg{},
|
||||
@@ -148,7 +148,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
domain.AppStateActive,
|
||||
anyArg{},
|
||||
@@ -181,7 +181,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM projections.apps2 WHERE (id = $1) AND (instance_id = $2)",
|
||||
expectedStmt: "DELETE FROM projections.apps3 WHERE (id = $1) AND (instance_id = $2)",
|
||||
expectedArgs: []interface{}{
|
||||
"app-id",
|
||||
"instance-id",
|
||||
@@ -209,7 +209,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM projections.apps2 WHERE (project_id = $1) AND (instance_id = $2)",
|
||||
expectedStmt: "DELETE FROM projections.apps3 WHERE (project_id = $1) AND (instance_id = $2)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
"instance-id",
|
||||
@@ -242,7 +242,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.apps2_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)",
|
||||
expectedStmt: "INSERT INTO projections.apps3_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)",
|
||||
expectedArgs: []interface{}{
|
||||
"app-id",
|
||||
"instance-id",
|
||||
@@ -252,7 +252,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
@@ -287,7 +287,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2_api_configs SET (client_secret, auth_method) = ($1, $2) WHERE (app_id = $3) AND (instance_id = $4)",
|
||||
expectedStmt: "UPDATE projections.apps3_api_configs SET (client_secret, auth_method) = ($1, $2) WHERE (app_id = $3) AND (instance_id = $4)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
@@ -296,7 +296,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
@@ -351,7 +351,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||
expectedStmt: "UPDATE projections.apps3_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
"app-id",
|
||||
@@ -359,7 +359,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
@@ -407,7 +407,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.apps2_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)",
|
||||
expectedStmt: "INSERT INTO projections.apps3_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)",
|
||||
expectedArgs: []interface{}{
|
||||
"app-id",
|
||||
"instance-id",
|
||||
@@ -430,7 +430,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
@@ -476,7 +476,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2_oidc_configs SET (version, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) WHERE (app_id = $15) AND (instance_id = $16)",
|
||||
expectedStmt: "UPDATE projections.apps3_oidc_configs SET (version, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) WHERE (app_id = $15) AND (instance_id = $16)",
|
||||
expectedArgs: []interface{}{
|
||||
domain.OIDCVersionV1,
|
||||
database.StringArray{"redirect.one.ch", "redirect.two.ch"},
|
||||
@@ -497,7 +497,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
@@ -552,7 +552,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||
expectedStmt: "UPDATE projections.apps3_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
"app-id",
|
||||
@@ -560,7 +560,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.apps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
|
@@ -13,9 +13,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
KeyProjectionTable = "projections.keys2"
|
||||
KeyProjectionTable = "projections.keys3"
|
||||
KeyPrivateTable = KeyProjectionTable + "_" + privateKeyTableSuffix
|
||||
KeyPublicTable = KeyProjectionTable + "_" + publicKeyTableSuffix
|
||||
CertificateTable = KeyProjectionTable + "_" + certificateTableSuffix
|
||||
|
||||
KeyColumnID = "id"
|
||||
KeyColumnCreationDate = "creation_date"
|
||||
@@ -37,14 +38,21 @@ const (
|
||||
KeyPublicColumnInstanceID = "instance_id"
|
||||
KeyPublicColumnExpiry = "expiry"
|
||||
KeyPublicColumnKey = "key"
|
||||
|
||||
certificateTableSuffix = "certificate"
|
||||
CertificateColumnID = "id"
|
||||
CertificateColumnInstanceID = "instance_id"
|
||||
CertificateColumnExpiry = "expiry"
|
||||
CertificateColumnCertificate = "certificate"
|
||||
)
|
||||
|
||||
type keyProjection struct {
|
||||
crdb.StatementHandler
|
||||
encryptionAlgorithm crypto.EncryptionAlgorithm
|
||||
encryptionAlgorithm crypto.EncryptionAlgorithm
|
||||
certEncryptionAlgorithm crypto.EncryptionAlgorithm
|
||||
}
|
||||
|
||||
func newKeyProjection(ctx context.Context, config crdb.StatementHandlerConfig, keyEncryptionAlgorithm crypto.EncryptionAlgorithm) *keyProjection {
|
||||
func newKeyProjection(ctx context.Context, config crdb.StatementHandlerConfig, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, certEncryptionAlgorithm crypto.EncryptionAlgorithm) *keyProjection {
|
||||
p := new(keyProjection)
|
||||
config.ProjectionName = KeyProjectionTable
|
||||
config.Reducers = p.reducers()
|
||||
@@ -82,8 +90,19 @@ func newKeyProjection(ctx context.Context, config crdb.StatementHandlerConfig, k
|
||||
publicKeyTableSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_public_ref_keys")),
|
||||
),
|
||||
crdb.NewSuffixedTable([]*crdb.Column{
|
||||
crdb.NewColumn(CertificateColumnID, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(CertificateColumnInstanceID, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(CertificateColumnExpiry, crdb.ColumnTypeTimestamp),
|
||||
crdb.NewColumn(CertificateColumnCertificate, crdb.ColumnTypeBytes),
|
||||
},
|
||||
crdb.NewPrimaryKey(CertificateColumnInstanceID, CertificateColumnID),
|
||||
certificateTableSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_certificate_ref_keys")),
|
||||
),
|
||||
)
|
||||
p.encryptionAlgorithm = keyEncryptionAlgorithm
|
||||
p.certEncryptionAlgorithm = certEncryptionAlgorithm
|
||||
p.StatementHandler = crdb.NewStatementHandler(ctx, config)
|
||||
|
||||
return p
|
||||
@@ -98,6 +117,10 @@ func (p *keyProjection) reducers() []handler.AggregateReducer {
|
||||
Event: keypair.AddedEventType,
|
||||
Reduce: p.reduceKeyPairAdded,
|
||||
},
|
||||
{
|
||||
Event: keypair.AddedCertificateEventType,
|
||||
Reduce: p.reduceCertificateAdded,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -151,5 +174,34 @@ func (p *keyProjection) reduceKeyPairAdded(event eventstore.Event) (*handler.Sta
|
||||
crdb.WithTableSuffix(publicKeyTableSuffix),
|
||||
))
|
||||
}
|
||||
|
||||
return crdb.NewMultiStatement(e, creates...), nil
|
||||
}
|
||||
|
||||
func (p *keyProjection) reduceCertificateAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, ok := event.(*keypair.AddedCertificateEvent)
|
||||
if !ok {
|
||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-SAbr09", "reduce.wrong.event.type %s", keypair.AddedCertificateEventType)
|
||||
}
|
||||
|
||||
if e.Certificate.Expiry.Before(time.Now()) {
|
||||
return crdb.NewNoOpStatement(e), nil
|
||||
}
|
||||
|
||||
certificate, err := crypto.Decrypt(e.Certificate.Key, p.certEncryptionAlgorithm)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "HANDL-Dajwig2f", "cannot decrypt certificate")
|
||||
}
|
||||
|
||||
creates := []func(eventstore.Event) crdb.Exec{crdb.AddCreateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(CertificateColumnID, e.Aggregate().ID),
|
||||
handler.NewCol(CertificateColumnInstanceID, e.Aggregate().InstanceID),
|
||||
handler.NewCol(CertificateColumnExpiry, e.Certificate.Expiry),
|
||||
handler.NewCol(CertificateColumnCertificate, certificate),
|
||||
},
|
||||
crdb.WithTableSuffix(certificateTableSuffix),
|
||||
)}
|
||||
|
||||
return crdb.NewMultiStatement(e, creates...), nil
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package projection
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -31,7 +32,7 @@ func TestKeyProjection_reduces(t *testing.T) {
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(keypair.AddedEventType),
|
||||
keypair.AggregateType,
|
||||
keypairAddedEventData(time.Now().Add(time.Hour)),
|
||||
keypairAddedEventData(domain.KeyUsageSigning, time.Now().Add(time.Hour)),
|
||||
), keypair.AddedEventMapper),
|
||||
},
|
||||
reduce: (&keyProjection{encryptionAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t))}).reduceKeyPairAdded,
|
||||
@@ -43,7 +44,7 @@ func TestKeyProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.keys2 (id, creation_date, change_date, resource_owner, instance_id, sequence, algorithm, use) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
|
||||
expectedStmt: "INSERT INTO projections.keys3 (id, creation_date, change_date, resource_owner, instance_id, sequence, algorithm, use) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
anyArg{},
|
||||
@@ -56,7 +57,7 @@ func TestKeyProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.keys2_private (id, instance_id, expiry, key) VALUES ($1, $2, $3, $4)",
|
||||
expectedStmt: "INSERT INTO projections.keys3_private (id, instance_id, expiry, key) VALUES ($1, $2, $3, $4)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
"instance-id",
|
||||
@@ -70,7 +71,7 @@ func TestKeyProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.keys2_public (id, instance_id, expiry, key) VALUES ($1, $2, $3, $4)",
|
||||
expectedStmt: "INSERT INTO projections.keys3_public (id, instance_id, expiry, key) VALUES ($1, $2, $3, $4)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
"instance-id",
|
||||
@@ -88,7 +89,7 @@ func TestKeyProjection_reduces(t *testing.T) {
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(keypair.AddedEventType),
|
||||
keypair.AggregateType,
|
||||
keypairAddedEventData(time.Now().Add(-time.Hour)),
|
||||
keypairAddedEventData(domain.KeyUsageSigning, time.Now().Add(-time.Hour)),
|
||||
), keypair.AddedEventMapper),
|
||||
},
|
||||
reduce: (&keyProjection{}).reduceKeyPairAdded,
|
||||
@@ -100,6 +101,36 @@ func TestKeyProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceCertificateAdded",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(keypair.AddedCertificateEventType),
|
||||
keypair.AggregateType,
|
||||
certificateAddedEventData(domain.KeyUsageSAMLMetadataSigning, time.Now().Add(time.Hour)),
|
||||
), keypair.AddedCertificateEventMapper),
|
||||
},
|
||||
reduce: (&keyProjection{certEncryptionAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t))}).reduceCertificateAdded,
|
||||
want: wantReduce{
|
||||
projection: KeyProjectionTable,
|
||||
aggregateType: eventstore.AggregateType("key_pair"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.keys3_certificate (id, instance_id, expiry, certificate) VALUES ($1, $2, $3, $4)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
"instance-id",
|
||||
anyArg{},
|
||||
[]byte("privateKey"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -116,6 +147,10 @@ func TestKeyProjection_reduces(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func keypairAddedEventData(t time.Time) []byte {
|
||||
return []byte(`{"algorithm": "algorithm", "usage": 0, "privateKey": {"key": {"cryptoType": 0, "algorithm": "enc", "keyID": "id", "crypted": "cHJpdmF0ZUtleQ=="}, "expiry": "` + t.Format(time.RFC3339) + `"}, "publicKey": {"key": {"cryptoType": 0, "algorithm": "enc", "keyID": "id", "crypted": "cHVibGljS2V5"}, "expiry": "` + t.Format(time.RFC3339) + `"}}`)
|
||||
func keypairAddedEventData(usage domain.KeyUsage, t time.Time) []byte {
|
||||
return []byte(`{"algorithm": "algorithm", "usage": ` + fmt.Sprintf("%d", usage) + `, "privateKey": {"key": {"cryptoType": 0, "algorithm": "enc", "keyID": "id", "crypted": "cHJpdmF0ZUtleQ=="}, "expiry": "` + t.Format(time.RFC3339) + `"}, "publicKey": {"key": {"cryptoType": 0, "algorithm": "enc", "keyID": "id", "crypted": "cHVibGljS2V5"}, "expiry": "` + t.Format(time.RFC3339) + `"}}`)
|
||||
}
|
||||
|
||||
func certificateAddedEventData(usage domain.KeyUsage, t time.Time) []byte {
|
||||
return []byte(`{"algorithm": "algorithm", "usage": ` + fmt.Sprintf("%d", usage) + `, "certificate": {"key": {"cryptoType": 0, "algorithm": "enc", "keyID": "id", "crypted": "cHJpdmF0ZUtleQ=="}, "expiry": "` + t.Format(time.RFC3339) + `"}}`)
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ var (
|
||||
NotificationsProjection interface{}
|
||||
)
|
||||
|
||||
func Start(ctx context.Context, sqlClient *sql.DB, es *eventstore.Eventstore, config Config, keyEncryptionAlgorithm crypto.EncryptionAlgorithm) error {
|
||||
func Start(ctx context.Context, sqlClient *sql.DB, es *eventstore.Eventstore, config Config, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, certEncryptionAlgorithm crypto.EncryptionAlgorithm) error {
|
||||
projectionConfig = crdb.StatementHandlerConfig{
|
||||
ProjectionHandlerConfig: handler.ProjectionHandlerConfig{
|
||||
HandlerConfig: handler.HandlerConfig{
|
||||
@@ -120,7 +120,7 @@ func Start(ctx context.Context, sqlClient *sql.DB, es *eventstore.Eventstore, co
|
||||
SMSConfigProjection = newSMSConfigProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["sms_config"]))
|
||||
OIDCSettingsProjection = newOIDCSettingsProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["oidc_settings"]))
|
||||
DebugNotificationProviderProjection = newDebugNotificationProviderProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["debug_notification_provider"]))
|
||||
KeyProjection = newKeyProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["keys"]), keyEncryptionAlgorithm)
|
||||
KeyProjection = newKeyProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["keys"]), keyEncryptionAlgorithm, certEncryptionAlgorithm)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -4,14 +4,15 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
sd "github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/rakyll/statik/fs"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
sd "github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -42,7 +43,7 @@ type Queries struct {
|
||||
multifactors domain.MultifactorConfigs
|
||||
}
|
||||
|
||||
func StartQueries(ctx context.Context, es *eventstore.Eventstore, sqlClient *sql.DB, projections projection.Config, defaults sd.SystemDefaults, idpConfigEncryption, otpEncryption, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, zitadelRoles []authz.RoleMapping) (repo *Queries, err error) {
|
||||
func StartQueries(ctx context.Context, es *eventstore.Eventstore, sqlClient *sql.DB, projections projection.Config, defaults sd.SystemDefaults, idpConfigEncryption, otpEncryption, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, certEncryptionAlgorithm crypto.EncryptionAlgorithm, zitadelRoles []authz.RoleMapping) (repo *Queries, err error) {
|
||||
statikLoginFS, err := fs.NewWithNamespace("login")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to start login statik dir")
|
||||
@@ -79,7 +80,7 @@ func StartQueries(ctx context.Context, es *eventstore.Eventstore, sqlClient *sql
|
||||
},
|
||||
}
|
||||
|
||||
err = projection.Start(ctx, sqlClient, es, projections, keyEncryptionAlgorithm)
|
||||
err = projection.Start(ctx, sqlClient, es, projections, keyEncryptionAlgorithm, certEncryptionAlgorithm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Reference in New Issue
Block a user