mirror of
https://github.com/smallstep/certificates.git
synced 2024-11-11 07:11:00 +00:00
Add support for functions in OIDC token transformation template
This commit is contained in:
parent
d5b0d92bce
commit
29202eff26
@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/v3/oidc"
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
|
"go.step.sm/crypto/x509util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
@ -85,11 +86,7 @@ func (o *OIDCOptions) validateAndInitialize() (err error) {
|
|||||||
return fmt.Errorf("failed parsing OIDC template: %w", err)
|
return fmt.Errorf("failed parsing OIDC template: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
transformTemplate := defaultTemplate
|
o.transform, err = parseTransform(o.TransformTemplate)
|
||||||
if o.TransformTemplate != "" {
|
|
||||||
transformTemplate = o.TransformTemplate
|
|
||||||
}
|
|
||||||
o.transform, err = template.New("transform").Parse(transformTemplate)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed parsing OIDC transformation template: %w", err)
|
return fmt.Errorf("failed parsing OIDC transformation template: %w", err)
|
||||||
}
|
}
|
||||||
@ -97,6 +94,14 @@ func (o *OIDCOptions) validateAndInitialize() (err error) {
|
|||||||
return nil
|
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) {
|
func (o *OIDCOptions) EvaluateTarget(deviceID string) (string, error) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
if err := o.target.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil {
|
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 {
|
if o.transform == nil || v == nil {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
// TODO(hs): add support for extracting error message from template "fail" function?
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
if err := o.transform.Execute(buf, v); err != nil {
|
if err := o.transform.Execute(buf, v); err != nil {
|
||||||
return nil, fmt.Errorf("failed executing OIDC transformation: %w", err)
|
return nil, fmt.Errorf("failed executing OIDC transformation: %w", err)
|
||||||
|
@ -9,9 +9,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestOIDCOptions_Transform(t *testing.T) {
|
func TestOIDCOptions_Transform(t *testing.T) {
|
||||||
defaultTransform, err := template.New("defaultTransform").Parse(`{"name": "{{ .name }}", "handle": "{{ .preferred_username }}"}`)
|
defaultTransform, err := parseTransform(``)
|
||||||
require.NoError(t, err)
|
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)
|
require.NoError(t, err)
|
||||||
type fields struct {
|
type fields struct {
|
||||||
transform *template.Template
|
transform *template.Template
|
||||||
@ -86,6 +88,23 @@ func TestOIDCOptions_Transform(t *testing.T) {
|
|||||||
"preferred_username": "Preferred",
|
"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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user