feat: impersonation roles (#7442)

* partial work done

* test IAM membership roles

* org membership tests

* console :(, translations and docs

* fix integration test

* fix tests

* add EnableImpersonation to security policy API

* fix integration test timestamp checking

* add security policy tests and fix projections

* add impersonation setting in console

* add security settings to the settings v2 API

* fix typo

* move impersonation to instance

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Tim Möhlmann
2024-02-28 12:21:11 +02:00
committed by GitHub
parent 68af4f59c9
commit 062d153cfe
60 changed files with 1624 additions and 144 deletions

View File

@@ -0,0 +1,34 @@
//go:build integration
package settings_test
import (
"context"
"os"
"testing"
"time"
"github.com/zitadel/zitadel/internal/integration"
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
)
var (
CTX, AdminCTX context.Context
Tester *integration.Tester
Client settings.SettingsServiceClient
)
func TestMain(m *testing.M) {
os.Exit(func() int {
ctx, _, cancel := integration.Contexts(3 * time.Minute)
defer cancel()
Tester = integration.NewTester(ctx)
defer Tester.Done()
CTX = ctx
AdminCTX = Tester.WithAuthorization(ctx, integration.IAMOwner)
Client = Tester.Client.SettingsV2
return m.Run()
}())
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/query"
object_pb "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
)
func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSettingsRequest) (*settings.GetLoginSettingsResponse, error) {
@@ -124,3 +124,23 @@ func (s *Server) GetGeneralSettings(ctx context.Context, _ *settings.GetGeneralS
DefaultLanguage: instance.DefaultLanguage().String(),
}, nil
}
func (s *Server) GetSecuritySettings(ctx context.Context, req *settings.GetSecuritySettingsRequest) (*settings.GetSecuritySettingsResponse, error) {
policy, err := s.query.SecurityPolicy(ctx)
if err != nil {
return nil, err
}
return &settings.GetSecuritySettingsResponse{
Settings: securityPolicyToSettingsPb(policy),
}, nil
}
func (s *Server) SetSecuritySettings(ctx context.Context, req *settings.SetSecuritySettingsRequest) (*settings.SetSecuritySettingsResponse, error) {
details, err := s.command.SetSecurityPolicy(ctx, securitySettingsToCommand(req))
if err != nil {
return nil, err
}
return &settings.SetSecuritySettingsResponse{
Details: object.DomainToDetailsPb(details),
}, nil
}

View File

@@ -3,6 +3,7 @@ package settings
import (
"google.golang.org/protobuf/types/known/durationpb"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
@@ -205,3 +206,21 @@ func idpTypeToPb(idpType domain.IDPType) settings.IdentityProviderType {
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_UNSPECIFIED
}
}
func securityPolicyToSettingsPb(policy *query.SecurityPolicy) *settings.SecuritySettings {
return &settings.SecuritySettings{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
Enabled: policy.EnableIframeEmbedding,
AllowedOrigins: policy.AllowedOrigins,
},
EnableImpersonation: policy.EnableImpersonation,
}
}
func securitySettingsToCommand(req *settings.SetSecuritySettingsRequest) *command.SecurityPolicy {
return &command.SecurityPolicy{
EnableIframeEmbedding: req.GetEmbeddedIframe().GetEnabled(),
AllowedOrigins: req.GetEmbeddedIframe().GetAllowedOrigins(),
EnableImpersonation: req.GetEnableImpersonation(),
}
}

View File

@@ -12,6 +12,7 @@ import (
"google.golang.org/protobuf/types/known/durationpb"
"github.com/zitadel/zitadel/internal/api/grpc"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
@@ -450,3 +451,35 @@ func Test_idpTypeToPb(t *testing.T) {
})
}
}
func Test_securityPolicyToSettingsPb(t *testing.T) {
want := &settings.SecuritySettings{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
Enabled: true,
AllowedOrigins: []string{"foo", "bar"},
},
EnableImpersonation: true,
}
got := securityPolicyToSettingsPb(&query.SecurityPolicy{
EnableIframeEmbedding: true,
AllowedOrigins: []string{"foo", "bar"},
EnableImpersonation: true,
})
assert.Equal(t, want, got)
}
func Test_securitySettingsToCommand(t *testing.T) {
want := &command.SecurityPolicy{
EnableIframeEmbedding: true,
AllowedOrigins: []string{"foo", "bar"},
EnableImpersonation: true,
}
got := securitySettingsToCommand(&settings.SetSecuritySettingsRequest{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
Enabled: true,
AllowedOrigins: []string{"foo", "bar"},
},
EnableImpersonation: true,
})
assert.Equal(t, want, got)
}

