179 lines
5.1 KiB
Go
179 lines
5.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"baron-sso-backend/internal/service"
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
func newOidcLoginTestApp(h *AuthHandler) *fiber.App {
|
|
app := fiber.New()
|
|
app.Post("/api/v1/auth/oidc/login/accept", h.AcceptOidcLoginRequest)
|
|
return app
|
|
}
|
|
|
|
func TestAcceptOidcLoginRequest_CookieOnly(t *testing.T) {
|
|
var gotSubject string
|
|
var gotChallenge string
|
|
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
|
switch r.URL.Host {
|
|
case "kratos.test":
|
|
if r.URL.Path != "/sessions/whoami" {
|
|
return httpResponse(r, http.StatusNotFound, "not found"), nil
|
|
}
|
|
if r.Header.Get("X-Session-Token") != "" {
|
|
return httpResponse(r, http.StatusUnauthorized, "invalid token"), nil
|
|
}
|
|
if r.Header.Get("Cookie") == "" {
|
|
return httpResponse(r, http.StatusUnauthorized, "missing cookie"), nil
|
|
}
|
|
return httpJSONAny(r, http.StatusOK, map[string]any{
|
|
"identity": map[string]any{
|
|
"id": "kratos-123",
|
|
"traits": map[string]any{},
|
|
},
|
|
}), nil
|
|
case "hydra.test":
|
|
if r.URL.Path != "/oauth2/auth/requests/login/accept" {
|
|
return httpResponse(r, http.StatusNotFound, "not found"), nil
|
|
}
|
|
gotChallenge = r.URL.Query().Get("login_challenge")
|
|
body, _ := io.ReadAll(r.Body)
|
|
var payload map[string]any
|
|
_ = json.Unmarshal(body, &payload)
|
|
if subject, ok := payload["subject"].(string); ok {
|
|
gotSubject = subject
|
|
}
|
|
return httpResponse(r, http.StatusOK, `{"redirect_to":"http://rp/cb"}`), nil
|
|
default:
|
|
return httpResponse(r, http.StatusNotFound, "not found"), nil
|
|
}
|
|
})
|
|
client := &http.Client{Transport: transport}
|
|
origDefault := http.DefaultClient
|
|
http.DefaultClient = client
|
|
defer func() {
|
|
http.DefaultClient = origDefault
|
|
}()
|
|
|
|
t.Setenv("KRATOS_PUBLIC_URL", "http://kratos.test")
|
|
|
|
h := &AuthHandler{
|
|
Hydra: &service.HydraAdminService{
|
|
AdminURL: "http://hydra.test",
|
|
HTTPClient: client,
|
|
},
|
|
}
|
|
app := newOidcLoginTestApp(h)
|
|
|
|
body, _ := json.Marshal(map[string]string{
|
|
"login_challenge": "challenge-123",
|
|
})
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/oidc/login/accept", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Cookie", "ory_kratos_session=abc123")
|
|
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
var got map[string]string
|
|
if err := json.NewDecoder(resp.Body).Decode(&got); err != nil {
|
|
t.Fatalf("failed to decode response: %v", err)
|
|
}
|
|
if got["redirectTo"] != "http://rp/cb" {
|
|
t.Fatalf("unexpected redirectTo: %v", got["redirectTo"])
|
|
}
|
|
if gotSubject != "kratos-123" {
|
|
t.Fatalf("unexpected subject: %v", gotSubject)
|
|
}
|
|
if gotChallenge != "challenge-123" {
|
|
t.Fatalf("unexpected login_challenge: %v", gotChallenge)
|
|
}
|
|
}
|
|
|
|
func TestAcceptOidcLoginRequest_TokenFallbackToCookie(t *testing.T) {
|
|
var gotSubject string
|
|
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
|
switch r.URL.Host {
|
|
case "kratos.test":
|
|
if r.URL.Path != "/sessions/whoami" {
|
|
return httpResponse(r, http.StatusNotFound, "not found"), nil
|
|
}
|
|
if r.Header.Get("X-Session-Token") != "" {
|
|
return httpResponse(r, http.StatusUnauthorized, "invalid token"), nil
|
|
}
|
|
if r.Header.Get("Cookie") == "" {
|
|
return httpResponse(r, http.StatusUnauthorized, "missing cookie"), nil
|
|
}
|
|
return httpJSONAny(r, http.StatusOK, map[string]any{
|
|
"identity": map[string]any{
|
|
"id": "kratos-456",
|
|
"traits": map[string]any{},
|
|
},
|
|
}), nil
|
|
case "hydra.test":
|
|
if r.URL.Path != "/oauth2/auth/requests/login/accept" {
|
|
return httpResponse(r, http.StatusNotFound, "not found"), nil
|
|
}
|
|
body, _ := io.ReadAll(r.Body)
|
|
var payload map[string]any
|
|
_ = json.Unmarshal(body, &payload)
|
|
if subject, ok := payload["subject"].(string); ok {
|
|
gotSubject = subject
|
|
}
|
|
return httpResponse(r, http.StatusOK, `{"redirect_to":"http://rp/cb"}`), nil
|
|
default:
|
|
return httpResponse(r, http.StatusNotFound, "not found"), nil
|
|
}
|
|
})
|
|
client := &http.Client{Transport: transport}
|
|
origDefault := http.DefaultClient
|
|
http.DefaultClient = client
|
|
defer func() {
|
|
http.DefaultClient = origDefault
|
|
}()
|
|
|
|
t.Setenv("KRATOS_PUBLIC_URL", "http://kratos.test")
|
|
|
|
h := &AuthHandler{
|
|
Hydra: &service.HydraAdminService{
|
|
AdminURL: "http://hydra.test",
|
|
HTTPClient: client,
|
|
},
|
|
}
|
|
app := newOidcLoginTestApp(h)
|
|
|
|
body, _ := json.Marshal(map[string]string{
|
|
"login_challenge": "challenge-456",
|
|
})
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/oidc/login/accept", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer invalid-token")
|
|
req.Header.Set("Cookie", "ory_kratos_session=def456")
|
|
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
if gotSubject != "kratos-456" {
|
|
t.Fatalf("unexpected subject: %v", gotSubject)
|
|
}
|
|
}
|