From ef657d7d2d798e51e4fd5d98fdd5720c91e74315 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Tue, 6 Feb 2024 13:17:49 +0100 Subject: [PATCH] Fix OIDC target --- acme/api/order_test.go | 1 + acme/api/wire_integration_test.go | 26 ++++++---- authority/provisioner/wire/dpop_options.go | 2 +- .../provisioner/wire/dpop_options_test.go | 2 +- authority/provisioner/wire/oidc_options.go | 3 -- .../provisioner/wire/oidc_options_test.go | 52 +++++++++++++++++++ 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/acme/api/order_test.go b/acme/api/order_test.go index da95bc23..6377b0fc 100644 --- a/acme/api/order_test.go +++ b/acme/api/order_test.go @@ -1755,6 +1755,7 @@ MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k= InsecureSkipSignatureCheck: true, Now: time.Now, }, + TransformTemplate: "https://target.example.com", }, DPOP: &wire.DPOPOptions{ SigningKey: []byte(fakeWireSigningKey), diff --git a/acme/api/wire_integration_test.go b/acme/api/wire_integration_test.go index c59af069..56e94cd2 100644 --- a/acme/api/wire_integration_test.go +++ b/acme/api/wire_integration_test.go @@ -25,6 +25,7 @@ import ( "github.com/smallstep/certificates/acme" "github.com/smallstep/certificates/acme/db/nosql" "github.com/smallstep/certificates/authority" + "github.com/smallstep/certificates/authority/config" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/authority/provisioner/wire" nosqlDB "github.com/smallstep/nosql" @@ -42,16 +43,23 @@ const ( ) func newWireProvisionerWithOptions(t *testing.T, options *provisioner.Options) *provisioner.ACME { - p := newProvWithOptions(options) - a, ok := p.(*provisioner.ACME) - if !ok { - t.Fatal("not a valid ACME provisioner") + t.Helper() + prov := &provisioner.ACME{ + Type: "ACME", + Name: "test@acme-provisioner.com", + Options: options, + Challenges: []provisioner.ACMEChallenge{ + provisioner.WIREOIDC_01, + provisioner.WIREDPOP_01, + }, } - a.Challenges = []provisioner.ACMEChallenge{ - provisioner.WIREOIDC_01, - provisioner.WIREDPOP_01, - } - return a + + err := prov.Init(provisioner.Config{ + Claims: config.GlobalProvisionerClaims, + }) + require.NoError(t, err) + + return prov } // TODO(hs): replace with test CA server + acmez based test client for diff --git a/authority/provisioner/wire/dpop_options.go b/authority/provisioner/wire/dpop_options.go index 303ddb41..010cd5ee 100644 --- a/authority/provisioner/wire/dpop_options.go +++ b/authority/provisioner/wire/dpop_options.go @@ -30,7 +30,7 @@ func (o *DPOPOptions) EvaluateTarget(deviceID string) (string, error) { } buf := new(bytes.Buffer) if err := o.target.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil { - return "", fmt.Errorf("failed executing dpop template: %w", err) + return "", fmt.Errorf("failed executing DPoP template: %w", err) } return buf.String(), nil } diff --git a/authority/provisioner/wire/dpop_options_test.go b/authority/provisioner/wire/dpop_options_test.go index 79507ce2..68aeb7cf 100644 --- a/authority/provisioner/wire/dpop_options_test.go +++ b/authority/provisioner/wire/dpop_options_test.go @@ -36,7 +36,7 @@ func TestDPOPOptions_EvaluateTarget(t *testing.T) { name: "fail/empty", fields: fields{target: target}, args: args{deviceID: ""}, expectedErr: errors.New("deviceID must not be empty"), }, { - name: "fail/template", fields: fields{target: failTarget}, args: args{deviceID: "bla"}, expectedErr: errors.New(`failed executing dpop template: template: DeviceID:1:32: executing "DeviceID" at <.DeviceId>: can't evaluate field DeviceId in type struct { DeviceID string }`), + name: "fail/template", fields: fields{target: failTarget}, args: args{deviceID: "bla"}, expectedErr: errors.New(`failed executing DPoP template: template: DeviceID:1:32: executing "DeviceID" at <.DeviceId>: can't evaluate field DeviceId in type struct { DeviceID string }`), }, } for _, tt := range tests { diff --git a/authority/provisioner/wire/oidc_options.go b/authority/provisioner/wire/oidc_options.go index d7f2b9ae..60403e43 100644 --- a/authority/provisioner/wire/oidc_options.go +++ b/authority/provisioner/wire/oidc_options.go @@ -125,9 +125,6 @@ func parseTransform(transformTemplate string) (*template.Template, error) { } func (o *OIDCOptions) EvaluateTarget(deviceID string) (string, error) { - if deviceID == "" { - return "", errors.New("deviceID must not be empty") - } buf := new(bytes.Buffer) if err := o.target.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil { return "", fmt.Errorf("failed executing OIDC template: %w", err) diff --git a/authority/provisioner/wire/oidc_options_test.go b/authority/provisioner/wire/oidc_options_test.go index 8b3eaa75..9a2203ca 100644 --- a/authority/provisioner/wire/oidc_options_test.go +++ b/authority/provisioner/wire/oidc_options_test.go @@ -1,6 +1,7 @@ package wire import ( + "errors" "testing" "text/template" @@ -119,3 +120,54 @@ func TestOIDCOptions_Transform(t *testing.T) { }) } } + +func TestOIDCOptions_EvaluateTarget(t *testing.T) { + tu := "http://target.example.com/{{.DeviceID}}" + target, err := template.New("DeviceID").Parse(tu) + require.NoError(t, err) + empty := "http://target.example.com" + emptyTarget, err := template.New("DeviceID").Parse(empty) + require.NoError(t, err) + fail := "https:/wire.com:15958/clients/{{.DeviceId}}/access-token" + failTarget, err := template.New("DeviceID").Parse(fail) + require.NoError(t, err) + type fields struct { + target *template.Template + } + type args struct { + deviceID string + } + tests := []struct { + name string + fields fields + args args + want string + expectedErr error + }{ + { + name: "ok", fields: fields{target: target}, args: args{deviceID: "deviceID"}, want: "http://target.example.com/deviceID", + }, + { + name: "ok/empty", fields: fields{target: emptyTarget}, args: args{deviceID: ""}, want: "http://target.example.com", + }, + { + name: "fail/template", fields: fields{target: failTarget}, args: args{deviceID: "bla"}, expectedErr: errors.New(`failed executing OIDC template: template: DeviceID:1:32: executing "DeviceID" at <.DeviceId>: can't evaluate field DeviceId in type struct { DeviceID string }`), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + o := &OIDCOptions{ + target: tt.fields.target, + } + got, err := o.EvaluateTarget(tt.args.deviceID) + if tt.expectedErr != nil { + assert.EqualError(t, err, tt.expectedErr.Error()) + assert.Empty(t, got) + return + } + + assert.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +}