1
0
forked from baron/baron-sso

네이버 계정 정합성 맞춤

This commit is contained in:
2026-06-15 19:54:09 +09:00
parent 8e9d015443
commit 4d468cd39f
97 changed files with 5837 additions and 2031 deletions

View File

@@ -36,6 +36,7 @@ func TestWorksmobileHTTPClientCreateUserPostsDirectoryAdminPasswordPayload(t *te
Email: "tester@samaneng.com",
UserExternalKey: "user-1",
UserName: WorksmobileUserName{LastName: "Tester"},
CellPhone: "+821041585840",
AliasEmails: []string{"tester.alias@samaneng.com", "tester.alias2@samaneng.com"},
Locale: "ko_KR",
PasswordConfig: WorksmobilePasswordConfig{
@@ -57,11 +58,13 @@ func TestWorksmobileHTTPClientCreateUserPostsDirectoryAdminPasswordPayload(t *te
require.NoError(t, json.Unmarshal(transport.requestBody, &payload))
require.Equal(t, "tester@samaneng.com", payload["email"])
require.Equal(t, "user-1", payload["userExternalKey"])
require.Equal(t, "+82 01041585840", payload["cellPhone"])
require.NotContains(t, payload, "privateEmail")
require.Equal(t, []any{"tester.alias@samaneng.com", "tester.alias2@samaneng.com"}, payload["aliasEmails"])
passwordConfig := payload["passwordConfig"].(map[string]any)
require.Equal(t, "ADMIN", passwordConfig["passwordCreationType"])
require.Len(t, passwordConfig["password"], 16)
require.Equal(t, true, passwordConfig["changePasswordAtNextLogin"])
}
func TestWorksmobileHTTPClientDeleteUserUsesDirectDirectoryDeleteForEmail(t *testing.T) {
@@ -92,7 +95,7 @@ func TestNewWorksmobileUserPatchPayloadNormalizesMalformedKoreanCellPhone(t *tes
UserName: WorksmobileUserName{LastName: "Phone Canonical User"},
})
require.Equal(t, "+821062836786", payload.CellPhone)
require.Equal(t, "+82 01062836786", payload.CellPhone)
}
func TestNewWorksmobileSCIMUserPayloadNormalizesMalformedKoreanCellPhone(t *testing.T) {
@@ -103,7 +106,7 @@ func TestNewWorksmobileSCIMUserPayloadNormalizesMalformedKoreanCellPhone(t *test
})
require.Len(t, payload.PhoneNumbers, 1)
require.Equal(t, "+821062836786", payload.PhoneNumbers[0].Value)
require.Equal(t, "+82 01062836786", payload.PhoneNumbers[0].Value)
}
func TestWorksmobileHTTPClientUpsertUserPatchesOnCreateConflictWithoutPasswordOrPrivateEmail(t *testing.T) {
@@ -155,6 +158,196 @@ func TestWorksmobileHTTPClientUpsertUserPatchesOnCreateConflictWithoutPasswordOr
require.Equal(t, "user-1", patchPayload["userExternalKey"])
}
func TestWorksmobileHTTPClientUpdateUserOnlyPatchesWithoutCreateOrPassword(t *testing.T) {
transport := &captureRoundTripper{
statusCode: http.StatusOK,
body: `{}`,
}
client := &WorksmobileHTTPClient{
BaseURL: "https://works.example.test",
DirectoryToken: "directory-token-1",
HTTPClient: &http.Client{Transport: transport},
}
err := client.UpdateUserOnly(context.Background(), WorksmobileUserPayload{
DomainID: 300285955,
Email: "moved@samaneng.com",
UserExternalKey: "user-1",
UserName: WorksmobileUserName{LastName: "Moved User"},
PrivateEmail: "private@example.com",
PasswordConfig: WorksmobilePasswordConfig{
PasswordCreationType: "ADMIN",
Password: "Aa1!Aa1!Aa1!Aa1!",
},
Organizations: []WorksmobileUserOrganization{
{
DomainID: 300285955,
Primary: true,
OrgUnits: []WorksmobileUserOrgUnit{
{OrgUnitID: "externalKey:new-tenant", Primary: true},
},
},
},
})
require.NoError(t, err)
require.Len(t, transport.requests, 1)
require.Equal(t, http.MethodPatch, transport.requests[0].Method)
require.Equal(t, "/v1.0/users/moved@samaneng.com", transport.requests[0].URL.Path)
var patchPayload map[string]any
require.NoError(t, json.Unmarshal(transport.requestBodies[0], &patchPayload))
require.NotContains(t, patchPayload, "passwordConfig")
require.NotContains(t, patchPayload, "privateEmail")
require.Equal(t, "moved@samaneng.com", patchPayload["email"])
require.Equal(t, "user-1", patchPayload["userExternalKey"])
}
func TestWorksmobileHTTPClientUpsertUserFallsBackToExternalKeyPatchWhenEmailPatchNotFound(t *testing.T) {
transport := &captureRoundTripper{
responses: []captureResponse{
{statusCode: http.StatusConflict, body: `{"code":"CONFLICT","description":"This externalKey(user-1) of user already exists."}`},
{statusCode: http.StatusNotFound, body: `{"code":"NOT_FOUND","description":"User (new-email@example.com) does not exist."}`},
{statusCode: http.StatusOK, body: `{}`},
},
}
client := &WorksmobileHTTPClient{
BaseURL: "https://works.example.test",
DirectoryToken: "directory-token-1",
HTTPClient: &http.Client{Transport: transport},
}
err := client.UpsertUser(context.Background(), WorksmobileUserPayload{
DomainID: 300286336,
Email: "new-email@example.com",
UserExternalKey: "user-1",
UserName: WorksmobileUserName{LastName: "Tester"},
Organizations: []WorksmobileUserOrganization{
{
DomainID: 300286336,
Primary: true,
OrgUnits: []WorksmobileUserOrgUnit{
{OrgUnitID: "externalKey:tenant-hanmac", Primary: true},
},
},
},
})
require.NoError(t, err)
require.Len(t, transport.requests, 3)
require.Equal(t, http.MethodPost, transport.requests[0].Method)
require.Equal(t, http.MethodPatch, transport.requests[1].Method)
require.Equal(t, "/v1.0/users/new-email@example.com", transport.requests[1].URL.Path)
require.Equal(t, http.MethodPatch, transport.requests[2].Method)
require.Equal(t, "/v1.0/users/user-1", transport.requests[2].URL.Path)
}
func TestWorksmobileHTTPClientUpsertUserFallsBackToRemoteIDPatchWhenExternalKeyPatchNotFound(t *testing.T) {
transport := &captureRoundTripper{
responses: []captureResponse{
{statusCode: http.StatusConflict, body: `{"code":"CONFLICT","description":"This externalKey(user-1) of user already exists."}`},
{statusCode: http.StatusNotFound, body: `{"code":"NOT_FOUND","description":"User (new-email@example.com) does not exist."}`},
{statusCode: http.StatusNotFound, body: `{"code":"NOT_FOUND","description":"User (user-1) does not exist."}`},
{statusCode: http.StatusOK, body: `{"users":[{"userId":"works-user-1","userExternalKey":"user-1","email":"old-email@example.com"}],"responseMetaData":{}}`},
{statusCode: http.StatusOK, body: `{}`},
},
}
client := &WorksmobileHTTPClient{
BaseURL: "https://works.example.test",
DirectoryToken: "directory-token-1",
DomainIDs: []int64{300286336},
HTTPClient: &http.Client{Transport: transport},
}
err := client.UpsertUser(context.Background(), WorksmobileUserPayload{
DomainID: 300286336,
Email: "new-email@example.com",
UserExternalKey: "user-1",
UserName: WorksmobileUserName{LastName: "Tester"},
Organizations: []WorksmobileUserOrganization{
{
DomainID: 300286336,
Primary: true,
OrgUnits: []WorksmobileUserOrgUnit{
{OrgUnitID: "externalKey:tenant-hanmac", Primary: true},
},
},
},
})
require.NoError(t, err)
require.Len(t, transport.requests, 5)
require.Equal(t, http.MethodGet, transport.requests[3].Method)
require.Equal(t, "/v1.0/users", transport.requests[3].URL.Path)
require.Equal(t, "300286336", transport.requests[3].URL.Query().Get("domainId"))
require.Equal(t, http.MethodPatch, transport.requests[4].Method)
require.Equal(t, "/v1.0/users/works-user-1", transport.requests[4].URL.Path)
}
func TestWorksmobileHTTPClientExternalKeyLookupStartsWithPayloadDomain(t *testing.T) {
transport := &captureRoundTripper{
responses: []captureResponse{
{statusCode: http.StatusConflict, body: `{"code":"CONFLICT","description":"This externalKey(user-1) of user already exists."}`},
{statusCode: http.StatusNotFound, body: `{"code":"NOT_FOUND","description":"User (new-email@example.com) does not exist."}`},
{statusCode: http.StatusNotFound, body: `{"code":"NOT_FOUND","description":"User (user-1) does not exist."}`},
{statusCode: http.StatusOK, body: `{"users":[],"responseMetaData":{}}`},
{statusCode: http.StatusOK, body: `{"users":[{"userId":"works-user-1","userExternalKey":"user-1","email":"old-email@example.com"}],"responseMetaData":{}}`},
{statusCode: http.StatusOK, body: `{}`},
},
}
client := &WorksmobileHTTPClient{
BaseURL: "https://works.example.test",
DirectoryToken: "directory-token-1",
DomainIDs: []int64{300285955, 300286336},
HTTPClient: &http.Client{Transport: transport},
}
err := client.UpsertUser(context.Background(), WorksmobileUserPayload{
DomainID: 300286336,
Email: "new-email@example.com",
UserExternalKey: "user-1",
UserName: WorksmobileUserName{LastName: "Tester"},
})
require.NoError(t, err)
require.Len(t, transport.requests, 6)
require.Equal(t, http.MethodGet, transport.requests[3].Method)
require.Equal(t, "300286336", transport.requests[3].URL.Query().Get("domainId"))
require.Equal(t, http.MethodGet, transport.requests[4].Method)
require.Equal(t, "300285955", transport.requests[4].URL.Query().Get("domainId"))
require.Equal(t, http.MethodPatch, transport.requests[5].Method)
require.Equal(t, "/v1.0/users/works-user-1", transport.requests[5].URL.Path)
}
func TestWorksmobileHTTPClientExternalKeyLookupRejectsDuplicateMatches(t *testing.T) {
transport := &captureRoundTripper{
responses: []captureResponse{
{statusCode: http.StatusConflict, body: `{"code":"CONFLICT","description":"This externalKey(user-1) of user already exists."}`},
{statusCode: http.StatusNotFound, body: `{"code":"NOT_FOUND","description":"User (new-email@example.com) does not exist."}`},
{statusCode: http.StatusNotFound, body: `{"code":"NOT_FOUND","description":"User (user-1) does not exist."}`},
{statusCode: http.StatusOK, body: `{"users":[{"userId":"works-user-1","userExternalKey":"user-1","email":"old-email-1@example.com"}],"responseMetaData":{}}`},
{statusCode: http.StatusOK, body: `{"users":[{"userId":"works-user-2","userExternalKey":"user-1","email":"old-email-2@example.com"}],"responseMetaData":{}}`},
},
}
client := &WorksmobileHTTPClient{
BaseURL: "https://works.example.test",
DirectoryToken: "directory-token-1",
DomainIDs: []int64{300286336, 300285955},
HTTPClient: &http.Client{Transport: transport},
}
err := client.UpsertUser(context.Background(), WorksmobileUserPayload{
DomainID: 300286336,
Email: "new-email@example.com",
UserExternalKey: "user-1",
UserName: WorksmobileUserName{LastName: "Tester"},
})
require.Error(t, err)
require.Contains(t, err.Error(), "multiple worksmobile users matched external key")
require.Len(t, transport.requests, 5)
}
func TestWorksmobileHTTPClientAddUserAliasEmailPostsDirectoryAliasEndpoint(t *testing.T) {
transport := &captureRoundTripper{
statusCode: http.StatusCreated,
@@ -637,6 +830,45 @@ func TestWorksmobileRelayWorkerProcessesUserCreateAndMarksProcessed(t *testing.T
require.Equal(t, "tester@samaneng.com", client.createdUsers[0].Email)
}
func TestWorksmobileRelayWorkerProcessesAutomaticUserUpdateOnlyWithoutCreate(t *testing.T) {
repo := &fakeWorksmobileOutboxRepo{
ready: []domain.WorksmobileOutbox{
{
ID: "job-1",
ResourceType: domain.WorksmobileResourceUser,
ResourceID: "user-1",
Action: domain.WorksmobileActionUpsert,
Status: domain.WorksmobileOutboxStatusPending,
Payload: worksmobileUserOutboxPayload("root-1", WorksmobileUserPayload{
Email: "moved@samaneng.com",
UserExternalKey: "user-1",
UserName: WorksmobileUserName{LastName: "Moved User"},
Organizations: []WorksmobileUserOrganization{
{
DomainID: 300285955,
Primary: true,
OrgUnits: []WorksmobileUserOrgUnit{
{OrgUnitID: "externalKey:new-tenant", Primary: true},
},
},
},
}),
},
},
}
repo.ready[0].Payload["provisioningMode"] = "update_only"
client := &fakeWorksmobileDirectoryClient{}
worker := NewWorksmobileRelayWorker(repo, client)
err := worker.ProcessOnce(context.Background())
require.NoError(t, err)
require.Equal(t, []string{"job-1"}, repo.processedIDs)
require.Empty(t, client.createdUsers)
require.Len(t, client.updatedUsers, 1)
require.Equal(t, "moved@samaneng.com", client.updatedUsers[0].Email)
}
func TestWorksmobileRelayWorkerRegistersAliasEmailsAfterUserUpsert(t *testing.T) {
repo := &fakeWorksmobileOutboxRepo{
ready: []domain.WorksmobileOutbox{
@@ -1482,6 +1714,7 @@ type fakeWorksmobileDirectoryClient struct {
createdOrgUnits []WorksmobileOrgUnitPayload
deletedOrgUnits []string
createdUsers []WorksmobileUserPayload
updatedUsers []WorksmobileUserPayload
deletedUsers []string
activeUsers []string
suspendedUsers []string
@@ -1610,6 +1843,11 @@ func (f *fakeWorksmobileDirectoryClient) UpsertUser(ctx context.Context, payload
return nil
}
func (f *fakeWorksmobileDirectoryClient) UpdateUserOnly(ctx context.Context, payload WorksmobileUserPayload) error {
f.updatedUsers = append(f.updatedUsers, payload)
return nil
}
func (f *fakeWorksmobileDirectoryClient) AddUserAliasEmail(ctx context.Context, userID string, email string) error {
f.aliasEmails = append(f.aliasEmails, userID+":"+email)
return nil