github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/pkg/authorization/middleware.go (about)

     1  package authorization // import "github.com/docker/docker/pkg/authorization"
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"sync"
     7  
     8  	"github.com/docker/docker/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/docker/docker/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  }