View File

@@ -0,0 +1,174 @@
//go:build integration
package settings_test
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/integration"
object_pb "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
)
func TestServer_GetSecuritySettings(t *testing.T) {
_, err := Client.SetSecuritySettings(AdminCTX, &settings.SetSecuritySettingsRequest{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
Enabled: true,
AllowedOrigins: []string{"foo", "bar"},
},
EnableImpersonation: true,
})
require.NoError(t, err)
tests := []struct {
name string
ctx context.Context
want *settings.GetSecuritySettingsResponse
wantErr bool
}{
{
name: "permission error",
ctx: Tester.WithAuthorization(CTX, integration.OrgOwner),
wantErr: true,
},
{
name: "success",
ctx: AdminCTX,
want: &settings.GetSecuritySettingsResponse{
Settings: &settings.SecuritySettings{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
Enabled: true,
AllowedOrigins: []string{"foo", "bar"},
},
EnableImpersonation: true,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resp, err := Client.GetSecuritySettings(tt.ctx, &settings.GetSecuritySettingsRequest{})
if tt.wantErr {
assert.Error(t, err)
return
}
require.NoError(t, err)
got, want := resp.GetSettings(), tt.want.GetSettings()
assert.Equal(t, want.GetEmbeddedIframe().GetEnabled(), got.GetEmbeddedIframe().GetEnabled(), "enable iframe embedding")
assert.Equal(t, want.GetEmbeddedIframe().GetAllowedOrigins(), got.GetEmbeddedIframe().GetAllowedOrigins(), "allowed origins")
assert.Equal(t, want.GetEnableImpersonation(), got.GetEnableImpersonation(), "enable impersonation")
})
}
}
func TestServer_SetSecuritySettings(t *testing.T) {
type args struct {
ctx context.Context
req *settings.SetSecuritySettingsRequest
}
tests := []struct {
name string
args args
want *settings.SetSecuritySettingsResponse
wantErr bool
}{
{
name: "permission error",
args: args{
ctx: Tester.WithAuthorization(CTX, integration.OrgOwner),
req: &settings.SetSecuritySettingsRequest{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
Enabled: true,
AllowedOrigins: []string{"foo.com", "bar.com"},
},
EnableImpersonation: true,
},
},
wantErr: true,
},
{
name: "success allowed origins",
args: args{
ctx: AdminCTX,
req: &settings.SetSecuritySettingsRequest{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
AllowedOrigins: []string{"foo.com", "bar.com"},
},
},
},
want: &settings.SetSecuritySettingsResponse{
Details: &object_pb.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(),
},
},
},
{
name: "success enable iframe embedding",
args: args{
ctx: AdminCTX,
req: &settings.SetSecuritySettingsRequest{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
Enabled: true,
},
},
},
want: &settings.SetSecuritySettingsResponse{
Details: &object_pb.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(),
},
},
},
{
name: "success impersonation",
args: args{
ctx: AdminCTX,
req: &settings.SetSecuritySettingsRequest{
EnableImpersonation: true,
},
},
want: &settings.SetSecuritySettingsResponse{
Details: &object_pb.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(),
},
},
},
{
name: "success all",
args: args{
ctx: AdminCTX,
req: &settings.SetSecuritySettingsRequest{
EmbeddedIframe: &settings.EmbeddedIframeSettings{
Enabled: true,
AllowedOrigins: []string{"foo.com", "bar.com"},
},
EnableImpersonation: true,
},
},
want: &settings.SetSecuritySettingsResponse{
Details: &object_pb.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(),
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Client.SetSecuritySettings(tt.args.ctx, tt.args.req)
if tt.wantErr {
assert.Error(t, err)
return
}
require.NoError(t, err)
integration.AssertDetails(t, tt.want, got)
})
}
}