Add support for functions in OIDC token transformation template

This commit is contained in:
Herman Slatman 2024-01-15 13:17:44 +01:00
parent d5b0d92bce
commit 29202eff26
No known key found for this signature in database
GPG Key ID: F4D8A44EA0A75A4F
2 changed files with 32 additions and 7 deletions

View File

@ -11,6 +11,7 @@ import (
"time"
"github.com/coreos/go-oidc/v3/oidc"
"go.step.sm/crypto/x509util"
)
type Provider struct {
@ -85,11 +86,7 @@ func (o *OIDCOptions) validateAndInitialize() (err error) {
return fmt.Errorf("failed parsing OIDC template: %w", err)
}
transformTemplate := defaultTemplate
if o.TransformTemplate != "" {
transformTemplate = o.TransformTemplate
}
o.transform, err = template.New("transform").Parse(transformTemplate)
o.transform, err = parseTransform(o.TransformTemplate)
if err != nil {
return fmt.Errorf("failed parsing OIDC transformation template: %w", err)
}
@ -97,6 +94,14 @@ func (o *OIDCOptions) validateAndInitialize() (err error) {
return nil
}
func parseTransform(transformTemplate string) (*template.Template, error) {
if transformTemplate == "" {
transformTemplate = defaultTemplate
}
return template.New("transform").Funcs(x509util.GetFuncMap()).Parse(transformTemplate)
}
func (o *OIDCOptions) EvaluateTarget(deviceID string) (string, error) {
buf := new(bytes.Buffer)
if err := o.target.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil {
@ -109,6 +114,7 @@ func (o *OIDCOptions) Transform(v map[string]any) (map[string]any, error) {
if o.transform == nil || v == nil {
return v, nil
}
// TODO(hs): add support for extracting error message from template "fail" function?
buf := new(bytes.Buffer)
if err := o.transform.Execute(buf, v); err != nil {
return nil, fmt.Errorf("failed executing OIDC transformation: %w", err)

View File

@ -9,9 +9,11 @@ import (
)
func TestOIDCOptions_Transform(t *testing.T) {
defaultTransform, err := template.New("defaultTransform").Parse(`{"name": "{{ .name }}", "handle": "{{ .preferred_username }}"}`)
defaultTransform, err := parseTransform(``)
require.NoError(t, err)
swapTransform, err := template.New("swapTransform").Parse(`{"name": "{{ .preferred_username }}", "handle": "{{ .name }}"}`)
swapTransform, err := parseTransform(`{"name": "{{ .preferred_username }}", "handle": "{{ .name }}"}`)
require.NoError(t, err)
funcTransform, err := parseTransform(`{"name": "{{ .name }}", "handle": "{{ first .usernames }}"}`)
require.NoError(t, err)
type fields struct {
transform *template.Template
@ -86,6 +88,23 @@ func TestOIDCOptions_Transform(t *testing.T) {
"preferred_username": "Preferred",
},
},
{
name: "ok/transform-with-functions",
fields: fields{
transform: funcTransform,
},
args: args{
v: map[string]any{
"name": "Example",
"usernames": []string{"name-1", "name-2", "name-3"},
},
},
want: map[string]any{
"name": "Example",
"handle": "name-1",
"usernames": []string{"name-1", "name-2", "name-3"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {