fix: allow invite codes for users with verified mails (#9962)

# Which Problems Are Solved

Users who started the invitation code verification, but haven't set up
any authentication method, need to be able to do so. This might require
a new invitation code, which was currently not possible since creation
was prevented for users with verified emails.

# How the Problems Are Solved

- Allow creation of invitation emails for users with verified emails.
- Merged the creation and resend into a single method, defaulting the
urlTemplate, applicatioName and authRequestID from the previous code (if
one exists). On the user service API, the `ResendInviteCode` endpoint
has been deprecated in favor of the `CreateInviteCode`

# Additional Changes

None

# Additional Context

- Noticed while investigating something internally.
- requires backport to 2.x and 3.x
This commit is contained in:
Livio Spring
2025-05-26 13:59:20 +02:00
committed by GitHub
parent eb0eed21fa
commit 833f6279e1
6 changed files with 71 additions and 125 deletions

View File

@@ -11,7 +11,6 @@ import (
"go.uber.org/mock/gomock"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
@@ -316,7 +315,7 @@ func TestCommands_ResendInviteCode(t *testing.T) {
userID: "",
},
want{
err: zerrors.ThrowInvalidArgument(nil, "COMMAND-2n8vs", "Errors.User.UserIDMissing"),
err: zerrors.ThrowInvalidArgument(nil, "COMMAND-4jio3", "Errors.User.UserIDMissing"),
},
},
{
@@ -362,7 +361,7 @@ func TestCommands_ResendInviteCode(t *testing.T) {
userID: "unknown",
},
want{
err: zerrors.ThrowPreconditionFailed(nil, "COMMAND-H3b2a", "Errors.User.NotFound"),
err: zerrors.ThrowPreconditionFailed(nil, "COMMAND-Wgvn4", "Errors.User.NotFound"),
},
},
{
@@ -580,76 +579,6 @@ func TestCommands_ResendInviteCode(t *testing.T) {
},
},
},
{
"resend with own user ok",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("userID", "org1").Aggregate,
"username", "firstName",
"lastName",
"nickName",
"displayName",
language.Afrikaans,
domain.GenderUnspecified,
"email",
false,
),
),
eventFromEventPusher(
user.NewHumanInviteCodeAddedEvent(context.Background(),
&user.NewAggregate("userID", "org1").Aggregate,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("code"),
},
time.Hour,
"",
false,
"",
"authRequestID",
),
),
),
expectPush(
eventFromEventPusher(
user.NewHumanInviteCodeAddedEvent(authz.NewMockContext("instanceID", "org1", "userID"),
&user.NewAggregate("userID", "org1").Aggregate,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("code"),
},
time.Hour,
"",
false,
"",
"authRequestID2",
),
),
),
),
checkPermission: newMockPermissionCheckNotAllowed(), // user does not have permission, is allowed in the own context
newEncryptedCodeWithDefault: mockEncryptedCodeWithDefault("code", time.Hour),
defaultSecretGenerators: &SecretGenerators{},
},
args{
ctx: authz.NewMockContext("instanceID", "org1", "userID"),
userID: "userID",
authRequestID: "authRequestID2",
},
want{
details: &domain.ObjectDetails{
ResourceOwner: "org1",
ID: "userID",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {