Commit cfb90242 authored by Jacob Vosmaer's avatar Jacob Vosmaer

Send JWT token with API requests

parent fe53d260
......@@ -5,3 +5,4 @@ testdata/public
gitlab-zip-cat
gitlab-zip-metadata
_build
/vendor
{
"ImportPath": "gitlab.com/gitlab-org/gitlab-workhorse",
"GoVersion": "go1.7",
"GodepVersion": "v74",
"Packages": [
"./..."
],
"Deps": [
{
"ImportPath": "github.com/dgrijalva/jwt-go",
"Comment": "v3.0.0",
"Rev": "d2709f9f1f31ebcda9651b03077758c1f3a0018c"
}
]
}
This directory tree is generated automatically by godep.
Please do not edit.
See https://github.com/tools/godep for more information.
......@@ -2,6 +2,7 @@ PREFIX=/usr/local
VERSION=$(shell git describe)-$(shell date -u +%Y%m%d.%H%M%S)
BUILD_DIR = $(shell pwd)
export GOPATH=${BUILD_DIR}/_build
GOBUILD=go build -ldflags "-X main.Version=${VERSION}"
PKG=gitlab.com/gitlab-org/gitlab-workhorse
......@@ -23,6 +24,8 @@ install: gitlab-workhorse gitlab-zip-cat gitlab-zip-metadata
${BUILD_DIR}/_build:
mkdir -p $@/src/${PKG}
tar -cf - --exclude _build --exclude .git . | (cd $@/src/${PKG} && tar -xf -)
PATH="${GOPATH}/bin:${PATH}" command -v godep || go get github.com/tools/godep
(cd $@/src/${PKG} && PATH="${GOPATH}/bin:${PATH}" godep restore)
touch $@
.PHONY: test
......
......@@ -30,7 +30,7 @@ func runPreAuthorizeHandler(t *testing.T, ts *httptest.Server, suffix string, ur
t.Fatal(err)
}
parsedURL := helper.URLMustParse(ts.URL)
a := api.NewAPI(parsedURL, "123", badgateway.TestRoundTripper(parsedURL))
a := api.NewAPI(parsedURL, "123", testhelper.SecretFile(), badgateway.TestRoundTripper(parsedURL))
response := httptest.NewRecorder()
a.PreAuthorizeHandler(okHandler, suffix).ServeHTTP(response, httpRequest)
......
......@@ -11,22 +11,30 @@ import (
"gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
"github.com/dgrijalva/jwt-go"
)
// Custom content type for API responses, to catch routing / programming mistakes
const ResponseContentType = "application/vnd.gitlab-workhorse+json"
const (
// Custom content type for API responses, to catch routing / programming mistakes
ResponseContentType = "application/vnd.gitlab-workhorse+json"
// Block size for HMAC SHA256
numSecretBytes = 64
)
type API struct {
Client *http.Client
URL *url.URL
Version string
Client *http.Client
URL *url.URL
Version string
SecretFile string
}
func NewAPI(myURL *url.URL, version string, roundTripper *badgateway.RoundTripper) *API {
func NewAPI(myURL *url.URL, version, secretFile string, roundTripper *badgateway.RoundTripper) *API {
return &API{
Client: &http.Client{Transport: roundTripper},
URL: myURL,
Version: version,
Client: &http.Client{Transport: roundTripper},
URL: myURL,
Version: version,
SecretFile: secretFile,
}
}
......@@ -122,6 +130,21 @@ func (api *API) newRequest(r *http.Request, body io.Reader, suffix string) (*htt
// configurations (Passenger) to solve auth request routing problems.
authReq.Header.Set("Gitlab-Workhorse", api.Version)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{Issuer: "gitlab-workhorse"})
secretBytes, err := ioutil.ReadFile(api.SecretFile)
if err != nil {
return nil, fmt.Errorf("read secretFile: %v", err)
}
if n := len(secretBytes); n != numSecretBytes {
return nil, fmt.Errorf("expected %d bytes in %s, found %d", numSecretBytes, api.SecretFile, n)
}
tokenString, err := token.SignedString(secretBytes)
if err != nil {
return nil, fmt.Errorf("sign JWT: %v", err)
}
authReq.Header.Set("Gitlab-Workhorse-Api-Request", tokenString)
return authReq, nil
}
......
......@@ -93,7 +93,7 @@ func testUploadArtifacts(contentType string, body io.Reader, t *testing.T, ts *h
response := httptest.NewRecorder()
parsedURL := helper.URLMustParse(ts.URL)
roundTripper := badgateway.TestRoundTripper(parsedURL)
apiClient := api.NewAPI(parsedURL, "123", roundTripper)
apiClient := api.NewAPI(parsedURL, "123", testhelper.SecretFile(), roundTripper)
proxyClient := proxy.NewProxy(parsedURL, "123", roundTripper)
UploadArtifacts(apiClient, proxyClient).ServeHTTP(response, httpRequest)
return response
......
......@@ -15,6 +15,10 @@ import (
"testing"
)
func SecretFile() string {
return path.Join(RootDir(), "testdata/test-secret")
}
func AssertResponseCode(t *testing.T, response *httptest.ResponseRecorder, expectedCode int) {
if response.Code != expectedCode {
t.Fatalf("for HTTP request expected to get %d, got %d instead", expectedCode, response.Code)
......@@ -52,11 +56,7 @@ func TestServerWithHandler(url *regexp.Regexp, handler http.HandlerFunc) *httpte
}
func BuildExecutables() (func(), error) {
_, currentFile, _, ok := runtime.Caller(0)
if !ok {
return nil, errors.New("BuildExecutables: calling runtime.Caller failed")
}
rootDir := path.Join(path.Dir(currentFile), "../..")
rootDir := RootDir()
// This method will be invoked more than once due to Go test
// parallelization. We must use a unique temp directory for each
......@@ -85,3 +85,11 @@ func BuildExecutables() (func(), error) {
os.RemoveAll(testDir)
}, nil
}
func RootDir() string {
_, currentFile, _, ok := runtime.Caller(0)
if !ok {
panic(errors.New("RootDir: calling runtime.Caller failed"))
}
return path.Join(path.Dir(currentFile), "../..")
}
......@@ -37,6 +37,7 @@ func (u *Upstream) configureRoutes() {
api := apipkg.NewAPI(
u.Backend,
u.Version,
u.SecretFile,
u.RoundTripper,
)
static := &staticpages.Static{u.DocumentRoot}
......
......@@ -23,6 +23,7 @@ var DefaultBackend = helper.URLMustParse("http://localhost:8080")
type Upstream struct {
Backend *url.URL
Version string
SecretFile string
DocumentRoot string
DevelopmentMode bool
......@@ -31,10 +32,11 @@ type Upstream struct {
RoundTripper *badgateway.RoundTripper
}
func NewUpstream(backend *url.URL, socket string, version string, documentRoot string, developmentMode bool, proxyHeadersTimeout time.Duration) *Upstream {
func NewUpstream(backend *url.URL, socket, version, secretFile, documentRoot string, developmentMode bool, proxyHeadersTimeout time.Duration) *Upstream {
up := Upstream{
Backend: backend,
Version: version,
SecretFile: secretFile,
DocumentRoot: documentRoot,
DevelopmentMode: developmentMode,
}
......
......@@ -40,6 +40,7 @@ var pprofListenAddr = flag.String("pprofListenAddr", "", "pprof listening addres
var documentRoot = flag.String("documentRoot", "public", "Path to static files content")
var proxyHeadersTimeout = flag.Duration("proxyHeadersTimeout", 5*time.Minute, "How long to wait for response headers when proxying the request")
var developmentMode = flag.Bool("developmentMode", false, "Allow to serve assets from Rails app")
var secretFile = flag.String("secretFile", "./.gitlab_workhorse_secret", "File with secret key to authenticate with authBackend")
func main() {
flag.Usage = func() {
......@@ -86,6 +87,7 @@ func main() {
*authBackend,
*authSocket,
Version,
*secretFile,
*documentRoot,
*developmentMode,
*proxyHeadersTimeout,
......
......@@ -829,6 +829,7 @@ func startWorkhorseServer(authBackend string) *httptest.Server {
helper.URLMustParse(authBackend),
"",
"123",
testhelper.SecretFile(),
testDocumentRoot,
false,
0,
......
AՃ+vy'jo8Bp"j6Slt܄&j˜׺;4/
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment