middleware.go 3.1 KB

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