middleware.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package server
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "io/ioutil"
  6. "net/http"
  7. "runtime"
  8. "strings"
  9. "github.com/Sirupsen/logrus"
  10. "github.com/docker/docker/api"
  11. "github.com/docker/docker/api/server/httputils"
  12. "github.com/docker/docker/dockerversion"
  13. "github.com/docker/docker/errors"
  14. "github.com/docker/docker/pkg/authorization"
  15. "github.com/docker/docker/pkg/version"
  16. "golang.org/x/net/context"
  17. )
  18. // middleware is an adapter to allow the use of ordinary functions as Docker API filters.
  19. // Any function that has the appropriate signature can be register as a middleware.
  20. type middleware func(handler httputils.APIFunc) httputils.APIFunc
  21. // debugRequestMiddleware dumps the request to logger
  22. func debugRequestMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  23. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  24. logrus.Debugf("%s %s", r.Method, r.RequestURI)
  25. if r.Method == "POST" {
  26. if err := httputils.CheckForJSON(r); err == nil {
  27. var buf bytes.Buffer
  28. if _, err := buf.ReadFrom(r.Body); err == nil {
  29. r.Body.Close()
  30. r.Body = ioutil.NopCloser(&buf)
  31. var postForm map[string]interface{}
  32. if err := json.Unmarshal(buf.Bytes(), &postForm); err == nil {
  33. if _, exists := postForm["password"]; exists {
  34. postForm["password"] = "*****"
  35. }
  36. formStr, errMarshal := json.Marshal(postForm)
  37. if errMarshal == nil {
  38. logrus.Debugf("form data: %s", string(formStr))
  39. } else {
  40. logrus.Debugf("form data: %q", postForm)
  41. }
  42. }
  43. }
  44. }
  45. }
  46. return handler(ctx, w, r, vars)
  47. }
  48. }
  49. // authorizationMiddleware perform authorization on the request.
  50. func (s *Server) authorizationMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  51. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  52. // FIXME: fill when authN gets in
  53. // User and UserAuthNMethod are taken from AuthN plugins
  54. // Currently tracked in https://github.com/docker/docker/pull/13994
  55. user := ""
  56. userAuthNMethod := ""
  57. authCtx := authorization.NewCtx(s.authZPlugins, user, userAuthNMethod, r.Method, r.RequestURI)
  58. if err := authCtx.AuthZRequest(w, r); err != nil {
  59. logrus.Errorf("AuthZRequest for %s %s returned error: %s", r.Method, r.RequestURI, err)
  60. return err
  61. }
  62. rw := authorization.NewResponseModifier(w)
  63. if err := handler(ctx, rw, r, vars); err != nil {
  64. logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.RequestURI, err)
  65. return err
  66. }
  67. if err := authCtx.AuthZResponse(rw, r); err != nil {
  68. logrus.Errorf("AuthZResponse for %s %s returned error: %s", r.Method, r.RequestURI, err)
  69. return err
  70. }
  71. return nil
  72. }
  73. }
  74. // userAgentMiddleware checks the User-Agent header looking for a valid docker client spec.
  75. func (s *Server) userAgentMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  76. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  77. if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
  78. dockerVersion := version.Version(s.cfg.Version)
  79. userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
  80. // v1.20 onwards includes the GOOS of the client after the version
  81. // such as Docker/1.7.0 (linux)
  82. if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") {
  83. userAgent[1] = strings.Split(userAgent[1], " ")[0]
  84. }
  85. if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
  86. logrus.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
  87. }
  88. }
  89. return handler(ctx, w, r, vars)
  90. }
  91. }
  92. // corsMiddleware sets the CORS header expectations in the server.
  93. func (s *Server) corsMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  94. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  95. // If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
  96. // otherwise, all head values will be passed to HTTP handler
  97. corsHeaders := s.cfg.CorsHeaders
  98. if corsHeaders == "" && s.cfg.EnableCors {
  99. corsHeaders = "*"
  100. }
  101. if corsHeaders != "" {
  102. writeCorsHeaders(w, r, corsHeaders)
  103. }
  104. return handler(ctx, w, r, vars)
  105. }
  106. }
  107. // versionMiddleware checks the api version requirements before passing the request to the server handler.
  108. func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  109. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  110. apiVersion := version.Version(vars["version"])
  111. if apiVersion == "" {
  112. apiVersion = api.DefaultVersion
  113. }
  114. if apiVersion.GreaterThan(api.DefaultVersion) {
  115. return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.DefaultVersion)
  116. }
  117. if apiVersion.LessThan(api.MinVersion) {
  118. return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.DefaultVersion)
  119. }
  120. w.Header().Set("Server", "Docker/"+dockerversion.Version+" ("+runtime.GOOS+")")
  121. ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion)
  122. return handler(ctx, w, r, vars)
  123. }
  124. }
  125. // handleWithGlobalMiddlwares wraps the handler function for a request with
  126. // the server's global middlewares. The order of the middlewares is backwards,
  127. // meaning that the first in the list will be evaluated last.
  128. //
  129. // Example: handleWithGlobalMiddlewares(s.getContainersName)
  130. //
  131. // s.loggingMiddleware(
  132. // s.userAgentMiddleware(
  133. // s.corsMiddleware(
  134. // versionMiddleware(s.getContainersName)
  135. // )
  136. // )
  137. // )
  138. // )
  139. func (s *Server) handleWithGlobalMiddlewares(handler httputils.APIFunc) httputils.APIFunc {
  140. middlewares := []middleware{
  141. versionMiddleware,
  142. s.corsMiddleware,
  143. s.userAgentMiddleware,
  144. }
  145. // Only want this on debug level
  146. if s.cfg.Logging && logrus.GetLevel() == logrus.DebugLevel {
  147. middlewares = append(middlewares, debugRequestMiddleware)
  148. }
  149. if len(s.cfg.AuthZPluginNames) > 0 {
  150. s.authZPlugins = authorization.NewPlugins(s.cfg.AuthZPluginNames)
  151. middlewares = append(middlewares, s.authorizationMiddleware)
  152. }
  153. h := handler
  154. for _, m := range middlewares {
  155. h = m(h)
  156. }
  157. return h
  158. }