Address auth package comments from stevvooe

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
This commit is contained in:
Josh Hawn 2014-12-17 11:35:35 -08:00
parent 88de2e11fb
commit d30a8321d8
4 changed files with 44 additions and 23 deletions

View File

@ -1,3 +1,33 @@
// Package auth defines a standard interface for request access controllers.
//
// An access controller has a simple interface with a single `Authorized`
// method which checks that a given request is authorized to perform one or
// more actions on one or more resources. This method should return a non-nil
// error if the requset is not authorized.
//
// An implementation registers its access controller by name with a constructor
// which accepts an options map for configuring the access controller.
//
// options := map[string]interface{}{"sillySecret": "whysosilly?"}
// accessController, _ := auth.GetAccessController("silly", options)
//
// This `accessController` can then be used in a request handler like so:
//
// func updateOrder(w http.ResponseWriter, r *http.Request) {
// orderNumber := r.FormValue("orderNumber")
// resource := auth.Resource{Type: "customerOrder", Name: orderNumber}
// access := auth.Access{Resource: resource, Action: "update"}
//
// if err := accessController.Authorized(r, access); err != nil {
// if challenge, ok := err.(auth.Challenge) {
// // Let the challenge write the response.
// challenge.ServeHTTP(w, r)
// } else {
// // Some other error.
// }
// }
// }
//
package auth package auth
import ( import (
@ -23,8 +53,11 @@ type Access struct {
// header values based on the error. // header values based on the error.
type Challenge interface { type Challenge interface {
error error
Status() int // ServeHTTP prepares the request to conduct the appropriate challenge
SetHeader(header http.Header) // response. For most implementations, simply calling ServeHTTP should be
// sufficient. Because no body is written, users may write a custom body after
// calling ServeHTTP, but any headers must be written before the call and may
// be overwritten.
ServeHTTP(w http.ResponseWriter, r *http.Request) ServeHTTP(w http.ResponseWriter, r *http.Request)
} }
@ -32,14 +65,12 @@ type Challenge interface {
// and required access levels for a request. Implementations can support both // and required access levels for a request. Implementations can support both
// complete denial and http authorization challenges. // complete denial and http authorization challenges.
type AccessController interface { type AccessController interface {
// Authorized returns non-nil if the request is granted the request // Authorized returns non-nil if the request is granted access. If one or
// access. If the error is non-nil, access should always be denied. The // more Access structs are provided, the requested access will be compared
// error may be of type Challenge, in which case the caller may have the // with what is available to the request. If the error is non-nil, access
// Challenge handle the request or choose what action to take based on the // should always be denied. The error may be of type Challenge, in which
// Challenge header or response status. // case the caller may have the Challenge handle the request or choose
// // what action to take based on the Challenge header or response status.
// In the future, other error types, besides Challenge, may be added to
// support more complex authorization flows.
Authorized(req *http.Request, access ...Access) error Authorized(req *http.Request, access ...Access) error
} }

View File

@ -114,7 +114,7 @@ func (ac *authChallenge) challengeParams() string {
// SetHeader sets the WWW-Authenticate value for the given header. // SetHeader sets the WWW-Authenticate value for the given header.
func (ac *authChallenge) SetHeader(header http.Header) { func (ac *authChallenge) SetHeader(header http.Header) {
header.Add(http.CanonicalHeaderKey("WWW-Authenticate"), ac.challengeParams()) header.Add("WWW-Authenticate", ac.challengeParams())
} }
// ServeHttp handles writing the challenge response // ServeHttp handles writing the challenge response

View File

@ -80,7 +80,6 @@ type Token struct {
Header *Header Header *Header
Claims *ClaimSet Claims *ClaimSet
Signature []byte Signature []byte
Valid bool
} }
// VerifyOptions is used to specify // VerifyOptions is used to specify
@ -150,11 +149,6 @@ func NewToken(rawToken string) (*Token, error) {
// Verify attempts to verify this token using the given options. // Verify attempts to verify this token using the given options.
// Returns a nil error if the token is valid. // Returns a nil error if the token is valid.
func (t *Token) Verify(verifyOpts VerifyOptions) error { func (t *Token) Verify(verifyOpts VerifyOptions) error {
if t.Valid {
// Token was already verified.
return nil
}
// Verify that the Issuer claim is a trusted authority. // Verify that the Issuer claim is a trusted authority.
if !verifyOpts.TrustedIssuers.Contains(t.Claims.Issuer) { if !verifyOpts.TrustedIssuers.Contains(t.Claims.Issuer) {
log.Errorf("token from untrusted issuer: %q", t.Claims.Issuer) log.Errorf("token from untrusted issuer: %q", t.Claims.Issuer)
@ -203,8 +197,8 @@ func (t *Token) Verify(verifyOpts VerifyOptions) error {
// Next, check if the signing key is one of the trusted keys. // Next, check if the signing key is one of the trusted keys.
if _, isTrustedKey := verifyOpts.TrustedKeys[signingKey.KeyID()]; isTrustedKey { if _, isTrustedKey := verifyOpts.TrustedKeys[signingKey.KeyID()]; isTrustedKey {
// We're done! The token was signed by a trusted key and has been verified! // We're done! The token was signed by
t.Valid = true // a trusted key and has been verified!
return nil return nil
} }
@ -301,7 +295,6 @@ func (t *Token) verifyCertificateChain(leafKey libtrust.PublicKey, roots *x509.C
} }
// The signing key's x509 chain is valid! // The signing key's x509 chain is valid!
t.Valid = true
return nil return nil
} }

View File

@ -206,9 +206,6 @@ func TestTokenVerify(t *testing.T) {
if err := token.Verify(verifyOps); err != nil { if err := token.Verify(verifyOps); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !token.Valid {
t.Fatal("token not marked as Valid")
}
} }
} }