mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 19:07:30 +00:00
feat: add custom org ID to AddOrganizationRequest (#9720)
# Which Problems Are Solved - It is not possible to specify a custom organization ID when creating an organization. According to https://github.com/zitadel/zitadel/discussions/9202#discussioncomment-11929464 this is "an inconsistency in the V2 API". # How the Problems Are Solved - Adds the `org_id` as an optional parameter to the `AddOrganizationRequest` in the `v2beta` API. # Additional Changes None. # Additional Context - Discussion [#9202](https://github.com/zitadel/zitadel/discussions/9202) - I was mostly interested in how much work it'd be to add this field. Then after completing this, I thought I'd submit this PR. I won't be angry if you just close this PR with the reasoning "we didn't ask for it". 😄 - Even though I don't think this is a breaking change, I didn't add this to the `v2` API yet (don't know what the process for this is TBH). The changes should be analogous, so if you want me to, just request it. --------- Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
This commit is contained in:
@@ -81,6 +81,18 @@ func TestServer_AddOrganization(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "no admin, custom org ID",
|
||||||
|
ctx: CTX,
|
||||||
|
req: &org.AddOrganizationRequest{
|
||||||
|
Name: gofakeit.AppName(),
|
||||||
|
OrgId: gu.Ptr("custom-org-ID"),
|
||||||
|
},
|
||||||
|
want: &org.AddOrganizationResponse{
|
||||||
|
OrganizationId: "custom-org-ID",
|
||||||
|
CreatedAdmins: []*org.AddOrganizationResponse_CreatedAdmin{},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "admin with init with userID passed for Human admin",
|
name: "admin with init with userID passed for Human admin",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
|
@@ -38,6 +38,16 @@ func createOrganization(ctx context.Context, name string) orgAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createOrganizationWithCustomOrgID(ctx context.Context, name string, orgID string) orgAttr {
|
||||||
|
orgResp := Instance.CreateOrganizationWithCustomOrgID(ctx, name, orgID)
|
||||||
|
orgResp.Details.CreationDate = orgResp.Details.ChangeDate
|
||||||
|
return orgAttr{
|
||||||
|
ID: orgResp.GetOrganizationId(),
|
||||||
|
Name: name,
|
||||||
|
Details: orgResp.GetDetails(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestServer_ListOrganizations(t *testing.T) {
|
func TestServer_ListOrganizations(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@@ -163,6 +173,35 @@ func TestServer_ListOrganizations(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "list org by custom id, ok",
|
||||||
|
args: args{
|
||||||
|
CTX,
|
||||||
|
&org.ListOrganizationsRequest{},
|
||||||
|
func(ctx context.Context, request *org.ListOrganizationsRequest) ([]orgAttr, error) {
|
||||||
|
orgs := make([]orgAttr, 1)
|
||||||
|
name := fmt.Sprintf("ListOrgs-%s", gofakeit.AppName())
|
||||||
|
orgID := gofakeit.Company()
|
||||||
|
orgs[0] = createOrganizationWithCustomOrgID(ctx, name, orgID)
|
||||||
|
request.Queries = []*org.SearchQuery{
|
||||||
|
OrganizationIdQuery(orgID),
|
||||||
|
}
|
||||||
|
return orgs, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &org.ListOrganizationsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 1,
|
||||||
|
Timestamp: timestamppb.Now(),
|
||||||
|
},
|
||||||
|
SortingColumn: 0,
|
||||||
|
Result: []*org.Organization{
|
||||||
|
{
|
||||||
|
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "list org by name, ok",
|
name: "list org by name, ok",
|
||||||
args: args{
|
args: args{
|
||||||
|
@@ -31,6 +31,7 @@ func addOrganizationRequestToCommand(request *org.AddOrganizationRequest) (*comm
|
|||||||
Name: request.GetName(),
|
Name: request.GetName(),
|
||||||
CustomDomain: "",
|
CustomDomain: "",
|
||||||
Admins: admins,
|
Admins: admins,
|
||||||
|
OrgID: request.GetOrgId(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,6 +38,21 @@ func Test_addOrganizationRequestToCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: zerrors.ThrowUnimplementedf(nil, "ORGv2-SD2r1", "userType oneOf %T in method AddOrganization not implemented", nil),
|
wantErr: zerrors.ThrowUnimplementedf(nil, "ORGv2-SD2r1", "userType oneOf %T in method AddOrganization not implemented", nil),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "custom org ID",
|
||||||
|
args: args{
|
||||||
|
request: &org.AddOrganizationRequest{
|
||||||
|
Name: "custom org ID",
|
||||||
|
OrgId: gu.Ptr("org-ID"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &command.OrgSetup{
|
||||||
|
Name: "custom org ID",
|
||||||
|
CustomDomain: "",
|
||||||
|
Admins: []*command.OrgSetupAdmin{},
|
||||||
|
OrgID: "org-ID",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "user ID",
|
name: "user ID",
|
||||||
args: args{
|
args: args{
|
||||||
|
@@ -79,6 +79,18 @@ func TestServer_AddOrganization(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "no admin, custom org ID",
|
||||||
|
ctx: CTX,
|
||||||
|
req: &org.AddOrganizationRequest{
|
||||||
|
Name: gofakeit.AppName(),
|
||||||
|
OrgId: gu.Ptr("custom-org-ID"),
|
||||||
|
},
|
||||||
|
want: &org.AddOrganizationResponse{
|
||||||
|
OrganizationId: "custom-org-ID",
|
||||||
|
CreatedAdmins: []*org.AddOrganizationResponse_CreatedAdmin{},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "admin with init",
|
name: "admin with init",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
|
@@ -31,6 +31,7 @@ func addOrganizationRequestToCommand(request *org.AddOrganizationRequest) (*comm
|
|||||||
Name: request.GetName(),
|
Name: request.GetName(),
|
||||||
CustomDomain: "",
|
CustomDomain: "",
|
||||||
Admins: admins,
|
Admins: admins,
|
||||||
|
OrgID: request.GetOrgId(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,6 +39,21 @@ func Test_addOrganizationRequestToCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: zerrors.ThrowUnimplementedf(nil, "ORGv2-SD2r1", "userType oneOf %T in method AddOrganization not implemented", nil),
|
wantErr: zerrors.ThrowUnimplementedf(nil, "ORGv2-SD2r1", "userType oneOf %T in method AddOrganization not implemented", nil),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "custom org ID",
|
||||||
|
args: args{
|
||||||
|
request: &org.AddOrganizationRequest{
|
||||||
|
Name: "custom org ID",
|
||||||
|
OrgId: gu.Ptr("org-ID"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &command.OrgSetup{
|
||||||
|
Name: "custom org ID",
|
||||||
|
CustomDomain: "",
|
||||||
|
Admins: []*command.OrgSetupAdmin{},
|
||||||
|
OrgID: "org-ID",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "user ID",
|
name: "user ID",
|
||||||
args: args{
|
args: args{
|
||||||
|
@@ -31,6 +31,7 @@ type OrgSetup struct {
|
|||||||
Name string
|
Name string
|
||||||
CustomDomain string
|
CustomDomain string
|
||||||
Admins []*OrgSetupAdmin
|
Admins []*OrgSetupAdmin
|
||||||
|
OrgID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrgSetupAdmin describes a user to be created (Human / Machine) or an existing (ID) to be used for an org setup.
|
// OrgSetupAdmin describes a user to be created (Human / Machine) or an existing (ID) to be used for an org setup.
|
||||||
@@ -64,6 +65,13 @@ type CreatedOrgAdmin struct {
|
|||||||
MachineKey *MachineKey
|
MachineKey *MachineKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *OrgSetup) Validate() (err error) {
|
||||||
|
if o.OrgID != "" && strings.TrimSpace(o.OrgID) == "" {
|
||||||
|
return zerrors.ThrowInvalidArgument(nil, "ORG-4ABd3", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Commands) setUpOrgWithIDs(ctx context.Context, o *OrgSetup, orgID string, allowInitialMail bool, userIDs ...string) (_ *CreatedOrg, err error) {
|
func (c *Commands) setUpOrgWithIDs(ctx context.Context, o *OrgSetup, orgID string, allowInitialMail bool, userIDs ...string) (_ *CreatedOrg, err error) {
|
||||||
cmds := c.newOrgSetupCommands(ctx, orgID, o)
|
cmds := c.newOrgSetupCommands(ctx, orgID, o)
|
||||||
for _, admin := range o.Admins {
|
for _, admin := range o.Admins {
|
||||||
@@ -233,12 +241,19 @@ func (c *orgSetupCommands) createdMachineAdmin(admin *OrgSetupAdmin) *CreatedOrg
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, allowInitialMail bool, userIDs ...string) (*CreatedOrg, error) {
|
func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, allowInitialMail bool, userIDs ...string) (*CreatedOrg, error) {
|
||||||
orgID, err := c.idGenerator.Next()
|
if err := o.Validate(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.setUpOrgWithIDs(ctx, o, orgID, allowInitialMail, userIDs...)
|
if o.OrgID == "" {
|
||||||
|
var err error
|
||||||
|
o.OrgID, err = c.idGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.setUpOrgWithIDs(ctx, o, o.OrgID, allowInitialMail, userIDs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOrgCommand defines the commands to create a new org,
|
// AddOrgCommand defines the commands to create a new org,
|
||||||
|
@@ -1344,6 +1344,22 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
|||||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument"),
|
err: zerrors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "org id empty, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: expectEventstore(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||||
|
setupOrg: &OrgSetup{
|
||||||
|
Name: "Org",
|
||||||
|
OrgID: " ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: zerrors.ThrowInvalidArgument(nil, "ORG-4ABd3", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "userID not existing, error",
|
name: "userID not existing, error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@@ -1523,6 +1539,45 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "no human added, custom org ID",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectPush(
|
||||||
|
eventFromEventPusher(org.NewOrgAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("custom-org-ID").Aggregate,
|
||||||
|
"Org",
|
||||||
|
)),
|
||||||
|
eventFromEventPusher(org.NewDomainAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("custom-org-ID").Aggregate, "org.iam-domain",
|
||||||
|
)),
|
||||||
|
eventFromEventPusher(org.NewDomainVerifiedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("custom-org-ID").Aggregate,
|
||||||
|
"org.iam-domain",
|
||||||
|
)),
|
||||||
|
eventFromEventPusher(org.NewDomainPrimarySetEvent(context.Background(),
|
||||||
|
&org.NewAggregate("custom-org-ID").Aggregate,
|
||||||
|
"org.iam-domain",
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||||
|
setupOrg: &OrgSetup{
|
||||||
|
Name: "Org",
|
||||||
|
OrgID: "custom-org-ID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
createdOrg: &CreatedOrg{
|
||||||
|
ObjectDetails: &domain.ObjectDetails{
|
||||||
|
ResourceOwner: "custom-org-ID",
|
||||||
|
},
|
||||||
|
CreatedAdmins: []*CreatedOrgAdmin{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "existing human added",
|
name: "existing human added",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
|
@@ -293,6 +293,15 @@ func SetOrgID(ctx context.Context, orgID string) context.Context {
|
|||||||
return metadata.NewOutgoingContext(ctx, md)
|
return metadata.NewOutgoingContext(ctx, md)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Instance) CreateOrganizationWithCustomOrgID(ctx context.Context, name, orgID string) *org.AddOrganizationResponse {
|
||||||
|
resp, err := i.Client.OrgV2.AddOrganization(ctx, &org.AddOrganizationRequest{
|
||||||
|
Name: name,
|
||||||
|
OrgId: gu.Ptr(orgID),
|
||||||
|
})
|
||||||
|
logging.OnError(err).Fatal("create org")
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Instance) CreateOrganizationWithUserID(ctx context.Context, name, userID string) *org.AddOrganizationResponse {
|
func (i *Instance) CreateOrganizationWithUserID(ctx context.Context, name, userID string) *org.AddOrganizationResponse {
|
||||||
resp, err := i.Client.OrgV2.AddOrganization(ctx, &org.AddOrganizationRequest{
|
resp, err := i.Client.OrgV2.AddOrganization(ctx, &org.AddOrganizationRequest{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
@@ -197,6 +197,14 @@ message AddOrganizationRequest{
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
repeated Admin admins = 2;
|
repeated Admin admins = 2;
|
||||||
|
// optionally set your own id unique for the organization.
|
||||||
|
optional string org_id = 3 [
|
||||||
|
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
max_length: 200;
|
||||||
|
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddOrganizationResponse{
|
message AddOrganizationResponse{
|
||||||
|
@@ -160,6 +160,14 @@ message AddOrganizationRequest{
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
repeated Admin admins = 2;
|
repeated Admin admins = 2;
|
||||||
|
// optionally set your own id unique for the organization.
|
||||||
|
optional string org_id = 3 [
|
||||||
|
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
max_length: 200;
|
||||||
|
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddOrganizationResponse{
|
message AddOrganizationResponse{
|
||||||
|
Reference in New Issue
Block a user