Files
ai-agent/internal/services/oidc_login_service_test.go
T
mlogclub eac039bba4 feat: add OIDC login support
- Introduced OIDC configuration options in config.example.yaml.
- Added OIDC client initialization and routes for OIDC login, callback, and exchange.
- Implemented OIDC login service to handle user authentication via OIDC.
- Created frontend components for OIDC login and callback handling.
- Updated user creation logic to support OIDC users and their identities.
- Enhanced error handling for OIDC login processes.
2026-05-24 20:49:10 +08:00

97 lines
3.1 KiB
Go

package services
import (
"strings"
"testing"
"cs-agent/internal/models"
"cs-agent/internal/pkg/config"
"cs-agent/internal/pkg/enums"
)
func TestOIDCLoginAutoCreatesSystemUser(t *testing.T) {
db := setupAuthServiceTestDB(t)
svc := newOIDCLoginService()
ret, err := svc.loginWithOIDCProfile(&oidcLoginProfile{
Subject: "sub-123",
Email: "ada@example.com",
PreferredUsername: "ada",
Name: "Ada Lovelace",
Picture: "https://example.com/ada.png",
RawProfile: `{"sub":"sub-123"}`,
}, config.AuthConfig{TokenTTLHours: 2}, "127.0.0.1", "go-test")
if err != nil {
t.Fatalf("loginWithOIDCProfile() error = %v", err)
}
if ret == nil || !strings.HasPrefix(ret.AccessToken, "ak_") {
t.Fatalf("expected ak_ access token, got %+v", ret)
}
var user models.User
if err := db.Take(&user, "username = ?", "ada").Error; err != nil {
t.Fatalf("expected OIDC user to be created: %v", err)
}
if user.Nickname != "Ada Lovelace" || user.Avatar != "https://example.com/ada.png" {
t.Fatalf("unexpected created user profile: %+v", user)
}
if user.Email == nil || *user.Email != "ada@example.com" {
t.Fatalf("expected email to be stored, got %+v", user.Email)
}
if user.Password != "" {
t.Fatalf("expected OIDC-created user password to be empty, got %q", user.Password)
}
var identity models.UserIdentity
if err := db.Take(&identity, "provider = ? AND provider_user_id = ?", enums.ThirdProviderOIDC, "sub-123").Error; err != nil {
t.Fatalf("expected OIDC identity to be created: %v", err)
}
if identity.UserID != user.ID || identity.ProviderName != "OIDC" || identity.Status != enums.StatusOk {
t.Fatalf("unexpected OIDC identity: %+v", identity)
}
var sessions []models.LoginSession
if err := db.Find(&sessions).Error; err != nil {
t.Fatalf("query login sessions: %v", err)
}
if len(sessions) != 1 || sessions[0].UserID != user.ID || sessions[0].Token != ret.AccessToken {
t.Fatalf("unexpected login sessions: %+v", sessions)
}
}
func TestOIDCLoginReusesExistingIdentity(t *testing.T) {
db := setupAuthServiceTestDB(t)
user := createAuthTestUser(t, db, "existing", "secret")
if err := db.Create(&models.UserIdentity{
UserID: user.ID,
Provider: enums.ThirdProviderOIDC,
ProviderUserID: "sub-123",
ProviderName: "OIDC",
Status: enums.StatusOk,
}).Error; err != nil {
t.Fatalf("seed OIDC identity: %v", err)
}
ret, err := newOIDCLoginService().loginWithOIDCProfile(&oidcLoginProfile{
Subject: "sub-123",
PreferredUsername: "ignored",
Name: "Updated Name",
Picture: "https://example.com/updated.png",
RawProfile: `{"sub":"sub-123"}`,
}, config.AuthConfig{TokenTTLHours: 2}, "127.0.0.1", "go-test")
if err != nil {
t.Fatalf("loginWithOIDCProfile() error = %v", err)
}
if ret == nil || ret.User == nil || ret.User.ID != user.ID {
t.Fatalf("expected existing user login response, got %+v", ret)
}
var count int64
if err := db.Model(&models.User{}).Count(&count).Error; err != nil {
t.Fatalf("count users: %v", err)
}
if count != 1 {
t.Fatalf("expected existing identity to reuse user, got %d users", count)
}
}