github.com/npaton/distribution@v2.3.1-rc.0+incompatible/registry/auth/silly/access.go (about) 1 // Package silly provides a simple authentication scheme that checks for the 2 // existence of an Authorization header and issues access if is present and 3 // non-empty. 4 // 5 // This package is present as an example implementation of a minimal 6 // auth.AccessController and for testing. This is not suitable for any kind of 7 // production security. 8 package silly 9 10 import ( 11 "fmt" 12 "net/http" 13 "strings" 14 15 "github.com/docker/distribution/context" 16 "github.com/docker/distribution/registry/auth" 17 ) 18 19 // accessController provides a simple implementation of auth.AccessController 20 // that simply checks for a non-empty Authorization header. It is useful for 21 // demonstration and testing. 22 type accessController struct { 23 realm string 24 service string 25 } 26 27 var _ auth.AccessController = &accessController{} 28 29 func newAccessController(options map[string]interface{}) (auth.AccessController, error) { 30 realm, present := options["realm"] 31 if _, ok := realm.(string); !present || !ok { 32 return nil, fmt.Errorf(`"realm" must be set for silly access controller`) 33 } 34 35 service, present := options["service"] 36 if _, ok := service.(string); !present || !ok { 37 return nil, fmt.Errorf(`"service" must be set for silly access controller`) 38 } 39 40 return &accessController{realm: realm.(string), service: service.(string)}, nil 41 } 42 43 // Authorized simply checks for the existence of the authorization header, 44 // responding with a bearer challenge if it doesn't exist. 45 func (ac *accessController) Authorized(ctx context.Context, accessRecords ...auth.Access) (context.Context, error) { 46 req, err := context.GetRequest(ctx) 47 if err != nil { 48 return nil, err 49 } 50 51 if req.Header.Get("Authorization") == "" { 52 challenge := challenge{ 53 realm: ac.realm, 54 service: ac.service, 55 } 56 57 if len(accessRecords) > 0 { 58 var scopes []string 59 for _, access := range accessRecords { 60 scopes = append(scopes, fmt.Sprintf("%s:%s:%s", access.Type, access.Resource.Name, access.Action)) 61 } 62 challenge.scope = strings.Join(scopes, " ") 63 } 64 65 return nil, &challenge 66 } 67 68 return auth.WithUser(ctx, auth.UserInfo{Name: "silly"}), nil 69 } 70 71 type challenge struct { 72 realm string 73 service string 74 scope string 75 } 76 77 var _ auth.Challenge = challenge{} 78 79 // SetHeaders sets a simple bearer challenge on the response. 80 func (ch challenge) SetHeaders(w http.ResponseWriter) { 81 header := fmt.Sprintf("Bearer realm=%q,service=%q", ch.realm, ch.service) 82 83 if ch.scope != "" { 84 header = fmt.Sprintf("%s,scope=%q", header, ch.scope) 85 } 86 87 w.Header().Set("WWW-Authenticate", header) 88 } 89 90 func (ch challenge) Error() string { 91 return fmt.Sprintf("silly authentication challenge: %#v", ch) 92 } 93 94 // init registers the silly auth backend. 95 func init() { 96 auth.Register("silly", auth.InitFunc(newAccessController)) 97 }