diff --git a/internal/api/grpc/user/v2/integration_test/intent_test.go b/internal/api/grpc/user/v2/integration_test/intent_test.go index 8ace29cb0..7f269ec2b 100644 --- a/internal/api/grpc/user/v2/integration_test/intent_test.go +++ b/internal/api/grpc/user/v2/integration_test/intent_test.go @@ -455,6 +455,23 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_CreateUser{ + CreateUser: &user.CreateUserRequest{ + UserType: &user.CreateUserRequest_Human_{ + Human: &user.CreateUserRequest_Human{ + Profile: &user.SetHumanProfile{ + PreferredLanguage: gu.Ptr("und"), + }, + IdpLinks: []*user.IDPLink{ + {IdpId: oauthIdpID, UserId: "id"}, + }, + Email: &user.SetHumanEmail{ + Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -502,6 +519,18 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { PreferredLanguage: gu.Ptr("und"), }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_UpdateUser{ + UpdateUser: &user.UpdateUserRequest{ + UserId: "user", + UserType: &user.UpdateUserRequest_Human_{ + Human: &user.UpdateUserRequest_Human{ + Profile: &user.UpdateUserRequest_Human_Profile{ + PreferredLanguage: gu.Ptr("und"), + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -582,6 +611,28 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_CreateUser{ + CreateUser: &user.CreateUserRequest{ + Username: gu.Ptr("username"), + UserType: &user.CreateUserRequest_Human_{ + Human: &user.CreateUserRequest_Human{ + Profile: &user.SetHumanProfile{ + PreferredLanguage: gu.Ptr("und"), + GivenName: "firstname", + FamilyName: "lastname", + DisplayName: gu.Ptr("displayname"), + }, + IdpLinks: []*user.IDPLink{ + {IdpId: azureIdpID, UserId: "id", UserName: "username"}, + }, + Email: &user.SetHumanEmail{ + Email: "email@email.com", + Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -639,6 +690,26 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_UpdateUser{ + UpdateUser: &user.UpdateUserRequest{ + Username: gu.Ptr("username"), + UserId: "user", + UserType: &user.UpdateUserRequest_Human_{ + Human: &user.UpdateUserRequest_Human{ + Profile: &user.UpdateUserRequest_Human_Profile{ + PreferredLanguage: gu.Ptr("und"), + GivenName: gu.Ptr("firstname"), + FamilyName: gu.Ptr("lastname"), + DisplayName: gu.Ptr("displayname"), + }, + Email: &user.SetHumanEmail{ + Email: "email@email.com", + Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -690,6 +761,24 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_CreateUser{ + CreateUser: &user.CreateUserRequest{ + Username: gu.Ptr("username"), + UserType: &user.CreateUserRequest_Human_{ + Human: &user.CreateUserRequest_Human{ + Profile: &user.SetHumanProfile{ + PreferredLanguage: gu.Ptr("und"), + }, + IdpLinks: []*user.IDPLink{ + {IdpId: oidcIdpID, UserId: "id", UserName: "username"}, + }, + Email: &user.SetHumanEmail{ + Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -736,6 +825,19 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { PreferredLanguage: gu.Ptr("und"), }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_UpdateUser{ + UpdateUser: &user.UpdateUserRequest{ + Username: gu.Ptr("username"), + UserId: "user", + UserType: &user.UpdateUserRequest_Human_{ + Human: &user.UpdateUserRequest_Human{ + Profile: &user.UpdateUserRequest_Human_Profile{ + PreferredLanguage: gu.Ptr("und"), + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -793,6 +895,24 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_CreateUser{ + CreateUser: &user.CreateUserRequest{ + Username: gu.Ptr("username"), + UserType: &user.CreateUserRequest_Human_{ + Human: &user.CreateUserRequest_Human{ + Profile: &user.SetHumanProfile{ + PreferredLanguage: gu.Ptr("en"), + }, + IdpLinks: []*user.IDPLink{ + {IdpId: ldapIdpID, UserId: "id", UserName: "username"}, + }, + Email: &user.SetHumanEmail{ + Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -846,6 +966,19 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { PreferredLanguage: gu.Ptr("en"), }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_UpdateUser{ + UpdateUser: &user.UpdateUserRequest{ + Username: gu.Ptr("username"), + UserId: "user", + UserType: &user.UpdateUserRequest_Human_{ + Human: &user.UpdateUserRequest_Human{ + Profile: &user.UpdateUserRequest_Human_Profile{ + PreferredLanguage: gu.Ptr("en"), + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -895,6 +1028,23 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_CreateUser{ + CreateUser: &user.CreateUserRequest{ + UserType: &user.CreateUserRequest_Human_{ + Human: &user.CreateUserRequest_Human{ + Profile: &user.SetHumanProfile{ + PreferredLanguage: gu.Ptr("und"), + }, + IdpLinks: []*user.IDPLink{ + {IdpId: samlIdpID, UserId: "id"}, + }, + Email: &user.SetHumanEmail{ + Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -940,6 +1090,18 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { PreferredLanguage: gu.Ptr("und"), }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_UpdateUser{ + UpdateUser: &user.UpdateUserRequest{ + UserId: "user", + UserType: &user.UpdateUserRequest_Human_{ + Human: &user.UpdateUserRequest_Human{ + Profile: &user.UpdateUserRequest_Human_Profile{ + PreferredLanguage: gu.Ptr("und"), + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -986,6 +1148,23 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_CreateUser{ + CreateUser: &user.CreateUserRequest{ + UserType: &user.CreateUserRequest_Human_{ + Human: &user.CreateUserRequest_Human{ + Profile: &user.SetHumanProfile{ + PreferredLanguage: gu.Ptr("und"), + }, + IdpLinks: []*user.IDPLink{ + {IdpId: jwtIdPID, UserId: "id"}, + }, + Email: &user.SetHumanEmail{ + Verification: &user.SetHumanEmail_SendCode{SendCode: &user.SendEmailVerificationCode{}}, + }, + }, + }, + }, + }, }, wantErr: false, }, @@ -1028,6 +1207,18 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { PreferredLanguage: gu.Ptr("und"), }, }, + UserAction: &user.RetrieveIdentityProviderIntentResponse_UpdateUser{ + UpdateUser: &user.UpdateUserRequest{ + UserId: "user", + UserType: &user.UpdateUserRequest_Human_{ + Human: &user.UpdateUserRequest_Human{ + Profile: &user.UpdateUserRequest_Human_Profile{ + PreferredLanguage: gu.Ptr("und"), + }, + }, + }, + }, + }, }, wantErr: false, }, diff --git a/internal/api/grpc/user/v2/intent.go b/internal/api/grpc/user/v2/intent.go index ddcab672e..e0f43c754 100644 --- a/internal/api/grpc/user/v2/intent.go +++ b/internal/api/grpc/user/v2/intent.go @@ -202,9 +202,11 @@ func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *connec return nil, err } if idpIntent.UserId == "" { - idpIntent.AddHumanUser = idpUserToAddHumanUser(idpUser, idpIntent.IdpInformation.IdpId) + idpIntent.AddHumanUser = idpUserToAddHumanUser(idpUser, idpIntent.IdpInformation.IdpId) //nolint:staticcheck + idpIntent.UserAction = idpUserToCreateUser(idpUser, idpIntent.IdpInformation.IdpId) } else { - idpIntent.UpdateHumanUser = idpUserToUpdateHumanUser(intent.UserID, idpUser) + idpIntent.UpdateHumanUser = idpUserToUpdateHumanUser(intent.UserID, idpUser) //nolint:staticcheck + idpIntent.UserAction = idpUserToUpdateUser(intent.UserID, idpUser) } return connect.NewResponse(idpIntent), nil } @@ -429,3 +431,105 @@ func idpUserToUpdateHumanUser(userID string, idpUser idp.User) *user.UpdateHuman } return updateHumanUser } + +func idpUserToCreateUser(idpUser idp.User, idpID string) *user.RetrieveIdentityProviderIntentResponse_CreateUser { + createUser := &user.CreateUserRequest{ + UserType: &user.CreateUserRequest_Human_{ + Human: &user.CreateUserRequest_Human{ + Profile: &user.SetHumanProfile{ + GivenName: idpUser.GetFirstName(), + FamilyName: idpUser.GetLastName(), + }, + Email: &user.SetHumanEmail{ + Email: string(idpUser.GetEmail()), + Verification: &user.SetHumanEmail_SendCode{}, + }, + IdpLinks: []*user.IDPLink{ + { + IdpId: idpID, + UserId: idpUser.GetID(), + UserName: idpUser.GetPreferredUsername(), + }, + }, + }, + }, + } + if username := idpUser.GetPreferredUsername(); username != "" { + createUser.Username = &username + } + if nickName := idpUser.GetNickname(); nickName != "" { + createUser.GetHuman().GetProfile().NickName = &nickName + } + if displayName := idpUser.GetDisplayName(); displayName != "" { + createUser.GetHuman().GetProfile().DisplayName = &displayName + } + if lang := idpUser.GetPreferredLanguage().String(); lang != "" { + createUser.GetHuman().GetProfile().PreferredLanguage = &lang + } + if isEmailVerified := idpUser.IsEmailVerified(); isEmailVerified { + createUser.GetHuman().GetEmail().Verification = &user.SetHumanEmail_IsVerified{IsVerified: isEmailVerified} + } + if phone := idpUser.GetPhone(); phone != "" { + createUser.GetHuman().Phone = &user.SetHumanPhone{ + Phone: string(phone), + Verification: &user.SetHumanPhone_SendCode{}, + } + if isPhoneVerified := idpUser.IsPhoneVerified(); isPhoneVerified { + createUser.GetHuman().GetPhone().Verification = &user.SetHumanPhone_IsVerified{IsVerified: isPhoneVerified} + } + } + return &user.RetrieveIdentityProviderIntentResponse_CreateUser{ + CreateUser: createUser, + } +} + +func idpUserToUpdateUser(userID string, idpUser idp.User) *user.RetrieveIdentityProviderIntentResponse_UpdateUser { + updateUser := &user.UpdateUserRequest{ + UserId: userID, + UserType: &user.UpdateUserRequest_Human_{ + Human: &user.UpdateUserRequest_Human{ + Profile: &user.UpdateUserRequest_Human_Profile{}, + }, + }, + } + if username := idpUser.GetPreferredUsername(); username != "" { + updateUser.Username = &username + } + if firstName := idpUser.GetFirstName(); firstName != "" { + updateUser.GetHuman().GetProfile().GivenName = &firstName + } + if lastName := idpUser.GetLastName(); lastName != "" { + updateUser.GetHuman().GetProfile().FamilyName = &lastName + } + if nickName := idpUser.GetNickname(); nickName != "" { + updateUser.GetHuman().GetProfile().NickName = &nickName + } + if displayName := idpUser.GetDisplayName(); displayName != "" { + updateUser.GetHuman().GetProfile().DisplayName = &displayName + } + if lang := idpUser.GetPreferredLanguage().String(); lang != "" { + updateUser.GetHuman().GetProfile().PreferredLanguage = &lang + } + if email := string(idpUser.GetEmail()); email != "" { + updateUser.GetHuman().Email = &user.SetHumanEmail{ + Email: email, + Verification: &user.SetHumanEmail_SendCode{}, + } + if isEmailVerified := idpUser.IsEmailVerified(); isEmailVerified { + updateUser.GetHuman().GetEmail().Verification = &user.SetHumanEmail_IsVerified{IsVerified: isEmailVerified} + } + } + if phone := string(idpUser.GetPhone()); phone != "" { + updateUser.GetHuman().Phone = &user.SetHumanPhone{ + Phone: phone, + Verification: &user.SetHumanPhone_SendCode{}, + } + if isPhoneVerified := idpUser.IsPhoneVerified(); isPhoneVerified { + updateUser.GetHuman().GetPhone().Verification = &user.SetHumanPhone_IsVerified{IsVerified: isPhoneVerified} + } + } + + return &user.RetrieveIdentityProviderIntentResponse_UpdateUser{ + UpdateUser: updateUser, + } +} diff --git a/internal/integration/sink/server.go b/internal/integration/sink/server.go index 385125fc7..647b05aee 100644 --- a/internal/integration/sink/server.go +++ b/internal/integration/sink/server.go @@ -408,7 +408,6 @@ func successfulIntentHandler(cmd *command.Commands, createIntent func(ctx contex return } w.Write(data) - return } } @@ -499,6 +498,9 @@ func createSuccessfulAzureADIntent(ctx context.Context, cmd *command.Commands, r func createSuccessfulOIDCIntent(ctx context.Context, cmd *command.Commands, req *SuccessfulIntentRequest) (*SuccessfulIntentResponse, error) { intentID, err := createIntent(ctx, cmd, req.InstanceID, req.IDPID) writeModel, err := cmd.GetIntentWriteModel(ctx, intentID, req.InstanceID) + if err != nil { + return nil, err + } idpUser := openid.NewUser( &oidc.UserInfo{ Subject: req.IDPUserID, @@ -535,7 +537,9 @@ func createSuccessfulSAMLIntent(ctx context.Context, cmd *command.Commands, req intentID, _ = createIntent(ctx, cmd, req.InstanceID, req.IDPID) } writeModel, err := cmd.GetIntentWriteModel(ctx, intentID, req.InstanceID) - + if err != nil { + return nil, err + } idpUser := &saml.UserMapper{ ID: req.IDPUserID, Attributes: map[string][]string{"attribute1": {"value1"}}, @@ -564,6 +568,9 @@ func createSuccessfulSAMLIntent(ctx context.Context, cmd *command.Commands, req func createSuccessfulLDAPIntent(ctx context.Context, cmd *command.Commands, req *SuccessfulIntentRequest) (*SuccessfulIntentResponse, error) { intentID, err := createIntent(ctx, cmd, req.InstanceID, req.IDPID) writeModel, err := cmd.GetIntentWriteModel(ctx, intentID, req.InstanceID) + if err != nil { + return nil, err + } username := "username" lang := language.Make("en") idpUser := ldap.NewUser( @@ -603,6 +610,9 @@ func createSuccessfulLDAPIntent(ctx context.Context, cmd *command.Commands, req func createSuccessfulJWTIntent(ctx context.Context, cmd *command.Commands, req *SuccessfulIntentRequest) (*SuccessfulIntentResponse, error) { intentID, err := createIntent(ctx, cmd, req.InstanceID, req.IDPID) writeModel, err := cmd.GetIntentWriteModel(ctx, intentID, req.InstanceID) + if err != nil { + return nil, err + } idpUser := &jwt.User{ IDTokenClaims: &oidc.IDTokenClaims{ TokenClaims: oidc.TokenClaims{ diff --git a/proto/zitadel/user/v2/user_service.proto b/proto/zitadel/user/v2/user_service.proto index b5815c4c2..daf83cdff 100644 --- a/proto/zitadel/user/v2/user_service.proto +++ b/proto/zitadel/user/v2/user_service.proto @@ -3219,15 +3219,43 @@ message RetrieveIdentityProviderIntentRequest{ message RetrieveIdentityProviderIntentResponse{ zitadel.object.v2.Details details = 1; - IDPInformation idp_information = 2; + IDPInformation idp_information = 2 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Information about the user returned by the external identity provider" + } + ]; string user_id = 3 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "ID of the user in Zitadel if external user is linked" example: "\"163840776835432345\""; } ]; - AddHumanUserRequest add_human_user = 4; - UpdateHumanUserRequest update_human_user = 5; + // Deprecated: use user_action.create_user instead. + AddHumanUserRequest add_human_user = 4 [ + deprecated = true, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Information to create a new human user with the IDP information. This field is deprecated, use create_user instead."; + } + ]; + // Deprecated: use user_action.update_user instead. + UpdateHumanUserRequest update_human_user = 5 [ + deprecated = true, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Information to update an existing human user with the IDP information. This field is deprecated, use update_user instead."; + } + ]; + oneof user_action { + CreateUserRequest create_user = 6 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Information to create a new human user with the IDP information."; + } + ]; + UpdateUserRequest update_user = 7 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Information to update an existing human user with the IDP information."; + } + ]; + } } message AddIDPLinkRequest{