From ccb887dc363da427129de376eb4114fe09b08d89 Mon Sep 17 00:00:00 2001 From: Liron Levin Date: Sun, 27 Mar 2016 15:53:37 +0300 Subject: [PATCH] Extend Docker authorization with TLS user information Currently Docker authorization framework does not use any user information, which already available in the Docker context for TLS connection. The purpose of this CR is to complete the existing authz work by adding the basic client certificate details (SUBJECT_NAME) and authentication method (TLS) to the authz request. We think this should be the default behavior when no extended authorization module is specified (currently WIP under #20883). Signed-off-by: Liron Levin Upstream-commit: 3c157713b31f542a4180e31da4cae7d677330a6f Component: engine --- .../api/server/middleware/authorization.go | 14 ++++-- .../docker_cli_authz_unix_test.go | 43 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/components/engine/api/server/middleware/authorization.go b/components/engine/api/server/middleware/authorization.go index cbfa99e7b3..0163d81fb8 100644 --- a/components/engine/api/server/middleware/authorization.go +++ b/components/engine/api/server/middleware/authorization.go @@ -13,11 +13,19 @@ import ( func NewAuthorizationMiddleware(plugins []authorization.Plugin) Middleware { return func(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - // FIXME: fill when authN gets in - // User and UserAuthNMethod are taken from AuthN plugins - // Currently tracked in https://github.com/docker/docker/pull/13994 + user := "" userAuthNMethod := "" + + // Default authorization using existing TLS connection credentials + // FIXME: Non trivial authorization mechanisms (such as advanced certificate validations, kerberos support + // and ldap) will be extracted using AuthN feature, which is tracked under: + // https://github.com/docker/docker/pull/20883 + if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { + user = r.TLS.PeerCertificates[0].Subject.CommonName + userAuthNMethod = "TLS" + } + authCtx := authorization.NewCtx(plugins, user, userAuthNMethod, r.Method, r.RequestURI) if err := authCtx.AuthZRequest(w, r); err != nil { diff --git a/components/engine/integration-cli/docker_cli_authz_unix_test.go b/components/engine/integration-cli/docker_cli_authz_unix_test.go index 0a208d75e1..6d58d6d3db 100644 --- a/components/engine/integration-cli/docker_cli_authz_unix_test.go +++ b/components/engine/integration-cli/docker_cli_authz_unix_test.go @@ -53,6 +53,8 @@ type authorizationController struct { psRequestCnt int // psRequestCnt counts the number of calls to list container request api psResponseCnt int // psResponseCnt counts the number of calls to list containers response API requestsURIs []string // requestsURIs stores all request URIs that are sent to the authorization controller + reqUser string + resUser string } func (s *DockerAuthzSuite) SetUpTest(c *check.C) { @@ -104,6 +106,7 @@ func (s *DockerAuthzSuite) SetUpSuite(c *check.C) { } b, err := json.Marshal(reqRes) c.Assert(err, check.IsNil) + s.ctrl.reqUser = authReq.User w.Write(b) }) @@ -131,6 +134,7 @@ func (s *DockerAuthzSuite) SetUpSuite(c *check.C) { } b, err := json.Marshal(resRes) c.Assert(err, check.IsNil) + s.ctrl.resUser = authReq.User w.Write(b) }) @@ -213,6 +217,45 @@ func (s *DockerAuthzSuite) TestAuthZPluginAllowRequest(c *check.C) { c.Assert(s.ctrl.psResponseCnt, check.Equals, 1) } +func (s *DockerAuthzSuite) TestAuthZPluginTls(c *check.C) { + + const testDaemonHTTPSAddr = "tcp://localhost:4271" + // start the daemon and load busybox, --net=none build fails otherwise + // cause it needs to pull busybox + if err := s.d.Start( + "--authorization-plugin="+testAuthZPlugin, + "--tlsverify", + "--tlscacert", + "fixtures/https/ca.pem", + "--tlscert", + "fixtures/https/server-cert.pem", + "--tlskey", + "fixtures/https/server-key.pem", + "-H", testDaemonHTTPSAddr); err != nil { + c.Fatalf("Could not start daemon with busybox: %v", err) + } + + s.ctrl.reqRes.Allow = true + s.ctrl.resRes.Allow = true + + out, _ := dockerCmd( + c, + "--tlsverify", + "--tlscacert", "fixtures/https/ca.pem", + "--tlscert", "fixtures/https/client-cert.pem", + "--tlskey", "fixtures/https/client-key.pem", + "-H", + testDaemonHTTPSAddr, + "version", + ) + if !strings.Contains(out, "Server") { + c.Fatalf("docker version should return information of server side") + } + + c.Assert(s.ctrl.reqUser, check.Equals, "client") + c.Assert(s.ctrl.resUser, check.Equals, "client") +} + func (s *DockerAuthzSuite) TestAuthZPluginDenyRequest(c *check.C) { err := s.d.Start("--authorization-plugin=" + testAuthZPlugin) c.Assert(err, check.IsNil)