package authn import ( "reflect" "time" "forge.cadoles.com/cadoles/bouncer/internal/store" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" ) type LayerOptions struct { MatchURLs []string `mapstructure:"matchURLs"` Headers HeadersOptions `mapstructure:"headers"` } type HeadersOptions struct { Rules []string `mapstructure:"rules"` } func DefaultLayerOptions() LayerOptions { return LayerOptions{ MatchURLs: []string{"*"}, Headers: HeadersOptions{ Rules: []string{ "del_headers('Remote-*')", "set_header('Remote-User', user.subject)", `map( toPairs(user.attrs), { let name = replace(lower(string(get(#, 0))), '_', '-'); set_header( 'Remote-User-Attr-' + name, get(#, 1) ) }) `, }, }, } } func fromStoreOptions(storeOptions store.LayerOptions) (*LayerOptions, error) { layerOptions := DefaultLayerOptions() if err := FromStoreOptions(storeOptions, &layerOptions); err != nil { return nil, errors.WithStack(err) } return &layerOptions, nil } func FromStoreOptions(storeOptions store.LayerOptions, dest any) error { config := mapstructure.DecoderConfig{ Result: dest, ZeroFields: true, DecodeHook: mapstructure.ComposeDecodeHookFunc( toDurationHookFunc(), ), } decoder, err := mapstructure.NewDecoder(&config) if err != nil { return errors.WithStack(err) } if err := decoder.Decode(storeOptions); err != nil { return errors.WithStack(err) } return nil } func toDurationHookFunc() mapstructure.DecodeHookFunc { return func( f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { if t != reflect.TypeOf(*new(time.Duration)) { return data, nil } switch f.Kind() { case reflect.String: return time.ParseDuration(data.(string)) case reflect.Int64: return time.Duration(data.(int64) * int64(time.Second)), nil default: return data, nil } // Convert it by parsing } }