mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:47:33 +00:00
feat: implement user schema management (#7416)
This PR adds the functionality to manage user schemas through the new user schema service. It includes the possibility to create a basic JSON schema and also provides a way on defining permissions (read, write) for owner and self context with an annotation. Further annotations for OIDC claims and SAML attribute mappings will follow. A guide on how to create a schema and assign permissions has been started. It will be extended though out the process of implementing the schema and users based on those. Note: This feature is in an early stage and therefore not enabled by default. To test it out, please enable the UserSchema feature flag on your instance / system though the feature service.
This commit is contained in:
@@ -13,6 +13,7 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) *command.
|
||||
LoginDefaultOrg: req.LoginDefaultOrg,
|
||||
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
|
||||
LegacyIntrospection: req.OidcLegacyIntrospection,
|
||||
UserSchema: req.UserSchema,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +23,7 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
|
||||
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
|
||||
OidcTriggerIntrospectionProjections: featureSourceToFlagPb(&f.TriggerIntrospectionProjections),
|
||||
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
|
||||
UserSchema: featureSourceToFlagPb(&f.UserSchema),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +32,7 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
|
||||
LoginDefaultOrg: req.LoginDefaultOrg,
|
||||
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
|
||||
LegacyIntrospection: req.OidcLegacyIntrospection,
|
||||
UserSchema: req.UserSchema,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +42,7 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
|
||||
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
|
||||
OidcTriggerIntrospectionProjections: featureSourceToFlagPb(&f.TriggerIntrospectionProjections),
|
||||
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
|
||||
UserSchema: featureSourceToFlagPb(&f.UserSchema),
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -21,11 +21,13 @@ func Test_systemFeaturesToCommand(t *testing.T) {
|
||||
LoginDefaultOrg: gu.Ptr(true),
|
||||
OidcTriggerIntrospectionProjections: gu.Ptr(false),
|
||||
OidcLegacyIntrospection: nil,
|
||||
UserSchema: gu.Ptr(true),
|
||||
}
|
||||
want := &command.SystemFeatures{
|
||||
LoginDefaultOrg: gu.Ptr(true),
|
||||
TriggerIntrospectionProjections: gu.Ptr(false),
|
||||
LegacyIntrospection: nil,
|
||||
UserSchema: gu.Ptr(true),
|
||||
}
|
||||
got := systemFeaturesToCommand(arg)
|
||||
assert.Equal(t, want, got)
|
||||
@@ -50,6 +52,10 @@ func Test_systemFeaturesToPb(t *testing.T) {
|
||||
Level: feature.LevelSystem,
|
||||
Value: true,
|
||||
},
|
||||
UserSchema: query.FeatureSource[bool]{
|
||||
Level: feature.LevelSystem,
|
||||
Value: true,
|
||||
},
|
||||
}
|
||||
want := &feature_pb.GetSystemFeaturesResponse{
|
||||
Details: &object.Details{
|
||||
@@ -69,6 +75,10 @@ func Test_systemFeaturesToPb(t *testing.T) {
|
||||
Enabled: true,
|
||||
Source: feature_pb.Source_SOURCE_SYSTEM,
|
||||
},
|
||||
UserSchema: &feature_pb.FeatureFlag{
|
||||
Enabled: true,
|
||||
Source: feature_pb.Source_SOURCE_SYSTEM,
|
||||
},
|
||||
}
|
||||
got := systemFeaturesToPb(arg)
|
||||
assert.Equal(t, want, got)
|
||||
@@ -79,11 +89,13 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
|
||||
LoginDefaultOrg: gu.Ptr(true),
|
||||
OidcTriggerIntrospectionProjections: gu.Ptr(false),
|
||||
OidcLegacyIntrospection: nil,
|
||||
UserSchema: gu.Ptr(true),
|
||||
}
|
||||
want := &command.InstanceFeatures{
|
||||
LoginDefaultOrg: gu.Ptr(true),
|
||||
TriggerIntrospectionProjections: gu.Ptr(false),
|
||||
LegacyIntrospection: nil,
|
||||
UserSchema: gu.Ptr(true),
|
||||
}
|
||||
got := instanceFeaturesToCommand(arg)
|
||||
assert.Equal(t, want, got)
|
||||
@@ -108,6 +120,10 @@ func Test_instanceFeaturesToPb(t *testing.T) {
|
||||
Level: feature.LevelInstance,
|
||||
Value: true,
|
||||
},
|
||||
UserSchema: query.FeatureSource[bool]{
|
||||
Level: feature.LevelInstance,
|
||||
Value: true,
|
||||
},
|
||||
}
|
||||
want := &feature_pb.GetInstanceFeaturesResponse{
|
||||
Details: &object.Details{
|
||||
@@ -127,6 +143,10 @@ func Test_instanceFeaturesToPb(t *testing.T) {
|
||||
Enabled: true,
|
||||
Source: feature_pb.Source_SOURCE_INSTANCE,
|
||||
},
|
||||
UserSchema: &feature_pb.FeatureFlag{
|
||||
Enabled: true,
|
||||
Source: feature_pb.Source_SOURCE_INSTANCE,
|
||||
},
|
||||
}
|
||||
got := instanceFeaturesToPb(arg)
|
||||
assert.Equal(t, want, got)
|
||||
|
@@ -218,6 +218,7 @@ func TestServer_GetSystemFeatures(t *testing.T) {
|
||||
assertFeatureFlag(t, tt.want.LoginDefaultOrg, got.LoginDefaultOrg)
|
||||
assertFeatureFlag(t, tt.want.OidcTriggerIntrospectionProjections, got.OidcTriggerIntrospectionProjections)
|
||||
assertFeatureFlag(t, tt.want.OidcLegacyIntrospection, got.OidcLegacyIntrospection)
|
||||
assertFeatureFlag(t, tt.want.UserSchema, got.UserSchema)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -384,6 +385,10 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
|
||||
Enabled: true,
|
||||
Source: feature.Source_SOURCE_SYSTEM,
|
||||
},
|
||||
UserSchema: &feature.FeatureFlag{
|
||||
Enabled: false,
|
||||
Source: feature.Source_SOURCE_UNSPECIFIED,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -392,6 +397,7 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
|
||||
_, err := Client.SetInstanceFeatures(IamCTX, &feature.SetInstanceFeaturesRequest{
|
||||
LoginDefaultOrg: gu.Ptr(true),
|
||||
OidcTriggerIntrospectionProjections: gu.Ptr(false),
|
||||
UserSchema: gu.Ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
@@ -408,6 +414,10 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
|
||||
Enabled: false,
|
||||
Source: feature.Source_SOURCE_INSTANCE,
|
||||
},
|
||||
UserSchema: &feature.FeatureFlag{
|
||||
Enabled: true,
|
||||
Source: feature.Source_SOURCE_INSTANCE,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -437,6 +447,10 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
|
||||
Enabled: true,
|
||||
Source: feature.Source_SOURCE_SYSTEM,
|
||||
},
|
||||
UserSchema: &feature.FeatureFlag{
|
||||
Enabled: false,
|
||||
Source: feature.Source_SOURCE_UNSPECIFIED,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -459,6 +473,7 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
|
||||
assertFeatureFlag(t, tt.want.LoginDefaultOrg, got.LoginDefaultOrg)
|
||||
assertFeatureFlag(t, tt.want.OidcTriggerIntrospectionProjections, got.OidcTriggerIntrospectionProjections)
|
||||
assertFeatureFlag(t, tt.want.OidcLegacyIntrospection, got.OidcLegacyIntrospection)
|
||||
assertFeatureFlag(t, tt.want.UserSchema, got.UserSchema)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
150
internal/api/grpc/user/schema/v3alpha/schema.go
Normal file
150
internal/api/grpc/user/schema/v3alpha/schema.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/user/schema/v3alpha"
|
||||
)
|
||||
|
||||
func (s *Server) CreateUserSchema(ctx context.Context, req *schema.CreateUserSchemaRequest) (*schema.CreateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchema, err := createUserSchemaToCommand(req, authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, details, err := s.command.CreateUserSchema(ctx, userSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.CreateUserSchemaResponse{
|
||||
Id: id,
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateUserSchema(ctx context.Context, req *schema.UpdateUserSchemaRequest) (*schema.UpdateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchema, err := updateUserSchemaToCommand(req, authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.UpdateUserSchema(ctx, userSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.UpdateUserSchemaResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
func (s *Server) DeactivateUserSchema(ctx context.Context, req *schema.DeactivateUserSchemaRequest) (*schema.DeactivateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.DeactivateUserSchema(ctx, req.GetId(), authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.DeactivateUserSchemaResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
func (s *Server) ReactivateUserSchema(ctx context.Context, req *schema.ReactivateUserSchemaRequest) (*schema.ReactivateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.ReactivateUserSchema(ctx, req.GetId(), authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.ReactivateUserSchemaResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
func (s *Server) DeleteUserSchema(ctx context.Context, req *schema.DeleteUserSchemaRequest) (*schema.DeleteUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.DeleteUserSchema(ctx, req.GetId(), authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.DeleteUserSchemaResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func checkUserSchemaEnabled(ctx context.Context) error {
|
||||
if authz.GetInstance(ctx).Features().UserSchema {
|
||||
return nil
|
||||
}
|
||||
return zerrors.ThrowPreconditionFailed(nil, "SCHEMA-SFjk3", "Errors.UserSchema.NotEnabled")
|
||||
}
|
||||
|
||||
func createUserSchemaToCommand(req *schema.CreateUserSchemaRequest, resourceOwner string) (*command.CreateUserSchema, error) {
|
||||
schema, err := req.GetSchema().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &command.CreateUserSchema{
|
||||
ResourceOwner: resourceOwner,
|
||||
Type: req.GetType(),
|
||||
Schema: schema,
|
||||
PossibleAuthenticators: authenticatorsToDomain(req.GetPossibleAuthenticators()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func updateUserSchemaToCommand(req *schema.UpdateUserSchemaRequest, resourceOwner string) (*command.UpdateUserSchema, error) {
|
||||
schema, err := req.GetSchema().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &command.UpdateUserSchema{
|
||||
ID: req.GetId(),
|
||||
ResourceOwner: resourceOwner,
|
||||
Type: req.Type,
|
||||
Schema: schema,
|
||||
PossibleAuthenticators: authenticatorsToDomain(req.GetPossibleAuthenticators()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func authenticatorsToDomain(authenticators []schema.AuthenticatorType) []domain.AuthenticatorType {
|
||||
types := make([]domain.AuthenticatorType, len(authenticators))
|
||||
for i, authenticator := range authenticators {
|
||||
types[i] = authenticatorTypeToDomain(authenticator)
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
func authenticatorTypeToDomain(authenticator schema.AuthenticatorType) domain.AuthenticatorType {
|
||||
switch authenticator {
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED:
|
||||
return domain.AuthenticatorTypeUnspecified
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME:
|
||||
return domain.AuthenticatorTypeUsername
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_PASSWORD:
|
||||
return domain.AuthenticatorTypePassword
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_WEBAUTHN:
|
||||
return domain.AuthenticatorTypeWebAuthN
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_TOTP:
|
||||
return domain.AuthenticatorTypeTOTP
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_EMAIL:
|
||||
return domain.AuthenticatorTypeOTPEmail
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_SMS:
|
||||
return domain.AuthenticatorTypeOTPSMS
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_AUTHENTICATION_KEY:
|
||||
return domain.AuthenticatorTypeAuthenticationKey
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_IDENTITY_PROVIDER:
|
||||
return domain.AuthenticatorTypeIdentityProvider
|
||||
default:
|
||||
return domain.AuthenticatorTypeUnspecified
|
||||
}
|
||||
}
|
812
internal/api/grpc/user/schema/v3alpha/schema_integration_test.go
Normal file
812
internal/api/grpc/user/schema/v3alpha/schema_integration_test.go
Normal file
@@ -0,0 +1,812 @@
|
||||
//go:build integration
|
||||
|
||||
package schema_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/user/schema/v3alpha"
|
||||
)
|
||||
|
||||
var (
|
||||
CTX context.Context
|
||||
Tester *integration.Tester
|
||||
Client schema.UserSchemaServiceClient
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(func() int {
|
||||
ctx, _, cancel := integration.Contexts(5 * time.Minute)
|
||||
defer cancel()
|
||||
|
||||
Tester = integration.NewTester(ctx)
|
||||
defer Tester.Done()
|
||||
|
||||
CTX = Tester.WithAuthorization(ctx, integration.IAMOwner)
|
||||
Client = Tester.Client.UserSchemaV3
|
||||
|
||||
return m.Run()
|
||||
}())
|
||||
}
|
||||
|
||||
func ensureFeatureEnabled(t *testing.T) {
|
||||
f, err := Tester.Client.FeatureV2.GetInstanceFeatures(CTX, &feature.GetInstanceFeaturesRequest{
|
||||
Inheritance: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
if f.UserSchema.GetEnabled() {
|
||||
return
|
||||
}
|
||||
_, err = Tester.Client.FeatureV2.SetInstanceFeatures(CTX, &feature.SetInstanceFeaturesRequest{
|
||||
UserSchema: gu.Ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
retryDuration := time.Minute
|
||||
if ctxDeadline, ok := CTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
require.EventuallyWithT(t,
|
||||
func(ttt *assert.CollectT) {
|
||||
f, err := Tester.Client.FeatureV2.GetInstanceFeatures(CTX, &feature.GetInstanceFeaturesRequest{
|
||||
Inheritance: true,
|
||||
})
|
||||
require.NoError(ttt, err)
|
||||
if f.UserSchema.GetEnabled() {
|
||||
return
|
||||
}
|
||||
},
|
||||
retryDuration,
|
||||
100*time.Millisecond,
|
||||
"timed out waiting for ensuring instance feature")
|
||||
}
|
||||
|
||||
func TestServer_CreateUserSchema(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
req *schema.CreateUserSchemaRequest
|
||||
want *schema.CreateUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission, error",
|
||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty type",
|
||||
ctx: CTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: "",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty schema, error",
|
||||
ctx: CTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid schema, error",
|
||||
ctx: CTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||
DataType: &schema.CreateUserSchemaRequest_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no authenticators, ok",
|
||||
ctx: CTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||
DataType: &schema.CreateUserSchemaRequest_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
want: &schema.CreateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid authenticator, error",
|
||||
ctx: CTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||
DataType: &schema.CreateUserSchemaRequest_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED,
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "with authenticator, ok",
|
||||
ctx: CTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||
DataType: &schema.CreateUserSchemaRequest_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME,
|
||||
},
|
||||
},
|
||||
want: &schema.CreateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with invalid permission, error",
|
||||
ctx: CTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||
DataType: &schema.CreateUserSchemaRequest_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"urn:zitadel:schema:permission": "read"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME,
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "with valid permission, ok",
|
||||
ctx: CTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
Type: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||
DataType: &schema.CreateUserSchemaRequest_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"urn:zitadel:schema:permission": {
|
||||
"owner": "rw",
|
||||
"self": "r"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME,
|
||||
},
|
||||
},
|
||||
want: &schema.CreateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ensureFeatureEnabled(t)
|
||||
got, err := Client.CreateUserSchema(tt.ctx, tt.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
assert.NotEmpty(t, got.GetId())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_UpdateUserSchema(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.UpdateUserSchemaRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
prepare func(request *schema.UpdateUserSchemaRequest) error
|
||||
args args
|
||||
want *schema.UpdateUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission, error",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
Type: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "missing id, error",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "not existing, error",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
request.Id = "notexisting"
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty type, error",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
Type: gu.Ptr(""),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update type, ok",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
Type: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)),
|
||||
},
|
||||
},
|
||||
want: &schema.UpdateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty schema, ok",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
DataType: &schema.UpdateUserSchemaRequest_Schema{},
|
||||
},
|
||||
},
|
||||
want: &schema.UpdateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid schema, error",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
DataType: &schema.UpdateUserSchemaRequest_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update schema, ok",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
DataType: &schema.UpdateUserSchemaRequest_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.UpdateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid authenticator, error",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update authenticator, ok",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.UpdateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inactive, error",
|
||||
prepare: func(request *schema.UpdateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
_, err := Client.DeactivateUserSchema(CTX, &schema.DeactivateUserSchemaRequest{
|
||||
Id: schemaID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.UpdateUserSchemaRequest{
|
||||
Type: gu.Ptr(fmt.Sprint(time.Now().UnixNano() + 1)),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ensureFeatureEnabled(t)
|
||||
err := tt.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.UpdateUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeactivateUserSchema(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.DeactivateUserSchemaRequest
|
||||
prepare func(request *schema.DeactivateUserSchemaRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.DeactivateUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "not existing, error",
|
||||
args: args{
|
||||
CTX,
|
||||
&schema.DeactivateUserSchemaRequest{
|
||||
Id: "notexisting",
|
||||
},
|
||||
func(request *schema.DeactivateUserSchemaRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "active, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&schema.DeactivateUserSchemaRequest{},
|
||||
func(request *schema.DeactivateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.DeactivateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inactive, error",
|
||||
args: args{
|
||||
CTX,
|
||||
&schema.DeactivateUserSchemaRequest{},
|
||||
func(request *schema.DeactivateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
_, err := Client.DeactivateUserSchema(CTX, &schema.DeactivateUserSchemaRequest{
|
||||
Id: schemaID,
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ensureFeatureEnabled(t)
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.DeactivateUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_ReactivateUserSchema(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.ReactivateUserSchemaRequest
|
||||
prepare func(request *schema.ReactivateUserSchemaRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.ReactivateUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "not existing, error",
|
||||
args: args{
|
||||
CTX,
|
||||
&schema.ReactivateUserSchemaRequest{
|
||||
Id: "notexisting",
|
||||
},
|
||||
func(request *schema.ReactivateUserSchemaRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "active, error",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.ReactivateUserSchemaRequest{},
|
||||
prepare: func(request *schema.ReactivateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "inactive, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.ReactivateUserSchemaRequest{},
|
||||
prepare: func(request *schema.ReactivateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
_, err := Client.DeactivateUserSchema(CTX, &schema.DeactivateUserSchemaRequest{
|
||||
Id: schemaID,
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &schema.ReactivateUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ensureFeatureEnabled(t)
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.ReactivateUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeleteUserSchema(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.DeleteUserSchemaRequest
|
||||
prepare func(request *schema.DeleteUserSchemaRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.DeleteUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "not existing, error",
|
||||
args: args{
|
||||
CTX,
|
||||
&schema.DeleteUserSchemaRequest{
|
||||
Id: "notexisting",
|
||||
},
|
||||
func(request *schema.DeleteUserSchemaRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "delete, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.DeleteUserSchemaRequest{},
|
||||
prepare: func(request *schema.DeleteUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.DeleteUserSchemaResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deleted, error",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.DeleteUserSchemaRequest{},
|
||||
prepare: func(request *schema.DeleteUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchema(CTX, t).GetId()
|
||||
request.Id = schemaID
|
||||
_, err := Client.DeleteUserSchema(CTX, &schema.DeleteUserSchemaRequest{
|
||||
Id: schemaID,
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ensureFeatureEnabled(t)
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.DeleteUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
51
internal/api/grpc/user/schema/v3alpha/server.go
Normal file
51
internal/api/grpc/user/schema/v3alpha/server.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/user/schema/v3alpha"
|
||||
)
|
||||
|
||||
var _ schema.UserSchemaServiceServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
schema.UnimplementedUserSchemaServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
}
|
||||
|
||||
type Config struct{}
|
||||
|
||||
func CreateServer(
|
||||
command *command.Commands,
|
||||
query *query.Queries,
|
||||
) *Server {
|
||||
return &Server{
|
||||
command: command,
|
||||
query: query,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
schema.RegisterUserSchemaServiceServer(grpcServer, s)
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
return schema.UserSchemaService_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) MethodPrefix() string {
|
||||
return schema.UserSchemaService_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return schema.UserSchemaService_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||
return schema.RegisterUserSchemaServiceHandler
|
||||
}
|
Reference in New Issue
Block a user