diff --git a/authority/authorize.go b/authority/authorize.go index 3c46203a..07505358 100644 --- a/authority/authorize.go +++ b/authority/authorize.go @@ -76,7 +76,7 @@ func (a *Authority) Authorize(ott string) ([]provisioner.SignOption, error) { // This check is meant as a stopgap solution to the current lack of a persistence layer. if a.config.AuthorityConfig != nil && !a.config.AuthorityConfig.DisableIssuedAtCheck { if claims.IssuedAt > 0 && claims.IssuedAt.Time().Before(a.startTime) { - return nil, &apiError{errors.New("token issued before the bootstrap of certificate authority"), + return nil, &apiError{errors.New("authorize: token issued before the bootstrap of certificate authority"), http.StatusUnauthorized, errContext} } } @@ -94,12 +94,17 @@ func (a *Authority) Authorize(ott string) ([]provisioner.SignOption, error) { UsedAt: time.Now().Unix(), Subject: claims.Subject, }); ok { - return nil, &apiError{errors.Errorf("token already used"), http.StatusUnauthorized, - errContext} + return nil, &apiError{errors.Errorf("authorize: token already used"), http.StatusUnauthorized, errContext} } } - return p.Authorize(ott) + // Call the provisioner Authorize method to get the signing options + opts, err := p.Authorize(ott) + if err != nil { + return nil, &apiError{errors.Wrap(err, "authorize"), http.StatusUnauthorized, errContext} + } + + return opts, nil } // authorizeRenewal tries to locate the step provisioner extension, and checks diff --git a/authority/authorize_test.go b/authority/authorize_test.go index e744f560..b677472d 100644 --- a/authority/authorize_test.go +++ b/authority/authorize_test.go @@ -136,7 +136,7 @@ func TestAuthorize(t *testing.T) { return &authorizeTest{ auth: a, ott: raw, - err: &apiError{errors.New("authorize: token KeyID cannot be empty"), + err: &apiError{errors.New("authorize: provisioner not found or invalid audience"), http.StatusUnauthorized, context{"ott": raw}}, } }, @@ -158,7 +158,7 @@ func TestAuthorize(t *testing.T) { return &authorizeTest{ auth: a, ott: raw, - err: &apiError{errors.New("authorize: provisioner with id step-cli:foo not found"), + err: &apiError{errors.New("authorize: provisioner not found or invalid audience"), http.StatusUnauthorized, context{"ott": raw}}, } }, @@ -184,8 +184,8 @@ func TestAuthorize(t *testing.T) { return &authorizeTest{ auth: _a, ott: raw, - err: &apiError{errors.New("authorize: invalid provisioner type"), - http.StatusInternalServerError, context{"ott": raw}}, + err: &apiError{errors.New("authorize: provisioner not found or invalid audience"), + http.StatusUnauthorized, context{"ott": raw}}, } }, "fail invalid issuer": func(t *testing.T) *authorizeTest { @@ -201,7 +201,7 @@ func TestAuthorize(t *testing.T) { return &authorizeTest{ auth: a, ott: raw, - err: &apiError{errors.New("authorize: provisioner with id invalid-issuer:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc not found"), + err: &apiError{errors.New("authorize: provisioner not found or invalid audience"), http.StatusUnauthorized, context{"ott": raw}}, } }, @@ -242,7 +242,7 @@ func TestAuthorize(t *testing.T) { return &authorizeTest{ auth: a, ott: raw, - err: &apiError{errors.New("square/go-jose: error in cryptographic primitive"), + err: &apiError{errors.New("authorize: error parsing claims: square/go-jose: error in cryptographic primitive"), http.StatusUnauthorized, context{"ott": raw}}, } }, @@ -262,7 +262,7 @@ func TestAuthorize(t *testing.T) { return &authorizeTest{ auth: a, ott: raw, - err: &apiError{errors.New("token already used"), + err: &apiError{errors.New("authorize: token already used"), http.StatusUnauthorized, context{"ott": raw}}, } }, @@ -280,7 +280,7 @@ func TestAuthorize(t *testing.T) { return &authorizeTest{ auth: a, ott: raw, - res: []interface{}{"1", "2", "3", "4"}, + res: []interface{}{"1", "2", "3", "4", "5", "6"}, } }, } diff --git a/authority/provisioner/utils_test.go b/authority/provisioner/utils_test.go index a796dcfc..f1912363 100644 --- a/authority/provisioner/utils_test.go +++ b/authority/provisioner/utils_test.go @@ -4,14 +4,10 @@ import ( "crypto" "encoding/hex" "encoding/json" - "net/http" - "net/http/httptest" "time" "github.com/smallstep/cli/crypto/randutil" "github.com/smallstep/cli/jose" - "github.com/smallstep/cli/token" - "github.com/smallstep/cli/token/provision" ) var testAudiences = []string{ @@ -210,90 +206,3 @@ func generateToken(sub, iss, aud string, sans []string, jwk *jose.JSONWebKey) (s } return jose.Signed(sig).Claims(claims).CompactSerialize() } - -func generateToken2(sub string, sans []string, kid, iss, aud, root string, notBefore, notAfter time.Time, jwk *jose.JSONWebKey) (string, error) { - // A random jwt id will be used to identify duplicated tokens - jwtID, err := randutil.Hex(64) // 256 bits - if err != nil { - return "", err - } - - tokOptions := []token.Options{ - token.WithJWTID(jwtID), - token.WithKid(kid), - token.WithIssuer(iss), - token.WithAudience(aud), - } - if len(root) > 0 { - tokOptions = append(tokOptions, token.WithRootCA(root)) - } - - // If there are no SANs then add the 'subject' (common-name) as the only SAN. - if len(sans) == 0 { - sans = []string{sub} - } - - tokOptions = append(tokOptions, token.WithSANS(sans)) - if !notBefore.IsZero() || !notAfter.IsZero() { - if notBefore.IsZero() { - notBefore = time.Now() - } - if notAfter.IsZero() { - notAfter = notBefore.Add(token.DefaultValidity) - } - tokOptions = append(tokOptions, token.WithValidity(notBefore, notAfter)) - } - - tok, err := provision.New(sub, tokOptions...) - if err != nil { - return "", err - } - - return tok.SignedString(jwk.Algorithm, jwk.Key) -} - -func parseToken(token string) (*jose.JSONWebToken, *jose.Claims, error) { - tok, err := jose.ParseSigned(token) - if err != nil { - return nil, nil, err - } - claims := new(jose.Claims) - if err := tok.UnsafeClaimsWithoutVerification(claims); err != nil { - return nil, nil, err - } - return tok, claims, nil -} - -func generateJWKServer(n int) *httptest.Server { - hits := struct { - Hits int `json:"hits"` - }{} - writeJSON := func(w http.ResponseWriter, v interface{}) { - b, err := json.Marshal(v) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - w.Header().Add("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(b) - } - // keySet, err := generateJSONWebKeySet(n) - defaultKeySet := must(generateJSONWebKeySet(2))[0].(jose.JSONWebKeySet) - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - hits.Hits++ - switch r.RequestURI { - case "/error": - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) - case "/hits": - writeJSON(w, hits) - case "/random": - keySet := must(generateJSONWebKeySet(2))[0].(jose.JSONWebKeySet) - w.Header().Add("Cache-Control", "max-age=5") - writeJSON(w, keySet) - default: - w.Header().Add("Cache-Control", "max-age=5") - writeJSON(w, defaultKeySet) - } - })) -}