1
0
forked from baron/baron-sso
Files
baron-sso/backend/internal/service/ory_service_test.go
Lectom 75f192fb24 merge: integrate origin dev into dev
Includes Worksmobile SSOT sync comparison updates, UUID import conflict resolution, and Playwright route mock stabilization.
2026-06-01 17:48:39 +09:00

227 lines
6.5 KiB
Go

package service
import (
"baron-sso-backend/internal/domain"
"bytes"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
)
// clientForHandler returns an http.Client that routes requests to the given handler
// without real network sockets.
func clientForHandler(h http.Handler) *http.Client {
return &http.Client{
Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) {
// Clone request body for handler
var bodyBytes []byte
if req.Body != nil {
bodyBytes, _ = io.ReadAll(req.Body)
}
r := httptest.NewRequest(req.Method, req.URL.String(), bytes.NewReader(bodyBytes))
r.Header = req.Header.Clone()
w := httptest.NewRecorder()
h.ServeHTTP(w, r)
return w.Result(), nil
}),
}
}
type roundTripperFunc func(req *http.Request) (*http.Response, error)
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { return f(req) }
func TestUpdateUserPassword_Success(t *testing.T) {
const (
loginID = "user@example.com"
identityID = "7f0dc8c3-9d5d-4f57-b3d1-123456789abc"
newPassword = "Sup3rStr0ng!Pass#2026"
)
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case strings.HasPrefix(r.URL.Path, "/admin/identities") && r.Method == http.MethodGet:
if r.URL.Path == "/admin/identities" {
q := r.URL.Query()
if got := q.Get("credentials_identifier"); got != loginID {
t.Fatalf("expected credentials_identifier=%s, got=%s", loginID, got)
}
_ = json.NewEncoder(w).Encode([]map[string]any{
{
"id": identityID,
"traits": map[string]any{
"email": loginID,
},
},
})
return
}
if r.URL.Path != "/admin/identities/"+identityID {
t.Fatalf("unexpected identity lookup path: %s", r.URL.Path)
}
_ = json.NewEncoder(w).Encode(map[string]any{
"id": identityID,
"schema_id": "default",
"state": "active",
"traits": map[string]any{
"email": loginID,
},
})
return
case r.URL.Path == "/admin/identities/"+identityID && r.Method == http.MethodPut:
body, _ := io.ReadAll(r.Body)
if !strings.Contains(string(body), "\"hashed_password\"") {
t.Fatalf("payload missing hashed_password, body=%s", string(body))
}
if strings.Contains(string(body), newPassword) {
t.Fatalf("payload must not contain plain password, body=%s", string(body))
}
if !strings.Contains(string(body), "\"schema_id\":\"default\"") {
t.Fatalf("payload missing schema_id, body=%s", string(body))
}
w.WriteHeader(http.StatusOK)
return
default:
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String())
}
})
provider := &OryProvider{
KratosAdminURL: "http://kratos-admin.local",
HTTPClient: clientForHandler(handler),
}
if err := provider.UpdateUserPassword(loginID, newPassword, nil); err != nil {
t.Fatalf("UpdateUserPassword returned error: %v", err)
}
}
func TestUpdateUserPassword_NotFound(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/admin/identities") && r.Method == http.MethodGet {
http.NotFound(w, r)
return
}
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String())
})
provider := &OryProvider{
KratosAdminURL: "http://kratos-admin.local",
HTTPClient: clientForHandler(handler),
}
err := provider.UpdateUserPassword("user@example.com", "Sup3rStr0ng!Pass#2026", nil)
if err == nil || !strings.Contains(err.Error(), "identity not found") {
t.Fatalf("expected identity not found error, got: %v", err)
}
}
func TestUpdateUserPassword_ServerError(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case strings.HasPrefix(r.URL.Path, "/admin/identities") && r.Method == http.MethodGet:
if r.URL.Path == "/admin/identities" {
_ = json.NewEncoder(w).Encode([]map[string]any{
{
"id": "abc",
"traits": map[string]any{
"email": "user@example.com",
},
},
})
return
}
if r.URL.Path == "/admin/identities/abc" {
_ = json.NewEncoder(w).Encode(map[string]any{
"id": "abc",
"schema_id": "default",
"state": "active",
"traits": map[string]any{
"email": "user@example.com",
},
})
return
}
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String())
case r.URL.Path == "/admin/identities/abc" && r.Method == http.MethodPut:
http.Error(w, "boom", http.StatusInternalServerError)
return
default:
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String())
}
})
provider := &OryProvider{
KratosAdminURL: "http://kratos-admin.local",
HTTPClient: clientForHandler(handler),
}
err := provider.UpdateUserPassword("user@example.com", "Sup3rStr0ng!Pass#2026", nil)
if err == nil || !strings.Contains(err.Error(), "password update failed") {
t.Fatalf("expected server error, got: %v", err)
}
}
func TestFindIdentityID_QueryEncoding(t *testing.T) {
loginID := "user+alias@example.com"
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
values, _ := url.ParseQuery(r.URL.RawQuery)
if values.Get("credentials_identifier") != loginID {
t.Fatalf("expected credentials_identifier=%s, got=%s", loginID, values.Get("credentials_identifier"))
}
_ = json.NewEncoder(w).Encode([]map[string]any{
{
"id": "id-123",
"traits": map[string]any{
"email": loginID,
},
},
})
})
provider := &OryProvider{
KratosAdminURL: "http://kratos-admin.local",
HTTPClient: clientForHandler(handler),
}
id, err := provider.findIdentityID(loginID)
if err != nil {
t.Fatalf("findIdentityID returned error: %v", err)
}
if id != "id-123" {
t.Fatalf("expected id-123, got %s", id)
}
}
func TestOryProvider_CreateUser_RejectsRequestedIdentityID(t *testing.T) {
const (
email = "newuser@test.com"
name = "New User"
customUuid = "550e8400-e29b-41d4-a716-446655440000"
password = "secret123456"
)
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String())
})
provider := &OryProvider{
KratosAdminURL: "http://kratos-admin.local",
HTTPClient: clientForHandler(handler),
}
id, err := provider.CreateUser(&domain.BrokerUser{
ID: customUuid,
Email: email,
Name: name,
}, password)
if err == nil || !strings.Contains(err.Error(), "requested identity id import is disabled") {
t.Fatalf("expected requested identity id rejection, got id=%s err=%v", id, err)
}
}