github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/pkg/authorization/middleware.go (about)

     1  package authorization
     2  
     3  import (
     4  	"net/http"
     5  	"sync"
     6  
     7  	"github.com/Sirupsen/logrus"
     8  	"github.com/docker/docker/pkg/plugingetter"
     9  	"golang.org/x/net/context"
    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  // GetAuthzPlugins gets authorization plugins
    29  func (m *Middleware) GetAuthzPlugins() []Plugin {
    30  	m.mu.Lock()
    31  	defer m.mu.Unlock()
    32  	return m.plugins
    33  }
    34  
    35  // SetAuthzPlugins sets authorization plugins
    36  func (m *Middleware) SetAuthzPlugins(plugins []Plugin) {
    37  	m.mu.Lock()
    38  	m.plugins = plugins
    39  	m.mu.Unlock()
    40  }
    41  
    42  // SetPlugins sets the plugin used for authorization
    43  func (m *Middleware) SetPlugins(names []string) {
    44  	m.mu.Lock()
    45  	m.plugins = newPlugins(names)
    46  	m.mu.Unlock()
    47  }
    48  
    49  // WrapHandler returns a new handler function wrapping the previous one in the request chain.
    50  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 {
    51  	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    52  		plugins := m.GetAuthzPlugins()
    53  		if len(plugins) == 0 {
    54  			return handler(ctx, w, r, vars)
    55  		}
    56  
    57  		user := ""
    58  		userAuthNMethod := ""
    59  
    60  		// Default authorization using existing TLS connection credentials
    61  		// FIXME: Non trivial authorization mechanisms (such as advanced certificate validations, kerberos support
    62  		// and ldap) will be extracted using AuthN feature, which is tracked under:
    63  		// https://github.com/docker/docker/pull/20883
    64  		if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
    65  			user = r.TLS.PeerCertificates[0].Subject.CommonName
    66  			userAuthNMethod = "TLS"
    67  		}
    68  
    69  		authCtx := NewCtx(plugins, user, userAuthNMethod, r.Method, r.RequestURI)
    70  
    71  		if err := authCtx.AuthZRequest(w, r); err != nil {
    72  			logrus.Errorf("AuthZRequest for %s %s returned error: %s", r.Method, r.RequestURI, err)
    73  			return err
    74  		}
    75  
    76  		rw := NewResponseModifier(w)
    77  
    78  		var errD error
    79  
    80  		if errD = handler(ctx, rw, r, vars); errD != nil {
    81  			logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.RequestURI, errD)
    82  		}
    83  
    84  		// There's a chance that the authCtx.plugins was updated. One of the reasons
    85  		// this can happen is when an authzplugin is disabled.
    86  		plugins = m.GetAuthzPlugins()
    87  		if len(plugins) == 0 {
    88  			logrus.Debug("There are no authz plugins in the chain")
    89  			return nil
    90  		}
    91  
    92  		authCtx.plugins = plugins
    93  
    94  		if err := authCtx.AuthZResponse(rw, r); errD == nil && err != nil {
    95  			logrus.Errorf("AuthZResponse for %s %s returned error: %s", r.Method, r.RequestURI, err)
    96  			return err
    97  		}
    98  
    99  		if errD != nil {
   100  			return errD
   101  		}
   102  
   103  		return nil
   104  	}
   105  }