forked from baron/baron-sso
- Added support for fixed UUIDs during bulk registration (Search-first + ExternalID mapping) - Implemented idempotency and visibility restoration for soft-deleted users - Enhanced bulk upload UI to show 'New/Updated/Unchanged' status and modified fields - Added logic to reclaim identifiers (login_id) from colliding records - Added frontend E2E and backend unit tests for UUID integrity and conflict handling - Fixed i18n, formatting, and mock tests to satisfy code-check - Applied 'go fix' for 'omitzero' tags and general Go standards
86 lines
2.4 KiB
Go
86 lines
2.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/go-jose/go-jose/v4"
|
|
josejwt "github.com/go-jose/go-jose/v4/jwt"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestBackchannelLogoutService_BuildLogoutToken(t *testing.T) {
|
|
t.Setenv("BACKCHANNEL_LOGOUT_ISSUER", "https://sso.example.com/oidc")
|
|
|
|
svc, err := NewBackchannelLogoutService()
|
|
require.NoError(t, err)
|
|
|
|
token, err := svc.BuildLogoutToken("client-1", "user-1", "sid-1")
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, token)
|
|
|
|
jwksRaw, err := svc.MarshalPublicJWKS()
|
|
require.NoError(t, err)
|
|
|
|
var jwks struct {
|
|
Keys []jose.JSONWebKey `json:"keys"`
|
|
}
|
|
require.NoError(t, json.Unmarshal(jwksRaw, &jwks))
|
|
require.Len(t, jwks.Keys, 1)
|
|
|
|
parsed, err := josejwt.ParseSigned(token, []jose.SignatureAlgorithm{jose.RS256})
|
|
require.NoError(t, err)
|
|
|
|
var claims struct {
|
|
Issuer string `json:"iss"`
|
|
Subject string `json:"sub"`
|
|
Aud any `json:"aud"`
|
|
Iat int64 `json:"iat"`
|
|
Jti string `json:"jti"`
|
|
Sid string `json:"sid"`
|
|
Events map[string]any `json:"events"`
|
|
}
|
|
require.NoError(t, parsed.Claims(jwks.Keys[0].Key, &claims))
|
|
|
|
assert.Equal(t, "https://sso.example.com/oidc", claims.Issuer)
|
|
assert.Equal(t, "user-1", claims.Subject)
|
|
switch aud := claims.Aud.(type) {
|
|
case string:
|
|
assert.Equal(t, "client-1", aud)
|
|
case []any:
|
|
assert.Len(t, aud, 1)
|
|
assert.Equal(t, "client-1", aud[0])
|
|
default:
|
|
t.Fatalf("unexpected aud type: %T", claims.Aud)
|
|
}
|
|
assert.NotZero(t, claims.Iat)
|
|
assert.NotEmpty(t, claims.Jti)
|
|
assert.Equal(t, "sid-1", claims.Sid)
|
|
_, ok := claims.Events[backchannelLogoutEventURI]
|
|
assert.True(t, ok)
|
|
}
|
|
|
|
func TestBackchannelLogoutService_SendLogoutToken(t *testing.T) {
|
|
var body string
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
assert.Equal(t, http.MethodPost, r.Method)
|
|
assert.Equal(t, "application/x-www-form-urlencoded", r.Header.Get("Content-Type"))
|
|
raw, _ := io.ReadAll(r.Body)
|
|
body = string(raw)
|
|
w.WriteHeader(http.StatusNoContent)
|
|
})
|
|
|
|
svc, err := NewBackchannelLogoutService()
|
|
require.NoError(t, err)
|
|
svc.HTTPClient = clientForHandler(handler)
|
|
|
|
statusCode, err := svc.SendLogoutToken(context.Background(), "https://rp.example.com/backchannel-logout", "signed-token")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusNoContent, statusCode)
|
|
assert.Equal(t, "logout_token=signed-token", body)
|
|
}
|