github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/pkg/authorization/middleware.go (about) 1 package authorization // import "github.com/demonoid81/moby/pkg/authorization" 2 3 import ( 4 "context" 5 "net/http" 6 "sync" 7 8 "github.com/demonoid81/moby/pkg/plugingetter" 9 "github.com/sirupsen/logrus" 10 ) 11 12 // Middleware uses a list of plugins to 13 // handle authorization in the API requests. 14 type Middleware struct { 15 mu sync.Mutex 16 plugins []Plugin 17 } 18 19 // NewMiddleware creates a new Middleware 20 // with a slice of plugins names. 21 func NewMiddleware(names []string, pg plugingetter.PluginGetter) *Middleware { 22 SetPluginGetter(pg) 23 return &Middleware{ 24 plugins: newPlugins(names), 25 } 26 } 27 28 func (m *Middleware) getAuthzPlugins() []Plugin { 29 m.mu.Lock() 30 defer m.mu.Unlock() 31 return m.plugins 32 } 33 34 // SetPlugins sets the plugin used for authorization 35 func (m *Middleware) SetPlugins(names []string) { 36 m.mu.Lock() 37 m.plugins = newPlugins(names) 38 m.mu.Unlock() 39 } 40 41 // RemovePlugin removes a single plugin from this authz middleware chain 42 func (m *Middleware) RemovePlugin(name string) { 43 m.mu.Lock() 44 defer m.mu.Unlock() 45 plugins := m.plugins[:0] 46 for _, authPlugin := range m.plugins { 47 if authPlugin.Name() != name { 48 plugins = append(plugins, authPlugin) 49 } 50 } 51 m.plugins = plugins 52 } 53 54 // WrapHandler returns a new handler function wrapping the previous one in the request chain. 55 func (m *Middleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 56 return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 57 plugins := m.getAuthzPlugins() 58 if len(plugins) == 0 { 59 return handler(ctx, w, r, vars) 60 } 61 62 user := "" 63 userAuthNMethod := "" 64 65 // Default authorization using existing TLS connection credentials 66 // FIXME: Non trivial authorization mechanisms (such as advanced certificate validations, kerberos support 67 // and ldap) will be extracted using AuthN feature, which is tracked under: 68 // https://github.com/demonoid81/moby/pull/20883 69 if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { 70 user = r.TLS.PeerCertificates[0].Subject.CommonName 71 userAuthNMethod = "TLS" 72 } 73 74 authCtx := NewCtx(plugins, user, userAuthNMethod, r.Method, r.RequestURI) 75 76 if err := authCtx.AuthZRequest(w, r); err != nil { 77 logrus.Errorf("AuthZRequest for %s %s returned error: %s", r.Method, r.RequestURI, err) 78 return err 79 } 80 81 rw := NewResponseModifier(w) 82 83 var errD error 84 85 if errD = handler(ctx, rw, r, vars); errD != nil { 86 logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.RequestURI, errD) 87 } 88 89 // There's a chance that the authCtx.plugins was updated. One of the reasons 90 // this can happen is when an authzplugin is disabled. 91 plugins = m.getAuthzPlugins() 92 if len(plugins) == 0 { 93 logrus.Debug("There are no authz plugins in the chain") 94 return nil 95 } 96 97 authCtx.plugins = plugins 98 99 if err := authCtx.AuthZResponse(rw, r); errD == nil && err != nil { 100 logrus.Errorf("AuthZResponse for %s %s returned error: %s", r.Method, r.RequestURI, err) 101 return err 102 } 103 104 if errD != nil { 105 return errD 106 } 107 108 return nil 109 } 110 }