|
|
@ -1,12 +1,20 @@
|
|
|
|
package wire
|
|
|
|
package wire
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"errors"
|
|
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"net/http/httptest"
|
|
|
|
"testing"
|
|
|
|
"testing"
|
|
|
|
"text/template"
|
|
|
|
"text/template"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/coreos/go-oidc/v3/oidc"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"go.step.sm/crypto/jose"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func TestOIDCOptions_Transform(t *testing.T) {
|
|
|
|
func TestOIDCOptions_Transform(t *testing.T) {
|
|
|
@ -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
|
|
|
|
|
|
|
|
}
|
|
|
|