Skip to content

Commit 14503cc

Browse files
committed
api/server/middleware: NewVersionMiddleware: add validation
Make sure the middleware cannot be initialized with out of range versions. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent e1897cb commit 14503cc

File tree

4 files changed

+88
-15
lines changed

4 files changed

+88
-15
lines changed

api/server/middleware/version.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"net/http"
77
"runtime"
88

9+
"github.com/docker/docker/api"
910
"github.com/docker/docker/api/server/httputils"
1011
"github.com/docker/docker/api/types/versions"
1112
)
@@ -32,12 +33,21 @@ type VersionMiddleware struct {
3233
}
3334

3435
// NewVersionMiddleware creates a VersionMiddleware with the given versions.
35-
func NewVersionMiddleware(serverVersion, defaultAPIVersion, minAPIVersion string) VersionMiddleware {
36-
return VersionMiddleware{
36+
func NewVersionMiddleware(serverVersion, defaultAPIVersion, minAPIVersion string) (*VersionMiddleware, error) {
37+
if versions.LessThan(defaultAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(defaultAPIVersion, api.DefaultVersion) {
38+
return nil, fmt.Errorf("invalid default API version (%s): must be between %s and %s", defaultAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion)
39+
}
40+
if versions.LessThan(minAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(minAPIVersion, api.DefaultVersion) {
41+
return nil, fmt.Errorf("invalid minimum API version (%s): must be between %s and %s", minAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion)
42+
}
43+
if versions.GreaterThan(minAPIVersion, defaultAPIVersion) {
44+
return nil, fmt.Errorf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", minAPIVersion, defaultAPIVersion)
45+
}
46+
return &VersionMiddleware{
3747
serverVersion: serverVersion,
3848
defaultAPIVersion: defaultAPIVersion,
3949
minAPIVersion: minAPIVersion,
40-
}
50+
}, nil
4151
}
4252

4353
type versionUnsupportedError struct {

api/server/middleware/version_test.go

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,60 @@ import (
1414
is "gotest.tools/v3/assert/cmp"
1515
)
1616

17+
func TestNewVersionMiddlewareValidation(t *testing.T) {
18+
tests := []struct {
19+
doc, defaultVersion, minVersion, expectedErr string
20+
}{
21+
{
22+
doc: "defaults",
23+
defaultVersion: api.DefaultVersion,
24+
minVersion: api.MinSupportedAPIVersion,
25+
},
26+
{
27+
doc: "invalid default lower than min",
28+
defaultVersion: api.MinSupportedAPIVersion,
29+
minVersion: api.DefaultVersion,
30+
expectedErr: fmt.Sprintf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", api.DefaultVersion, api.MinSupportedAPIVersion),
31+
},
32+
{
33+
doc: "invalid default too low",
34+
defaultVersion: "0.1",
35+
minVersion: api.MinSupportedAPIVersion,
36+
expectedErr: fmt.Sprintf("invalid default API version (0.1): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
37+
},
38+
{
39+
doc: "invalid default too high",
40+
defaultVersion: "9999.9999",
41+
minVersion: api.DefaultVersion,
42+
expectedErr: fmt.Sprintf("invalid default API version (9999.9999): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
43+
},
44+
{
45+
doc: "invalid minimum too low",
46+
defaultVersion: api.MinSupportedAPIVersion,
47+
minVersion: "0.1",
48+
expectedErr: fmt.Sprintf("invalid minimum API version (0.1): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
49+
},
50+
{
51+
doc: "invalid minimum too high",
52+
defaultVersion: api.DefaultVersion,
53+
minVersion: "9999.9999",
54+
expectedErr: fmt.Sprintf("invalid minimum API version (9999.9999): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
55+
},
56+
}
57+
58+
for _, tc := range tests {
59+
tc := tc
60+
t.Run(tc.doc, func(t *testing.T) {
61+
_, err := NewVersionMiddleware("1.2.3", tc.defaultVersion, tc.minVersion)
62+
if tc.expectedErr == "" {
63+
assert.Check(t, err)
64+
} else {
65+
assert.Check(t, is.Error(err, tc.expectedErr))
66+
}
67+
})
68+
}
69+
}
70+
1771
func TestVersionMiddlewareVersion(t *testing.T) {
1872
expectedVersion := "<not set>"
1973
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -22,7 +76,8 @@ func TestVersionMiddlewareVersion(t *testing.T) {
2276
return nil
2377
}
2478

25-
m := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
79+
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
80+
assert.NilError(t, err)
2681
h := m.WrapHandler(handler)
2782

2883
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
@@ -71,15 +126,16 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
71126
return nil
72127
}
73128

74-
m := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
129+
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
130+
assert.NilError(t, err)
75131
h := m.WrapHandler(handler)
76132

77133
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
78134
resp := httptest.NewRecorder()
79135
ctx := context.Background()
80136

81137
vars := map[string]string{"version": "0.1"}
82-
err := h(ctx, resp, req, vars)
138+
err = h(ctx, resp, req, vars)
83139
assert.Check(t, is.ErrorContains(err, ""))
84140

85141
hdr := resp.Result().Header

api/server/server_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ import (
1515
func TestMiddlewares(t *testing.T) {
1616
srv := &Server{}
1717

18-
const apiMinVersion = "1.12"
19-
srv.UseMiddleware(middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, apiMinVersion))
18+
m, err := middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, api.MinSupportedAPIVersion)
19+
if err != nil {
20+
t.Fatal(err)
21+
}
22+
srv.UseMiddleware(*m)
2023

2124
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
2225
resp := httptest.NewRecorder()

cmd/dockerd/daemon.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,10 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
256256
pluginStore := plugin.NewStore()
257257

258258
var apiServer apiserver.Server
259-
cli.authzMiddleware = initMiddlewares(&apiServer, cli.Config, pluginStore)
259+
cli.authzMiddleware, err = initMiddlewares(&apiServer, cli.Config, pluginStore)
260+
if err != nil {
261+
return errors.Wrap(err, "failed to start API server")
262+
}
260263

261264
d, err := daemon.NewDaemon(ctx, cli.Config, pluginStore, cli.authzMiddleware)
262265
if err != nil {
@@ -708,14 +711,15 @@ func (opts routerOptions) Build() []router.Router {
708711
return routers
709712
}
710713

711-
func initMiddlewares(s *apiserver.Server, cfg *config.Config, pluginStore plugingetter.PluginGetter) *authorization.Middleware {
712-
v := dockerversion.Version
713-
714+
func initMiddlewares(s *apiserver.Server, cfg *config.Config, pluginStore plugingetter.PluginGetter) (*authorization.Middleware, error) {
714715
exp := middleware.NewExperimentalMiddleware(cfg.Experimental)
715716
s.UseMiddleware(exp)
716717

717-
vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, cfg.MinAPIVersion)
718-
s.UseMiddleware(vm)
718+
vm, err := middleware.NewVersionMiddleware(dockerversion.Version, api.DefaultVersion, cfg.MinAPIVersion)
719+
if err != nil {
720+
return nil, err
721+
}
722+
s.UseMiddleware(*vm)
719723

720724
if cfg.CorsHeaders != "" {
721725
c := middleware.NewCORSMiddleware(cfg.CorsHeaders)
@@ -724,7 +728,7 @@ func initMiddlewares(s *apiserver.Server, cfg *config.Config, pluginStore plugin
724728

725729
authzMiddleware := authorization.NewMiddleware(cfg.AuthorizationPlugins, pluginStore)
726730
s.UseMiddleware(authzMiddleware)
727-
return authzMiddleware
731+
return authzMiddleware, nil
728732
}
729733

730734
func (cli *DaemonCli) getContainerdDaemonOpts() ([]supervisor.DaemonOpt, error) {

0 commit comments

Comments
 (0)