Merge pull request #105 from smallstep/okta-support

Address support on OIDC provisioners
This commit is contained in:
Mariano Cano 2019-09-20 15:33:11 -07:00 committed by GitHub
commit 59526d3225
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 12 deletions

View file

@ -4,7 +4,10 @@ import (
"context"
"crypto/x509"
"encoding/json"
"net"
"net/http"
"net/url"
"path"
"strings"
"time"
@ -55,6 +58,7 @@ type OIDC struct {
Admins []string `json:"admins,omitempty"`
Domains []string `json:"domains,omitempty"`
Groups []string `json:"groups,omitempty"`
ListenAddress string `json:"listenAddress,omitempty"`
Claims *Claims `json:"claims,omitempty"`
configuration openIDConfiguration
keyStore *keyStore
@ -133,13 +137,27 @@ func (o *OIDC) Init(config Config) (err error) {
return errors.New("configurationEndpoint cannot be empty")
}
// Validate listenAddress if given
if o.ListenAddress != "" {
if _, _, err := net.SplitHostPort(o.ListenAddress); err != nil {
return errors.Wrap(err, "error parsing listenAddress")
}
}
// Update claims with global ones
if o.claimer, err = NewClaimer(o.Claims, config.Claims); err != nil {
return err
}
// Decode and validate openid-configuration endpoint
if err := getAndDecode(o.ConfigurationEndpoint, &o.configuration); err != nil {
u, err := url.Parse(o.ConfigurationEndpoint)
if err != nil {
return errors.Wrapf(err, "error parsing %s", o.ConfigurationEndpoint)
}
if !strings.Contains(u.Path, "/.well-known/openid-configuration") {
u.Path = path.Join(u.Path, "/.well-known/openid-configuration")
}
if err := getAndDecode(u.String(), &o.configuration); err != nil {
return err
}
if err := o.configuration.Validate(); err != nil {

View file

@ -81,6 +81,7 @@ func TestOIDC_Init(t *testing.T) {
Claims *Claims
Admins []string
Domains []string
ListenAddress string
}
type args struct {
config Config
@ -91,16 +92,21 @@ func TestOIDC_Init(t *testing.T) {
args args
wantErr bool
}{
{"ok", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, false},
{"ok-admins", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/openid-configuration", nil, []string{"foo@smallstep.com"}, nil}, args{config}, false},
{"ok-domains", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/openid-configuration", nil, nil, []string{"smallstep.com"}}, args{config}, false},
{"ok-no-secret", fields{"oidc", "name", "client-id", "", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, false},
{"no-name", fields{"oidc", "", "client-id", "client-secret", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, true},
{"no-type", fields{"", "name", "client-id", "client-secret", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, true},
{"no-client-id", fields{"oidc", "name", "", "client-secret", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, true},
{"no-configuration", fields{"oidc", "name", "client-id", "client-secret", "", nil, nil, nil}, args{config}, true},
{"bad-configuration", fields{"oidc", "name", "client-id", "client-secret", srv.URL, nil, nil, nil}, args{config}, true},
{"bad-claims", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/openid-configuration", badClaims, nil, nil}, args{config}, true},
{"ok", fields{"oidc", "name", "client-id", "client-secret", srv.URL, nil, nil, nil, ""}, args{config}, false},
{"ok-admins", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/.well-known/openid-configuration", nil, []string{"foo@smallstep.com"}, nil, ""}, args{config}, false},
{"ok-domains", fields{"oidc", "name", "client-id", "client-secret", srv.URL, nil, nil, []string{"smallstep.com"}, ""}, args{config}, false},
{"ok-listen-port", fields{"oidc", "name", "client-id", "client-secret", srv.URL, nil, nil, nil, ":10000"}, args{config}, false},
{"ok-listen-host-port", fields{"oidc", "name", "client-id", "client-secret", srv.URL, nil, nil, nil, "127.0.0.1:10000"}, args{config}, false},
{"ok-no-secret", fields{"oidc", "name", "client-id", "", srv.URL, nil, nil, nil, ""}, args{config}, false},
{"no-name", fields{"oidc", "", "client-id", "client-secret", srv.URL, nil, nil, nil, ""}, args{config}, true},
{"no-type", fields{"", "name", "client-id", "client-secret", srv.URL, nil, nil, nil, ""}, args{config}, true},
{"no-client-id", fields{"oidc", "name", "", "client-secret", srv.URL, nil, nil, nil, ""}, args{config}, true},
{"no-configuration", fields{"oidc", "name", "client-id", "client-secret", "", nil, nil, nil, ""}, args{config}, true},
{"bad-configuration", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/random", nil, nil, nil, ""}, args{config}, true},
{"bad-claims", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/.well-known/openid-configuration", badClaims, nil, nil, ""}, args{config}, true},
{"bad-parse-url", fields{"oidc", "name", "client-id", "client-secret", ":", nil, nil, nil, ""}, args{config}, true},
{"bad-get-url", fields{"oidc", "name", "client-id", "client-secret", "https://", nil, nil, nil, ""}, args{config}, true},
{"bad-listen-address", fields{"oidc", "name", "client-id", "client-secret", srv.URL, nil, nil, nil, "127.0.0.1"}, args{config}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -111,9 +117,12 @@ func TestOIDC_Init(t *testing.T) {
ConfigurationEndpoint: tt.fields.ConfigurationEndpoint,
Claims: tt.fields.Claims,
Admins: tt.fields.Admins,
Domains: tt.fields.Domains,
ListenAddress: tt.fields.ListenAddress,
}
if err := p.Init(tt.args.config); (err != nil) != tt.wantErr {
t.Errorf("OIDC.Init() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr == false {
assert.Len(t, 2, p.keyStore.keySet.Keys)

View file

@ -709,7 +709,7 @@ func generateJWKServer(n int) *httptest.Server {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
case "/hits":
writeJSON(w, hits)
case "/openid-configuration", "/.well-known/openid-configuration":
case "/.well-known/openid-configuration":
writeJSON(w, openIDConfiguration{Issuer: "the-issuer", JWKSetURI: srv.URL + "/jwks_uri"})
case "/random":
keySet := must(generateJSONWebKeySet(n))[0].(jose.JSONWebKeySet)

View file

@ -111,6 +111,7 @@ is G-Suite.
"configurationEndpoint": "https://accounts.google.com/.well-known/openid-configuration",
"admins": ["you@smallstep.com"],
"domains": ["smallstep.com"],
"listenAddress": ":10000",
"claims": {
"maxTLSCertDuration": "8h",
"defaultTLSCertDuration": "2h",
@ -141,6 +142,12 @@ is G-Suite.
* `domains` (optional): is the list of domains valid. If provided only the
emails with the provided domains will be able to authenticate.
* `listenAddress` (optional): is the loopback address (`:port` or `host:port`)
where the authorization server will redirect to complete the authorization
flow. If it's not defined `step` will use `127.0.0.1` with a random port. This
configuration is only required if the authorization server doesn't allow any
port to be specified at the time of the request for loopback IP redirect URIs.
* `claims` (optional): overwrites the default claims set in the authority, see
the [JWK](#jwk) section for all the options.