diff --git a/cmd/vela-worker/server.go b/cmd/vela-worker/server.go index cecd9210..d9810659 100644 --- a/cmd/vela-worker/server.go +++ b/cmd/vela-worker/server.go @@ -30,8 +30,8 @@ func (w *Worker) server() (http.Handler, *tls.Config) { // https://pkg.go.dev/github.com/go-vela/worker/router?tab=doc#Load _server := router.Load( middleware.RequestVersion, + middleware.ServerAddress(w.Config.Server.Address), middleware.Executors(w.Executors), - middleware.Secret(w.Config.Server.Secret), middleware.Logger(logrus.StandardLogger(), time.RFC3339, true), ) diff --git a/go.mod b/go.mod index 9c85d09a..cc15e3ba 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,9 @@ require ( github.com/docker/docker v20.10.23+incompatible github.com/docker/go-units v0.5.0 github.com/gin-gonic/gin v1.9.0 - github.com/go-vela/sdk-go v0.18.1 - github.com/go-vela/server v0.18.1 - github.com/go-vela/types v0.18.1 + github.com/go-vela/sdk-go v0.18.2-0.20230327141933-e8d38c73b1bb + github.com/go-vela/server v0.18.2-0.20230324155739-73f83fcfd004 + github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c github.com/google/go-cmp v0.5.9 github.com/joho/godotenv v1.5.1 github.com/opencontainers/image-spec v1.0.2 @@ -34,7 +34,7 @@ require ( github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/alicebob/miniredis/v2 v2.30.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396 // indirect + github.com/buildkite/yaml v0.0.0-20230306222819-0e4e032d4835 // indirect github.com/bytedance/sonic v1.8.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect diff --git a/go.sum b/go.sum index 2f666479..6d05d5c5 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bsm/ginkgo/v2 v2.5.0 h1:aOAnND1T40wEdAtkGSkvSICWeQ8L3UASX7YVCqQx+eQ= github.com/bsm/gomega v1.20.0 h1:JhAwLmtRzXFTx2AkALSLa8ijZafntmhSoU63Ok18Uq8= -github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396 h1:qLN32md48xyTEqw6XEZMyNMre7njm0XXvDrea6NVwOM= -github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396/go.mod h1:AV5wtJnn1/CRaRGlJ8xspkMWfKXV0/pkJVgGleTIrfk= +github.com/buildkite/yaml v0.0.0-20230306222819-0e4e032d4835 h1:Zfkih+Opdv9y5AOob+8iMsaMYnans+Ozrkb8wiPHbj0= +github.com/buildkite/yaml v0.0.0-20230306222819-0e4e032d4835/go.mod h1:AV5wtJnn1/CRaRGlJ8xspkMWfKXV0/pkJVgGleTIrfk= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -156,12 +156,12 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-vela/sdk-go v0.18.1 h1:qsm8XWjr9btNDL8c58JC93sstRUybL/TklWgeeft860= -github.com/go-vela/sdk-go v0.18.1/go.mod h1:QmfXBAdJ9prgE78TK13XJI8YjvGZA5hc+h79CbvgYGU= -github.com/go-vela/server v0.18.1 h1:INd+nwLh0c+WA+8diIh4scLkByGBGZHiyVd5doLSolQ= -github.com/go-vela/server v0.18.1/go.mod h1:WyJEXyJYYASfqN9PDuHqlBTbhsSRIzOn1E7tM2phZMA= -github.com/go-vela/types v0.18.1 h1:V/luHLnCEaJhD1m9PZCZicIasg8Op6MCK+utkz+gQiU= -github.com/go-vela/types v0.18.1/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= +github.com/go-vela/sdk-go v0.18.2-0.20230327141933-e8d38c73b1bb h1:JXEolOu+HFktExoDFcGYIdWS9LfPAQnQMIB4Rm48WS0= +github.com/go-vela/sdk-go v0.18.2-0.20230327141933-e8d38c73b1bb/go.mod h1:N8qFPxB0RsHrSYr01GVwgOOowtSfhvjXtJ1cRBaeTc4= +github.com/go-vela/server v0.18.2-0.20230324155739-73f83fcfd004 h1:yJis1sso5c0ZoeZLfZ/lYsjfxU7H9cYP/VJXssRxDa8= +github.com/go-vela/server v0.18.2-0.20230324155739-73f83fcfd004/go.mod h1:b+7XeGHO4ynIinY9mpWb6ye9psdwHpsAqMWy5oC+zJ0= +github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c h1:lnCL1knUGvgZQG4YBHSs/CZnxNBfqFUBlGhyq9LO9uk= +github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index 135d452c..85dd60d8 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -9,29 +9,79 @@ import ( "net/http" "strings" + "github.com/go-vela/sdk-go/vela" "github.com/go-vela/types" - "github.com/go-vela/worker/router/middleware/user" + "github.com/go-vela/worker/router/middleware/token" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) -// MustServer ensures the user is the vela server. +// MustServer ensures the caller is the vela server. func MustServer() gin.HandlerFunc { return func(c *gin.Context) { - u := user.Retrieve(c) + // retrieve the callers token from the request headers + tkn, err := token.Retrieve(c.Request) + if err != nil { + msg := fmt.Sprintf("error parsing token: %v", err) + + logrus.Error(msg) + + c.AbortWithStatusJSON(http.StatusBadRequest, types.Error{Message: &msg}) + + return + } + + // retrieve the configured server address from the context + addr := c.MustGet("server-address").(string) + + // create a temporary client to validate the incoming request + vela, err := vela.NewClient(addr, "vela-worker", nil) + if err != nil { + msg := fmt.Sprintf("error creating vela client: %s", err) + + logrus.Error(msg) + + c.AbortWithStatusJSON(http.StatusInternalServerError, types.Error{Message: &msg}) + + return + } + + // validate a token was provided + if strings.EqualFold(tkn, "") { + msg := "missing token" + + logrus.Error(msg) + + c.AbortWithStatusJSON(http.StatusBadRequest, types.Error{Message: &msg}) - if strings.EqualFold(u.GetName(), "vela-server") { return } - msg := fmt.Sprintf("User %s is not a platform admin", u.GetName()) + // set the token auth provided in the callers request header + vela.Authentication.SetTokenAuth(tkn) - err := c.Error(fmt.Errorf(msg)) + // validate the token with the configured vela server + resp, err := vela.Authentication.ValidateToken() if err != nil { - logrus.Error(err) + msg := fmt.Sprintf("error validating token: %s", err) + + logrus.Error(msg) + + c.AbortWithStatusJSON(http.StatusInternalServerError, types.Error{Message: &msg}) + + return } - c.AbortWithStatusJSON(http.StatusUnauthorized, types.Error{Message: &msg}) + // if ValidateToken returned anything other than 200 consider the token invalid + if resp.StatusCode != http.StatusOK { + msg := "unable to validate token" + + logrus.Error(msg) + + c.AbortWithStatusJSON(http.StatusUnauthorized, types.Error{Message: &msg}) + + return + } } } diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index 64eb967c..c0e634a0 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -10,85 +10,333 @@ import ( "net/http/httptest" "testing" - "github.com/go-vela/worker/router/middleware/user" - - "github.com/go-vela/types/library" - "github.com/gin-gonic/gin" ) -func TestPerm_MustServer_success(t *testing.T) { +func TestPerm_MustServer_ValidateToken200(t *testing.T) { + // setup types + tkn := "superSecret" + + // setup context + gin.SetMode(gin.TestMode) + + // setup mock worker router + workerResp := httptest.NewRecorder() + workerCtx, workerEngine := gin.CreateTestContext(workerResp) + + // fake request made to the worker router + workerCtx.Request, _ = http.NewRequest(http.MethodGet, "/build/cancel", nil) + workerCtx.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) + + // setup mock server router + // the URL of the mock server router is injected into the mock worker router + serverResp := httptest.NewRecorder() + _, serverEngine := gin.CreateTestContext(serverResp) + + // mocked token validation endpoint used in MustServer + serverEngine.GET("/validate-token", func(c *gin.Context) { + // token is not expired and matches server token + c.Status(http.StatusOK) + }) + + serverMock := httptest.NewServer(serverEngine) + defer serverMock.Close() + + workerEngine.Use(func(c *gin.Context) { c.Set("server-address", serverMock.URL) }) + + // attach perm middleware that we are testing + workerEngine.Use(MustServer()) + workerEngine.GET("/build/cancel", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + workerMock := httptest.NewServer(workerEngine) + defer workerMock.Close() + + // run test + workerEngine.ServeHTTP(workerCtx.Writer, workerCtx.Request) + + if workerResp.Code != http.StatusOK { + t.Errorf("MustServer returned %v, want %v", workerResp.Code, http.StatusOK) + } +} + +func TestPerm_MustServer_ValidateToken401(t *testing.T) { + // setup types + tkn := "superSecret" + + // setup context + gin.SetMode(gin.TestMode) + + // setup mock worker router + workerResp := httptest.NewRecorder() + workerCtx, workerEngine := gin.CreateTestContext(workerResp) + + // fake request made to the worker router + workerCtx.Request, _ = http.NewRequest(http.MethodGet, "/build/cancel", nil) + workerCtx.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) + + // setup mock server router + // the URL of the mock server router is injected into the mock worker router + serverResp := httptest.NewRecorder() + _, serverEngine := gin.CreateTestContext(serverResp) + + // mocked token validation endpoint used in MustServer + serverEngine.GET("/validate-token", func(c *gin.Context) { + // test that validate-token returning a 401 works as expected + c.Status(http.StatusUnauthorized) + }) + + serverMock := httptest.NewServer(serverEngine) + defer serverMock.Close() + + workerEngine.Use(func(c *gin.Context) { c.Set("server-address", serverMock.URL) }) + + // attach perm middleware that we are testing + workerEngine.Use(MustServer()) + workerEngine.GET("/build/cancel", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + workerMock := httptest.NewServer(workerEngine) + defer workerMock.Close() + + // run test + workerEngine.ServeHTTP(workerCtx.Writer, workerCtx.Request) + + if workerResp.Code != http.StatusUnauthorized { + t.Errorf("MustServer returned %v, want %v", workerResp.Code, http.StatusUnauthorized) + } +} + +func TestPerm_MustServer_ValidateToken404(t *testing.T) { + // setup types + tkn := "superSecret" + + // setup context + gin.SetMode(gin.TestMode) + + // setup mock worker router + workerResp := httptest.NewRecorder() + workerCtx, workerEngine := gin.CreateTestContext(workerResp) + + // fake request made to the worker router + workerCtx.Request, _ = http.NewRequest(http.MethodGet, "/build/cancel", nil) + workerCtx.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) + + // setup mock server router + // the URL of the mock server router is injected into the mock worker router + serverResp := httptest.NewRecorder() + _, serverEngine := gin.CreateTestContext(serverResp) + + // skip mocked token validation endpoint used in MustServer + // test that validate-token returning a 404 works as expected + + serverMock := httptest.NewServer(serverEngine) + defer serverMock.Close() + + workerEngine.Use(func(c *gin.Context) { c.Set("server-address", serverMock.URL) }) + + // attach perm middleware that we are testing + workerEngine.Use(MustServer()) + workerEngine.GET("/build/cancel", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + workerMock := httptest.NewServer(workerEngine) + defer workerMock.Close() + + // run test + workerEngine.ServeHTTP(workerCtx.Writer, workerCtx.Request) + + if workerResp.Code != http.StatusUnauthorized { + t.Errorf("MustServer returned %v, want %v", workerResp.Code, http.StatusUnauthorized) + } +} + +func TestPerm_MustServer_ValidateToken500(t *testing.T) { // setup types - secret := "superSecret" + tkn := "superSecret" + + // setup context + gin.SetMode(gin.TestMode) + + // setup mock worker router + workerResp := httptest.NewRecorder() + workerCtx, workerEngine := gin.CreateTestContext(workerResp) + + // fake request made to the worker router + workerCtx.Request, _ = http.NewRequest(http.MethodGet, "/build/cancel", nil) + workerCtx.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) + + // setup mock server router + // the URL of the mock server router is injected into the mock worker router + serverResp := httptest.NewRecorder() + _, serverEngine := gin.CreateTestContext(serverResp) + + // mocked token validation endpoint used in MustServer + serverEngine.GET("/validate-token", func(c *gin.Context) { + // validate-token returning a server error + c.Status(http.StatusInternalServerError) + }) + + serverMock := httptest.NewServer(serverEngine) + defer serverMock.Close() - u := new(library.User) - u.SetID(1) - u.SetName("vela-server") - u.SetToken("bar") - u.SetHash("baz") - u.SetAdmin(true) + workerEngine.Use(func(c *gin.Context) { c.Set("server-address", serverMock.URL) }) + + // attach perm middleware that we are testing + workerEngine.Use(MustServer()) + workerEngine.GET("/build/cancel", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + workerMock := httptest.NewServer(workerEngine) + defer workerMock.Close() + + // run test + workerEngine.ServeHTTP(workerCtx.Writer, workerCtx.Request) + + if workerResp.Code != http.StatusUnauthorized { + t.Errorf("MustServer returned %v, want %v", workerResp.Code, http.StatusUnauthorized) + } +} + +func TestPerm_MustServer_BadServerAddress(t *testing.T) { + // setup types + tkn := "superSecret" + badServerAddress := "test.example.com" // setup context gin.SetMode(gin.TestMode) - resp := httptest.NewRecorder() - context, engine := gin.CreateTestContext(resp) - context.Request, _ = http.NewRequest(http.MethodGet, "/server/users", nil) - context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", secret)) + // setup mock worker router + workerResp := httptest.NewRecorder() + workerCtx, workerEngine := gin.CreateTestContext(workerResp) + + // fake request made to the worker router + workerCtx.Request, _ = http.NewRequest(http.MethodGet, "/build/cancel", nil) + workerCtx.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) - // setup vela mock server - engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) - engine.Use(user.Establish()) - engine.Use(MustServer()) - engine.GET("/server/users", func(c *gin.Context) { + // setup mock server router + // the URL of the mock server router is injected into the mock worker router + serverResp := httptest.NewRecorder() + _, serverEngine := gin.CreateTestContext(serverResp) + + // mocked token validation endpoint used in MustServer + serverEngine.GET("/validate-token", func(c *gin.Context) { c.Status(http.StatusOK) }) - s1 := httptest.NewServer(engine) - defer s1.Close() + serverMock := httptest.NewServer(serverEngine) + defer serverMock.Close() + + workerEngine.Use(func(c *gin.Context) { c.Set("server-address", badServerAddress) }) + + // attach perm middleware that we are testing + workerEngine.Use(MustServer()) + workerEngine.GET("/build/cancel", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + workerMock := httptest.NewServer(workerEngine) + defer workerMock.Close() // run test - engine.ServeHTTP(context.Writer, context.Request) + workerEngine.ServeHTTP(workerCtx.Writer, workerCtx.Request) - if resp.Code != http.StatusOK { - t.Errorf("MustServer returned %v, want %v", resp.Code, http.StatusOK) + if workerResp.Code != http.StatusInternalServerError { + t.Errorf("MustServer returned %v, want %v", workerResp.Code, http.StatusInternalServerError) } } -func TestPerm_MustServer_failure(t *testing.T) { +func TestPerm_MustServer_NoToken(t *testing.T) { // setup types - secret := "foo" + tkn := "" + + // setup context + gin.SetMode(gin.TestMode) + + // setup mock worker router + workerResp := httptest.NewRecorder() + workerCtx, workerEngine := gin.CreateTestContext(workerResp) + + // fake request made to the worker router + workerCtx.Request, _ = http.NewRequest(http.MethodGet, "/build/cancel", nil) + workerCtx.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) - u := new(library.User) - u.SetID(1) - u.SetName("not-vela-server") - u.SetToken("bar") - u.SetHash("baz") - u.SetAdmin(true) + // setup mock server router + // the URL of the mock server router is injected into the mock worker router + serverResp := httptest.NewRecorder() + _, serverEngine := gin.CreateTestContext(serverResp) + // mocked token validation endpoint used in MustServer + serverEngine.GET("/validate-token", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + serverMock := httptest.NewServer(serverEngine) + defer serverMock.Close() + + workerEngine.Use(func(c *gin.Context) { c.Set("server-address", serverMock.URL) }) + + // attach perm middleware that we are testing + workerEngine.Use(MustServer()) + workerEngine.GET("/build/cancel", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + workerMock := httptest.NewServer(workerEngine) + defer workerMock.Close() + + // run test + workerEngine.ServeHTTP(workerCtx.Writer, workerCtx.Request) + + if workerResp.Code != http.StatusBadRequest { + t.Errorf("MustServer returned %v, want %v", workerResp.Code, http.StatusBadRequest) + } +} + +func TestPerm_MustServer_NoAuth(t *testing.T) { // setup context gin.SetMode(gin.TestMode) - resp := httptest.NewRecorder() - context, engine := gin.CreateTestContext(resp) - context.Request, _ = http.NewRequest(http.MethodGet, "/server/users", nil) - context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", secret)) + // setup mock worker router + workerResp := httptest.NewRecorder() + workerCtx, workerEngine := gin.CreateTestContext(workerResp) + + // fake request made to the worker router + workerCtx.Request, _ = http.NewRequest(http.MethodGet, "/build/cancel", nil) + // test that skipping adding an authorization header is handled properly + + // setup mock server router + // the URL of the mock server router is injected into the mock worker router + serverResp := httptest.NewRecorder() + _, serverEngine := gin.CreateTestContext(serverResp) + + // mocked token validation endpoint used in MustServer + serverEngine.GET("/validate-token", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + serverMock := httptest.NewServer(serverEngine) + defer serverMock.Close() + + workerEngine.Use(func(c *gin.Context) { c.Set("server-address", serverMock.URL) }) - // setup vela mock server - engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) - engine.Use(func(c *gin.Context) { c.Set("user", u) }) - engine.Use(MustServer()) - engine.GET("/server/users", func(c *gin.Context) { + // attach perm middleware that we are testing + workerEngine.Use(MustServer()) + workerEngine.GET("/build/cancel", func(c *gin.Context) { c.Status(http.StatusOK) }) - s1 := httptest.NewServer(engine) - defer s1.Close() + workerMock := httptest.NewServer(workerEngine) + defer workerMock.Close() // run test - engine.ServeHTTP(context.Writer, context.Request) + workerEngine.ServeHTTP(workerCtx.Writer, workerCtx.Request) - if resp.Code != http.StatusUnauthorized { - t.Errorf("MustServer returned %v, want %v", resp.Code, http.StatusUnauthorized) + if workerResp.Code != http.StatusBadRequest { + t.Errorf("MustServer returned %v, want %v", workerResp.Code, http.StatusBadRequest) } } diff --git a/router/middleware/secret.go b/router/middleware/secret.go deleted file mode 100644 index c880a425..00000000 --- a/router/middleware/secret.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package middleware - -import ( - "github.com/gin-gonic/gin" -) - -// Secret is a middleware function that attaches the secret used for -// server <-> agent communication to the context of every http.Request. -func Secret(secret string) gin.HandlerFunc { - return func(c *gin.Context) { - c.Set("secret", secret) - c.Next() - } -} diff --git a/router/middleware/secret_test.go b/router/middleware/secret_test.go deleted file mode 100644 index 1f37a084..00000000 --- a/router/middleware/secret_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package middleware - -import ( - "net/http" - "net/http/httptest" - "reflect" - "testing" - - "github.com/gin-gonic/gin" -) - -func TestMiddleware_Secret(t *testing.T) { - // setup types - got := "" - want := "foobar" - - // setup context - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, engine := gin.CreateTestContext(resp) - context.Request, _ = http.NewRequest(http.MethodGet, "/health", nil) - - // setup mock server - engine.Use(Secret(want)) - engine.GET("/health", func(c *gin.Context) { - got = c.Value("secret").(string) - - c.Status(http.StatusOK) - }) - - // run test - engine.ServeHTTP(context.Writer, context.Request) - - if resp.Code != http.StatusOK { - t.Errorf("Secret returned %v, want %v", resp.Code, http.StatusOK) - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("Secret is %v, want %v", got, want) - } -} diff --git a/router/middleware/server.go b/router/middleware/server.go new file mode 100644 index 00000000..3c93dbfb --- /dev/null +++ b/router/middleware/server.go @@ -0,0 +1,18 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "github.com/gin-gonic/gin" +) + +// ServerAddress is a middleware function that attaches the +// server address to the context of every http.Request. +func ServerAddress(addr string) gin.HandlerFunc { + return func(c *gin.Context) { + c.Set("server-address", addr) + c.Next() + } +} diff --git a/router/middleware/user/context.go b/router/middleware/user/context.go deleted file mode 100644 index 944a1f3e..00000000 --- a/router/middleware/user/context.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package user - -import ( - "context" - - "github.com/go-vela/types/library" -) - -const key = "user" - -// Setter defines a context that enables setting values. -type Setter interface { - Set(string, interface{}) -} - -// FromContext returns the User associated with this context. -func FromContext(c context.Context) *library.User { - value := c.Value(key) - if value == nil { - return nil - } - - u, ok := value.(*library.User) - if !ok { - return nil - } - - return u -} - -// ToContext adds the User to this context if it supports -// the Setter interface. -func ToContext(c Setter, u *library.User) { - c.Set(key, u) -} diff --git a/router/middleware/user/context_test.go b/router/middleware/user/context_test.go deleted file mode 100644 index 6cfe188a..00000000 --- a/router/middleware/user/context_test.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package user - -import ( - "testing" - - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" -) - -func TestUser_FromContext(t *testing.T) { - // setup types - uID := int64(1) - want := &library.User{ID: &uID} - - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - context.Set(key, want) - - // run test - got := FromContext(context) - - if got != want { - t.Errorf("FromContext is %v, want %v", got, want) - } -} - -func TestUser_FromContext_Bad(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - context.Set(key, nil) - - // run test - got := FromContext(context) - - if got != nil { - t.Errorf("FromContext is %v, want nil", got) - } -} - -func TestUser_FromContext_WrongType(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - context.Set(key, 1) - - // run test - got := FromContext(context) - - if got != nil { - t.Errorf("FromContext is %v, want nil", got) - } -} - -func TestUser_FromContext_Empty(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - - // run test - got := FromContext(context) - - if got != nil { - t.Errorf("FromContext is %v, want nil", got) - } -} - -func TestUser_ToContext(t *testing.T) { - // setup types - uID := int64(1) - want := &library.User{ID: &uID} - - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - ToContext(context, want) - - // run test - got := context.Value(key) - - if got != want { - t.Errorf("ToContext is %v, want %v", got, want) - } -} diff --git a/router/middleware/user/doc.go b/router/middleware/user/doc.go deleted file mode 100644 index 7ba0a485..00000000 --- a/router/middleware/user/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -// Package user provides the ability for inserting -// Vela user resources into or extracting Vela user -// resources from the middleware chain for the API. -// -// Usage: -// -// import "github.com/go-vela/worker/router/middleware/user" -package user diff --git a/router/middleware/user/user.go b/router/middleware/user/user.go deleted file mode 100644 index 817aa0e9..00000000 --- a/router/middleware/user/user.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package user - -import ( - "net/http" - "strings" - - "github.com/go-vela/worker/router/middleware/token" - - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" -) - -// Retrieve gets the user in the given context. -func Retrieve(c *gin.Context) *library.User { - return FromContext(c) -} - -// Establish sets the user in the given context. -func Establish() gin.HandlerFunc { - return func(c *gin.Context) { - u := new(library.User) - - t, err := token.Retrieve(c.Request) - if err != nil { - c.AbortWithStatusJSON(http.StatusUnauthorized, err.Error()) - return - } - - secret := c.MustGet("secret").(string) - if strings.EqualFold(t, secret) { - u.SetName("vela-server") - u.SetActive(true) - u.SetAdmin(true) - } - - ToContext(c, u) - c.Next() - } -} diff --git a/router/middleware/user/user_test.go b/router/middleware/user/user_test.go deleted file mode 100644 index b4f8b52f..00000000 --- a/router/middleware/user/user_test.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package user - -import ( - "fmt" - "net/http" - "net/http/httptest" - "reflect" - "testing" - - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" -) - -func TestUser_Retrieve(t *testing.T) { - // setup types - want := new(library.User) - want.SetID(1) - - // setup context - gin.SetMode(gin.TestMode) - - context, _ := gin.CreateTestContext(nil) - ToContext(context, want) - - // run test - got := Retrieve(context) - - if got != want { - t.Errorf("Retrieve is %v, want %v", got, want) - } -} - -func TestUser_Establish(t *testing.T) { - // setup types - secret := "superSecret" - got := new(library.User) - want := new(library.User) - want.SetName("vela-server") - want.SetActive(true) - want.SetAdmin(true) - - // setup context - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, engine := gin.CreateTestContext(resp) - context.Request, _ = http.NewRequest(http.MethodGet, "/users/vela-server", nil) - context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", secret)) - - // setup vela mock server - engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) - engine.Use(Establish()) - engine.GET("/users/:user", func(c *gin.Context) { - got = Retrieve(c) - - c.Status(http.StatusOK) - }) - - s1 := httptest.NewServer(engine) - defer s1.Close() - - // run test - engine.ServeHTTP(context.Writer, context.Request) - - if resp.Code != http.StatusOK { - t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusOK) - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("Establish is %v, want %v", got, want) - } -} - -func TestUser_Establish_NoToken(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, engine := gin.CreateTestContext(resp) - context.Request, _ = http.NewRequest(http.MethodGet, "/users/foo", nil) - - // setup mock server - engine.Use(Establish()) - - // run test - engine.ServeHTTP(context.Writer, context.Request) - - if resp.Code != http.StatusUnauthorized { - t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusUnauthorized) - } -} - -func TestUser_Establish_SecretValid(t *testing.T) { - // setup types - secret := "superSecret" - - want := new(library.User) - want.SetName("vela-server") - want.SetActive(true) - want.SetAdmin(true) - - got := new(library.User) - - // setup context - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, engine := gin.CreateTestContext(resp) - context.Request, _ = http.NewRequest(http.MethodGet, "/users/vela-server", nil) - context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", secret)) - - // setup vela mock server - engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) - engine.Use(Establish()) - engine.GET("/users/:user", func(c *gin.Context) { - got = Retrieve(c) - - c.Status(http.StatusOK) - }) - - s := httptest.NewServer(engine) - defer s.Close() - - // run test - engine.ServeHTTP(context.Writer, context.Request) - - if resp.Code != http.StatusOK { - t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusOK) - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("Establish is %v, want %v", got, want) - } -} - -func TestUser_Establish_NoAuthorizeUser(t *testing.T) { - // setup types - secret := "superSecret" - - // setup context - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, engine := gin.CreateTestContext(resp) - context.Request, _ = http.NewRequest(http.MethodGet, "/users/foo?access_token=bar", nil) - - // setup vela mock server - engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) - engine.Use(Establish()) - - // run test - engine.ServeHTTP(context.Writer, context.Request) - - if resp.Code != http.StatusUnauthorized { - t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusUnauthorized) - } -} diff --git a/router/router.go b/router/router.go index 222029df..14b3955c 100644 --- a/router/router.go +++ b/router/router.go @@ -31,7 +31,6 @@ import ( "github.com/go-vela/worker/api" "github.com/go-vela/worker/router/middleware" "github.com/go-vela/worker/router/middleware/perm" - "github.com/go-vela/worker/router/middleware/user" ) const ( @@ -95,7 +94,7 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { // add a collection of endpoints for handling API related requests // // https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc#RouterGroup.Group - baseAPI := r.Group(base, user.Establish(), perm.MustServer()) + baseAPI := r.Group(base, perm.MustServer()) { // add an endpoint for shutting down the worker //