diff --git a/go.mod b/go.mod index f0cc493ca..ff6ae630a 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/go-vela/types v0.7.4 github.com/google/go-cmp v0.5.4 github.com/google/go-github/v29 v29.0.3 + github.com/google/go-github/v33 v33.0.0 github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.2.0 github.com/hashicorp/go-hclog v0.10.0 // indirect diff --git a/go.sum b/go.sum index c9fe89c5a..39627997f 100644 --- a/go.sum +++ b/go.sum @@ -233,6 +233,8 @@ github.com/google/go-github/v24 v24.0.1 h1:KCt1LjMJEey1qvPXxa9SjaWxwTsCWSq6p2Ju5 github.com/google/go-github/v24 v24.0.1/go.mod h1:CRqaW1Uns1TCkP0wqTpxYyRxRjxwvKU/XSS44u6X74M= github.com/google/go-github/v29 v29.0.3 h1:IktKCTwU//aFHnpA+2SLIi7Oo9uhAzgsdZNbcAqhgdc= github.com/google/go-github/v29 v29.0.3/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= +github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM= +github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= diff --git a/source/github/authentication.go b/source/github/authentication.go index 6d964e3af..66a4fb59c 100644 --- a/source/github/authentication.go +++ b/source/github/authentication.go @@ -9,10 +9,12 @@ import ( "errors" "fmt" "net/http" + "net/url" + "strings" "github.com/go-vela/server/random" - "github.com/go-vela/types/library" + "github.com/google/go-github/v33/github" "github.com/sirupsen/logrus" ) @@ -110,6 +112,49 @@ func (c *client) AuthenticateToken(r *http.Request) (*library.User, error) { return nil, errors.New("no token provided") } + // create http client to connect to GitHub + // + // nolint: lll // ignore long line length due to variable names + transport := github.BasicAuthTransport{Username: c.OConfig.ClientID, Password: c.OConfig.ClientSecret} + // create client to connect to GitHub API + client := github.NewClient(transport.Client()) + // check if github url was set + if c.URL != "" && c.URL != "https://github.com" { + // check if address has trailing slash + if !strings.HasSuffix(c.URL, "/") { + // add trailing slash + c.URL = c.URL + "/api/v3/" + } + // parse the provided url into url type + enterpriseURL, err := url.Parse(c.URL) + if err != nil { + return nil, err + } + // set the base and upload url + client.BaseURL = enterpriseURL + client.UploadURL = enterpriseURL + } + // check if the provided token was created by Vela + _, resp, err := client.Authorizations.Check(context.Background(), c.OConfig.ClientID, token) + // check if the error is of type ErrorResponse + if gerr, ok := err.(*github.ErrorResponse); ok { + // check the status code + switch gerr.Response.StatusCode { + // 404 is expected when non vela token is used + case http.StatusNotFound: + break + default: + return nil, err + } + } else if err != nil { + return nil, err + } + + // return error if the token was created by Vela + if resp.StatusCode != http.StatusNotFound { + return nil, errors.New("token must not be created by vela") + } + u, err := c.Authorize(token) if err != nil { return nil, err diff --git a/source/github/authentication_test.go b/source/github/authentication_test.go index e79906faf..438832e58 100644 --- a/source/github/authentication_test.go +++ b/source/github/authentication_test.go @@ -384,6 +384,42 @@ func TestGithub_Authenticate_Invalid_Token(t *testing.T) { } } +func TestGithub_Authenticate_Vela_Token(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodPost, "/authenticate/token", nil) + context.Request.Header.Set("Token", "vela") + + engine.GET("/api/v3/user", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/user.json") + }) + + engine.POST("/api/v3/applications/foo/token", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + client, _ := NewTest(s.URL) + + // run test + _, err := client.AuthenticateToken(context.Request) + if resp.Code != http.StatusOK { + t.Errorf("Authenticate returned %v, want %v", resp.Code, http.StatusOK) + } + + if err == nil { + t.Error("Authenticate should have returned err") + } +} + func TestGithub_LoginWCreds(t *testing.T) { // setup context gin.SetMode(gin.TestMode)