forked from TrueCloudLab/distribution
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:
parent
88de2e11fb
commit
d30a8321d8
4 changed files with 44 additions and 23 deletions
51
auth/auth.go
51
auth/auth.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue