Commit cfb90242 authored by Jacob Vosmaer's avatar Jacob Vosmaer

Send JWT token with API requests

parent fe53d260
...@@ -5,3 +5,4 @@ testdata/public ...@@ -5,3 +5,4 @@ testdata/public
gitlab-zip-cat gitlab-zip-cat
gitlab-zip-metadata gitlab-zip-metadata
_build _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 ...@@ -2,6 +2,7 @@ PREFIX=/usr/local
VERSION=$(shell git describe)-$(shell date -u +%Y%m%d.%H%M%S) VERSION=$(shell git describe)-$(shell date -u +%Y%m%d.%H%M%S)
BUILD_DIR = $(shell pwd) BUILD_DIR = $(shell pwd)
export GOPATH=${BUILD_DIR}/_build export GOPATH=${BUILD_DIR}/_build
GOBUILD=go build -ldflags "-X main.Version=${VERSION}" GOBUILD=go build -ldflags "-X main.Version=${VERSION}"
PKG=gitlab.com/gitlab-org/gitlab-workhorse PKG=gitlab.com/gitlab-org/gitlab-workhorse
...@@ -23,6 +24,8 @@ install: gitlab-workhorse gitlab-zip-cat gitlab-zip-metadata ...@@ -23,6 +24,8 @@ install: gitlab-workhorse gitlab-zip-cat gitlab-zip-metadata
${BUILD_DIR}/_build: ${BUILD_DIR}/_build:
mkdir -p $@/src/${PKG} mkdir -p $@/src/${PKG}
tar -cf - --exclude _build --exclude .git . | (cd $@/src/${PKG} && tar -xf -) 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 $@ touch $@
.PHONY: test .PHONY: test
......
...@@ -30,7 +30,7 @@ func runPreAuthorizeHandler(t *testing.T, ts *httptest.Server, suffix string, ur ...@@ -30,7 +30,7 @@ func runPreAuthorizeHandler(t *testing.T, ts *httptest.Server, suffix string, ur
t.Fatal(err) t.Fatal(err)
} }
parsedURL := helper.URLMustParse(ts.URL) 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() response := httptest.NewRecorder()
a.PreAuthorizeHandler(okHandler, suffix).ServeHTTP(response, httpRequest) a.PreAuthorizeHandler(okHandler, suffix).ServeHTTP(response, httpRequest)
......
...@@ -11,22 +11,30 @@ import ( ...@@ -11,22 +11,30 @@ import (
"gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway" "gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper" "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 (
const ResponseContentType = "application/vnd.gitlab-workhorse+json" // 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 { type API struct {
Client *http.Client Client *http.Client
URL *url.URL URL *url.URL
Version string 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{ return &API{
Client: &http.Client{Transport: roundTripper}, Client: &http.Client{Transport: roundTripper},
URL: myURL, URL: myURL,
Version: version, Version: version,
SecretFile: secretFile,
} }
} }
...@@ -122,6 +130,21 @@ func (api *API) newRequest(r *http.Request, body io.Reader, suffix string) (*htt ...@@ -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. // configurations (Passenger) to solve auth request routing problems.
authReq.Header.Set("Gitlab-Workhorse", api.Version) 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 return authReq, nil
} }
......
...@@ -93,7 +93,7 @@ func testUploadArtifacts(contentType string, body io.Reader, t *testing.T, ts *h ...@@ -93,7 +93,7 @@ func testUploadArtifacts(contentType string, body io.Reader, t *testing.T, ts *h
response := httptest.NewRecorder() response := httptest.NewRecorder()
parsedURL := helper.URLMustParse(ts.URL) parsedURL := helper.URLMustParse(ts.URL)
roundTripper := badgateway.TestRoundTripper(parsedURL) roundTripper := badgateway.TestRoundTripper(parsedURL)
apiClient := api.NewAPI(parsedURL, "123", roundTripper) apiClient := api.NewAPI(parsedURL, "123", testhelper.SecretFile(), roundTripper)
proxyClient := proxy.NewProxy(parsedURL, "123", roundTripper) proxyClient := proxy.NewProxy(parsedURL, "123", roundTripper)
UploadArtifacts(apiClient, proxyClient).ServeHTTP(response, httpRequest) UploadArtifacts(apiClient, proxyClient).ServeHTTP(response, httpRequest)
return response return response
......
...@@ -15,6 +15,10 @@ import ( ...@@ -15,6 +15,10 @@ import (
"testing" "testing"
) )
func SecretFile() string {
return path.Join(RootDir(), "testdata/test-secret")
}
func AssertResponseCode(t *testing.T, response *httptest.ResponseRecorder, expectedCode int) { func AssertResponseCode(t *testing.T, response *httptest.ResponseRecorder, expectedCode int) {
if response.Code != expectedCode { if response.Code != expectedCode {
t.Fatalf("for HTTP request expected to get %d, got %d instead", expectedCode, response.Code) 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 ...@@ -52,11 +56,7 @@ func TestServerWithHandler(url *regexp.Regexp, handler http.HandlerFunc) *httpte
} }
func BuildExecutables() (func(), error) { func BuildExecutables() (func(), error) {
_, currentFile, _, ok := runtime.Caller(0) rootDir := RootDir()
if !ok {
return nil, errors.New("BuildExecutables: calling runtime.Caller failed")
}
rootDir := path.Join(path.Dir(currentFile), "../..")
// This method will be invoked more than once due to Go test // This method will be invoked more than once due to Go test
// parallelization. We must use a unique temp directory for each // parallelization. We must use a unique temp directory for each
...@@ -85,3 +85,11 @@ func BuildExecutables() (func(), error) { ...@@ -85,3 +85,11 @@ func BuildExecutables() (func(), error) {
os.RemoveAll(testDir) os.RemoveAll(testDir)
}, nil }, 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() { ...@@ -37,6 +37,7 @@ func (u *Upstream) configureRoutes() {
api := apipkg.NewAPI( api := apipkg.NewAPI(
u.Backend, u.Backend,
u.Version, u.Version,
u.SecretFile,
u.RoundTripper, u.RoundTripper,
) )
static := &staticpages.Static{u.DocumentRoot} static := &staticpages.Static{u.DocumentRoot}
......
...@@ -23,6 +23,7 @@ var DefaultBackend = helper.URLMustParse("http://localhost:8080") ...@@ -23,6 +23,7 @@ var DefaultBackend = helper.URLMustParse("http://localhost:8080")
type Upstream struct { type Upstream struct {
Backend *url.URL Backend *url.URL
Version string Version string
SecretFile string
DocumentRoot string DocumentRoot string
DevelopmentMode bool DevelopmentMode bool
...@@ -31,10 +32,11 @@ type Upstream struct { ...@@ -31,10 +32,11 @@ type Upstream struct {
RoundTripper *badgateway.RoundTripper 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{ up := Upstream{
Backend: backend, Backend: backend,
Version: version, Version: version,
SecretFile: secretFile,
DocumentRoot: documentRoot, DocumentRoot: documentRoot,
DevelopmentMode: developmentMode, DevelopmentMode: developmentMode,
} }
......
...@@ -40,6 +40,7 @@ var pprofListenAddr = flag.String("pprofListenAddr", "", "pprof listening addres ...@@ -40,6 +40,7 @@ var pprofListenAddr = flag.String("pprofListenAddr", "", "pprof listening addres
var documentRoot = flag.String("documentRoot", "public", "Path to static files content") 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 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 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() { func main() {
flag.Usage = func() { flag.Usage = func() {
...@@ -86,6 +87,7 @@ func main() { ...@@ -86,6 +87,7 @@ func main() {
*authBackend, *authBackend,
*authSocket, *authSocket,
Version, Version,
*secretFile,
*documentRoot, *documentRoot,
*developmentMode, *developmentMode,
*proxyHeadersTimeout, *proxyHeadersTimeout,
......
...@@ -829,6 +829,7 @@ func startWorkhorseServer(authBackend string) *httptest.Server { ...@@ -829,6 +829,7 @@ func startWorkhorseServer(authBackend string) *httptest.Server {
helper.URLMustParse(authBackend), helper.URLMustParse(authBackend),
"", "",
"123", "123",
testhelper.SecretFile(),
testDocumentRoot, testDocumentRoot,
false, false,
0, 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