forked from TrueCloudLab/certificates
Merge pull request #105 from smallstep/okta-support
Address support on OIDC provisioners
This commit is contained in:
commit
59526d3225
4 changed files with 46 additions and 12 deletions
|
@ -4,7 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -55,6 +58,7 @@ type OIDC struct {
|
||||||
Admins []string `json:"admins,omitempty"`
|
Admins []string `json:"admins,omitempty"`
|
||||||
Domains []string `json:"domains,omitempty"`
|
Domains []string `json:"domains,omitempty"`
|
||||||
Groups []string `json:"groups,omitempty"`
|
Groups []string `json:"groups,omitempty"`
|
||||||
|
ListenAddress string `json:"listenAddress,omitempty"`
|
||||||
Claims *Claims `json:"claims,omitempty"`
|
Claims *Claims `json:"claims,omitempty"`
|
||||||
configuration openIDConfiguration
|
configuration openIDConfiguration
|
||||||
keyStore *keyStore
|
keyStore *keyStore
|
||||||
|
@ -133,13 +137,27 @@ func (o *OIDC) Init(config Config) (err error) {
|
||||||
return errors.New("configurationEndpoint cannot be empty")
|
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
|
// Update claims with global ones
|
||||||
if o.claimer, err = NewClaimer(o.Claims, config.Claims); err != nil {
|
if o.claimer, err = NewClaimer(o.Claims, config.Claims); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode and validate openid-configuration endpoint
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
if err := o.configuration.Validate(); err != nil {
|
if err := o.configuration.Validate(); err != nil {
|
||||||
|
|
|
@ -81,6 +81,7 @@ func TestOIDC_Init(t *testing.T) {
|
||||||
Claims *Claims
|
Claims *Claims
|
||||||
Admins []string
|
Admins []string
|
||||||
Domains []string
|
Domains []string
|
||||||
|
ListenAddress string
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
config Config
|
config Config
|
||||||
|
@ -91,16 +92,21 @@ func TestOIDC_Init(t *testing.T) {
|
||||||
args args
|
args args
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, false},
|
{"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 + "/openid-configuration", nil, []string{"foo@smallstep.com"}, 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 + "/openid-configuration", nil, nil, []string{"smallstep.com"}}, args{config}, false},
|
{"ok-domains", fields{"oidc", "name", "client-id", "client-secret", srv.URL, 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},
|
{"ok-listen-port", fields{"oidc", "name", "client-id", "client-secret", srv.URL, nil, nil, nil, ":10000"}, args{config}, false},
|
||||||
{"no-name", fields{"oidc", "", "client-id", "client-secret", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, true},
|
{"ok-listen-host-port", fields{"oidc", "name", "client-id", "client-secret", srv.URL, nil, nil, nil, "127.0.0.1:10000"}, args{config}, false},
|
||||||
{"no-type", fields{"", "name", "client-id", "client-secret", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, true},
|
{"ok-no-secret", fields{"oidc", "name", "client-id", "", srv.URL, nil, nil, nil, ""}, args{config}, false},
|
||||||
{"no-client-id", fields{"oidc", "name", "", "client-secret", srv.URL + "/openid-configuration", nil, nil, nil}, args{config}, true},
|
{"no-name", fields{"oidc", "", "client-id", "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},
|
{"no-type", fields{"", "name", "client-id", "client-secret", srv.URL, nil, nil, nil, ""}, args{config}, true},
|
||||||
{"bad-configuration", fields{"oidc", "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},
|
||||||
{"bad-claims", fields{"oidc", "name", "client-id", "client-secret", srv.URL + "/openid-configuration", badClaims, 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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -111,9 +117,12 @@ func TestOIDC_Init(t *testing.T) {
|
||||||
ConfigurationEndpoint: tt.fields.ConfigurationEndpoint,
|
ConfigurationEndpoint: tt.fields.ConfigurationEndpoint,
|
||||||
Claims: tt.fields.Claims,
|
Claims: tt.fields.Claims,
|
||||||
Admins: tt.fields.Admins,
|
Admins: tt.fields.Admins,
|
||||||
|
Domains: tt.fields.Domains,
|
||||||
|
ListenAddress: tt.fields.ListenAddress,
|
||||||
}
|
}
|
||||||
if err := p.Init(tt.args.config); (err != nil) != tt.wantErr {
|
if err := p.Init(tt.args.config); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("OIDC.Init() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("OIDC.Init() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if tt.wantErr == false {
|
if tt.wantErr == false {
|
||||||
assert.Len(t, 2, p.keyStore.keySet.Keys)
|
assert.Len(t, 2, p.keyStore.keySet.Keys)
|
||||||
|
|
|
@ -709,7 +709,7 @@ func generateJWKServer(n int) *httptest.Server {
|
||||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||||
case "/hits":
|
case "/hits":
|
||||||
writeJSON(w, 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"})
|
writeJSON(w, openIDConfiguration{Issuer: "the-issuer", JWKSetURI: srv.URL + "/jwks_uri"})
|
||||||
case "/random":
|
case "/random":
|
||||||
keySet := must(generateJSONWebKeySet(n))[0].(jose.JSONWebKeySet)
|
keySet := must(generateJSONWebKeySet(n))[0].(jose.JSONWebKeySet)
|
||||||
|
|
|
@ -111,6 +111,7 @@ is G-Suite.
|
||||||
"configurationEndpoint": "https://accounts.google.com/.well-known/openid-configuration",
|
"configurationEndpoint": "https://accounts.google.com/.well-known/openid-configuration",
|
||||||
"admins": ["you@smallstep.com"],
|
"admins": ["you@smallstep.com"],
|
||||||
"domains": ["smallstep.com"],
|
"domains": ["smallstep.com"],
|
||||||
|
"listenAddress": ":10000",
|
||||||
"claims": {
|
"claims": {
|
||||||
"maxTLSCertDuration": "8h",
|
"maxTLSCertDuration": "8h",
|
||||||
"defaultTLSCertDuration": "2h",
|
"defaultTLSCertDuration": "2h",
|
||||||
|
@ -141,6 +142,12 @@ is G-Suite.
|
||||||
* `domains` (optional): is the list of domains valid. If provided only the
|
* `domains` (optional): is the list of domains valid. If provided only the
|
||||||
emails with the provided domains will be able to authenticate.
|
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
|
* `claims` (optional): overwrites the default claims set in the authority, see
|
||||||
the [JWK](#jwk) section for all the options.
|
the [JWK](#jwk) section for all the options.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue