mirror of
https://github.com/teamhanko/hanko.git
synced 2025-11-01 22:28:27 +08:00
feat: custom jwt claims
This commit is contained in:
committed by
GitHub
parent
bc9eece531
commit
efeca4a76f
261
backend/session/template_test.go
Normal file
261
backend/session/template_test.go
Normal file
@ -0,0 +1,261 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/lestrrat-go/jwx/v2/jwt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/teamhanko/hanko/backend/dto"
|
||||
)
|
||||
|
||||
func TestProcessTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
template string
|
||||
data JWTTemplateData
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "simple template",
|
||||
template: "Hello {{.User.Email.Address}}",
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{
|
||||
Email: &dto.EmailJWT{
|
||||
Address: "test@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "Hello test@example.com",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "template with pipelining",
|
||||
template: "Hello {{.User.Email.Address | printf \"%s\" }}",
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{
|
||||
Email: &dto.EmailJWT{
|
||||
Address: "test@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "Hello test@example.com",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "template with conditional",
|
||||
template: "{{if .User.Email.IsVerified}}Verified{{else}}Unverified{{end}} user {{.User.Email.Address}}",
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{
|
||||
Email: &dto.EmailJWT{
|
||||
Address: "test@example.com",
|
||||
IsVerified: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "Verified user test@example.com",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid template",
|
||||
template: "Hello {{.InvalidField}}",
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{},
|
||||
},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty template",
|
||||
template: "",
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{},
|
||||
},
|
||||
want: "",
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseClaimTemplateValue(tt.template, tt.data)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessClaimValue(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
value interface{}
|
||||
data JWTTemplateData
|
||||
want interface{}
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "string template",
|
||||
value: "Hello {{.User.Email.Address}}",
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{
|
||||
Email: &dto.EmailJWT{
|
||||
Address: "test@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "Hello test@example.com",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "nested map with templates",
|
||||
value: map[string]interface{}{
|
||||
"greeting": "Hello {{.User.Email.Address}}",
|
||||
"nested": map[string]interface{}{
|
||||
"message": "Welcome {{.User.Email.Address}}",
|
||||
},
|
||||
},
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{
|
||||
Email: &dto.EmailJWT{
|
||||
Address: "test@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: map[string]interface{}{
|
||||
"greeting": "Hello test@example.com",
|
||||
"nested": map[string]interface{}{
|
||||
"message": "Welcome test@example.com",
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "slice with templates",
|
||||
value: []interface{}{
|
||||
"Hello {{.User.Email.Address}}",
|
||||
map[string]interface{}{
|
||||
"message": "Welcome {{.User.Email.Address}}",
|
||||
},
|
||||
},
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{
|
||||
Email: &dto.EmailJWT{
|
||||
Address: "test@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []interface{}{
|
||||
"Hello test@example.com",
|
||||
map[string]interface{}{
|
||||
"message": "Welcome test@example.com",
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "non-string primitive",
|
||||
value: 42,
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{},
|
||||
},
|
||||
want: 42,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid template in map",
|
||||
value: map[string]interface{}{
|
||||
"message": "Hello {{.InvalidField}}",
|
||||
},
|
||||
data: JWTTemplateData{
|
||||
User: &dto.UserJWT{},
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := processClaimTemplate(tt.value, tt.data)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessClaimTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
claims map[string]interface{}
|
||||
user dto.UserJWT
|
||||
expectedClaims map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "successful claim processing",
|
||||
claims: map[string]interface{}{
|
||||
"email": "{{.User.Email.Address}}",
|
||||
"verified": "{{.User.Email.IsVerified}}",
|
||||
"static_string": "static-value",
|
||||
"static_bool": false,
|
||||
},
|
||||
user: dto.UserJWT{
|
||||
Email: &dto.EmailJWT{
|
||||
Address: "test@example.com",
|
||||
IsVerified: true,
|
||||
},
|
||||
},
|
||||
expectedClaims: map[string]interface{}{
|
||||
"email": "test@example.com",
|
||||
"verified": true,
|
||||
"static_string": "static-value",
|
||||
"static_bool": false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "partial claim processing with errors",
|
||||
claims: map[string]interface{}{
|
||||
"valid": "{{.User.Email.Address}}",
|
||||
"invalid": "{{.InvalidField}}",
|
||||
"static": "static-value",
|
||||
},
|
||||
user: dto.UserJWT{
|
||||
Email: &dto.EmailJWT{
|
||||
Address: "test@example.com",
|
||||
},
|
||||
},
|
||||
expectedClaims: map[string]interface{}{
|
||||
"valid": "test@example.com",
|
||||
"static": "static-value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
token := jwt.New()
|
||||
err := ProcessJWTTemplate(token, tt.claims, tt.user)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Verify each expected claim
|
||||
for key, expectedValue := range tt.expectedClaims {
|
||||
value, exists := token.Get(key)
|
||||
assert.True(t, exists, "claim %s should exist", key)
|
||||
assert.Equal(t, expectedValue, value, "claim %s should have correct value", key)
|
||||
}
|
||||
|
||||
// For the error case, verify the invalid claim was not set
|
||||
if tt.name == "partial claim processing with errors" {
|
||||
_, exists := token.Get("invalid")
|
||||
assert.False(t, exists, "invalid claim should not be set")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user