diff --git a/e2e/cypress/e2e/humans/humans.cy.ts b/e2e/cypress/e2e/humans/humans.cy.ts index 8b29b05db3..19abe258c5 100644 --- a/e2e/cypress/e2e/humans/humans.cy.ts +++ b/e2e/cypress/e2e/humans/humans.cy.ts @@ -1,56 +1,67 @@ import { apiAuth } from '../../support/api/apiauth'; import { ensureHumanUserExists, ensureUserDoesntExist } from '../../support/api/users'; import { loginname } from '../../support/login/users'; +import { ensureDomainPolicy } from '../../support/api/policies'; describe('humans', () => { const humansPath = `/users?type=human`; - const testHumanUserNameAdd = 'e2ehumanusernameadd'; - const testHumanUserNameRemove = 'e2ehumanusernameremove'; - beforeEach(() => { - apiAuth().as('api'); - }); - - describe('add', () => { - beforeEach(`ensure it doesn't exist already`, function () { - ensureUserDoesntExist(this.api, loginname(testHumanUserNameAdd, Cypress.env('ORGANIZATION'))); - cy.visit(humansPath); + [ + { mustBeDomain: false, addName: 'e2ehumanusernameaddGlobal', removeName: 'e2ehumanusernameremoveGlobal' }, + { mustBeDomain: false, addName: 'e2ehumanusernameadd@test.com', removeName: 'e2ehumanusernameremove@test.com' }, + { mustBeDomain: true, addName: 'e2ehumanusernameadd', removeName: 'e2ehumanusernameremove' }, + ].forEach((user) => { + beforeEach(() => { + apiAuth().as('api'); }); - it('should add a user', () => { - cy.get('[data-e2e="create-user-button"]').click(); - cy.url().should('contain', 'users/create'); - cy.get('[formcontrolname="email"]').type('dummy@dummy.com'); - //force needed due to the prefilled username prefix - cy.get('[formcontrolname="userName"]').type(loginname(testHumanUserNameAdd, Cypress.env('ORGANIZATION'))); - cy.get('[formcontrolname="firstName"]').type('e2ehumanfirstname'); - cy.get('[formcontrolname="lastName"]').type('e2ehumanlastname'); - cy.get('[formcontrolname="phone"]').type('+41 123456789'); - cy.get('[data-e2e="create-button"]').click(); - cy.get('.data-e2e-success'); - const loginName = loginname(testHumanUserNameAdd, Cypress.env('ORGANIZATION')); - cy.contains('[data-e2e="copy-loginname"]', loginName).click(); - cy.clipboardMatches(loginName); - cy.shouldNotExist({ selector: '.data-e2e-failure' }); - }); - }); + describe(`add "${user.addName}" with domain setting "${user.mustBeDomain}"`, () => { + beforeEach(`ensure it doesn't exist already`, function () { + ensureDomainPolicy(this.api, user.mustBeDomain, true, false); + ensureUserDoesntExist(this.api, user.addName); + cy.visit(humansPath); + }); - describe('remove', () => { - beforeEach('ensure it exists', function () { - ensureHumanUserExists(this.api, loginname(testHumanUserNameRemove, Cypress.env('ORGANIZATION'))); - cy.visit(humansPath); + it('should add a user', () => { + cy.get('[data-e2e="create-user-button"]').click(); + cy.url().should('contain', 'users/create'); + cy.get('[formcontrolname="email"]').type('dummy@dummy.com'); + //force needed due to the prefilled username prefix + cy.get('[formcontrolname="userName"]').type(user.addName); + cy.get('[formcontrolname="firstName"]').type('e2ehumanfirstname'); + cy.get('[formcontrolname="lastName"]').type('e2ehumanlastname'); + cy.get('[formcontrolname="phone"]').type('+41 123456789'); + cy.get('[data-e2e="create-button"]').click(); + cy.get('.data-e2e-success'); + let loginName = user.addName; + if (user.mustBeDomain) { + loginName = loginname(user.addName, Cypress.env('ORGANIZATION')); + } + cy.contains('[data-e2e="copy-loginname"]', loginName).click(); + cy.clipboardMatches(loginName); + cy.shouldNotExist({ selector: '.data-e2e-failure' }); + }); }); - it('should delete a human user', () => { - const rowSelector = `tr:contains(${testHumanUserNameRemove})`; - cy.get(rowSelector).find('[data-e2e="enabled-delete-button"]').click({ force: true }); - cy.get('[data-e2e="confirm-dialog-input"]') - .focus() - .type(loginname(testHumanUserNameRemove, Cypress.env('ORGANIZATION'))); - cy.get('[data-e2e="confirm-dialog-button"]').click(); - cy.get('.data-e2e-success'); - cy.shouldNotExist({ selector: rowSelector, timeout: 2000 }); - cy.shouldNotExist({ selector: '.data-e2e-failure' }); + describe(`remove "${user.removeName}" with domain setting "${user.mustBeDomain}"`, () => { + beforeEach('ensure it exists', function () { + ensureHumanUserExists(this.api, user.removeName); + cy.visit(humansPath); + }); + + let loginName = user.removeName; + if (user.mustBeDomain) { + loginName = loginname(user.removeName, Cypress.env('ORGANIZATION')); + } + it('should delete a human user', () => { + const rowSelector = `tr:contains(${user.removeName})`; + cy.get(rowSelector).find('[data-e2e="enabled-delete-button"]').click({ force: true }); + cy.get('[data-e2e="confirm-dialog-input"]').focus().type(loginName); + cy.get('[data-e2e="confirm-dialog-button"]').click(); + cy.get('.data-e2e-success'); + cy.shouldNotExist({ selector: rowSelector, timeout: 2000 }); + cy.shouldNotExist({ selector: '.data-e2e-failure' }); + }); }); }); }); diff --git a/e2e/cypress/e2e/machines/machines.cy.ts b/e2e/cypress/e2e/machines/machines.cy.ts index fe3dba0149..327e1c2215 100644 --- a/e2e/cypress/e2e/machines/machines.cy.ts +++ b/e2e/cypress/e2e/machines/machines.cy.ts @@ -1,53 +1,67 @@ import { apiAuth } from '../../support/api/apiauth'; import { ensureMachineUserExists, ensureUserDoesntExist } from '../../support/api/users'; import { loginname } from '../../support/login/users'; +import { ensureDomainPolicy } from '../../support/api/policies'; describe('machines', () => { + const machinesPath = `/users?type=machine`; + beforeEach(() => { apiAuth().as('api'); }); - const machinesPath = `/users?type=machine`; - const testMachineUserNameAdd = 'e2emachineusernameadd'; - const testMachineUserNameRemove = 'e2emachineusernameremove'; + [ + { mustBeDomain: false, addName: 'e2emachineusernameaddGlobal', removeName: 'e2emachineusernameremoveGlobal' }, + { mustBeDomain: false, addName: 'e2emachineusernameadd@test.com', removeName: 'e2emachineusernameremove@test.com' }, + { mustBeDomain: true, addName: 'e2emachineusernameadd', removeName: 'e2emachineusernameremove' }, + ].forEach((machine) => { + describe(`add "${machine.addName}" with domain setting "${machine.mustBeDomain}"`, () => { + beforeEach(`ensure it doesn't exist already`, function () { + ensureDomainPolicy(this.api, machine.mustBeDomain, false, false); + ensureUserDoesntExist(this.api, machine.addName); + cy.visit(machinesPath); + }); - describe('add', () => { - beforeEach(`ensure it doesn't exist already`, function () { - ensureUserDoesntExist(this.api, testMachineUserNameAdd); - cy.visit(machinesPath); + it('should add a machine', () => { + cy.get('[data-e2e="create-user-button"]').click(); + cy.url().should('contain', 'users/create-machine'); + //force needed due to the prefilled username prefix + cy.get('[formcontrolname="userName"]').type(machine.addName); + cy.get('[formcontrolname="name"]').type('e2emachinename'); + cy.get('[formcontrolname="description"]').type('e2emachinedescription'); + cy.get('[data-e2e="create-button"]').click(); + cy.get('.data-e2e-success'); + let loginName = machine.addName; + if (machine.mustBeDomain) { + loginName = loginname(machine.addName, Cypress.env('ORGANIZATION')); + } + cy.contains('[data-e2e="copy-loginname"]', loginName).click(); + cy.clipboardMatches(loginName); + cy.shouldNotExist({ selector: '.data-e2e-failure' }); + }); }); - it('should add a machine', () => { - cy.get('[data-e2e="create-user-button"]').click(); - cy.url().should('contain', 'users/create-machine'); - //force needed due to the prefilled username prefix - cy.get('[formcontrolname="userName"]').type(testMachineUserNameAdd); - cy.get('[formcontrolname="name"]').type('e2emachinename'); - cy.get('[formcontrolname="description"]').type('e2emachinedescription'); - cy.get('[data-e2e="create-button"]').click(); - cy.get('.data-e2e-success'); - cy.contains('[data-e2e="copy-loginname"]', testMachineUserNameAdd).click(); - cy.clipboardMatches(testMachineUserNameAdd); - cy.shouldNotExist({ selector: '.data-e2e-failure' }); - }); - }); + describe(`remove "${machine.removeName}" with domain setting "${machine.mustBeDomain}"`, () => { + beforeEach('ensure it exists', function () { + ensureMachineUserExists(this.api, machine.removeName); + cy.visit(machinesPath); + }); - describe('edit', () => { - beforeEach('ensure it exists', function () { - ensureMachineUserExists(this.api, testMachineUserNameRemove); - cy.visit(machinesPath); - }); + let loginName = machine.removeName; + if (machine.mustBeDomain) { + loginName = loginname(machine.removeName, Cypress.env('ORGANIZATION')); + } + it('should delete a machine', () => { + const rowSelector = `tr:contains(${machine.removeName})`; + cy.get(rowSelector).find('[data-e2e="enabled-delete-button"]').click({ force: true }); + cy.get('[data-e2e="confirm-dialog-input"]').focus().type(loginName); + cy.get('[data-e2e="confirm-dialog-button"]').click(); + cy.get('.data-e2e-success'); + cy.shouldNotExist({ selector: rowSelector, timeout: 2000 }); + cy.shouldNotExist({ selector: '.data-e2e-failure' }); + }); - it('should delete a machine', () => { - const rowSelector = `tr:contains(${testMachineUserNameRemove})`; - cy.get(rowSelector).find('[data-e2e="enabled-delete-button"]').click({ force: true }); - cy.get('[data-e2e="confirm-dialog-input"]').focus().type(testMachineUserNameRemove); - cy.get('[data-e2e="confirm-dialog-button"]').click(); - cy.get('.data-e2e-success'); - cy.shouldNotExist({ selector: rowSelector, timeout: 2000 }); - cy.shouldNotExist({ selector: '.data-e2e-failure' }); + it('should create a personal access token'); }); - - it('should create a personal access token'); }); }); diff --git a/e2e/cypress/support/api/ensure.ts b/e2e/cypress/support/api/ensure.ts index 86ce397bf1..7b0faebd9e 100644 --- a/e2e/cypress/support/api/ensure.ts +++ b/e2e/cypress/support/api/ensure.ts @@ -56,7 +56,6 @@ export function ensureSetting( 'PUT', body, (entity) => !!entity, - (body) => body?.settings?.id, ); } @@ -66,14 +65,15 @@ function awaitDesired( search: () => Cypress.Chainable, initialSequence?: number, ) { - search().then((resp) => { + return search().then((resp) => { const foundExpectedEntity = expectEntity(resp.entity); const foundExpectedSequence = !initialSequence || resp.sequence >= initialSequence; - if (!foundExpectedEntity || !foundExpectedSequence) { + const check = !foundExpectedEntity || !foundExpectedSequence; + if (check) { expect(trials, `trying ${trials} more times`).to.be.greaterThan(0); cy.wait(1000); - awaitDesired(trials - 1, expectEntity, search, initialSequence); + return awaitDesired(trials - 1, expectEntity, search, initialSequence); } }); } @@ -117,7 +117,8 @@ export function ensureSomething( }); }) .then((data) => { - awaitDesired(90, expectEntity, search, data.sequence); - return cy.wrap(data.id); + return awaitDesired(90, expectEntity, search, data.sequence).then(() => { + return cy.wrap(data.id); + }); }); } diff --git a/e2e/cypress/support/api/orgs.ts b/e2e/cypress/support/api/orgs.ts index e41f285112..1141f1caea 100644 --- a/e2e/cypress/support/api/orgs.ts +++ b/e2e/cypress/support/api/orgs.ts @@ -12,7 +12,7 @@ export function ensureOrgExists(api: API, name: string): Cypress.Chainable { - return { entity: res.org, id: res.org?.id, sequence: res.org?.details?.sequence }; + return { entity: res.org, id: res.org?.id, sequence: parseInt(res.org?.details?.sequence) }; }, ), () => `${api.mgmtBaseURL}/orgs`, @@ -25,6 +25,6 @@ export function ensureOrgExists(api: API, name: string): Cypress.Chainable { return searchSomething(api, `${api.mgmtBaseURL}/orgs/me`, 'GET', (res) => { - return { entity: res.org, id: res.org.id, sequence: res.org.details.sequence }; + return { entity: res.org, id: res.org.id, sequence: parseInt(res.org.details.sequence) }; }).then((res) => res.entity.id); } diff --git a/e2e/cypress/support/api/policies.ts b/e2e/cypress/support/api/policies.ts index d38c2df806..3ad70b0353 100644 --- a/e2e/cypress/support/api/policies.ts +++ b/e2e/cypress/support/api/policies.ts @@ -1,5 +1,6 @@ import { requestHeaders } from './apiauth'; import { API } from './types'; +import { ensureSetting } from './ensure'; export enum Policy { Label = 'label', @@ -15,3 +16,38 @@ export function resetPolicy(api: API, policy: Policy) { return null; }); } + +export function ensureDomainPolicy( + api: API, + userLoginMustBeDomain: boolean, + validateOrgDomains: boolean, + smtpSenderAddressMatchesInstanceDomain: boolean, +): Cypress.Chainable { + return ensureSetting( + api, + `${api.adminBaseURL}/policies/domain`, + (body: any) => { + const result = { + sequence: parseInt(body.policy?.details?.sequence), + id: body.policy?.details?.resourceOwner, + entity: null, + }; + if ( + body.policy && + (body.policy.userLoginMustBeDomain ? body.policy.userLoginMustBeDomain : false) == userLoginMustBeDomain && + (body.policy.validateOrgDomains ? body.policy.validateOrgDomains : false) == validateOrgDomains && + (body.policy.smtpSenderAddressMatchesInstanceDomain ? body.policy.smtpSenderAddressMatchesInstanceDomain : false) == + smtpSenderAddressMatchesInstanceDomain + ) { + return { ...result, entity: body.policy }; + } + return result; + }, + `${api.adminBaseURL}/policies/domain`, + { + userLoginMustBeDomain: userLoginMustBeDomain, + validateOrgDomains: validateOrgDomains, + smtpSenderAddressMatchesInstanceDomain: smtpSenderAddressMatchesInstanceDomain, + }, + ); +} diff --git a/internal/api/ui/login/external_login_handler.go b/internal/api/ui/login/external_login_handler.go index ea4565deb9..ecd7259483 100644 --- a/internal/api/ui/login/external_login_handler.go +++ b/internal/api/ui/login/external_login_handler.go @@ -474,9 +474,9 @@ func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *query.DomainPolicy, lin } if orgIamPolicy.UserLoginMustBeDomain { - splittedUsername := strings.Split(username, "@") - if len(splittedUsername) > 1 { - username = splittedUsername[0] + index := strings.LastIndex(username, "@") + if index > 1 { + username = username[:index] } } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index e32d150f56..62271fd5db 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -700,12 +700,12 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain func (repo *AuthRequestRepo) checkDomainDiscovery(ctx context.Context, request *domain.AuthRequest, loginName string) bool { // check if there's a suffix in the loginname - split := strings.Split(loginName, "@") - if len(split) < 2 { + index := strings.LastIndex(loginName, "@") + if index < 0 { return false } // check if the suffix matches a verified domain - org, err := repo.Query.OrgByVerifiedDomain(ctx, split[len(split)-1]) + org, err := repo.Query.OrgByVerifiedDomain(ctx, loginName[index+1:]) if err != nil { return false } diff --git a/internal/command/user_human.go b/internal/command/user_human.go index fd8995a487..f0b7fe8bf2 100644 --- a/internal/command/user_human.go +++ b/internal/command/user_human.go @@ -235,12 +235,12 @@ func userValidateDomain(ctx context.Context, a *user.Aggregate, username string, return nil } - usernameSplit := strings.Split(username, "@") - if len(usernameSplit) != 2 { - return errors.ThrowInvalidArgument(nil, "COMMAND-Dfd21", "Errors.User.Invalid") + index := strings.LastIndex(username, "@") + if index < 0 { + return nil } - domainCheck := NewOrgDomainVerifiedWriteModel(usernameSplit[1]) + domainCheck := NewOrgDomainVerifiedWriteModel(username[index+1:]) events, err := filter(ctx, domainCheck.Query()) if err != nil { return err @@ -443,16 +443,15 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain. human.Username = strings.TrimSpace(human.Username) human.EmailAddress = strings.TrimSpace(human.EmailAddress) if !domainPolicy.UserLoginMustBeDomain { - usernameSplit := strings.Split(human.Username, "@") - if len(usernameSplit) != 2 { - return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-Dfd21", "Errors.User.Invalid") - } - domainCheck := NewOrgDomainVerifiedWriteModel(usernameSplit[1]) - if err := c.eventstore.FilterToQueryReducer(ctx, domainCheck); err != nil { - return nil, nil, err - } - if domainCheck.Verified && domainCheck.ResourceOwner != orgID { - return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-SFd21", "Errors.User.DomainNotAllowedAsUsername") + index := strings.LastIndex(human.Username, "@") + if index > 1 { + domainCheck := NewOrgDomainVerifiedWriteModel(human.Username[index+1:]) + if err := c.eventstore.FilterToQueryReducer(ctx, domainCheck); err != nil { + return nil, nil, err + } + if domainCheck.Verified && domainCheck.ResourceOwner != orgID { + return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-SFd21", "Errors.User.DomainNotAllowedAsUsername") + } } } diff --git a/internal/command/user_human_test.go b/internal/command/user_human_test.go index 2dc0d66a4f..5e9ed14c0c 100644 --- a/internal/command/user_human_test.go +++ b/internal/command/user_human_test.go @@ -480,6 +480,224 @@ func TestCommandSide_AddHuman(t *testing.T) { }, }, }, + { + name: "add human, email verified, userLoginMustBeDomain false, ok", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + false, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewPasswordComplexityPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + 1, + false, + false, + false, + false, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher( + newAddHumanEvent("password", true, ""), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(context.Background(), + &userAgg.Aggregate), + ), + }, + uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", false)), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + human: &AddHuman{ + Username: "username", + Password: "password", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@test.ch", + Verified: true, + }, + PreferredLanguage: language.English, + PasswordChangeRequired: true, + }, + secretGenerator: GetMockSecretGenerator(t), + }, + res: res{ + want: &domain.HumanDetails{ + ID: "user1", + ObjectDetails: domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + }, + { + name: "add human claimed domain, userLoginMustBeDomain false, error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + false, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate("org2").Aggregate, + "test.ch", + ), + ), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + human: &AddHuman{ + Username: "username@test.ch", + Password: "password", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@test.ch", + Verified: true, + }, + PreferredLanguage: language.English, + PasswordChangeRequired: true, + }, + secretGenerator: GetMockSecretGenerator(t), + }, + res: res{ + err: errors.IsErrorInvalidArgument, + }, + }, + { + name: "add human domain, userLoginMustBeDomain false, ok", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + false, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + "test.ch", + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewPasswordComplexityPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + 1, + false, + false, + false, + false, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher( + func() eventstore.Command { + event := user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "username@test.ch", + "firstname", + "lastname", + "", + "firstname lastname", + language.English, + domain.GenderUnspecified, + "email@test.ch", + true, + ) + event.AddPasswordData(&crypto.CryptoValue{ + CryptoType: crypto.TypeHash, + Algorithm: "hash", + KeyID: "", + Crypted: []byte("password"), + }, true) + return event + }(), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(context.Background(), + &userAgg.Aggregate), + ), + }, + uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username@test.ch", "org1", false)), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + human: &AddHuman{ + Username: "username@test.ch", + Password: "password", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@test.ch", + Verified: true, + }, + PreferredLanguage: language.English, + PasswordChangeRequired: true, + }, + secretGenerator: GetMockSecretGenerator(t), + }, + + res: res{ + want: &domain.HumanDetails{ + ID: "user1", + ObjectDetails: domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + }, { name: "add human (with phone), ok", fields: fields{ @@ -2140,6 +2358,118 @@ func TestCommandSide_RegisterHuman(t *testing.T) { }, }, }, + { + name: "username without @, ok", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + false, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewPasswordComplexityPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + 1, + false, + false, + false, + false, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewLoginPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + false, + true, + false, + false, + false, + false, + false, + false, + false, + domain.PasswordlessTypeNotAllowed, + "", + time.Hour*1, + time.Hour*2, + time.Hour*3, + time.Hour*4, + time.Hour*5, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher( + newRegisterHumanEvent("username", "password", false, ""), + ), + eventFromEventPusher( + user.NewHumanInitialCodeAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("a"), + }, + time.Hour*1, + ), + ), + }, + uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", false)), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + human: &domain.Human{ + Password: &domain.Password{ + SecretString: "password", + }, + Profile: &domain.Profile{ + FirstName: "firstname", + LastName: "lastname", + }, + Email: &domain.Email{ + EmailAddress: "email@test.ch", + }, + Username: "username", + }, + secretGenerator: GetMockSecretGenerator(t), + }, + res: res{ + want: &domain.Human{ + ObjectRoot: models.ObjectRoot{ + AggregateID: "user1", + ResourceOwner: "org1", + }, + Username: "username", + Profile: &domain.Profile{ + FirstName: "firstname", + LastName: "lastname", + DisplayName: "firstname lastname", + PreferredLanguage: language.Und, + }, + Email: &domain.Email{ + EmailAddress: "email@test.ch", + }, + State: domain.UserStateInitial, + }, + }, + }, { name: "add human (with password and initial code), ok", fields: fields{ diff --git a/internal/notification/types/domain_claimed.go b/internal/notification/types/domain_claimed.go index cc6159454b..69ab8413ca 100644 --- a/internal/notification/types/domain_claimed.go +++ b/internal/notification/types/domain_claimed.go @@ -10,8 +10,9 @@ import ( func (notify Notify) SendDomainClaimed(user *query.NotifyUser, origin, username string) error { url := login.LoginLink(origin, user.ResourceOwner) + index := strings.LastIndex(user.LastEmail, "@") args := make(map[string]interface{}) args["TempUsername"] = username - args["Domain"] = strings.Split(user.LastEmail, "@")[1] + args["Domain"] = user.LastEmail[index+1:] return notify(url, args, domain.DomainClaimedMessageType, true) }