mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-03 12:52:16 +00:00
feat: get/list Zitadel IdP (#12394)
# Which Problems Are Solved This PR extends the functionality of `GetProviderByID`, `ListProviders` v1 endpoints and `GetIDPByID` v2 endpoint to also return Zitadel IdP when queried. # How the Problems Are Solved - Add `PROVIDER_TYPE_ZITADEL` and a `ZitadelConfig` to `zitadel.idp.v1.ProviderConfig` (v1 APIs). - Add `IDP_TYPE_ZITADEL`, `ZitadelConfig`, `InstanceRolesInfo` in v2 `idp.proto` - Extend internal/query IDP template querying to include a `ZitadelIDPTemplate` (incl. issuer, client credentials, scopes, instance roles info). - Add/extend integration tests for updating + fetching providers by ID and listing providers. # Additional Changes N/A # Additional Context Closes https://github.com/zitadel/zitadel/issues/12051 --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
parent
39ad66bded
commit
77169181a3
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin"
|
||||
@@ -227,41 +228,22 @@ func Test_AddZitadelProvider(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
existingProvider, err := Instance.Client.Admin.AddZitadelProvider(AdminCTX, &admin_pb.AddZitadelProviderRequest{
|
||||
Name: "Zitadel Support IdP",
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
ClientSecret: "test-secret",
|
||||
Scopes: []string{"email", "profile"},
|
||||
ProviderOptions: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, existingProvider.GetId())
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *admin_pb.UpdateZitadelProviderRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr error
|
||||
wantResponse *admin_pb.UpdateZitadelProviderResponse
|
||||
name string
|
||||
args args
|
||||
wantErr error
|
||||
wantResponse *admin_pb.UpdateZitadelProviderResponse
|
||||
wantUpdatedProvider *idp_pb.Provider
|
||||
}{
|
||||
{
|
||||
name: "no permissions, error",
|
||||
args: args{
|
||||
ctx: Instance.WithAuthorizationToken(CTX, integration.UserTypeNoPermission),
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
ClientSecret: "test-secret",
|
||||
@@ -278,7 +260,6 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
args: args{
|
||||
ctx: Instance.WithAuthorizationToken(CTX, integration.UserTypeLogin),
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Issuer: "acme.example.com",
|
||||
Scopes: []string{"email", "profile"},
|
||||
ProviderOptions: &idp_pb.Options{
|
||||
@@ -289,21 +270,11 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
},
|
||||
wantErr: status.Error(codes.PermissionDenied, "No matching permissions found (AUTH-5mWD2)"),
|
||||
},
|
||||
{
|
||||
name: "missing required field: id",
|
||||
args: args{
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{},
|
||||
},
|
||||
wantErr: status.Error(codes.InvalidArgument, "invalid UpdateZitadelProviderRequest.Id: value length must be between 1 and 200 runes, inclusive"),
|
||||
},
|
||||
{
|
||||
name: "missing required field: name",
|
||||
args: args{
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
},
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{},
|
||||
},
|
||||
wantErr: status.Error(codes.InvalidArgument, "invalid UpdateZitadelProviderRequest.Name: value length must be between 1 and 200 runes, inclusive"),
|
||||
},
|
||||
@@ -312,7 +283,6 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
args: args{
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Name: "Zitadel Support IdP updated",
|
||||
},
|
||||
},
|
||||
@@ -323,7 +293,6 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
args: args{
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Name: "Zitadel Support IdP updated",
|
||||
Issuer: "acme.example.com",
|
||||
},
|
||||
@@ -335,7 +304,6 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
args: args{
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Name: "Zitadel Support IdP updated",
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
@@ -361,22 +329,54 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
ResourceOwner: Instance.Instance.Id,
|
||||
},
|
||||
},
|
||||
wantUpdatedProvider: &idp_pb.Provider{
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: "Zitadel Support IdP updated",
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_SYSTEM,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile", "openid", "offline_access"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
{
|
||||
OrganizationId: "org2",
|
||||
OrganizationDomain: "org2.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update with scopes unset, ok",
|
||||
args: args{
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Name: "Zitadel Support IdP updated again",
|
||||
Name: "Zitadel Support IdP updated 1",
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: nil,
|
||||
Scopes: []string{},
|
||||
ProviderOptions: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: false,
|
||||
},
|
||||
InstanceRolesInfo: nil,
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org3",
|
||||
OrganizationDomain: "org3.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResponse: &admin_pb.UpdateZitadelProviderResponse{
|
||||
@@ -384,12 +384,42 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
ResourceOwner: Instance.Instance.Id,
|
||||
},
|
||||
},
|
||||
wantUpdatedProvider: &idp_pb.Provider{
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: "Zitadel Support IdP updated 1",
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_SYSTEM,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: nil, // unset scopes
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org3",
|
||||
OrganizationDomain: "org3.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// create a new provider per subtest
|
||||
existingProvider := Instance.AddZitadelProvider(AdminCTX, integration.IDPName())
|
||||
|
||||
// build request using this provider ID
|
||||
tt.args.req.Id = existingProvider.GetId()
|
||||
|
||||
before := time.Now()
|
||||
got, err := Client.UpdateZitadelProvider(tt.args.ctx, tt.args.req)
|
||||
updateResp, err := Client.UpdateZitadelProvider(tt.args.ctx, tt.args.req)
|
||||
after := time.Now()
|
||||
if tt.wantErr != nil {
|
||||
require.Error(t, err)
|
||||
@@ -400,11 +430,292 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, got)
|
||||
assert.WithinRange(t, got.GetDetails().GetChangeDate().AsTime(), before, after)
|
||||
assert.Equal(t, tt.wantResponse.GetDetails().GetResourceOwner(), got.GetDetails().GetResourceOwner())
|
||||
assert.NotNil(t, updateResp)
|
||||
assert.WithinRange(t, updateResp.GetDetails().GetChangeDate().AsTime(), before, after)
|
||||
assert.Equal(t, tt.wantResponse.GetDetails().GetResourceOwner(), updateResp.GetDetails().GetResourceOwner())
|
||||
|
||||
// todo: check if the update was actually applied by fetching the provider and checking its fields when the functionality is implemented
|
||||
// get provider by ID and assert that the updated provider matches the expected values
|
||||
getResp, err := Client.GetProviderByID(AdminCTX, &admin_pb.GetProviderByIDRequest{Id: existingProvider.GetId()})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, updateResp.GetDetails().GetChangeDate().AsTime(), getResp.GetIdp().GetDetails().GetChangeDate().AsTime())
|
||||
tt.wantUpdatedProvider.Id = existingProvider.GetId()
|
||||
assertProvider(t, tt.wantUpdatedProvider, getResp.GetIdp())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UpdateZitadelProvider_MissingID(t *testing.T) {
|
||||
_ = Instance.AddZitadelProvider(AdminCTX, integration.IDPName())
|
||||
// Attempt to update the provider without specifying the ID
|
||||
updateResp, err := Client.UpdateZitadelProvider(AdminCTX, &admin_pb.UpdateZitadelProviderRequest{})
|
||||
require.Error(t, err)
|
||||
grpcStatus, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, codes.InvalidArgument, grpcStatus.Code())
|
||||
assert.Equal(t, "invalid UpdateZitadelProviderRequest.Id: value length must be between 1 and 200 runes, inclusive", grpcStatus.Message())
|
||||
require.Nil(t, updateResp)
|
||||
}
|
||||
|
||||
func Test_GetProviderByID(t *testing.T) {
|
||||
providerName := integration.IDPName()
|
||||
existingProvider := Instance.AddZitadelProvider(AdminCTX, providerName)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
req *admin_pb.GetProviderByIDRequest
|
||||
wantErr error
|
||||
wantResp *admin_pb.GetProviderByIDResponse
|
||||
}{
|
||||
{
|
||||
name: "no permissions",
|
||||
ctx: Instance.WithAuthorizationToken(CTX, integration.UserTypeNoPermission),
|
||||
req: &admin_pb.GetProviderByIDRequest{
|
||||
Id: "idp-id",
|
||||
},
|
||||
wantErr: status.Error(codes.NotFound, "membership not found (AUTHZ-cdgFk)"),
|
||||
},
|
||||
{
|
||||
name: "invalid ID",
|
||||
ctx: AdminCTX,
|
||||
wantErr: status.Error(codes.InvalidArgument, "invalid GetProviderByIDRequest.Id: value length must be between 1 and 200 runes, inclusive"),
|
||||
},
|
||||
{
|
||||
name: "non-existing ID",
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.GetProviderByIDRequest{
|
||||
Id: "non-existing-id",
|
||||
},
|
||||
wantErr: status.Error(codes.NotFound, "Identity Provider Configuration doesn't exist (QUERY-SAFrt)"),
|
||||
},
|
||||
{
|
||||
name: "insufficient permissions", // no iam.idp.read permissions set
|
||||
ctx: integration.WithSystemUserWithNoPermissionsAuthorization(CTX),
|
||||
req: &admin_pb.GetProviderByIDRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
},
|
||||
wantErr: status.Error(codes.PermissionDenied, "No matching permissions found (AUTH-5mWD2)"),
|
||||
},
|
||||
{
|
||||
name: "found",
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.GetProviderByIDRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
},
|
||||
wantResp: &admin_pb.GetProviderByIDResponse{
|
||||
Idp: &idp_pb.Provider{
|
||||
Id: existingProvider.GetId(),
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: providerName,
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_SYSTEM,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Client.GetProviderByID(tt.ctx, tt.req)
|
||||
if tt.wantErr != nil {
|
||||
require.Error(t, err)
|
||||
grpcStatus, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, status.Code(tt.wantErr), grpcStatus.Code())
|
||||
assert.Equal(t, status.Convert(tt.wantErr).Message(), grpcStatus.Message())
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, got)
|
||||
assert.Equal(t, existingProvider.GetDetails().GetCreationDate().AsTime(), got.GetIdp().GetDetails().GetCreationDate().AsTime())
|
||||
assert.Equal(t, existingProvider.GetDetails().GetResourceOwner(), got.GetIdp().GetDetails().GetResourceOwner())
|
||||
assertProvider(t, tt.wantResp.GetIdp(), got.GetIdp())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ListProviders(t *testing.T) {
|
||||
provider1Name := integration.IDPName()
|
||||
provider1 := Instance.AddZitadelProvider(AdminCTX, provider1Name)
|
||||
|
||||
provider2Name := integration.IDPName()
|
||||
provider2 := Instance.AddZitadelProvider(AdminCTX, provider2Name)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
req *admin_pb.ListProvidersRequest
|
||||
wantResp *admin_pb.ListProvidersResponse
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "no permissions",
|
||||
ctx: Instance.WithAuthorizationToken(CTX, integration.UserTypeNoPermission),
|
||||
req: &admin_pb.ListProvidersRequest{},
|
||||
wantErr: status.Error(codes.NotFound, "membership not found (AUTHZ-cdgFk)"),
|
||||
},
|
||||
{
|
||||
name: "insufficient permissions", // no iam.idp.read permissions set
|
||||
ctx: integration.WithSystemUserWithNoPermissionsAuthorization(CTX),
|
||||
req: &admin_pb.ListProvidersRequest{},
|
||||
wantErr: status.Error(codes.PermissionDenied, "No matching permissions found (AUTH-5mWD2)"),
|
||||
},
|
||||
{
|
||||
name: "list by id",
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.ListProvidersRequest{
|
||||
Query: &object_pb.ListQuery{
|
||||
Asc: false,
|
||||
},
|
||||
Queries: []*admin_pb.ProviderQuery{
|
||||
{
|
||||
Query: &admin_pb.ProviderQuery_IdpIdQuery{
|
||||
IdpIdQuery: &idp_pb.IDPIDQuery{
|
||||
Id: provider2.GetId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResp: &admin_pb.ListProvidersResponse{
|
||||
Details: &object_pb.ListDetails{
|
||||
TotalResult: 1,
|
||||
},
|
||||
Result: []*idp_pb.Provider{
|
||||
{
|
||||
Id: provider2.GetId(),
|
||||
Details: &object_pb.ObjectDetails{
|
||||
CreationDate: provider2.GetDetails().GetCreationDate(),
|
||||
ChangeDate: provider2.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: provider2.GetDetails().GetResourceOwner(),
|
||||
},
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: provider2Name,
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_SYSTEM,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list by name",
|
||||
ctx: AdminCTX,
|
||||
req: &admin_pb.ListProvidersRequest{
|
||||
Query: &object_pb.ListQuery{
|
||||
Asc: false,
|
||||
},
|
||||
Queries: []*admin_pb.ProviderQuery{
|
||||
{
|
||||
Query: &admin_pb.ProviderQuery_IdpNameQuery{
|
||||
IdpNameQuery: &idp_pb.IDPNameQuery{
|
||||
Name: provider1Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResp: &admin_pb.ListProvidersResponse{
|
||||
Details: &object_pb.ListDetails{
|
||||
TotalResult: 1,
|
||||
},
|
||||
Result: []*idp_pb.Provider{
|
||||
{
|
||||
Id: provider1.GetId(),
|
||||
Details: &object_pb.ObjectDetails{
|
||||
CreationDate: provider1.GetDetails().GetCreationDate(),
|
||||
ChangeDate: provider1.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: provider1.GetDetails().GetResourceOwner(),
|
||||
},
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: provider1Name,
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_SYSTEM,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Client.ListProviders(tt.ctx, tt.req)
|
||||
if tt.wantErr != nil {
|
||||
require.Error(t, err)
|
||||
grpcStatus, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, status.Code(tt.wantErr), grpcStatus.Code())
|
||||
assert.Equal(t, status.Convert(tt.wantErr).Message(), grpcStatus.Message())
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, got)
|
||||
assert.Equal(t, tt.wantResp.GetDetails().GetTotalResult(), got.GetDetails().GetTotalResult())
|
||||
for i, want := range tt.wantResp.GetResult() {
|
||||
assert.Equal(t, want.GetDetails().GetCreationDate().AsTime(), got.GetResult()[i].GetDetails().GetCreationDate().AsTime())
|
||||
assert.Equal(t, Instance.ID(), got.GetResult()[i].GetDetails().GetResourceOwner())
|
||||
assertProvider(t, want, got.GetResult()[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertProvider(t *testing.T, expected, actual *idp_pb.Provider) {
|
||||
assert.Equal(t, expected.GetId(), actual.GetId())
|
||||
assert.Equal(t, expected.GetState(), actual.GetState())
|
||||
assert.Equal(t, expected.GetName(), actual.GetName())
|
||||
assert.Equal(t, expected.GetOwner(), actual.GetOwner())
|
||||
assert.Equal(t, expected.GetType(), actual.GetType())
|
||||
assert.True(t, proto.Equal(expected.GetConfig(), actual.GetConfig()), "expected: %v, actual: %v", expected.GetConfig(), actual.GetConfig())
|
||||
}
|
||||
|
||||
@@ -415,6 +415,8 @@ func providerTypeToPb(idpType domain.IDPType) idp_pb.ProviderType {
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_APPLE
|
||||
case domain.IDPTypeSAML:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_SAML
|
||||
case domain.IDPTypeZitadel:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL
|
||||
case domain.IDPTypeUnspecified:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_UNSPECIFIED
|
||||
default:
|
||||
@@ -480,6 +482,10 @@ func configToPb(config *query.IDPTemplate) *idp_pb.ProviderConfig {
|
||||
samlConfigToPb(providerConfig, config.SAMLIDPTemplate)
|
||||
return providerConfig
|
||||
}
|
||||
if config.ZitadelIDPTemplate != nil {
|
||||
zitadelConfigToPb(providerConfig, config.ZitadelIDPTemplate)
|
||||
return providerConfig
|
||||
}
|
||||
return providerConfig
|
||||
}
|
||||
|
||||
@@ -677,6 +683,24 @@ func samlConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.SAMLI
|
||||
}
|
||||
}
|
||||
|
||||
func zitadelConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.ZitadelIDPTemplate) {
|
||||
instanceRolesInfo := make([]*idp_pb.InstanceRolesInfo, 0, len(template.InstanceRolesInfo))
|
||||
for _, role := range template.InstanceRolesInfo {
|
||||
instanceRolesInfo = append(instanceRolesInfo, &idp_pb.InstanceRolesInfo{
|
||||
OrganizationDomain: role.OrganizationDomain,
|
||||
OrganizationId: role.OrganizationID,
|
||||
})
|
||||
}
|
||||
providerConfig.Config = &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
ClientId: template.ClientID,
|
||||
Issuer: template.Issuer,
|
||||
Scopes: template.Scopes,
|
||||
InstanceRolesInfo: instanceRolesInfo,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func bindingToPb(binding string) idp_pb.SAMLBinding {
|
||||
switch binding {
|
||||
case "":
|
||||
|
||||
@@ -202,6 +202,102 @@ func TestServer_GetIDPByID(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "idp by ID, instance, Zitadel provider, ok",
|
||||
args: args{
|
||||
IamCTX,
|
||||
&idp.GetIDPByIDRequest{},
|
||||
func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr {
|
||||
name := integration.IDPName()
|
||||
resp := Instance.AddZitadelProvider(ctx, name)
|
||||
request.Id = resp.Id
|
||||
return &idpAttr{
|
||||
resp.GetId(),
|
||||
name,
|
||||
&object.Details{
|
||||
Sequence: resp.Details.Sequence,
|
||||
CreationDate: resp.Details.CreationDate,
|
||||
ChangeDate: resp.Details.ChangeDate,
|
||||
ResourceOwner: resp.Details.ResourceOwner,
|
||||
}}
|
||||
},
|
||||
},
|
||||
want: &idp.GetIDPByIDResponse{
|
||||
Idp: &idp.IDP{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
},
|
||||
State: idp.IDPState_IDP_STATE_ACTIVE,
|
||||
Type: idp.IDPType_IDP_TYPE_ZITADEL,
|
||||
Config: &idp.IDPConfig{
|
||||
Config: &idp.IDPConfig_Zitadel{
|
||||
Zitadel: &idp.ZitadelConfig{
|
||||
ClientId: "test-client",
|
||||
Issuer: "zitadel.example.com",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Options: &idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "idp by ID, org, Zitadel provider, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&idp.GetIDPByIDRequest{},
|
||||
func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr {
|
||||
name := integration.IDPName()
|
||||
resp := Instance.AddOrgZitadelProvider(ctx, name)
|
||||
request.Id = resp.Id
|
||||
return &idpAttr{
|
||||
resp.GetId(),
|
||||
name,
|
||||
&object.Details{
|
||||
Sequence: resp.Details.Sequence,
|
||||
CreationDate: resp.Details.CreationDate,
|
||||
ChangeDate: resp.Details.ChangeDate,
|
||||
ResourceOwner: resp.Details.ResourceOwner,
|
||||
}}
|
||||
},
|
||||
},
|
||||
want: &idp.GetIDPByIDResponse{
|
||||
Idp: &idp.IDP{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
},
|
||||
State: idp.IDPState_IDP_STATE_ACTIVE,
|
||||
Type: idp.IDPType_IDP_TYPE_ZITADEL,
|
||||
Config: &idp.IDPConfig{
|
||||
Config: &idp.IDPConfig_Zitadel{
|
||||
Zitadel: &idp.ZitadelConfig{
|
||||
ClientId: "test-client",
|
||||
Issuer: "zitadel.example.com",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Options: &idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -85,6 +85,8 @@ func idpTypeToPb(idpType domain.IDPType) idp_pb.IDPType {
|
||||
return idp_pb.IDPType_IDP_TYPE_APPLE
|
||||
case domain.IDPTypeSAML:
|
||||
return idp_pb.IDPType_IDP_TYPE_SAML
|
||||
case domain.IDPTypeZitadel:
|
||||
return idp_pb.IDPType_IDP_TYPE_ZITADEL
|
||||
case domain.IDPTypeUnspecified:
|
||||
return idp_pb.IDPType_IDP_TYPE_UNSPECIFIED
|
||||
default:
|
||||
@@ -150,6 +152,10 @@ func configToPb(config *query.IDPTemplate) *idp_pb.IDPConfig {
|
||||
samlConfigToPb(idpConfig, config.SAMLIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.ZitadelIDPTemplate != nil {
|
||||
zitadelConfigToPb(idpConfig, config.ZitadelIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
return idpConfig
|
||||
}
|
||||
|
||||
@@ -387,3 +393,21 @@ func signatureAlgorithmToPb(signatureAlgorithm string) idp_pb.SAMLSignatureAlgor
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func zitadelConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.ZitadelIDPTemplate) {
|
||||
instanceRolesInfo := make([]*idp_pb.InstanceRolesInfo, 0, len(template.InstanceRolesInfo))
|
||||
for _, role := range template.InstanceRolesInfo {
|
||||
instanceRolesInfo = append(instanceRolesInfo, &idp_pb.InstanceRolesInfo{
|
||||
OrganizationId: role.OrganizationID,
|
||||
OrganizationDomain: role.OrganizationDomain,
|
||||
})
|
||||
}
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
ClientId: template.ClientID,
|
||||
Issuer: template.Issuer,
|
||||
Scopes: template.Scopes,
|
||||
InstanceRolesInfo: instanceRolesInfo,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp"
|
||||
@@ -233,41 +234,22 @@ func Test_AddZitadelProvider(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
existingProvider, err := Instance.Client.Mgmt.AddZitadelProvider(OrgCTX, &mgmt_pb.AddZitadelProviderRequest{
|
||||
Name: "Zitadel Support IdP",
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
ClientSecret: "test-secret",
|
||||
Scopes: []string{"email", "profile"},
|
||||
ProviderOptions: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, existingProvider.GetId())
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *mgmt_pb.UpdateZitadelProviderRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr error
|
||||
wantResponse *mgmt_pb.UpdateZitadelProviderResponse
|
||||
name string
|
||||
args args
|
||||
wantErr error
|
||||
wantResponse *mgmt_pb.UpdateZitadelProviderResponse
|
||||
wantUpdatedProvider *idp_pb.Provider
|
||||
}{
|
||||
{
|
||||
name: "no permissions, error",
|
||||
args: args{
|
||||
ctx: Instance.WithAuthorizationToken(CTX, integration.UserTypeNoPermission),
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
ClientSecret: "test-secret",
|
||||
@@ -284,7 +266,6 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
args: args{
|
||||
ctx: Instance.WithAuthorizationToken(CTX, integration.UserTypeLogin),
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Issuer: "acme.example.com",
|
||||
Scopes: []string{"email", "profile"},
|
||||
ProviderOptions: &idp_pb.Options{
|
||||
@@ -295,21 +276,11 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
},
|
||||
wantErr: status.Error(codes.PermissionDenied, "No matching permissions found (AUTH-5mWD2)"),
|
||||
},
|
||||
{
|
||||
name: "missing required field: id",
|
||||
args: args{
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{},
|
||||
},
|
||||
wantErr: status.Error(codes.InvalidArgument, "invalid UpdateZitadelProviderRequest.Id: value length must be between 1 and 200 runes, inclusive"),
|
||||
},
|
||||
{
|
||||
name: "missing required field: name",
|
||||
args: args{
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
},
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{},
|
||||
},
|
||||
wantErr: status.Error(codes.InvalidArgument, "invalid UpdateZitadelProviderRequest.Name: value length must be between 1 and 200 runes, inclusive"),
|
||||
},
|
||||
@@ -318,7 +289,6 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
args: args{
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Name: "Zitadel Support IdP updated",
|
||||
},
|
||||
},
|
||||
@@ -329,7 +299,6 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
args: args{
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Name: "Zitadel Support IdP updated",
|
||||
Issuer: "acme.example.com",
|
||||
},
|
||||
@@ -341,15 +310,10 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
args: args{
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Name: "Zitadel Support IdP updated",
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile", "openid", "offline_access"},
|
||||
ProviderOptions: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: false,
|
||||
},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
@@ -367,22 +331,51 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
ResourceOwner: Instance.DefaultOrg.Id,
|
||||
},
|
||||
},
|
||||
wantUpdatedProvider: &idp_pb.Provider{
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: "Zitadel Support IdP updated",
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile", "openid", "offline_access"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
{
|
||||
OrganizationId: "org2",
|
||||
OrganizationDomain: "org2.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update with scopes unset, ok",
|
||||
args: args{
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
Name: "Zitadel Support IdP updated again",
|
||||
Name: "Zitadel Support IdP updated 1",
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{},
|
||||
Scopes: []string{}, // scopes unset -> will be updated by the API
|
||||
ProviderOptions: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: false,
|
||||
IsAutoCreation: true,
|
||||
},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org3",
|
||||
OrganizationDomain: "org3.com",
|
||||
},
|
||||
},
|
||||
InstanceRolesInfo: nil,
|
||||
},
|
||||
},
|
||||
wantResponse: &mgmt_pb.UpdateZitadelProviderResponse{
|
||||
@@ -390,12 +383,80 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
ResourceOwner: Instance.DefaultOrg.Id,
|
||||
},
|
||||
},
|
||||
wantUpdatedProvider: &idp_pb.Provider{
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: "Zitadel Support IdP updated 1",
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsAutoCreation: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: nil, // unset scopes
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org3",
|
||||
OrganizationDomain: "org3.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update with instance roles info not set, ok",
|
||||
args: args{
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.UpdateZitadelProviderRequest{
|
||||
Name: "Zitadel Support IdP updated 2",
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "openid"},
|
||||
ProviderOptions: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
InstanceRolesInfo: nil, // instance roles info isn't set -> will be unset by the API
|
||||
},
|
||||
},
|
||||
wantResponse: &mgmt_pb.UpdateZitadelProviderResponse{
|
||||
Details: &object_pb.ObjectDetails{
|
||||
ResourceOwner: Instance.DefaultOrg.Id,
|
||||
},
|
||||
},
|
||||
wantUpdatedProvider: &idp_pb.Provider{
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: "Zitadel Support IdP updated 2",
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "acme.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "openid"},
|
||||
InstanceRolesInfo: nil, // instance roles info isn't set
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// create a new provider per subtest and set the ID in the request
|
||||
zitadelProvider := Instance.AddOrgZitadelProvider(OrgCTX, integration.IDPName())
|
||||
tt.args.req.Id = zitadelProvider.Id
|
||||
|
||||
before := time.Now()
|
||||
got, err := Client.UpdateZitadelProvider(tt.args.ctx, tt.args.req)
|
||||
updateResp, err := Client.UpdateZitadelProvider(tt.args.ctx, tt.args.req)
|
||||
after := time.Now()
|
||||
if tt.wantErr != nil {
|
||||
require.Error(t, err)
|
||||
@@ -406,11 +467,371 @@ func Test_UpdateZitadelProvider(t *testing.T) {
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, got)
|
||||
assert.WithinRange(t, got.GetDetails().GetChangeDate().AsTime(), before, after)
|
||||
assert.Equal(t, tt.wantResponse.GetDetails().GetResourceOwner(), got.GetDetails().GetResourceOwner())
|
||||
assert.NotNil(t, updateResp)
|
||||
assert.WithinRange(t, updateResp.GetDetails().GetChangeDate().AsTime(), before, after)
|
||||
assert.Equal(t, tt.wantResponse.GetDetails().GetResourceOwner(), updateResp.GetDetails().GetResourceOwner())
|
||||
|
||||
// todo: check if the update was actually applied by fetching the provider and checking its fields when the functionality is implemented
|
||||
// get provider by ID and assert that the updated provider matches the expected values
|
||||
getResp, err := Client.GetProviderByID(OrgCTX, &mgmt_pb.GetProviderByIDRequest{Id: zitadelProvider.Id})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, updateResp.GetDetails().GetChangeDate().AsTime(), getResp.GetIdp().GetDetails().GetChangeDate().AsTime())
|
||||
tt.wantUpdatedProvider.Id = zitadelProvider.Id
|
||||
assertProvider(t, tt.wantUpdatedProvider, getResp.GetIdp())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UpdateZitadelProvider_MissingID(t *testing.T) {
|
||||
_ = Instance.AddOrgZitadelProvider(OrgCTX, integration.IDPName())
|
||||
// Attempt to update the provider without specifying the ID
|
||||
updateResp, err := Client.UpdateZitadelProvider(OrgCTX, &mgmt_pb.UpdateZitadelProviderRequest{})
|
||||
require.Error(t, err)
|
||||
grpcStatus, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, codes.InvalidArgument, grpcStatus.Code())
|
||||
assert.Equal(t, "invalid UpdateZitadelProviderRequest.Id: value length must be between 1 and 200 runes, inclusive", grpcStatus.Message())
|
||||
require.Nil(t, updateResp)
|
||||
}
|
||||
|
||||
func Test_GetProviderByID(t *testing.T) {
|
||||
name := integration.IDPName()
|
||||
existingProvider := Instance.AddOrgZitadelProvider(OrgCTX, name)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
req *mgmt_pb.GetProviderByIDRequest
|
||||
wantErr error
|
||||
wantResp *mgmt_pb.GetProviderByIDResponse
|
||||
}{
|
||||
{
|
||||
name: "no permissions",
|
||||
ctx: Instance.WithAuthorizationToken(CTX, integration.UserTypeNoPermission),
|
||||
req: &mgmt_pb.GetProviderByIDRequest{
|
||||
Id: "idp-id",
|
||||
},
|
||||
wantErr: status.Error(codes.NotFound, "membership not found (AUTHZ-cdgFk)"),
|
||||
},
|
||||
{
|
||||
name: "invalid ID",
|
||||
ctx: OrgCTX,
|
||||
wantErr: status.Error(codes.InvalidArgument, "invalid GetProviderByIDRequest.Id: value length must be between 1 and 200 runes, inclusive"),
|
||||
},
|
||||
{
|
||||
name: "non-existing ID",
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.GetProviderByIDRequest{
|
||||
Id: "non-existing-id",
|
||||
},
|
||||
wantErr: status.Error(codes.NotFound, "Identity Provider Configuration doesn't exist (QUERY-SAFrt)"),
|
||||
},
|
||||
{
|
||||
name: "insufficient permissions", // no org.idp.read permissions set
|
||||
ctx: integration.WithSystemUserWithNoPermissionsAuthorization(CTX),
|
||||
req: &mgmt_pb.GetProviderByIDRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
},
|
||||
wantErr: status.Error(codes.PermissionDenied, "No matching permissions found (AUTH-5mWD2)"),
|
||||
},
|
||||
{
|
||||
name: "found",
|
||||
ctx: OrgCTX,
|
||||
req: &mgmt_pb.GetProviderByIDRequest{
|
||||
Id: existingProvider.GetId(),
|
||||
},
|
||||
wantResp: &mgmt_pb.GetProviderByIDResponse{
|
||||
Idp: &idp_pb.Provider{
|
||||
Id: existingProvider.GetId(),
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: name,
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Client.GetProviderByID(tt.ctx, tt.req)
|
||||
if tt.wantErr != nil {
|
||||
require.Error(t, err)
|
||||
grpcStatus, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, status.Code(tt.wantErr), grpcStatus.Code())
|
||||
assert.Equal(t, status.Convert(tt.wantErr).Message(), grpcStatus.Message())
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, got)
|
||||
assert.Equal(t, existingProvider.GetDetails().GetCreationDate().AsTime(), got.GetIdp().GetDetails().GetCreationDate().AsTime())
|
||||
assert.Equal(t, existingProvider.GetDetails().GetResourceOwner(), got.GetIdp().GetDetails().GetResourceOwner())
|
||||
assertProvider(t, tt.wantResp.GetIdp(), got.GetIdp())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ListProviders(t *testing.T) {
|
||||
org := Instance.CreateOrganization(IAMOwnerCTX, integration.OrganizationName(), integration.Email())
|
||||
require.NotEmpty(t, org.GetOrganizationId())
|
||||
orgCtx := integration.SetOrgID(IAMOwnerCTX, org.GetOrganizationId())
|
||||
|
||||
provider1Name := integration.IDPName()
|
||||
provider1 := Instance.AddOrgZitadelProvider(orgCtx, provider1Name)
|
||||
provider2Name := integration.IDPName()
|
||||
provider2 := Instance.AddOrgZitadelProvider(orgCtx, provider2Name)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
req *mgmt_pb.ListProvidersRequest
|
||||
wantResp *mgmt_pb.ListProvidersResponse
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "no permissions",
|
||||
ctx: Instance.WithAuthorizationToken(CTX, integration.UserTypeNoPermission),
|
||||
req: &mgmt_pb.ListProvidersRequest{},
|
||||
wantErr: status.Error(codes.NotFound, "membership not found (AUTHZ-cdgFk)"),
|
||||
},
|
||||
{
|
||||
name: "insufficient permissions", // no iam.idp.read permissions set
|
||||
ctx: integration.WithSystemUserWithNoPermissionsAuthorization(CTX),
|
||||
req: &mgmt_pb.ListProvidersRequest{},
|
||||
wantErr: status.Error(codes.PermissionDenied, "No matching permissions found (AUTH-5mWD2)"),
|
||||
},
|
||||
{
|
||||
name: "list by id",
|
||||
ctx: orgCtx,
|
||||
req: &mgmt_pb.ListProvidersRequest{
|
||||
Query: &object_pb.ListQuery{
|
||||
Asc: false,
|
||||
},
|
||||
Queries: []*mgmt_pb.ProviderQuery{
|
||||
{
|
||||
Query: &mgmt_pb.ProviderQuery_IdpIdQuery{
|
||||
IdpIdQuery: &idp_pb.IDPIDQuery{
|
||||
Id: provider2.GetId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResp: &mgmt_pb.ListProvidersResponse{
|
||||
Details: &object_pb.ListDetails{
|
||||
TotalResult: 1,
|
||||
},
|
||||
Result: []*idp_pb.Provider{
|
||||
{
|
||||
Id: provider2.GetId(),
|
||||
Details: &object_pb.ObjectDetails{
|
||||
CreationDate: provider2.GetDetails().GetCreationDate(),
|
||||
ChangeDate: provider2.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: provider2.GetDetails().GetResourceOwner(),
|
||||
},
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: provider2Name,
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list by name",
|
||||
ctx: orgCtx,
|
||||
req: &mgmt_pb.ListProvidersRequest{
|
||||
Query: &object_pb.ListQuery{
|
||||
Asc: false,
|
||||
},
|
||||
Queries: []*mgmt_pb.ProviderQuery{
|
||||
{
|
||||
Query: &mgmt_pb.ProviderQuery_IdpNameQuery{
|
||||
IdpNameQuery: &idp_pb.IDPNameQuery{
|
||||
Name: provider1Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResp: &mgmt_pb.ListProvidersResponse{
|
||||
Details: &object_pb.ListDetails{
|
||||
TotalResult: 1,
|
||||
},
|
||||
Result: []*idp_pb.Provider{
|
||||
{
|
||||
Id: provider1.GetId(),
|
||||
Details: &object_pb.ObjectDetails{
|
||||
CreationDate: provider1.GetDetails().GetCreationDate(),
|
||||
ChangeDate: provider1.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: provider1.GetDetails().GetResourceOwner(),
|
||||
},
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: provider1Name,
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list all providers",
|
||||
ctx: orgCtx,
|
||||
req: &mgmt_pb.ListProvidersRequest{
|
||||
Query: &object_pb.ListQuery{
|
||||
Asc: true,
|
||||
},
|
||||
},
|
||||
wantResp: &mgmt_pb.ListProvidersResponse{
|
||||
Details: &object_pb.ListDetails{
|
||||
TotalResult: 2,
|
||||
},
|
||||
Result: []*idp_pb.Provider{
|
||||
{
|
||||
Id: provider1.GetId(),
|
||||
Details: &object_pb.ObjectDetails{
|
||||
CreationDate: provider1.GetDetails().GetCreationDate(),
|
||||
ChangeDate: provider1.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: provider1.GetDetails().GetResourceOwner(),
|
||||
},
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: provider1Name,
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: provider2.GetId(),
|
||||
Details: &object_pb.ObjectDetails{
|
||||
CreationDate: provider2.GetDetails().GetCreationDate(),
|
||||
ChangeDate: provider2.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: provider2.GetDetails().GetResourceOwner(),
|
||||
},
|
||||
State: idp_pb.IDPState_IDP_STATE_ACTIVE,
|
||||
Name: provider2Name,
|
||||
Owner: idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG,
|
||||
Type: idp_pb.ProviderType_PROVIDER_TYPE_ZITADEL,
|
||||
Config: &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
Config: &idp_pb.ProviderConfig_Zitadel{
|
||||
Zitadel: &idp_pb.ZitadelConfig{
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
Scopes: []string{"email", "profile"},
|
||||
InstanceRolesInfo: []*idp_pb.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Client.ListProviders(tt.ctx, tt.req)
|
||||
if tt.wantErr != nil {
|
||||
require.Error(t, err)
|
||||
grpcStatus, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, status.Code(tt.wantErr), grpcStatus.Code())
|
||||
assert.Equal(t, status.Convert(tt.wantErr).Message(), grpcStatus.Message())
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, got)
|
||||
assert.Equal(t, tt.wantResp.GetDetails().GetTotalResult(), got.GetDetails().GetTotalResult())
|
||||
for i, want := range tt.wantResp.GetResult() {
|
||||
assert.Equal(t, want.GetDetails().GetCreationDate().AsTime(), got.GetResult()[i].GetDetails().GetCreationDate().AsTime())
|
||||
assert.Equal(t, org.GetOrganizationId(), got.GetResult()[i].GetDetails().GetResourceOwner())
|
||||
assertProvider(t, want, got.GetResult()[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertProvider(t *testing.T, expected, actual *idp_pb.Provider) {
|
||||
assert.Equal(t, expected.GetId(), actual.GetId())
|
||||
assert.Equal(t, expected.GetState(), actual.GetState())
|
||||
assert.Equal(t, expected.GetName(), actual.GetName())
|
||||
assert.Equal(t, expected.GetOwner(), actual.GetOwner())
|
||||
assert.Equal(t, expected.GetType(), actual.GetType())
|
||||
assert.True(t, proto.Equal(expected.GetConfig(), actual.GetConfig()), "expected: %v, actual: %v", expected.GetConfig(), actual.GetConfig())
|
||||
}
|
||||
|
||||
@@ -2461,10 +2461,10 @@ func (wm *ZitadelIDPWriteModel) NewChanges(
|
||||
if wm.Issuer != issuer {
|
||||
changes = append(changes, idp.ChangeZitadelIDPIssuer(issuer))
|
||||
}
|
||||
if scopes != nil && !slices.Equal(wm.Scopes, scopes) {
|
||||
if !slices.Equal(wm.Scopes, scopes) {
|
||||
changes = append(changes, idp.ChangeZitadelIDPScopes(scopes))
|
||||
}
|
||||
if info != nil && !slices.Equal(wm.InstanceRolesInfo, info) {
|
||||
if !slices.Equal(wm.InstanceRolesInfo, info) {
|
||||
changes = append(changes, idp.ChangeZitadelIDPInstanceRolesInfo(info))
|
||||
}
|
||||
opts := wm.Changes(options)
|
||||
|
||||
@@ -6424,6 +6424,8 @@ func TestCommands_UpdateInstanceZitadelProvider(t *testing.T) {
|
||||
KeyID: "id",
|
||||
Crypted: []byte("newSecret"),
|
||||
}),
|
||||
idp.ChangeZitadelIDPInstanceRolesInfo(nil),
|
||||
idp.ChangeZitadelIDPScopes(nil),
|
||||
},
|
||||
),
|
||||
),
|
||||
@@ -6489,6 +6491,17 @@ func TestCommands_UpdateInstanceZitadelProvider(t *testing.T) {
|
||||
Name: "name",
|
||||
Issuer: "issuer",
|
||||
ClientID: "clientID",
|
||||
Scopes: []string{openid.ScopeOpenID, openid.ScopeEmail},
|
||||
InstanceRolesInfo: []idp.RolesInfo{
|
||||
{
|
||||
OrganizationID: "org1",
|
||||
OrganizationDomain: "example-org1.com",
|
||||
},
|
||||
{
|
||||
OrganizationID: "org2",
|
||||
OrganizationDomain: "example-org2.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -6756,7 +6769,7 @@ func TestCommands_UpdateInstanceZitadelProvider(t *testing.T) {
|
||||
Issuer: "new issuer",
|
||||
ClientID: "clientID2",
|
||||
ClientSecret: "newSecret",
|
||||
Scopes: nil,
|
||||
Scopes: []string{openid.ScopeOpenID, openid.ScopeEmail},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
|
||||
@@ -6459,6 +6459,8 @@ func TestCommands_UpdateOrgZitadelIDP(t *testing.T) {
|
||||
KeyID: "id",
|
||||
Crypted: []byte("newSecret"),
|
||||
}),
|
||||
idp.ChangeZitadelIDPScopes(nil),
|
||||
idp.ChangeZitadelIDPInstanceRolesInfo(nil),
|
||||
},
|
||||
),
|
||||
),
|
||||
@@ -6524,6 +6526,17 @@ func TestCommands_UpdateOrgZitadelIDP(t *testing.T) {
|
||||
Name: "name",
|
||||
Issuer: "issuer",
|
||||
ClientID: "clientID",
|
||||
Scopes: []string{openid.ScopeOpenID, openid.ScopeEmail},
|
||||
InstanceRolesInfo: []idp.RolesInfo{
|
||||
{
|
||||
OrganizationID: "org1",
|
||||
OrganizationDomain: "example-org1.com",
|
||||
},
|
||||
{
|
||||
OrganizationID: "org2",
|
||||
OrganizationDomain: "example-org2.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -6791,7 +6804,7 @@ func TestCommands_UpdateOrgZitadelIDP(t *testing.T) {
|
||||
Issuer: "new issuer",
|
||||
ClientID: "clientID2",
|
||||
ClientSecret: "newSecret",
|
||||
Scopes: nil,
|
||||
Scopes: []string{openid.ScopeOpenID, openid.ScopeEmail},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
|
||||
@@ -752,6 +752,48 @@ func (i *Instance) AddOrgGenericOAuthProvider(ctx context.Context, name string)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) AddZitadelProvider(ctx context.Context, name string) *admin.AddZitadelProviderResponse {
|
||||
resp, err := i.Client.Admin.AddZitadelProvider(ctx, &admin.AddZitadelProviderRequest{
|
||||
Name: name,
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
ClientSecret: "test-secret",
|
||||
Scopes: []string{"email", "profile"},
|
||||
ProviderOptions: &idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
InstanceRolesInfo: []*idp.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
})
|
||||
logging.OnError(err).Panic("create zitadel idp")
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) AddOrgZitadelProvider(ctx context.Context, name string) *mgmt.AddZitadelProviderResponse {
|
||||
resp, err := i.Client.Mgmt.AddZitadelProvider(ctx, &mgmt.AddZitadelProviderRequest{
|
||||
Name: name,
|
||||
Issuer: "zitadel.example.com",
|
||||
ClientId: "test-client",
|
||||
ClientSecret: "test-secret",
|
||||
Scopes: []string{"email", "profile"},
|
||||
ProviderOptions: &idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
},
|
||||
InstanceRolesInfo: []*idp.InstanceRolesInfo{
|
||||
{
|
||||
OrganizationId: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
})
|
||||
logging.OnError(err).Panic("create org zitadel idp")
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) AddGenericOIDCProvider(ctx context.Context, name string) *admin.AddGenericOIDCProviderResponse {
|
||||
resp, err := i.Client.Admin.AddGenericOIDCProvider(ctx, &admin.AddGenericOIDCProviderRequest{
|
||||
Name: name,
|
||||
|
||||
@@ -47,6 +47,7 @@ type IDPTemplate struct {
|
||||
*LDAPIDPTemplate
|
||||
*AppleIDPTemplate
|
||||
*SAMLIDPTemplate
|
||||
*ZitadelIDPTemplate
|
||||
}
|
||||
|
||||
type IDPTemplates struct {
|
||||
@@ -170,6 +171,15 @@ type SAMLIDPTemplate struct {
|
||||
FederatedLogoutEnabled bool
|
||||
}
|
||||
|
||||
type ZitadelIDPTemplate struct {
|
||||
IDPID string
|
||||
ClientID string
|
||||
ClientSecret *crypto.CryptoValue
|
||||
Issuer string
|
||||
Scopes database.TextArray[string]
|
||||
InstanceRolesInfo database.JSONArray[idp.RolesInfo]
|
||||
}
|
||||
|
||||
var (
|
||||
idpTemplateTable = table{
|
||||
name: projection.IDPTemplateTable,
|
||||
@@ -741,6 +751,41 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
zitadelIdpTemplateTable = table{
|
||||
name: projection.IDPTemplateZitadelTable,
|
||||
instanceIDCol: projection.ZitadelInstanceIDCol,
|
||||
}
|
||||
ZitadelIDCol = Column{
|
||||
name: projection.ZitadelIDCol,
|
||||
table: zitadelIdpTemplateTable,
|
||||
}
|
||||
ZitadelInstanceIDCol = Column{
|
||||
name: projection.ZitadelInstanceIDCol,
|
||||
table: zitadelIdpTemplateTable,
|
||||
}
|
||||
ZitadelIssuerCol = Column{
|
||||
name: projection.ZitadelIssuerCol,
|
||||
table: zitadelIdpTemplateTable,
|
||||
}
|
||||
ZitadelClientIDCol = Column{
|
||||
name: projection.ZitadelClientIDCol,
|
||||
table: zitadelIdpTemplateTable,
|
||||
}
|
||||
ZitadelClientSecretCol = Column{
|
||||
name: projection.ZitadelClientSecretCol,
|
||||
table: zitadelIdpTemplateTable,
|
||||
}
|
||||
ZitadelScopesCol = Column{
|
||||
name: projection.ZitadelScopesCol,
|
||||
table: zitadelIdpTemplateTable,
|
||||
}
|
||||
ZitadelInstanceRolesInfoCol = Column{
|
||||
name: projection.ZitadelInstanceRolesInfoCol,
|
||||
table: zitadelIdpTemplateTable,
|
||||
}
|
||||
)
|
||||
|
||||
// IDPTemplateByID searches for the requested id with permission check if necessary
|
||||
func (q *Queries) IDPTemplateByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool, permissionCheck domain.PermissionCheck, queries ...SearchQuery) (template *IDPTemplate, err error) {
|
||||
idp, err := q.idpTemplateByID(ctx, shouldTriggerBulk, id, withOwnerRemoved, queries...)
|
||||
@@ -998,6 +1043,13 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
AppleKeyIDCol.identifier(),
|
||||
ApplePrivateKeyCol.identifier(),
|
||||
AppleScopesCol.identifier(),
|
||||
// zitadel
|
||||
ZitadelIDCol.identifier(),
|
||||
ZitadelIssuerCol.identifier(),
|
||||
ZitadelClientIDCol.identifier(),
|
||||
ZitadelClientSecretCol.identifier(),
|
||||
ZitadelScopesCol.identifier(),
|
||||
ZitadelInstanceRolesInfoCol.identifier(),
|
||||
).From(idpTemplateTable.identifier()).
|
||||
LeftJoin(join(OAuthIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(OIDCIDCol, IDPTemplateIDCol)).
|
||||
@@ -1011,6 +1063,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
LeftJoin(join(SAMLIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(AppleIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(ZitadelIDCol, IDPTemplateIDCol)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*IDPTemplate, error) {
|
||||
idpTemplate := new(IDPTemplate)
|
||||
@@ -1121,6 +1174,13 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
applePrivateKey := new(crypto.CryptoValue)
|
||||
appleScopes := database.TextArray[string]{}
|
||||
|
||||
zitadelID := sql.NullString{}
|
||||
zitadelClientID := sql.NullString{}
|
||||
zitadelClientSecret := new(crypto.CryptoValue)
|
||||
zitadelIssuer := sql.NullString{}
|
||||
zitadelScopes := database.TextArray[string]{}
|
||||
zitadelInstanceRolesInfo := database.JSONArray[idp.RolesInfo]{}
|
||||
|
||||
err := row.Scan(
|
||||
&idpTemplate.ID,
|
||||
&idpTemplate.ResourceOwner,
|
||||
@@ -1240,6 +1300,13 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
&appleKeyID,
|
||||
&applePrivateKey,
|
||||
&appleScopes,
|
||||
// zitadel
|
||||
&zitadelID,
|
||||
&zitadelIssuer,
|
||||
&zitadelClientID,
|
||||
&zitadelClientSecret,
|
||||
&zitadelScopes,
|
||||
&zitadelInstanceRolesInfo,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
@@ -1392,7 +1459,16 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
Scopes: appleScopes,
|
||||
}
|
||||
}
|
||||
|
||||
if zitadelID.Valid {
|
||||
idpTemplate.ZitadelIDPTemplate = &ZitadelIDPTemplate{
|
||||
IDPID: zitadelID.String,
|
||||
ClientID: zitadelClientID.String,
|
||||
ClientSecret: zitadelClientSecret,
|
||||
Issuer: zitadelIssuer.String,
|
||||
Scopes: zitadelScopes,
|
||||
InstanceRolesInfo: zitadelInstanceRolesInfo,
|
||||
}
|
||||
}
|
||||
return idpTemplate, nil
|
||||
}
|
||||
}
|
||||
@@ -1518,6 +1594,13 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
AppleKeyIDCol.identifier(),
|
||||
ApplePrivateKeyCol.identifier(),
|
||||
AppleScopesCol.identifier(),
|
||||
// zitadel
|
||||
ZitadelIDCol.identifier(),
|
||||
ZitadelIssuerCol.identifier(),
|
||||
ZitadelClientIDCol.identifier(),
|
||||
ZitadelClientSecretCol.identifier(),
|
||||
ZitadelScopesCol.identifier(),
|
||||
ZitadelInstanceRolesInfoCol.identifier(),
|
||||
// count
|
||||
countColumn.identifier(),
|
||||
).From(idpTemplateTable.identifier()).
|
||||
@@ -1533,6 +1616,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
LeftJoin(join(SAMLIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(AppleIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(ZitadelIDCol, IDPTemplateIDCol)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*IDPTemplates, error) {
|
||||
templates := make([]*IDPTemplate, 0)
|
||||
@@ -1646,6 +1730,13 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
applePrivateKey := new(crypto.CryptoValue)
|
||||
appleScopes := database.TextArray[string]{}
|
||||
|
||||
zitadelID := sql.NullString{}
|
||||
zitadelIssuer := sql.NullString{}
|
||||
zitadelClientID := sql.NullString{}
|
||||
zitadelClientSecret := new(crypto.CryptoValue)
|
||||
zitadelScopes := database.TextArray[string]{}
|
||||
zitadelInstanceRolesInfo := database.JSONArray[idp.RolesInfo]{}
|
||||
|
||||
err := rows.Scan(
|
||||
&idpTemplate.ID,
|
||||
&idpTemplate.ResourceOwner,
|
||||
@@ -1765,6 +1856,13 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
&appleKeyID,
|
||||
&applePrivateKey,
|
||||
&appleScopes,
|
||||
// zitadel
|
||||
&zitadelID,
|
||||
&zitadelIssuer,
|
||||
&zitadelClientID,
|
||||
&zitadelClientSecret,
|
||||
&zitadelScopes,
|
||||
&zitadelInstanceRolesInfo,
|
||||
&count,
|
||||
)
|
||||
|
||||
@@ -1916,6 +2014,16 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
Scopes: appleScopes,
|
||||
}
|
||||
}
|
||||
if zitadelID.Valid {
|
||||
idpTemplate.ZitadelIDPTemplate = &ZitadelIDPTemplate{
|
||||
IDPID: zitadelID.String,
|
||||
Issuer: zitadelIssuer.String,
|
||||
ClientID: zitadelClientID.String,
|
||||
ClientSecret: zitadelClientSecret,
|
||||
Scopes: zitadelScopes,
|
||||
InstanceRolesInfo: zitadelInstanceRolesInfo,
|
||||
}
|
||||
}
|
||||
templates = append(templates, idpTemplate)
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,14 @@ var (
|
||||
` projections.idp_templates6_apple.team_id,` +
|
||||
` projections.idp_templates6_apple.key_id,` +
|
||||
` projections.idp_templates6_apple.private_key,` +
|
||||
` projections.idp_templates6_apple.scopes` +
|
||||
` projections.idp_templates6_apple.scopes,` +
|
||||
// zitadel
|
||||
` projections.idp_templates6_zitadel.idp_id,` +
|
||||
` projections.idp_templates6_zitadel.issuer,` +
|
||||
` projections.idp_templates6_zitadel.client_id,` +
|
||||
` projections.idp_templates6_zitadel.client_secret,` +
|
||||
` projections.idp_templates6_zitadel.scopes,` +
|
||||
` projections.idp_templates6_zitadel.instance_roles_info` +
|
||||
` FROM projections.idp_templates6` +
|
||||
` LEFT JOIN projections.idp_templates6_oauth2 ON projections.idp_templates6.id = projections.idp_templates6_oauth2.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_oauth2.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_oidc ON projections.idp_templates6.id = projections.idp_templates6_oidc.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_oidc.instance_id` +
|
||||
@@ -146,7 +153,8 @@ var (
|
||||
` LEFT JOIN projections.idp_templates6_google ON projections.idp_templates6.id = projections.idp_templates6_google.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_google.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_saml ON projections.idp_templates6.id = projections.idp_templates6_saml.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_saml.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_ldap2 ON projections.idp_templates6.id = projections.idp_templates6_ldap2.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_ldap2.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_apple ON projections.idp_templates6.id = projections.idp_templates6_apple.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_apple.instance_id`
|
||||
` LEFT JOIN projections.idp_templates6_apple ON projections.idp_templates6.id = projections.idp_templates6_apple.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_apple.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_zitadel ON projections.idp_templates6.id = projections.idp_templates6_zitadel.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_zitadel.instance_id`
|
||||
idpTemplateCols = []string{
|
||||
"id",
|
||||
"resource_owner",
|
||||
@@ -266,6 +274,13 @@ var (
|
||||
"key_id",
|
||||
"private_key",
|
||||
"scopes",
|
||||
// zitadel config
|
||||
"idp_id",
|
||||
"issuer",
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"scopes",
|
||||
"instance_roles_info",
|
||||
}
|
||||
idpTemplatesQuery = `SELECT projections.idp_templates6.id,` +
|
||||
` projections.idp_templates6.resource_owner,` +
|
||||
@@ -385,6 +400,13 @@ var (
|
||||
` projections.idp_templates6_apple.key_id,` +
|
||||
` projections.idp_templates6_apple.private_key,` +
|
||||
` projections.idp_templates6_apple.scopes,` +
|
||||
// zitadel
|
||||
` projections.idp_templates6_zitadel.idp_id,` +
|
||||
` projections.idp_templates6_zitadel.issuer,` +
|
||||
` projections.idp_templates6_zitadel.client_id,` +
|
||||
` projections.idp_templates6_zitadel.client_secret,` +
|
||||
` projections.idp_templates6_zitadel.scopes,` +
|
||||
` projections.idp_templates6_zitadel.instance_roles_info,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.idp_templates6` +
|
||||
` LEFT JOIN projections.idp_templates6_oauth2 ON projections.idp_templates6.id = projections.idp_templates6_oauth2.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_oauth2.instance_id` +
|
||||
@@ -398,7 +420,8 @@ var (
|
||||
` LEFT JOIN projections.idp_templates6_google ON projections.idp_templates6.id = projections.idp_templates6_google.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_google.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_saml ON projections.idp_templates6.id = projections.idp_templates6_saml.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_saml.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_ldap2 ON projections.idp_templates6.id = projections.idp_templates6_ldap2.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_ldap2.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_apple ON projections.idp_templates6.id = projections.idp_templates6_apple.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_apple.instance_id`
|
||||
` LEFT JOIN projections.idp_templates6_apple ON projections.idp_templates6.id = projections.idp_templates6_apple.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_apple.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates6_zitadel ON projections.idp_templates6.id = projections.idp_templates6_zitadel.idp_id AND projections.idp_templates6.instance_id = projections.idp_templates6_zitadel.instance_id`
|
||||
idpTemplatesCols = []string{
|
||||
"id",
|
||||
"resource_owner",
|
||||
@@ -518,6 +541,14 @@ var (
|
||||
"key_id",
|
||||
"private_key",
|
||||
"scopes",
|
||||
// zitadel config
|
||||
"idp_id",
|
||||
"issuer",
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"scopes",
|
||||
"instance_roles_info",
|
||||
// count
|
||||
"count",
|
||||
}
|
||||
)
|
||||
@@ -677,6 +708,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -834,6 +872,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -989,6 +1034,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -1143,6 +1195,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -1295,6 +1354,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -1447,6 +1513,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -1600,6 +1673,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -1752,6 +1832,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -1910,6 +1997,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -2083,6 +2177,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
"key_id",
|
||||
nil,
|
||||
database.TextArray[string]{"profile"},
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -2111,6 +2212,172 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplateByIDQuery zitadel idp",
|
||||
prepare: prepareIDPTemplateByIDQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(idpTemplateQuery),
|
||||
idpTemplateCols,
|
||||
[]driver.Value{
|
||||
"idp-id",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeZitadel,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.AutoLinkingOptionUsername,
|
||||
// oauth
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// oidc
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// jwt
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// github
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// github enterprise
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// gitlab
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// gitlab self hosted
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// google
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// apple
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
"idp-id",
|
||||
"issuer",
|
||||
"client_id",
|
||||
nil,
|
||||
database.TextArray[string]{"profile"},
|
||||
[]byte(`[{"organizationId":"org1","organizationDomain":"org1.com"}]`),
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &IDPTemplate{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeZitadel,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
AutoLinking: domain.AutoLinkingOptionUsername,
|
||||
ZitadelIDPTemplate: &ZitadelIDPTemplate{
|
||||
IDPID: "idp-id",
|
||||
Issuer: "issuer",
|
||||
ClientID: "client_id",
|
||||
ClientSecret: nil,
|
||||
Scopes: []string{"profile"},
|
||||
InstanceRolesInfo: []idp.RolesInfo{
|
||||
{
|
||||
OrganizationID: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplateByIDQuery no config",
|
||||
prepare: prepareIDPTemplateByIDQuery,
|
||||
@@ -2237,6 +2504,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -2419,6 +2693,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -2601,6 +2882,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -2756,6 +3044,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-saml",
|
||||
@@ -2876,6 +3171,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-google",
|
||||
@@ -2996,6 +3298,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-oauth",
|
||||
@@ -3116,6 +3425,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-oidc",
|
||||
@@ -3236,6 +3552,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-jwt",
|
||||
@@ -3356,13 +3679,147 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-zitadel",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeZitadel,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.AutoLinkingOptionUsername,
|
||||
// oauth
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// oidc
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// jwt
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// github
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// github enterprise
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// gitlab
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// gitlab self hosted
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// google
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// saml
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// apple
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// zitadel
|
||||
"idp-id-zitadel",
|
||||
"issuer",
|
||||
"client_id",
|
||||
nil,
|
||||
database.TextArray[string]{"profile"},
|
||||
[]byte(`[{"organizationId":"org1","organizationDomain":"org1.com"}]`),
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &IDPTemplates{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 6,
|
||||
Count: 7,
|
||||
},
|
||||
Templates: []*IDPTemplate{
|
||||
{
|
||||
@@ -3458,7 +3915,6 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
Scopes: []string{"profile"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
@@ -3535,6 +3991,35 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
Audience: "audience",
|
||||
},
|
||||
},
|
||||
{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id-zitadel",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeZitadel,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
AutoLinking: domain.AutoLinkingOptionUsername,
|
||||
ZitadelIDPTemplate: &ZitadelIDPTemplate{
|
||||
IDPID: "idp-id-zitadel",
|
||||
Issuer: "issuer",
|
||||
ClientID: "client_id",
|
||||
ClientSecret: nil,
|
||||
Scopes: []string{"profile"},
|
||||
InstanceRolesInfo: []idp.RolesInfo{
|
||||
{
|
||||
OrganizationID: "org1",
|
||||
OrganizationDomain: "org1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -274,6 +274,7 @@ enum ProviderType {
|
||||
PROVIDER_TYPE_GOOGLE = 10;
|
||||
PROVIDER_TYPE_APPLE = 11;
|
||||
PROVIDER_TYPE_SAML = 12;
|
||||
PROVIDER_TYPE_ZITADEL = 13;
|
||||
}
|
||||
|
||||
enum SAMLBinding {
|
||||
@@ -312,6 +313,7 @@ message ProviderConfig {
|
||||
AzureADConfig azure_ad = 11;
|
||||
AppleConfig apple = 12;
|
||||
SAMLConfig saml = 13;
|
||||
ZitadelConfig zitadel = 14;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,6 +527,32 @@ message AzureADConfig {
|
||||
];
|
||||
}
|
||||
|
||||
message ZitadelConfig {
|
||||
string issuer = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"https://zitadel.example.com/\"";
|
||||
description: "the OIDC issuer of the identity provider";
|
||||
}
|
||||
];
|
||||
string client_id = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
description: "client id generated by the identity provider";
|
||||
}
|
||||
];
|
||||
repeated string scopes = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\"]";
|
||||
description: "the scopes requested by Zitadel during the request to the identity provider";
|
||||
}
|
||||
];
|
||||
repeated zitadel.idp.v1.InstanceRolesInfo instance_roles_info = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "the information about the organization and domain of the instance roles";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message Options {
|
||||
bool is_linking_allowed = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
|
||||
@@ -55,6 +55,7 @@ enum IDPType {
|
||||
IDP_TYPE_GOOGLE = 10;
|
||||
IDP_TYPE_APPLE = 11;
|
||||
IDP_TYPE_SAML = 12;
|
||||
IDP_TYPE_ZITADEL = 13;
|
||||
}
|
||||
|
||||
enum SAMLBinding {
|
||||
@@ -93,6 +94,7 @@ message IDPConfig {
|
||||
AzureADConfig azure_ad = 11;
|
||||
AppleConfig apple = 12;
|
||||
SAMLConfig saml = 13;
|
||||
ZitadelConfig zitadel = 14;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,3 +441,49 @@ message AppleConfig {
|
||||
"[\"name\", \"email\"]";
|
||||
} ];
|
||||
}
|
||||
|
||||
message InstanceRolesInfo {
|
||||
string organization_id = 1
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example:
|
||||
"\"69629023906488334\"";
|
||||
description:
|
||||
"the id of the organization";
|
||||
} ];
|
||||
string organization_domain = 2
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example:
|
||||
"\"example-org.com\"";
|
||||
description:
|
||||
"the domain of the organization";
|
||||
} ];
|
||||
}
|
||||
|
||||
message ZitadelConfig {
|
||||
string issuer = 1
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example:
|
||||
"\"https://zitadel.example.com/\"";
|
||||
description:
|
||||
"the OIDC issuer of the identity provider";
|
||||
} ];
|
||||
string client_id = 2
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example:
|
||||
"\"client-id\"";
|
||||
description:
|
||||
"client id generated by the identity provider";
|
||||
} ];
|
||||
repeated string scopes = 3
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example:
|
||||
"[\"openid\", \"profile\", \"email\"]";
|
||||
description:
|
||||
"the scopes requested by Zitadel during the request to the identity provider";
|
||||
} ];
|
||||
repeated InstanceRolesInfo instance_roles_info = 4
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description:
|
||||
"the information about the organization and domain of the instance roles";
|
||||
} ];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user