Skip to content

Commit

Permalink
refactor: map claims converter
Browse files Browse the repository at this point in the history
  • Loading branch information
james-d-elliott committed Dec 8, 2024
1 parent 54a771a commit d697229
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
5 changes: 5 additions & 0 deletions token/jwt/claims_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import (
"authelia.com/provider/oauth2/x/errorsx"
)

// NewMapClaims returns a set of MapClaims from an object that has the appropriate JSON tags.
func NewMapClaims(obj any) (claims MapClaims) {
return toMap(obj)
}

// MapClaims is a simple map based claims structure.
type MapClaims map[string]any

Expand Down
76 changes: 76 additions & 0 deletions token/jwt/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"crypto/sha512"
"fmt"
"hash"
"reflect"
"regexp"
"strings"

Expand Down Expand Up @@ -467,3 +468,78 @@ func newError(message string, err error, more ...error) error {
err = fmt.Errorf(format, args...)
return err
}

func toMap(obj any) (result map[string]any) {
result = map[string]any{}

if obj == nil {
return result
}

v := reflect.TypeOf(obj)

reflectValue := reflect.ValueOf(obj)
reflectValue = reflect.Indirect(reflectValue)

if v.Kind() == reflect.Ptr {
v = v.Elem()
}

for i := 0; i < v.NumField(); i++ {
tag, opts := parseTag(v.Field(i).Tag.Get("json"))
field := reflectValue.Field(i).Interface()
if tag != "" && tag != "-" {
if opts.Contains("omitempty") && isEmptyValue(reflect.ValueOf(field)) {
continue
}

if v.Field(i).Type.Kind() == reflect.Struct {
result[tag] = toMap(field)
} else {
result[tag] = field
}
}
}

return result
}

type tagOptionsJSON string

func parseTag(tag string) (string, tagOptionsJSON) {
tag, opt, _ := strings.Cut(tag, ",")
return tag, tagOptionsJSON(opt)
}

func (o tagOptionsJSON) Contains(optionName string) bool {
if len(o) == 0 {
return false
}

s := string(o)

for s != "" {
var name string
name, s, _ = strings.Cut(s, ",")
if name == optionName {
return true
}
}

return false
}

func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Float32, reflect.Float64,
reflect.Interface, reflect.Pointer:
return v.IsZero()
default:
return false
}
}

0 comments on commit d697229

Please sign in to comment.