github.com/kim0/docker@v0.6.2-0.20161130212042-4addda3f07e7/pkg/authorization/middleware.go (about)

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