diff --git a/docs/docs/apis/proto/admin.md b/docs/docs/apis/proto/admin.md
index a2e6cde824..0a1dc2edd9 100644
--- a/docs/docs/apis/proto/admin.md
+++ b/docs/docs/apis/proto/admin.md
@@ -1072,10 +1072,12 @@ This is an empty request
| styling_type | zitadel.idp.v1.IDPStylingType | - | enum.defined_only: true
|
| client_id | string | - | string.min_len: 1
string.max_len: 200
|
| client_secret | string | - | string.min_len: 1
string.max_len: 200
|
-| issuer | string | - | string.min_len: 1
string.max_len: 200
|
+| issuer | string | Fill the issuer if the identity provider is oidc discovery compliant If the identity provider is only oauth2 compliant or does not serve a openid configuration, fill the authorization and token endpoint instead | string.max_len: 200
|
| scopes | repeated string | - | |
| display_name_mapping | zitadel.idp.v1.OIDCMappingField | - | enum.defined_only: true
|
| username_mapping | zitadel.idp.v1.OIDCMappingField | - | enum.defined_only: true
|
+| authorization_endpoint | string | If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer | string.max_len: 500
|
+| token_endpoint | string | If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer | string.max_len: 500
|
@@ -2498,12 +2500,14 @@ This is an empty request
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| idp_id | string | - | string.min_len: 1
string.max_len: 200
|
-| issuer | string | - | string.min_len: 1
string.max_len: 200
|
+| issuer | string | Fill the issuer if the identity provider is oidc discovery compliant If the identity provider is only oauth2 compliant or does not serve a openid configuration, fill the authorization and token endpoint instead | string.min_len: 1
string.max_len: 200
|
| client_id | string | - | string.min_len: 1
string.max_len: 200
|
| client_secret | string | - | string.max_len: 200
|
| scopes | repeated string | - | |
| display_name_mapping | zitadel.idp.v1.OIDCMappingField | - | enum.defined_only: true
|
| username_mapping | zitadel.idp.v1.OIDCMappingField | - | enum.defined_only: true
|
+| authorization_endpoint | string | If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer | string.max_len: 500
|
+| token_endpoint | string | If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer | string.max_len: 500
|
diff --git a/docs/docs/apis/proto/idp.md b/docs/docs/apis/proto/idp.md
index de646c8879..28e95ca36e 100644
--- a/docs/docs/apis/proto/idp.md
+++ b/docs/docs/apis/proto/idp.md
@@ -100,6 +100,8 @@ title: zitadel/idp.proto
| scopes | repeated string | - | |
| display_name_mapping | OIDCMappingField | - | |
| username_mapping | OIDCMappingField | - | |
+| authorization_endpoint | string | - | string.max_len: 500
|
+| token_endpoint | string | - | string.max_len: 500
|
diff --git a/docs/docs/apis/proto/management.md b/docs/docs/apis/proto/management.md
index 4730ebb47a..8df950489b 100644
--- a/docs/docs/apis/proto/management.md
+++ b/docs/docs/apis/proto/management.md
@@ -3007,10 +3007,12 @@ This is an empty request
| styling_type | zitadel.idp.v1.IDPStylingType | - | enum.defined_only: true
|
| client_id | string | - | string.min_len: 1
string.max_len: 200
|
| client_secret | string | - | string.min_len: 1
string.max_len: 200
|
-| issuer | string | - | string.min_len: 1
string.max_len: 200
|
+| issuer | string | Fill the issuer if the identity provider is oidc discovery compliant If the identity provider is only oauth2 compliant or does not serve a openid configuration, fill the authorization and token endpoint instead | string.max_len: 200
|
| scopes | repeated string | - | |
| display_name_mapping | zitadel.idp.v1.OIDCMappingField | - | enum.defined_only: true
|
| username_mapping | zitadel.idp.v1.OIDCMappingField | - | enum.defined_only: true
|
+| authorization_endpoint | string | If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer | string.max_len: 500
|
+| token_endpoint | string | If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer | string.max_len: 500
|
@@ -6901,10 +6903,12 @@ This is an empty request
| idp_id | string | - | string.min_len: 1
string.max_len: 200
|
| client_id | string | - | string.min_len: 1
string.max_len: 200
|
| client_secret | string | - | string.max_len: 200
|
-| issuer | string | - | string.min_len: 1
string.max_len: 200
|
+| issuer | string | Fill the issuer if the identity provider is oidc discovery compliant If the identity provider is only oauth2 compliant or does not serve a openid configuration, fill the authorization and token endpoint instead | string.min_len: 1
string.max_len: 200
|
| scopes | repeated string | - | |
| display_name_mapping | zitadel.idp.v1.OIDCMappingField | - | enum.defined_only: true
|
| username_mapping | zitadel.idp.v1.OIDCMappingField | - | enum.defined_only: true
|
+| authorization_endpoint | string | If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer | string.max_len: 500
|
+| token_endpoint | string | If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer | string.max_len: 500
|
diff --git a/go.mod b/go.mod
index d76a37649b..df53035d50 100644
--- a/go.mod
+++ b/go.mod
@@ -69,6 +69,7 @@ require (
go.opentelemetry.io/otel/exporters/stdout v0.13.0
go.opentelemetry.io/otel/sdk v0.13.0
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
+ golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/text v0.3.6
golang.org/x/tools v0.1.1
diff --git a/go.sum b/go.sum
index cd53e0d22f..21f2bb0fec 100644
--- a/go.sum
+++ b/go.sum
@@ -240,7 +240,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.1 h1:4CF52PCseTFt4bE+Yk3dIpdVi7XWuPVMhPtm4FaIJPM=
github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ=
diff --git a/internal/api/grpc/admin/idp.go b/internal/api/grpc/admin/idp.go
index 631d6d4c73..a1dc990a33 100644
--- a/internal/api/grpc/admin/idp.go
+++ b/internal/api/grpc/admin/idp.go
@@ -33,7 +33,7 @@ func (s *Server) AddOIDCIDP(ctx context.Context, req *admin_pb.AddOIDCIDPRequest
return nil, err
}
return &admin_pb.AddOIDCIDPResponse{
- IdpId: config.AggregateID,
+ IdpId: config.IDPConfigID,
Details: object_pb.AddToDetailsPb(
config.Sequence,
config.ChangeDate,
diff --git a/internal/api/grpc/admin/idp_converter.go b/internal/api/grpc/admin/idp_converter.go
index c74eff76d1..6e62e3a011 100644
--- a/internal/api/grpc/admin/idp_converter.go
+++ b/internal/api/grpc/admin/idp_converter.go
@@ -24,6 +24,8 @@ func addOIDCIDPRequestToDomainOIDCIDPConfig(req *admin_pb.AddOIDCIDPRequest) *do
ClientID: req.ClientId,
ClientSecretString: req.ClientSecret,
Issuer: req.Issuer,
+ AuthorizationEndpoint: req.AuthorizationEndpoint,
+ TokenEndpoint: req.TokenEndpoint,
Scopes: req.Scopes,
IDPDisplayNameMapping: idp_grpc.MappingFieldToDomain(req.DisplayNameMapping),
UsernameMapping: idp_grpc.MappingFieldToDomain(req.UsernameMapping),
@@ -44,6 +46,8 @@ func updateOIDCConfigToDomain(req *admin_pb.UpdateIDPOIDCConfigRequest) *domain.
ClientID: req.ClientId,
ClientSecretString: req.ClientSecret,
Issuer: req.Issuer,
+ AuthorizationEndpoint: req.AuthorizationEndpoint,
+ TokenEndpoint: req.TokenEndpoint,
Scopes: req.Scopes,
IDPDisplayNameMapping: idp_grpc.MappingFieldToDomain(req.DisplayNameMapping),
UsernameMapping: idp_grpc.MappingFieldToDomain(req.UsernameMapping),
diff --git a/internal/api/grpc/admin/idp_converter_test.go b/internal/api/grpc/admin/idp_converter_test.go
index f9389a1c3d..a716e55c12 100644
--- a/internal/api/grpc/admin/idp_converter_test.go
+++ b/internal/api/grpc/admin/idp_converter_test.go
@@ -20,14 +20,16 @@ func Test_addOIDCIDPRequestToDomain(t *testing.T) {
name: "all fields filled",
args: args{
req: &admin_pb.AddOIDCIDPRequest{
- Name: "ZITADEL",
- StylingType: idp.IDPStylingType_STYLING_TYPE_GOOGLE,
- ClientId: "test1234",
- ClientSecret: "test4321",
- Issuer: "zitadel.ch",
- Scopes: []string{"email", "profile"},
- DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
- UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ Name: "ZITADEL",
+ StylingType: idp.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "test1234",
+ ClientSecret: "test4321",
+ Issuer: "zitadel.ch",
+ AuthorizationEndpoint: "https://accounts.zitadel.ch/oauth/v2/authorize",
+ TokenEndpoint: "https://api.zitadel.ch/oauth/v2/token",
+ Scopes: []string{"email", "profile"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
},
},
},
@@ -60,12 +62,14 @@ func Test_addOIDCIDPRequestToDomainOIDCIDPConfig(t *testing.T) {
name: "all fields filled",
args: args{
req: &admin_pb.AddOIDCIDPRequest{
- ClientId: "test1234",
- ClientSecret: "test4321",
- Issuer: "zitadel.ch",
- Scopes: []string{"email", "profile"},
- DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
- UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ ClientId: "test1234",
+ ClientSecret: "test4321",
+ Issuer: "zitadel.ch",
+ AuthorizationEndpoint: "https://accounts.zitadel.ch/oauth/v2/authorize",
+ TokenEndpoint: "https://api.zitadel.ch/oauth/v2/token",
+ Scopes: []string{"email", "profile"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
},
},
},
@@ -126,13 +130,15 @@ func Test_updateOIDCConfigToDomain(t *testing.T) {
name: "all fields filled",
args: args{
req: &admin_pb.UpdateIDPOIDCConfigRequest{
- IdpId: "4208",
- Issuer: "zitadel.ch",
- ClientId: "ZITEADEL",
- ClientSecret: "i'm so secret",
- Scopes: []string{"profile"},
- DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
- UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ IdpId: "4208",
+ Issuer: "zitadel.ch",
+ AuthorizationEndpoint: "https://accounts.zitadel.ch/oauth/v2/authorize",
+ TokenEndpoint: "https://api.zitadel.ch/oauth/v2/token",
+ ClientId: "ZITEADEL",
+ ClientSecret: "i'm so secret",
+ Scopes: []string{"profile"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
},
},
},
diff --git a/internal/api/grpc/idp/converter.go b/internal/api/grpc/idp/converter.go
index 33edef14e0..d5232b6658 100644
--- a/internal/api/grpc/idp/converter.go
+++ b/internal/api/grpc/idp/converter.go
@@ -133,11 +133,13 @@ func IDPStylingTypeToPb(stylingType domain.IDPConfigStylingType) idp_pb.IDPStyli
func ModelIDPViewToConfigPb(config *iam_model.IDPConfigView) *idp_pb.IDP_OidcConfig {
return &idp_pb.IDP_OidcConfig{
OidcConfig: &idp_pb.OIDCConfig{
- ClientId: config.OIDCClientID,
- Issuer: config.OIDCIssuer,
- Scopes: config.OIDCScopes,
- DisplayNameMapping: ModelMappingFieldToPb(config.OIDCIDPDisplayNameMapping),
- UsernameMapping: ModelMappingFieldToPb(config.OIDCUsernameMapping),
+ ClientId: config.OIDCClientID,
+ Issuer: config.OIDCIssuer,
+ Scopes: config.OIDCScopes,
+ DisplayNameMapping: ModelMappingFieldToPb(config.OIDCIDPDisplayNameMapping),
+ UsernameMapping: ModelMappingFieldToPb(config.OIDCUsernameMapping),
+ AuthorizationEndpoint: config.OAuthAuthorizationEndpoint,
+ TokenEndpoint: config.OAuthTokenEndpoint,
},
}
}
@@ -145,23 +147,13 @@ func ModelIDPViewToConfigPb(config *iam_model.IDPConfigView) *idp_pb.IDP_OidcCon
func IDPViewToConfigPb(config *domain.IDPConfigView) *idp_pb.IDP_OidcConfig {
return &idp_pb.IDP_OidcConfig{
OidcConfig: &idp_pb.OIDCConfig{
- ClientId: config.OIDCClientID,
- Issuer: config.OIDCIssuer,
- Scopes: config.OIDCScopes,
- DisplayNameMapping: MappingFieldToPb(config.OIDCIDPDisplayNameMapping),
- UsernameMapping: MappingFieldToPb(config.OIDCUsernameMapping),
- },
- }
-}
-
-func OIDCConfigToPb(config *domain.OIDCIDPConfig) *idp_pb.IDP_OidcConfig {
- return &idp_pb.IDP_OidcConfig{
- OidcConfig: &idp_pb.OIDCConfig{
- ClientId: config.ClientID,
- Issuer: config.Issuer,
- Scopes: config.Scopes,
- DisplayNameMapping: MappingFieldToPb(config.IDPDisplayNameMapping),
- UsernameMapping: MappingFieldToPb(config.UsernameMapping),
+ ClientId: config.OIDCClientID,
+ Issuer: config.OIDCIssuer,
+ AuthorizationEndpoint: config.OAuthAuthorizationEndpoint,
+ TokenEndpoint: config.OAuthTokenEndpoint,
+ Scopes: config.OIDCScopes,
+ DisplayNameMapping: MappingFieldToPb(config.OIDCIDPDisplayNameMapping),
+ UsernameMapping: MappingFieldToPb(config.OIDCUsernameMapping),
},
}
}
diff --git a/internal/api/grpc/management/idp.go b/internal/api/grpc/management/idp.go
index 6ec192040d..60d6619d51 100644
--- a/internal/api/grpc/management/idp.go
+++ b/internal/api/grpc/management/idp.go
@@ -32,7 +32,7 @@ func (s *Server) AddOrgOIDCIDP(ctx context.Context, req *mgmt_pb.AddOrgOIDCIDPRe
return nil, err
}
return &mgmt_pb.AddOrgOIDCIDPResponse{
- IdpId: config.AggregateID,
+ IdpId: config.IDPConfigID,
Details: object_pb.AddToDetailsPb(
config.Sequence,
config.ChangeDate,
diff --git a/internal/api/grpc/management/idp_converter.go b/internal/api/grpc/management/idp_converter.go
index 241e3be779..a3a8125c0d 100644
--- a/internal/api/grpc/management/idp_converter.go
+++ b/internal/api/grpc/management/idp_converter.go
@@ -24,6 +24,8 @@ func addOIDCIDPRequestToDomainOIDCIDPConfig(req *mgmt_pb.AddOrgOIDCIDPRequest) *
ClientID: req.ClientId,
ClientSecretString: req.ClientSecret,
Issuer: req.Issuer,
+ AuthorizationEndpoint: req.AuthorizationEndpoint,
+ TokenEndpoint: req.TokenEndpoint,
Scopes: req.Scopes,
IDPDisplayNameMapping: idp_grpc.MappingFieldToDomain(req.DisplayNameMapping),
UsernameMapping: idp_grpc.MappingFieldToDomain(req.UsernameMapping),
@@ -44,6 +46,8 @@ func updateOIDCConfigToDomain(req *mgmt_pb.UpdateOrgIDPOIDCConfigRequest) *domai
ClientID: req.ClientId,
ClientSecretString: req.ClientSecret,
Issuer: req.Issuer,
+ AuthorizationEndpoint: req.AuthorizationEndpoint,
+ TokenEndpoint: req.TokenEndpoint,
Scopes: req.Scopes,
IDPDisplayNameMapping: idp_grpc.MappingFieldToDomain(req.DisplayNameMapping),
UsernameMapping: idp_grpc.MappingFieldToDomain(req.UsernameMapping),
diff --git a/internal/api/grpc/management/idp_converter_test.go b/internal/api/grpc/management/idp_converter_test.go
index b7571d0dae..9db7683d11 100644
--- a/internal/api/grpc/management/idp_converter_test.go
+++ b/internal/api/grpc/management/idp_converter_test.go
@@ -20,14 +20,16 @@ func Test_addOIDCIDPRequestToDomain(t *testing.T) {
name: "all fields filled",
args: args{
req: &mgmt_pb.AddOrgOIDCIDPRequest{
- Name: "ZITADEL",
- StylingType: idp.IDPStylingType_STYLING_TYPE_GOOGLE,
- ClientId: "test1234",
- ClientSecret: "test4321",
- Issuer: "zitadel.ch",
- Scopes: []string{"email", "profile"},
- DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
- UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ Name: "ZITADEL",
+ StylingType: idp.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "test1234",
+ ClientSecret: "test4321",
+ Issuer: "zitadel.ch",
+ AuthorizationEndpoint: "https://accounts.zitadel.ch/oauth/v2/authorize",
+ TokenEndpoint: "https://api.zitadel.ch/oauth/v2/token",
+ Scopes: []string{"email", "profile"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
},
},
},
@@ -60,12 +62,14 @@ func Test_addOIDCIDPRequestToDomainOIDCIDPConfig(t *testing.T) {
name: "all fields filled",
args: args{
req: &mgmt_pb.AddOrgOIDCIDPRequest{
- ClientId: "test1234",
- ClientSecret: "test4321",
- Issuer: "zitadel.ch",
- Scopes: []string{"email", "profile"},
- DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
- UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ ClientId: "test1234",
+ ClientSecret: "test4321",
+ Issuer: "zitadel.ch",
+ AuthorizationEndpoint: "https://accounts.zitadel.ch/oauth/v2/authorize",
+ TokenEndpoint: "https://api.zitadel.ch/oauth/v2/token",
+ Scopes: []string{"email", "profile"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
},
},
},
@@ -126,13 +130,15 @@ func Test_updateOIDCConfigToDomain(t *testing.T) {
name: "all fields filled",
args: args{
req: &mgmt_pb.UpdateOrgIDPOIDCConfigRequest{
- IdpId: "4208",
- Issuer: "zitadel.ch",
- ClientId: "ZITEADEL",
- ClientSecret: "i'm so secret",
- Scopes: []string{"profile"},
- DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
- UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ IdpId: "4208",
+ Issuer: "zitadel.ch",
+ AuthorizationEndpoint: "https://accounts.zitadel.ch/oauth/v2/authorize",
+ TokenEndpoint: "https://api.zitadel.ch/oauth/v2/token",
+ ClientId: "ZITEADEL",
+ ClientSecret: "i'm so secret",
+ Scopes: []string{"profile"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
},
},
},
diff --git a/internal/command/iam_converter.go b/internal/command/iam_converter.go
index cbe41a3c7c..e0eafdad2e 100644
--- a/internal/command/iam_converter.go
+++ b/internal/command/iam_converter.go
@@ -145,6 +145,8 @@ func writeModelToIDPOIDCConfig(wm *OIDCConfigWriteModel) *domain.OIDCIDPConfig {
IDPConfigID: wm.IDPConfigID,
IDPDisplayNameMapping: wm.IDPDisplayNameMapping,
Issuer: wm.Issuer,
+ AuthorizationEndpoint: wm.AuthorizationEndpoint,
+ TokenEndpoint: wm.TokenEndpoint,
Scopes: wm.Scopes,
UsernameMapping: wm.UserNameMapping,
}
diff --git a/internal/command/iam_idp_config.go b/internal/command/iam_idp_config.go
index 22745e1e41..3d1cda2c0a 100644
--- a/internal/command/iam_idp_config.go
+++ b/internal/command/iam_idp_config.go
@@ -44,6 +44,8 @@ func (c *Commands) AddDefaultIDPConfig(ctx context.Context, config *domain.IDPCo
config.OIDCConfig.ClientID,
idpConfigID,
config.OIDCConfig.Issuer,
+ config.OIDCConfig.AuthorizationEndpoint,
+ config.OIDCConfig.TokenEndpoint,
clientSecret,
config.OIDCConfig.IDPDisplayNameMapping,
config.OIDCConfig.UsernameMapping,
diff --git a/internal/command/iam_idp_config_test.go b/internal/command/iam_idp_config_test.go
index 86fced7d52..a900b6efa0 100644
--- a/internal/command/iam_idp_config_test.go
+++ b/internal/command/iam_idp_config_test.go
@@ -76,6 +76,8 @@ func TestCommandSide_AddDefaultIDPConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -102,6 +104,8 @@ func TestCommandSide_AddDefaultIDPConfig(t *testing.T) {
OIDCConfig: &domain.OIDCIDPConfig{
ClientID: "clientid1",
Issuer: "issuer",
+ AuthorizationEndpoint: "authorization-endpoint",
+ TokenEndpoint: "token-endpoint",
ClientSecretString: "secret",
Scopes: []string{"scope"},
IDPDisplayNameMapping: domain.OIDCMappingFieldEmail,
@@ -216,6 +220,8 @@ func TestCommandSide_ChangeDefaultIDPConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
diff --git a/internal/command/iam_idp_oidc_config.go b/internal/command/iam_idp_oidc_config.go
index 9838bf3bb7..9db8da5dbf 100644
--- a/internal/command/iam_idp_oidc_config.go
+++ b/internal/command/iam_idp_oidc_config.go
@@ -27,6 +27,8 @@ func (c *Commands) ChangeDefaultIDPOIDCConfig(ctx context.Context, config *domai
config.IDPConfigID,
config.ClientID,
config.Issuer,
+ config.AuthorizationEndpoint,
+ config.TokenEndpoint,
config.ClientSecretString,
c.idpConfigSecretCrypto,
config.IDPDisplayNameMapping,
diff --git a/internal/command/iam_idp_oidc_config_model.go b/internal/command/iam_idp_oidc_config_model.go
index de91f25b7b..238e98d256 100644
--- a/internal/command/iam_idp_oidc_config_model.go
+++ b/internal/command/iam_idp_oidc_config_model.go
@@ -90,6 +90,8 @@ func (wm *IAMIDPOIDCConfigWriteModel) NewChangedEvent(
idpConfigID,
clientID,
issuer,
+ authorizationEndpoint,
+ tokenEndpoint,
clientSecretString string,
secretCrypto crypto.Crypto,
idpDisplayNameMapping,
@@ -113,6 +115,12 @@ func (wm *IAMIDPOIDCConfigWriteModel) NewChangedEvent(
if wm.Issuer != issuer {
changes = append(changes, idpconfig.ChangeIssuer(issuer))
}
+ if wm.AuthorizationEndpoint != authorizationEndpoint {
+ changes = append(changes, idpconfig.ChangeAuthorizationEndpoint(authorizationEndpoint))
+ }
+ if wm.TokenEndpoint != tokenEndpoint {
+ changes = append(changes, idpconfig.ChangeTokenEndpoint(tokenEndpoint))
+ }
if idpDisplayNameMapping.Valid() && wm.IDPDisplayNameMapping != idpDisplayNameMapping {
changes = append(changes, idpconfig.ChangeIDPDisplayNameMapping(idpDisplayNameMapping))
}
diff --git a/internal/command/iam_idp_oidc_config_test.go b/internal/command/iam_idp_oidc_config_test.go
index 479b417f17..425cfc791c 100644
--- a/internal/command/iam_idp_oidc_config_test.go
+++ b/internal/command/iam_idp_oidc_config_test.go
@@ -92,6 +92,8 @@ func TestCommandSide_ChangeDefaultIDPOIDCConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -144,6 +146,8 @@ func TestCommandSide_ChangeDefaultIDPOIDCConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -165,6 +169,8 @@ func TestCommandSide_ChangeDefaultIDPOIDCConfig(t *testing.T) {
IDPConfigID: "config1",
ClientID: "clientid1",
Issuer: "issuer",
+ AuthorizationEndpoint: "authorization-endpoint",
+ TokenEndpoint: "token-endpoint",
Scopes: []string{"scope"},
IDPDisplayNameMapping: domain.OIDCMappingFieldEmail,
UsernameMapping: domain.OIDCMappingFieldEmail,
@@ -195,6 +201,8 @@ func TestCommandSide_ChangeDefaultIDPOIDCConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -214,6 +222,8 @@ func TestCommandSide_ChangeDefaultIDPOIDCConfig(t *testing.T) {
"config1",
"clientid-changed",
"issuer-changed",
+ "authorization-endpoint-changed",
+ "token-endpoint-changed",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -236,6 +246,8 @@ func TestCommandSide_ChangeDefaultIDPOIDCConfig(t *testing.T) {
IDPConfigID: "config1",
ClientID: "clientid-changed",
Issuer: "issuer-changed",
+ AuthorizationEndpoint: "authorization-endpoint-changed",
+ TokenEndpoint: "token-endpoint-changed",
ClientSecretString: "secret-changed",
Scopes: []string{"scope", "scope2"},
IDPDisplayNameMapping: domain.OIDCMappingFieldPreferredLoginName,
@@ -251,6 +263,8 @@ func TestCommandSide_ChangeDefaultIDPOIDCConfig(t *testing.T) {
IDPConfigID: "config1",
ClientID: "clientid-changed",
Issuer: "issuer-changed",
+ AuthorizationEndpoint: "authorization-endpoint-changed",
+ TokenEndpoint: "token-endpoint-changed",
Scopes: []string{"scope", "scope2"},
IDPDisplayNameMapping: domain.OIDCMappingFieldPreferredLoginName,
UsernameMapping: domain.OIDCMappingFieldPreferredLoginName,
@@ -278,13 +292,15 @@ func TestCommandSide_ChangeDefaultIDPOIDCConfig(t *testing.T) {
}
}
-func newDefaultIDPOIDCConfigChangedEvent(ctx context.Context, configID, clientID, issuer string, secret *crypto.CryptoValue, displayMapping, usernameMapping domain.OIDCMappingField, scopes []string) *iam.IDPOIDCConfigChangedEvent {
+func newDefaultIDPOIDCConfigChangedEvent(ctx context.Context, configID, clientID, issuer, authorizationEndpoint, tokenEndpoint string, secret *crypto.CryptoValue, displayMapping, usernameMapping domain.OIDCMappingField, scopes []string) *iam.IDPOIDCConfigChangedEvent {
event, _ := iam.NewIDPOIDCConfigChangedEvent(ctx,
&iam.NewAggregate().Aggregate,
configID,
[]idpconfig.OIDCConfigChanges{
idpconfig.ChangeClientID(clientID),
idpconfig.ChangeIssuer(issuer),
+ idpconfig.ChangeAuthorizationEndpoint(authorizationEndpoint),
+ idpconfig.ChangeTokenEndpoint(tokenEndpoint),
idpconfig.ChangeClientSecret(secret),
idpconfig.ChangeIDPDisplayNameMapping(displayMapping),
idpconfig.ChangeUserNameMapping(usernameMapping),
diff --git a/internal/command/oidc_config_model.go b/internal/command/oidc_config_model.go
index 6fa34d3ae8..2802af55fb 100644
--- a/internal/command/oidc_config_model.go
+++ b/internal/command/oidc_config_model.go
@@ -10,11 +10,13 @@ import (
type OIDCConfigWriteModel struct {
eventstore.WriteModel
- IDPConfigID string
- ClientID string
- ClientSecret *crypto.CryptoValue
- Issuer string
- Scopes []string
+ IDPConfigID string
+ ClientID string
+ ClientSecret *crypto.CryptoValue
+ Issuer string
+ AuthorizationEndpoint string
+ TokenEndpoint string
+ Scopes []string
IDPDisplayNameMapping domain.OIDCMappingField
UserNameMapping domain.OIDCMappingField
@@ -45,6 +47,8 @@ func (wm *OIDCConfigWriteModel) reduceConfigAddedEvent(e *idpconfig.OIDCConfigAd
wm.ClientID = e.ClientID
wm.ClientSecret = e.ClientSecret
wm.Issuer = e.Issuer
+ wm.AuthorizationEndpoint = e.AuthorizationEndpoint
+ wm.TokenEndpoint = e.TokenEndpoint
wm.Scopes = e.Scopes
wm.IDPDisplayNameMapping = e.IDPDisplayNameMapping
wm.UserNameMapping = e.UserNameMapping
@@ -58,6 +62,12 @@ func (wm *OIDCConfigWriteModel) reduceConfigChangedEvent(e *idpconfig.OIDCConfig
if e.Issuer != nil {
wm.Issuer = *e.Issuer
}
+ if e.AuthorizationEndpoint != nil {
+ wm.AuthorizationEndpoint = *e.AuthorizationEndpoint
+ }
+ if e.TokenEndpoint != nil {
+ wm.TokenEndpoint = *e.TokenEndpoint
+ }
if len(e.Scopes) > 0 {
wm.Scopes = e.Scopes
}
diff --git a/internal/command/org_idp_config.go b/internal/command/org_idp_config.go
index 9abf73e3e1..6c90438074 100644
--- a/internal/command/org_idp_config.go
+++ b/internal/command/org_idp_config.go
@@ -47,6 +47,8 @@ func (c *Commands) AddIDPConfig(ctx context.Context, config *domain.IDPConfig, r
config.OIDCConfig.ClientID,
idpConfigID,
config.OIDCConfig.Issuer,
+ config.OIDCConfig.AuthorizationEndpoint,
+ config.OIDCConfig.TokenEndpoint,
clientSecret,
config.OIDCConfig.IDPDisplayNameMapping,
config.OIDCConfig.UsernameMapping,
diff --git a/internal/command/org_idp_config_test.go b/internal/command/org_idp_config_test.go
index 8ffbbad682..781849ea4e 100644
--- a/internal/command/org_idp_config_test.go
+++ b/internal/command/org_idp_config_test.go
@@ -104,6 +104,8 @@ func TestCommandSide_AddIDPConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -131,6 +133,8 @@ func TestCommandSide_AddIDPConfig(t *testing.T) {
OIDCConfig: &domain.OIDCIDPConfig{
ClientID: "clientid1",
Issuer: "issuer",
+ AuthorizationEndpoint: "authorization-endpoint",
+ TokenEndpoint: "token-endpoint",
ClientSecretString: "secret",
Scopes: []string{"scope"},
IDPDisplayNameMapping: domain.OIDCMappingFieldEmail,
@@ -264,6 +268,8 @@ func TestCommandSide_ChangeIDPConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
diff --git a/internal/command/org_idp_oidc_config.go b/internal/command/org_idp_oidc_config.go
index 9e3531dbdc..4e15166cf0 100644
--- a/internal/command/org_idp_oidc_config.go
+++ b/internal/command/org_idp_oidc_config.go
@@ -30,6 +30,8 @@ func (c *Commands) ChangeIDPOIDCConfig(ctx context.Context, config *domain.OIDCI
config.IDPConfigID,
config.ClientID,
config.Issuer,
+ config.AuthorizationEndpoint,
+ config.TokenEndpoint,
config.ClientSecretString,
c.idpConfigSecretCrypto,
config.IDPDisplayNameMapping,
diff --git a/internal/command/org_idp_oidc_config_model.go b/internal/command/org_idp_oidc_config_model.go
index a88719ffd6..87eb01e3b2 100644
--- a/internal/command/org_idp_oidc_config_model.go
+++ b/internal/command/org_idp_oidc_config_model.go
@@ -90,6 +90,8 @@ func (wm *IDPOIDCConfigWriteModel) NewChangedEvent(
idpConfigID,
clientID,
issuer,
+ authorizationEndpoint,
+ tokenEndpoint,
clientSecretString string,
secretCrypto crypto.Crypto,
idpDisplayNameMapping,
@@ -113,6 +115,12 @@ func (wm *IDPOIDCConfigWriteModel) NewChangedEvent(
if wm.Issuer != issuer {
changes = append(changes, idpconfig.ChangeIssuer(issuer))
}
+ if wm.AuthorizationEndpoint != authorizationEndpoint {
+ changes = append(changes, idpconfig.ChangeAuthorizationEndpoint(authorizationEndpoint))
+ }
+ if wm.TokenEndpoint != tokenEndpoint {
+ changes = append(changes, idpconfig.ChangeTokenEndpoint(tokenEndpoint))
+ }
if idpDisplayNameMapping.Valid() && wm.IDPDisplayNameMapping != idpDisplayNameMapping {
changes = append(changes, idpconfig.ChangeIDPDisplayNameMapping(idpDisplayNameMapping))
}
diff --git a/internal/command/org_idp_oidc_config_test.go b/internal/command/org_idp_oidc_config_test.go
index 30a94380e6..ec835de87e 100644
--- a/internal/command/org_idp_oidc_config_test.go
+++ b/internal/command/org_idp_oidc_config_test.go
@@ -112,6 +112,8 @@ func TestCommandSide_ChangeIDPOIDCConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -165,6 +167,8 @@ func TestCommandSide_ChangeIDPOIDCConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -186,6 +190,8 @@ func TestCommandSide_ChangeIDPOIDCConfig(t *testing.T) {
IDPConfigID: "config1",
ClientID: "clientid1",
Issuer: "issuer",
+ AuthorizationEndpoint: "authorization-endpoint",
+ TokenEndpoint: "token-endpoint",
Scopes: []string{"scope"},
IDPDisplayNameMapping: domain.OIDCMappingFieldEmail,
UsernameMapping: domain.OIDCMappingFieldEmail,
@@ -217,6 +223,8 @@ func TestCommandSide_ChangeIDPOIDCConfig(t *testing.T) {
"clientid1",
"config1",
"issuer",
+ "authorization-endpoint",
+ "token-endpoint",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -237,6 +245,8 @@ func TestCommandSide_ChangeIDPOIDCConfig(t *testing.T) {
"config1",
"clientid-changed",
"issuer-changed",
+ "authorization-endpoint-changed",
+ "token-endpoint-changed",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
@@ -259,6 +269,8 @@ func TestCommandSide_ChangeIDPOIDCConfig(t *testing.T) {
IDPConfigID: "config1",
ClientID: "clientid-changed",
Issuer: "issuer-changed",
+ AuthorizationEndpoint: "authorization-endpoint-changed",
+ TokenEndpoint: "token-endpoint-changed",
ClientSecretString: "secret-changed",
Scopes: []string{"scope", "scope2"},
IDPDisplayNameMapping: domain.OIDCMappingFieldPreferredLoginName,
@@ -275,6 +287,8 @@ func TestCommandSide_ChangeIDPOIDCConfig(t *testing.T) {
IDPConfigID: "config1",
ClientID: "clientid-changed",
Issuer: "issuer-changed",
+ AuthorizationEndpoint: "authorization-endpoint-changed",
+ TokenEndpoint: "token-endpoint-changed",
Scopes: []string{"scope", "scope2"},
IDPDisplayNameMapping: domain.OIDCMappingFieldPreferredLoginName,
UsernameMapping: domain.OIDCMappingFieldPreferredLoginName,
@@ -302,13 +316,15 @@ func TestCommandSide_ChangeIDPOIDCConfig(t *testing.T) {
}
}
-func newIDPOIDCConfigChangedEvent(ctx context.Context, orgID, configID, clientID, issuer string, secret *crypto.CryptoValue, displayMapping, usernameMapping domain.OIDCMappingField, scopes []string) *org.IDPOIDCConfigChangedEvent {
+func newIDPOIDCConfigChangedEvent(ctx context.Context, orgID, configID, clientID, issuer, authorizationEndpoint, tokenEndpoint string, secret *crypto.CryptoValue, displayMapping, usernameMapping domain.OIDCMappingField, scopes []string) *org.IDPOIDCConfigChangedEvent {
event, _ := org.NewIDPOIDCConfigChangedEvent(ctx,
&org.NewAggregate(orgID, orgID).Aggregate,
configID,
[]idpconfig.OIDCConfigChanges{
idpconfig.ChangeClientID(clientID),
idpconfig.ChangeIssuer(issuer),
+ idpconfig.ChangeAuthorizationEndpoint(authorizationEndpoint),
+ idpconfig.ChangeTokenEndpoint(tokenEndpoint),
idpconfig.ChangeClientSecret(secret),
idpconfig.ChangeIDPDisplayNameMapping(displayMapping),
idpconfig.ChangeUserNameMapping(usernameMapping),
diff --git a/internal/domain/idp_config.go b/internal/domain/idp_config.go
index 3561345cf6..063eb17fe5 100644
--- a/internal/domain/idp_config.go
+++ b/internal/domain/idp_config.go
@@ -1,9 +1,10 @@
package domain
import (
+ "time"
+
"github.com/caos/zitadel/internal/crypto"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
- "time"
)
type IDPConfig struct {
@@ -27,13 +28,15 @@ type IDPConfigView struct {
Sequence uint64
IDPProviderType IdentityProviderType
- IsOIDC bool
- OIDCClientID string
- OIDCClientSecret *crypto.CryptoValue
- OIDCIssuer string
- OIDCScopes []string
- OIDCIDPDisplayNameMapping OIDCMappingField
- OIDCUsernameMapping OIDCMappingField
+ IsOIDC bool
+ OIDCClientID string
+ OIDCClientSecret *crypto.CryptoValue
+ OIDCIssuer string
+ OIDCScopes []string
+ OIDCIDPDisplayNameMapping OIDCMappingField
+ OIDCUsernameMapping OIDCMappingField
+ OAuthAuthorizationEndpoint string
+ OAuthTokenEndpoint string
}
type OIDCIDPConfig struct {
@@ -43,6 +46,8 @@ type OIDCIDPConfig struct {
ClientSecret *crypto.CryptoValue
ClientSecretString string
Issuer string
+ AuthorizationEndpoint string
+ TokenEndpoint string
Scopes []string
IDPDisplayNameMapping OIDCMappingField
UsernameMapping OIDCMappingField
diff --git a/internal/iam/model/idp_config_view.go b/internal/iam/model/idp_config_view.go
index 948a8726fc..37de4feed4 100644
--- a/internal/iam/model/idp_config_view.go
+++ b/internal/iam/model/idp_config_view.go
@@ -19,13 +19,15 @@ type IDPConfigView struct {
Sequence uint64
IDPProviderType IDPProviderType
- IsOIDC bool
- OIDCClientID string
- OIDCClientSecret *crypto.CryptoValue
- OIDCIssuer string
- OIDCScopes []string
- OIDCIDPDisplayNameMapping OIDCMappingField
- OIDCUsernameMapping OIDCMappingField
+ IsOIDC bool
+ OIDCClientID string
+ OIDCClientSecret *crypto.CryptoValue
+ OIDCIssuer string
+ OIDCScopes []string
+ OIDCIDPDisplayNameMapping OIDCMappingField
+ OIDCUsernameMapping OIDCMappingField
+ OAuthAuthorizationEndpoint string
+ OAuthTokenEndpoint string
}
type IDPConfigSearchRequest struct {
diff --git a/internal/iam/repository/view/model/idp_config.go b/internal/iam/repository/view/model/idp_config.go
index 52c6020900..5470dc634b 100644
--- a/internal/iam/repository/view/model/idp_config.go
+++ b/internal/iam/repository/view/model/idp_config.go
@@ -2,17 +2,19 @@ package model
import (
"encoding/json"
- "github.com/caos/zitadel/internal/crypto"
"time"
+ "github.com/caos/zitadel/internal/crypto"
+
es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
"github.com/caos/logging"
+ "github.com/lib/pq"
+
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/model"
- "github.com/lib/pq"
)
const (
@@ -32,56 +34,39 @@ type IDPConfigView struct {
IDPState int32 `json:"-" gorm:"column:idp_state"`
IDPProviderType int32 `json:"-" gorm:"column:idp_provider_type"`
- IsOIDC bool `json:"-" gorm:"column:is_oidc"`
- OIDCClientID string `json:"clientId" gorm:"column:oidc_client_id"`
- OIDCClientSecret *crypto.CryptoValue `json:"clientSecret" gorm:"column:oidc_client_secret"`
- OIDCIssuer string `json:"issuer" gorm:"column:oidc_issuer"`
- OIDCScopes pq.StringArray `json:"scopes" gorm:"column:oidc_scopes"`
- OIDCIDPDisplayNameMapping int32 `json:"idpDisplayNameMapping" gorm:"column:oidc_idp_display_name_mapping"`
- OIDCUsernameMapping int32 `json:"usernameMapping" gorm:"column:oidc_idp_username_mapping"`
+ IsOIDC bool `json:"-" gorm:"column:is_oidc"`
+ OIDCClientID string `json:"clientId" gorm:"column:oidc_client_id"`
+ OIDCClientSecret *crypto.CryptoValue `json:"clientSecret" gorm:"column:oidc_client_secret"`
+ OIDCIssuer string `json:"issuer" gorm:"column:oidc_issuer"`
+ OIDCScopes pq.StringArray `json:"scopes" gorm:"column:oidc_scopes"`
+ OIDCIDPDisplayNameMapping int32 `json:"idpDisplayNameMapping" gorm:"column:oidc_idp_display_name_mapping"`
+ OIDCUsernameMapping int32 `json:"usernameMapping" gorm:"column:oidc_idp_username_mapping"`
+ OAuthAuthorizationEndpoint string `json:"authorizationEndpoint" gorm:"column:oauth_authorization_endpoint"`
+ OAuthTokenEndpoint string `json:"tokenEndpoint" gorm:"column:oauth_token_endpoint"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}
-func IDPConfigViewFromModel(idp *model.IDPConfigView) *IDPConfigView {
- return &IDPConfigView{
- IDPConfigID: idp.IDPConfigID,
- AggregateID: idp.AggregateID,
- IDPState: int32(idp.State),
- Name: idp.Name,
- StylingType: int32(idp.StylingType),
- Sequence: idp.Sequence,
- CreationDate: idp.CreationDate,
- ChangeDate: idp.ChangeDate,
- IDPProviderType: int32(idp.IDPProviderType),
- IsOIDC: idp.IsOIDC,
- OIDCClientID: idp.OIDCClientID,
- OIDCClientSecret: idp.OIDCClientSecret,
- OIDCIssuer: idp.OIDCIssuer,
- OIDCScopes: idp.OIDCScopes,
- OIDCIDPDisplayNameMapping: int32(idp.OIDCIDPDisplayNameMapping),
- OIDCUsernameMapping: int32(idp.OIDCUsernameMapping),
- }
-}
-
func IDPConfigViewToModel(idp *IDPConfigView) *model.IDPConfigView {
return &model.IDPConfigView{
- IDPConfigID: idp.IDPConfigID,
- AggregateID: idp.AggregateID,
- State: model.IDPConfigState(idp.IDPState),
- Name: idp.Name,
- StylingType: model.IDPStylingType(idp.StylingType),
- Sequence: idp.Sequence,
- CreationDate: idp.CreationDate,
- ChangeDate: idp.ChangeDate,
- IDPProviderType: model.IDPProviderType(idp.IDPProviderType),
- IsOIDC: idp.IsOIDC,
- OIDCClientID: idp.OIDCClientID,
- OIDCClientSecret: idp.OIDCClientSecret,
- OIDCIssuer: idp.OIDCIssuer,
- OIDCScopes: idp.OIDCScopes,
- OIDCIDPDisplayNameMapping: model.OIDCMappingField(idp.OIDCIDPDisplayNameMapping),
- OIDCUsernameMapping: model.OIDCMappingField(idp.OIDCUsernameMapping),
+ IDPConfigID: idp.IDPConfigID,
+ AggregateID: idp.AggregateID,
+ State: model.IDPConfigState(idp.IDPState),
+ Name: idp.Name,
+ StylingType: model.IDPStylingType(idp.StylingType),
+ Sequence: idp.Sequence,
+ CreationDate: idp.CreationDate,
+ ChangeDate: idp.ChangeDate,
+ IDPProviderType: model.IDPProviderType(idp.IDPProviderType),
+ IsOIDC: idp.IsOIDC,
+ OIDCClientID: idp.OIDCClientID,
+ OIDCClientSecret: idp.OIDCClientSecret,
+ OIDCIssuer: idp.OIDCIssuer,
+ OIDCScopes: idp.OIDCScopes,
+ OIDCIDPDisplayNameMapping: model.OIDCMappingField(idp.OIDCIDPDisplayNameMapping),
+ OIDCUsernameMapping: model.OIDCMappingField(idp.OIDCUsernameMapping),
+ OAuthAuthorizationEndpoint: idp.OAuthAuthorizationEndpoint,
+ OAuthTokenEndpoint: idp.OAuthTokenEndpoint,
}
}
diff --git a/internal/query/converter.go b/internal/query/converter.go
index dc815e0360..71e4f4f66e 100644
--- a/internal/query/converter.go
+++ b/internal/query/converter.go
@@ -45,6 +45,8 @@ func readModelToIDPConfigView(rm *IAMIDPConfigReadModel) *domain.IDPConfigView {
converted.OIDCIssuer = rm.OIDCConfig.Issuer
converted.OIDCScopes = rm.OIDCConfig.Scopes
converted.OIDCUsernameMapping = rm.OIDCConfig.UserNameMapping
+ converted.OAuthAuthorizationEndpoint = rm.OIDCConfig.AuthorizationEndpoint
+ converted.OAuthTokenEndpoint = rm.OIDCConfig.TokenEndpoint
}
return converted
}
diff --git a/internal/query/oidc_config_model.go b/internal/query/oidc_config_model.go
index b0ee26f9c9..5353d0d176 100644
--- a/internal/query/oidc_config_model.go
+++ b/internal/query/oidc_config_model.go
@@ -14,6 +14,8 @@ type OIDCConfigReadModel struct {
ClientID string
ClientSecret *crypto.CryptoValue
Issuer string
+ AuthorizationEndpoint string
+ TokenEndpoint string
Scopes []string
IDPDisplayNameMapping domain.OIDCMappingField
UserNameMapping domain.OIDCMappingField
@@ -37,6 +39,8 @@ func (rm *OIDCConfigReadModel) reduceConfigAddedEvent(e *idpconfig.OIDCConfigAdd
rm.ClientID = e.ClientID
rm.ClientSecret = e.ClientSecret
rm.Issuer = e.Issuer
+ rm.AuthorizationEndpoint = e.AuthorizationEndpoint
+ rm.TokenEndpoint = e.TokenEndpoint
rm.Scopes = e.Scopes
rm.IDPDisplayNameMapping = e.IDPDisplayNameMapping
rm.UserNameMapping = e.UserNameMapping
@@ -49,6 +53,12 @@ func (rm *OIDCConfigReadModel) reduceConfigChangedEvent(e *idpconfig.OIDCConfigC
if e.Issuer != nil {
rm.Issuer = *e.Issuer
}
+ if e.AuthorizationEndpoint != nil {
+ rm.AuthorizationEndpoint = *e.AuthorizationEndpoint
+ }
+ if e.TokenEndpoint != nil {
+ rm.TokenEndpoint = *e.TokenEndpoint
+ }
if len(e.Scopes) > 0 {
rm.Scopes = e.Scopes
}
diff --git a/internal/repository/iam/idp_oidc_config.go b/internal/repository/iam/idp_oidc_config.go
index 5bf1a04308..19f8e2d137 100644
--- a/internal/repository/iam/idp_oidc_config.go
+++ b/internal/repository/iam/idp_oidc_config.go
@@ -24,7 +24,9 @@ func NewIDPOIDCConfigAddedEvent(
aggregate *eventstore.Aggregate,
clientID,
idpConfigID,
- issuer string,
+ issuer,
+ authorizationEndpoint,
+ tokenEndpoint string,
clientSecret *crypto.CryptoValue,
idpDisplayNameMapping,
userNameMapping domain.OIDCMappingField,
@@ -41,6 +43,8 @@ func NewIDPOIDCConfigAddedEvent(
clientID,
idpConfigID,
issuer,
+ authorizationEndpoint,
+ tokenEndpoint,
clientSecret,
idpDisplayNameMapping,
userNameMapping,
diff --git a/internal/repository/idpconfig/oidc_config.go b/internal/repository/idpconfig/oidc_config.go
index ef7edf2150..9f04ab1afb 100644
--- a/internal/repository/idpconfig/oidc_config.go
+++ b/internal/repository/idpconfig/oidc_config.go
@@ -18,11 +18,13 @@ const (
type OIDCConfigAddedEvent struct {
eventstore.BaseEvent `json:"-"`
- IDPConfigID string `json:"idpConfigId"`
- ClientID string `json:"clientId,omitempty"`
- ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
- Issuer string `json:"issuer,omitempty"`
- Scopes []string `json:"scopes,omitempty"`
+ IDPConfigID string `json:"idpConfigId"`
+ ClientID string `json:"clientId,omitempty"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
+ Issuer string `json:"issuer,omitempty"`
+ AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"`
+ TokenEndpoint string `json:"tokenEndpoint,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
IDPDisplayNameMapping domain.OIDCMappingField `json:"idpDisplayNameMapping,omitempty"`
UserNameMapping domain.OIDCMappingField `json:"usernameMapping,omitempty"`
@@ -40,7 +42,9 @@ func NewOIDCConfigAddedEvent(
base *eventstore.BaseEvent,
clientID,
idpConfigID,
- issuer string,
+ issuer,
+ authorizationEndpoint,
+ tokenEndpoint string,
clientSecret *crypto.CryptoValue,
idpDisplayNameMapping,
userNameMapping domain.OIDCMappingField,
@@ -53,6 +57,8 @@ func NewOIDCConfigAddedEvent(
ClientID: clientID,
ClientSecret: clientSecret,
Issuer: issuer,
+ AuthorizationEndpoint: authorizationEndpoint,
+ TokenEndpoint: tokenEndpoint,
Scopes: scopes,
IDPDisplayNameMapping: idpDisplayNameMapping,
UserNameMapping: userNameMapping,
@@ -77,10 +83,12 @@ type OIDCConfigChangedEvent struct {
IDPConfigID string `json:"idpConfigId"`
- ClientID *string `json:"clientId,omitempty"`
- ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
- Issuer *string `json:"issuer,omitempty"`
- Scopes []string `json:"scopes,omitempty"`
+ ClientID *string `json:"clientId,omitempty"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
+ Issuer *string `json:"issuer,omitempty"`
+ AuthorizationEndpoint *string `json:"authorizationEndpoint,omitempty"`
+ TokenEndpoint *string `json:"tokenEndpoint,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
IDPDisplayNameMapping *domain.OIDCMappingField `json:"idpDisplayNameMapping,omitempty"`
UserNameMapping *domain.OIDCMappingField `json:"usernameMapping,omitempty"`
@@ -132,6 +140,18 @@ func ChangeIssuer(issuer string) func(*OIDCConfigChangedEvent) {
}
}
+func ChangeAuthorizationEndpoint(authorizationEndpoint string) func(*OIDCConfigChangedEvent) {
+ return func(e *OIDCConfigChangedEvent) {
+ e.AuthorizationEndpoint = &authorizationEndpoint
+ }
+}
+
+func ChangeTokenEndpoint(tokenEndpoint string) func(*OIDCConfigChangedEvent) {
+ return func(e *OIDCConfigChangedEvent) {
+ e.TokenEndpoint = &tokenEndpoint
+ }
+}
+
func ChangeIDPDisplayNameMapping(idpDisplayNameMapping domain.OIDCMappingField) func(*OIDCConfigChangedEvent) {
return func(e *OIDCConfigChangedEvent) {
e.IDPDisplayNameMapping = &idpDisplayNameMapping
diff --git a/internal/repository/org/idp_oidc_config.go b/internal/repository/org/idp_oidc_config.go
index 8c9e07f323..11bf562cfe 100644
--- a/internal/repository/org/idp_oidc_config.go
+++ b/internal/repository/org/idp_oidc_config.go
@@ -24,7 +24,9 @@ func NewIDPOIDCConfigAddedEvent(
aggregate *eventstore.Aggregate,
clientID,
idpConfigID,
- issuer string,
+ issuer,
+ authorizationEndpoint,
+ tokenEndpoint string,
clientSecret *crypto.CryptoValue,
idpDisplayNameMapping,
userNameMapping domain.OIDCMappingField,
@@ -41,6 +43,8 @@ func NewIDPOIDCConfigAddedEvent(
clientID,
idpConfigID,
issuer,
+ authorizationEndpoint,
+ tokenEndpoint,
clientSecret,
idpDisplayNameMapping,
userNameMapping,
diff --git a/internal/ui/login/handler/external_login_handler.go b/internal/ui/login/handler/external_login_handler.go
index 13c89566ba..55642053bd 100644
--- a/internal/ui/login/handler/external_login_handler.go
+++ b/internal/ui/login/handler/external_login_handler.go
@@ -3,6 +3,8 @@ package handler
import (
"github.com/caos/oidc/pkg/client/rp"
"github.com/caos/oidc/pkg/oidc"
+ "golang.org/x/oauth2"
+
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
@@ -119,7 +121,29 @@ func (l *Login) getRPConfig(w http.ResponseWriter, r *http.Request, authReq *dom
l.renderError(w, r, authReq, err)
return nil
}
- provider, err := rp.NewRelyingPartyOIDC(idpConfig.OIDCIssuer, idpConfig.OIDCClientID, oidcClientSecret, l.baseURL+callbackEndpoint, idpConfig.OIDCScopes, rp.WithVerifierOpts(rp.WithIssuedAtOffset(3*time.Second)))
+ if idpConfig.OIDCIssuer != "" {
+ provider, err := rp.NewRelyingPartyOIDC(idpConfig.OIDCIssuer, idpConfig.OIDCClientID, oidcClientSecret, l.baseURL+callbackEndpoint, idpConfig.OIDCScopes, rp.WithVerifierOpts(rp.WithIssuedAtOffset(3*time.Second)))
+ if err != nil {
+ l.renderError(w, r, authReq, err)
+ return nil
+ }
+ return provider
+ }
+ if idpConfig.OAuthAuthorizationEndpoint == "" || idpConfig.OAuthTokenEndpoint == "" {
+ l.renderError(w, r, authReq, caos_errors.ThrowPreconditionFailed(nil, "RP-4n0fs", "Errors.IdentityProvider.InvalidConfig"))
+ return nil
+ }
+ oauth2Config := &oauth2.Config{
+ ClientID: idpConfig.OIDCClientID,
+ ClientSecret: oidcClientSecret,
+ Endpoint: oauth2.Endpoint{
+ AuthURL: idpConfig.OAuthAuthorizationEndpoint,
+ TokenURL: idpConfig.OAuthTokenEndpoint,
+ },
+ RedirectURL: l.baseURL + callbackEndpoint,
+ Scopes: idpConfig.OIDCScopes,
+ }
+ provider, err := rp.NewRelyingPartyOAuth(oauth2Config, rp.WithVerifierOpts(rp.WithIssuedAtOffset(3*time.Second)))
if err != nil {
l.renderError(w, r, authReq, err)
return nil
diff --git a/internal/ui/login/static/i18n/de.yaml b/internal/ui/login/static/i18n/de.yaml
index 8969b96c72..a8eb109319 100644
--- a/internal/ui/login/static/i18n/de.yaml
+++ b/internal/ui/login/static/i18n/de.yaml
@@ -296,5 +296,7 @@ Errors:
IDPTypeNotImplemented: IDP Typ ist nicht implementiert
NotAllowed: Externer Login Provider ist nicht erlaubt
GrantRequired: Der Login an diese Applikation ist nicht möglich. Der Benutzer benötigt mindestens eine Berechtigung an der Applikation. Bitte melde dich bei deinem Administrator.
+ IdentityProvider:
+ InvalidConfig: Identitäts Provider Konfiguration ist ungültig
optional: (optional)
diff --git a/internal/ui/login/static/i18n/en.yaml b/internal/ui/login/static/i18n/en.yaml
index 79e8bfbe8f..9bd0fbcfd7 100644
--- a/internal/ui/login/static/i18n/en.yaml
+++ b/internal/ui/login/static/i18n/en.yaml
@@ -295,6 +295,7 @@ Errors:
IDPTypeNotImplemented: IDP Type is not implemented
NotAllowed: External Login Provider not allowed
GrantRequired: Login not possible. The user is required to have at least one grant on the application. Please contact your administrator.
-
+ IdentityProvider:
+ InvalidConfig: Identity Provider configuration is invalid
optional: (optional)
diff --git a/migrations/cockroach/V1.54__oauth_idp.sql b/migrations/cockroach/V1.54__oauth_idp.sql
new file mode 100644
index 0000000000..cfbccd9ddf
--- /dev/null
+++ b/migrations/cockroach/V1.54__oauth_idp.sql
@@ -0,0 +1,7 @@
+ALTER TABLE auth.idp_configs ADD COLUMN oauth_authorization_endpoint TEXT;
+ALTER TABLE adminapi.idp_configs ADD COLUMN oauth_authorization_endpoint TEXT;
+ALTER TABLE management.idp_configs ADD COLUMN oauth_authorization_endpoint TEXT;
+
+ALTER TABLE auth.idp_configs ADD COLUMN oauth_token_endpoint TEXT;
+ALTER TABLE adminapi.idp_configs ADD COLUMN oauth_token_endpoint TEXT;
+ALTER TABLE management.idp_configs ADD COLUMN oauth_token_endpoint TEXT;
\ No newline at end of file
diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto
index a7ac1c4368..23453c7b6c 100644
--- a/proto/zitadel/admin.proto
+++ b/proto/zitadel/admin.proto
@@ -2281,12 +2281,13 @@ message AddOIDCIDPRequest {
max_length: 200;
}
];
+ // Fill the issuer if the identity provider is oidc discovery compliant
+ // If the identity provider is only oauth2 compliant or does not serve a openid configuration, fill the authorization and token endpoint instead
string issuer = 5 [
- (validate.rules).string = {min_len: 1, max_len: 200},
+ (validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"https://accounts.google.com\"";
description: "the oidc issuer of the identity provider";
- min_length: 1;
max_length: 200;
}
];
@@ -2308,6 +2309,24 @@ message AddOIDCIDPRequest {
description: "definition which field is mapped to the email of the user";
}
];
+ // If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer
+ string authorization_endpoint = 9 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://accounts.google.com/o/oauth2/v2/auth\"";
+ description: "the oauth2 authorization endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
+ // If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer
+ string token_endpoint = 10 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://oauth2.googleapis.com/token\"";
+ description: "the oauth2 token endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
}
message AddOIDCIDPResponse {
@@ -2420,6 +2439,8 @@ message UpdateIDPOIDCConfigRequest {
max_length: 200;
}
];
+ // Fill the issuer if the identity provider is oidc discovery compliant
+ // If the identity provider is only oauth2 compliant or does not serve a openid configuration, fill the authorization and token endpoint instead
string issuer = 2 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@@ -2462,6 +2483,24 @@ message UpdateIDPOIDCConfigRequest {
description: "definition which field is mapped to the email of the user";
}
];
+ // If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer
+ string authorization_endpoint = 8 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://accounts.google.com/o/oauth2/v2/auth\"";
+ description: "the oauth2 authorization endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
+ // If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer
+ string token_endpoint = 9 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://oauth2.googleapis.com/token\"";
+ description: "the oauth2 token endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
}
message UpdateIDPOIDCConfigResponse {
diff --git a/proto/zitadel/idp.proto b/proto/zitadel/idp.proto
index d6fb1a6884..dbdfc21caa 100644
--- a/proto/zitadel/idp.proto
+++ b/proto/zitadel/idp.proto
@@ -153,6 +153,22 @@ message OIDCConfig {
description: "definition which field is mapped to the email of the user";
}
];
+ string authorization_endpoint = 6 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://accounts.google.com/o/oauth2/v2/auth\"";
+ description: "the oauth2 authorization endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
+ string token_endpoint = 7 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://oauth2.googleapis.com/token\"";
+ description: "the oauth2 token endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
}
enum OIDCMappingField {
diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto
index a6b9a3413e..d21c82bd4e 100644
--- a/proto/zitadel/management.proto
+++ b/proto/zitadel/management.proto
@@ -4585,8 +4585,10 @@ message AddOrgOIDCIDPRequest {
description: "client secret generated by the identity provider";
}
];
+ // Fill the issuer if the identity provider is oidc discovery compliant
+ // If the identity provider is only oauth2 compliant or does not serve a openid configuration, fill the authorization and token endpoint instead
string issuer = 5 [
- (validate.rules).string = {min_len: 1, max_len: 200},
+ (validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"https://accounts.google.com\"";
description: "the oidc issuer of the identity provider";
@@ -4610,6 +4612,24 @@ message AddOrgOIDCIDPRequest {
description: "definition which field is mapped to the email of the user";
}
];
+ // If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer
+ string authorization_endpoint = 9 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://accounts.google.com/o/oauth2/v2/auth\"";
+ description: "the oauth2 authorization endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
+ // If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer
+ string token_endpoint = 10 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://oauth2.googleapis.com/token\"";
+ description: "the oauth2 token endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
}
message AddOrgOIDCIDPResponse {
@@ -4680,6 +4700,8 @@ message UpdateOrgIDPOIDCConfigRequest {
description: "client secret generated by the identity provider. If empty the secret is not overwritten";
}
];
+ // Fill the issuer if the identity provider is oidc discovery compliant
+ // If the identity provider is only oauth2 compliant or does not serve a openid configuration, fill the authorization and token endpoint instead
string issuer = 4 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@@ -4705,6 +4727,24 @@ message UpdateOrgIDPOIDCConfigRequest {
description: "definition which field is mapped to the email of the user";
}
];
+ // If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer
+ string authorization_endpoint = 8 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://accounts.google.com/o/oauth2/v2/auth\"";
+ description: "the oauth2 authorization endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
+ // If the identity provider does not serve an openid configuration, fill the authorization and token endpoint instead of the issuer
+ string token_endpoint = 9 [
+ (validate.rules).string = {max_len: 500},
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"https://oauth2.googleapis.com/token\"";
+ description: "the oauth2 token endpoint of the identity provider";
+ max_length: 500;
+ }
+ ];
}
message UpdateOrgIDPOIDCConfigResponse {