package handler import ( "baron-sso-backend/internal/domain" "bytes" "context" "encoding/json" "io" "net/http" ) // --- Mock IDP Provider --- type mockIdpProvider struct { userExists bool name string signInInfo *domain.AuthInfo issueSession *domain.AuthInfo verifyCodeInfo *domain.AuthInfo err error initiateLinkErr error updateCalled bool updatedLoginID string updatedPassword string } func (m *mockIdpProvider) Name() string { if m.name != "" { return m.name } return "mock-idp" } func (m *mockIdpProvider) GetMetadata() (*domain.IDPMetadata, error) { return nil, m.err } func (m *mockIdpProvider) CreateUser(user *domain.BrokerUser, password string) (string, error) { return "mock-user-id", m.err } func (m *mockIdpProvider) SignIn(loginID, password string) (*domain.AuthInfo, error) { return m.signInInfo, m.err } func (m *mockIdpProvider) UserExists(loginID string) (bool, error) { return m.userExists, m.err } func (m *mockIdpProvider) IssueSession(loginID string) (*domain.AuthInfo, error) { if m.issueSession != nil { return m.issueSession, m.err } return &domain.AuthInfo{ SessionToken: &domain.Token{JWT: "valid-jwt", SessionID: "valid-sid"}, }, m.err } func (m *mockIdpProvider) InitiateLinkLogin(loginID, returnTo string) (*domain.LinkLoginInit, error) { if m.initiateLinkErr != nil { return nil, m.initiateLinkErr } return &domain.LinkLoginInit{FlowID: "mock-flow-id", Mode: "code"}, m.err } func (m *mockIdpProvider) VerifyLoginCode(loginID, flowID, code string) (*domain.AuthInfo, error) { return m.verifyCodeInfo, m.err } func (m *mockIdpProvider) GetPasswordPolicy() (*domain.PasswordPolicy, error) { return nil, m.err } func (m *mockIdpProvider) InitiatePasswordReset(loginID, redirectUrl string) error { return m.err } func (m *mockIdpProvider) VerifyPasswordResetToken(token string) (*domain.AuthInfo, error) { return nil, m.err } func (m *mockIdpProvider) UpdateUserPassword(loginID, newPassword string, r *http.Request) error { m.updateCalled = true m.updatedLoginID = loginID m.updatedPassword = newPassword return m.err } // --- Mock Audit Repository --- type mockAuditRepo struct { logs []domain.AuditLog } func (m *mockAuditRepo) Create(log *domain.AuditLog) error { m.logs = append(m.logs, *log) return nil } func (m *mockAuditRepo) FindPage(ctx context.Context, limit int, cursor *domain.AuditCursor) ([]domain.AuditLog, error) { return m.logs, nil } func (m *mockAuditRepo) FindByUserAndEvents(ctx context.Context, userID string, eventTypes []string, limit int) ([]domain.AuditLog, error) { var results []domain.AuditLog for _, log := range m.logs { if log.UserID == userID { for _, et := range eventTypes { if log.EventType == et { results = append(results, log) break } } } } return results, nil } func (m *mockAuditRepo) Ping(ctx context.Context) error { return nil } // --- Mock Consent Repository --- type mockConsentRepo struct { consents []domain.ClientConsent } func (m *mockConsentRepo) Upsert(ctx context.Context, consent *domain.ClientConsent) error { m.consents = append(m.consents, *consent) return nil } func (m *mockConsentRepo) ListBySubject(ctx context.Context, subject string) ([]domain.ClientConsent, error) { var results []domain.ClientConsent for _, c := range m.consents { if c.Subject == subject { results = append(results, c) } } return results, nil } func (m *mockConsentRepo) Delete(ctx context.Context, clientID, subject string) error { return nil } func (m *mockConsentRepo) List(ctx context.Context, clientID string, limit, offset int) ([]domain.ClientConsentWithTenantInfo, int64, error) { return nil, 0, nil } func (m *mockConsentRepo) ListByTenant(ctx context.Context, clientID, tenantID string, limit, offset int) ([]domain.ClientConsentWithTenantInfo, int64, error) { return nil, 0, nil } // --- Mock Secret Repository --- type mockSecretRepo struct { secrets map[string]string } func (m *mockSecretRepo) Upsert(ctx context.Context, clientID, secret string) error { if m.secrets == nil { m.secrets = make(map[string]string) } m.secrets[clientID] = secret return nil } func (m *mockSecretRepo) GetByID(ctx context.Context, clientID string) (string, error) { return m.secrets[clientID], nil } func (m *mockSecretRepo) Delete(ctx context.Context, clientID string) error { delete(m.secrets, clientID) return nil } // --- HTTP Mock Helpers --- type roundTripFunc func(req *http.Request) (*http.Response, error) func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { return f(req) } func setDefaultHTTPClientForTest(t interface{ Cleanup(func()) }, transport http.RoundTripper) { origDefault := http.DefaultClient http.DefaultClient = &http.Client{Transport: transport} t.Cleanup(func() { http.DefaultClient = origDefault }) } func httpResponse(r *http.Request, code int, body string) *http.Response { return &http.Response{ StatusCode: code, Header: make(http.Header), Body: io.NopCloser(bytes.NewBufferString(body)), Request: r, } } func httpJSONAny(r *http.Request, code int, data any) *http.Response { body, _ := json.Marshal(data) return &http.Response{ StatusCode: code, Header: http.Header{ "Content-Type": []string{"application/json"}, }, Body: io.NopCloser(bytes.NewBuffer(body)), Request: r, } }