Skip to content

Commit

Permalink
Add test for OIDC auto discovery configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
hslatman committed Feb 6, 2024
1 parent 138c101 commit 745017c
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 13 deletions.
26 changes: 14 additions & 12 deletions authority/provisioner/wire/oidc_options.go
Expand Up @@ -15,13 +15,13 @@ import (
)

type Provider struct {
DiscoveryBaseURL string `json:"discoveryBaseUrl,omitempty"` // TODO: probably safe to change to our usual configuration style
IssuerURL string `json:"issuer,omitempty"`
AuthURL string `json:"authorization_endpoint,omitempty"`
TokenURL string `json:"token_endpoint,omitempty"`
JWKSURL string `json:"jwks_uri,omitempty"`
UserInfoURL string `json:"userinfo_endpoint,omitempty"`
Algorithms []string `json:"id_token_signing_alg_values_supported,omitempty"`
DiscoveryBaseURL string `json:"discoveryBaseUrl,omitempty"`
IssuerURL string `json:"issuerUrl,omitempty"`
AuthURL string `json:"authorizationUrl,omitempty"`
TokenURL string `json:"tokenUrl,omitempty"`
JWKSURL string `json:"jwksUrl,omitempty"`
UserInfoURL string `json:"userInfoUrl,omitempty"`
Algorithms []string `json:"signatureAlgorithms,omitempty"`
}

type Config struct {
Expand Down Expand Up @@ -94,13 +94,15 @@ func (o *OIDCOptions) validateAndInitialize() (err error) {
if o.Provider == nil {
return errors.New("provider not set")
}
if o.Provider.IssuerURL == "" {
return errors.New("issuer URL must not be empty")
if o.Provider.IssuerURL == "" && o.Provider.DiscoveryBaseURL == "" {
return errors.New("either OIDC discovery or issuer URL must be set")
}

o.oidcProviderConfig, err = toOIDCProviderConfig(o.Provider)
if err != nil {
return fmt.Errorf("failed creationg OIDC provider config: %w", err)
if o.Provider.DiscoveryBaseURL == "" {
o.oidcProviderConfig, err = toOIDCProviderConfig(o.Provider)
if err != nil {
return fmt.Errorf("failed creationg OIDC provider config: %w", err)
}
}

o.target, err = template.New("DeviceID").Parse(o.Provider.IssuerURL)
Expand Down
132 changes: 132 additions & 0 deletions authority/provisioner/wire/oidc_options_test.go
@@ -1,12 +1,20 @@
package wire

import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"testing"
"text/template"

"github.com/coreos/go-oidc/v3/oidc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.step.sm/crypto/jose"
)

func TestOIDCOptions_Transform(t *testing.T) {
Expand Down Expand Up @@ -171,3 +179,127 @@ func TestOIDCOptions_EvaluateTarget(t *testing.T) {
})
}
}

func TestOIDCOptions_GetVerifier(t *testing.T) {
signerJWK, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0)
require.NoError(t, err)
require.NoError(t, err)
srv := mustDiscoveryServer(t, signerJWK.Public())
defer srv.Close()
type fields struct {
Provider *Provider
Config *Config
TransformTemplate string
}
tests := []struct {
name string
fields fields
ctx context.Context
want *oidc.IDTokenVerifier
wantErr bool
}{
{
name: "fail/invalid-discovery-url",
fields: fields{
Provider: &Provider{
DiscoveryBaseURL: "http://invalid.example.com",
},
Config: &Config{
ClientID: "client-id",
},
TransformTemplate: "http://target.example.com/{{.DeviceID}}",
},
ctx: context.Background(),
wantErr: true,
},
{
name: "ok/auto",
fields: fields{
Provider: &Provider{
DiscoveryBaseURL: srv.URL,
},
Config: &Config{
ClientID: "client-id",
},
TransformTemplate: "http://target.example.com/{{.DeviceID}}",
},
ctx: context.Background(),
},
{
name: "ok/fixed",
fields: fields{
Provider: &Provider{
IssuerURL: "http://issuer.example.com",
},
Config: &Config{
ClientID: "client-id",
},
TransformTemplate: "http://target.example.com/{{.DeviceID}}",
},
ctx: context.Background(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &OIDCOptions{
Provider: tt.fields.Provider,
Config: tt.fields.Config,
TransformTemplate: tt.fields.TransformTemplate,
}

err := o.validateAndInitialize()
require.NoError(t, err)

verifier, err := o.GetVerifier(tt.ctx)
if tt.wantErr {
assert.Error(t, err)
assert.Nil(t, verifier)
return
}

assert.NoError(t, err)
assert.NotNil(t, verifier)
if assert.NotNil(t, o.provider) {
assert.NotNil(t, o.provider.Endpoint())
}
})
}
}

func mustDiscoveryServer(t *testing.T, pub jose.JSONWebKey) *httptest.Server {
t.Helper()
mux := http.NewServeMux()
server := httptest.NewServer(mux)
b, err := json.Marshal(struct {
Keys []jose.JSONWebKey `json:"keys,omitempty"`
}{
Keys: []jose.JSONWebKey{pub},
})
require.NoError(t, err)
jwks := string(b)

wellKnown := fmt.Sprintf(`{
"issuer": "%[1]s",
"authorization_endpoint": "%[1]s/auth",
"token_endpoint": "%[1]s/token",
"jwks_uri": "%[1]s/keys",
"userinfo_endpoint": "%[1]s/userinfo",
"id_token_signing_alg_values_supported": ["ES256"]
}`, server.URL)

mux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, req *http.Request) {
_, err := io.WriteString(w, wellKnown)
if err != nil {
w.WriteHeader(500)
}
})
mux.HandleFunc("/keys", func(w http.ResponseWriter, req *http.Request) {
_, err := io.WriteString(w, jwks)
if err != nil {
w.WriteHeader(500)
}
})

t.Cleanup(server.Close)
return server
}
2 changes: 1 addition & 1 deletion authority/provisioner/wire/wire_options_test.go
Expand Up @@ -55,7 +55,7 @@ MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
},
DPOP: &DPOPOptions{},
},
expectedErr: errors.New("failed initializing OIDC options: issuer URL must not be empty"),
expectedErr: errors.New("failed initializing OIDC options: either OIDC discovery or issuer URL must be set"),
},
{
name: "fail/invalid-issuer-url",
Expand Down

0 comments on commit 745017c

Please sign in to comment.