Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-workhorse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-workhorse
Commits
9e79e5ba
Commit
9e79e5ba
authored
Apr 30, 2020
by
Robert Speicher
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '8-30-stable' of gitlab.com:gitlab-org/security/gitlab-workhorse into 8-30-stable
parents
0b04008c
d0573443
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
145 additions
and
74 deletions
+145
-74
CHANGELOG
CHANGELOG
+4
-0
VERSION
VERSION
+1
-1
internal/artifacts/artifacts_upload.go
internal/artifacts/artifacts_upload.go
+8
-13
internal/artifacts/artifacts_upload_test.go
internal/artifacts/artifacts_upload_test.go
+17
-1
internal/testhelper/testhelper.go
internal/testhelper/testhelper.go
+17
-0
internal/upload/accelerate.go
internal/upload/accelerate.go
+1
-41
internal/upload/saved_file_tracker.go
internal/upload/saved_file_tracker.go
+55
-0
internal/upload/saved_file_tracker_test.go
internal/upload/saved_file_tracker_test.go
+39
-0
internal/upload/uploads_test.go
internal/upload/uploads_test.go
+1
-1
upload_test.go
upload_test.go
+2
-17
No files found.
CHANGELOG
View file @
9e79e5ba
...
...
@@ -2,6 +2,10 @@
Formerly known as 'gitlab-git-http-server'.
v 8.30.1
- Sign artifact multipart fields in Workhorse
v 8.30.0
- Proxy ActionCable websocket connection !454
...
...
VERSION
View file @
9e79e5ba
8.30.
0
8.30.
1
internal/artifacts/artifacts_upload.go
View file @
9e79e5ba
...
...
@@ -19,7 +19,8 @@ import (
type
artifactsUploadProcessor
struct
{
opts
*
filestore
.
SaveFileOpts
stored
bool
upload
.
SavedFileTracker
}
func
(
a
*
artifactsUploadProcessor
)
generateMetadataFromZip
(
ctx
context
.
Context
,
file
*
filestore
.
FileHandler
)
(
*
filestore
.
FileHandler
,
error
)
{
...
...
@@ -79,10 +80,10 @@ func (a *artifactsUploadProcessor) ProcessFile(ctx context.Context, formName str
if
formName
!=
"file"
{
return
fmt
.
Errorf
(
"invalid form field: %q"
,
formName
)
}
if
a
.
stored
{
if
a
.
Count
()
>
0
{
return
fmt
.
Errorf
(
"artifacts request contains more than one file"
)
}
a
.
stored
=
true
a
.
Track
(
formName
,
file
.
LocalPath
)
select
{
case
<-
ctx
.
Done
()
:
...
...
@@ -99,26 +100,20 @@ func (a *artifactsUploadProcessor) ProcessFile(ctx context.Context, formName str
for
k
,
v
:=
range
metadata
.
GitLabFinalizeFields
(
"metadata"
)
{
writer
.
WriteField
(
k
,
v
)
}
a
.
Track
(
"metadata"
,
metadata
.
LocalPath
)
}
}
return
nil
}
func
(
a
*
artifactsUploadProcessor
)
ProcessField
(
ctx
context
.
Context
,
formName
string
,
writer
*
multipart
.
Writer
)
error
{
return
nil
}
func
(
a
*
artifactsUploadProcessor
)
Finalize
(
ctx
context
.
Context
)
error
{
return
nil
}
func
(
a
*
artifactsUploadProcessor
)
Name
()
string
{
return
"artifacts"
}
func
UploadArtifacts
(
myAPI
*
api
.
API
,
h
http
.
Handler
)
http
.
Handler
{
return
myAPI
.
PreAuthorizeHandler
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
{
mg
:=
&
artifactsUploadProcessor
{
opts
:
filestore
.
GetOpts
(
a
)}
mg
:=
&
artifactsUploadProcessor
{
opts
:
filestore
.
GetOpts
(
a
)
,
SavedFileTracker
:
upload
.
SavedFileTracker
{
Request
:
r
}
}
upload
.
HandleFileUploads
(
w
,
r
,
h
,
a
,
mg
)
},
"/authorize"
)
...
...
internal/artifacts/artifacts_upload_test.go
View file @
9e79e5ba
...
...
@@ -14,13 +14,18 @@ import (
"os"
"testing"
jwt
"github.com/dgrijalva/jwt-go"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/upload"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/upstream/roundtripper"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/zipartifacts"
"github.com/stretchr/testify/require"
)
const
(
...
...
@@ -128,7 +133,18 @@ func TestUploadHandlerAddingMetadata(t *testing.T) {
}
defer
os
.
RemoveAll
(
tempPath
)
ts
:=
testArtifactsUploadServer
(
t
,
api
.
Response
{
TempPath
:
tempPath
},
nil
)
ts
:=
testArtifactsUploadServer
(
t
,
api
.
Response
{
TempPath
:
tempPath
},
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
jwtToken
,
err
:=
jwt
.
Parse
(
r
.
Header
.
Get
(
upload
.
RewrittenFieldsHeader
),
testhelper
.
ParseJWT
)
require
.
NoError
(
t
,
err
)
rewrittenFields
:=
jwtToken
.
Claims
.
(
jwt
.
MapClaims
)[
"rewritten_fields"
]
.
(
map
[
string
]
interface
{})
require
.
Equal
(
t
,
2
,
len
(
rewrittenFields
))
require
.
Contains
(
t
,
rewrittenFields
,
"file"
)
require
.
Contains
(
t
,
rewrittenFields
,
"metadata"
)
},
)
defer
ts
.
Close
()
var
buffer
bytes
.
Buffer
...
...
internal/testhelper/testhelper.go
View file @
9e79e5ba
...
...
@@ -15,6 +15,8 @@ import (
"strings"
"testing"
jwt
"github.com/dgrijalva/jwt-go"
"gitlab.com/gitlab-org/labkit/log"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/secret"
...
...
@@ -174,3 +176,18 @@ func LoadFile(t *testing.T, filePath string) string {
}
return
string
(
content
)
}
func
ParseJWT
(
token
*
jwt
.
Token
)
(
interface
{},
error
)
{
// Don't forget to validate the alg is what you expect:
if
_
,
ok
:=
token
.
Method
.
(
*
jwt
.
SigningMethodHMAC
);
!
ok
{
return
nil
,
fmt
.
Errorf
(
"unexpected signing method: %v"
,
token
.
Header
[
"alg"
])
}
ConfigureSecret
()
secretBytes
,
err
:=
secret
.
Bytes
()
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"read secret from file: %v"
,
err
)
}
return
secretBytes
,
nil
}
internal/upload/accelerate.go
View file @
9e79e5ba
package
upload
import
(
"context"
"fmt"
"mime/multipart"
"net/http"
jwt
"github.com/dgrijalva/jwt-go"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/secret"
)
const
RewrittenFieldsHeader
=
"Gitlab-Workhorse-Multipart-Fields"
type
savedFileTracker
struct
{
request
*
http
.
Request
rewrittenFields
map
[
string
]
string
}
type
MultipartClaims
struct
{
RewrittenFields
map
[
string
]
string
`json:"rewritten_fields"`
jwt
.
StandardClaims
...
...
@@ -27,38 +18,7 @@ type MultipartClaims struct {
func
Accelerate
(
rails
filestore
.
PreAuthorizer
,
h
http
.
Handler
)
http
.
Handler
{
return
rails
.
PreAuthorizeHandler
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
{
s
:=
&
savedFileTracker
{
r
equest
:
r
}
s
:=
&
SavedFileTracker
{
R
equest
:
r
}
HandleFileUploads
(
w
,
r
,
h
,
a
,
s
)
},
"/authorize"
)
}
func
(
s
*
savedFileTracker
)
ProcessFile
(
_
context
.
Context
,
fieldName
string
,
file
*
filestore
.
FileHandler
,
_
*
multipart
.
Writer
)
error
{
if
s
.
rewrittenFields
==
nil
{
s
.
rewrittenFields
=
make
(
map
[
string
]
string
)
}
s
.
rewrittenFields
[
fieldName
]
=
file
.
LocalPath
return
nil
}
func
(
s
*
savedFileTracker
)
ProcessField
(
_
context
.
Context
,
_
string
,
_
*
multipart
.
Writer
)
error
{
return
nil
}
func
(
s
*
savedFileTracker
)
Finalize
(
_
context
.
Context
)
error
{
if
s
.
rewrittenFields
==
nil
{
return
nil
}
claims
:=
MultipartClaims
{
s
.
rewrittenFields
,
secret
.
DefaultClaims
}
tokenString
,
err
:=
secret
.
JWTTokenString
(
claims
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"savedFileTracker.Finalize: %v"
,
err
)
}
s
.
request
.
Header
.
Set
(
RewrittenFieldsHeader
,
tokenString
)
return
nil
}
func
(
a
*
savedFileTracker
)
Name
()
string
{
return
"accelerate"
}
internal/upload/saved_file_tracker.go
0 → 100644
View file @
9e79e5ba
package
upload
import
(
"context"
"fmt"
"mime/multipart"
"net/http"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/secret"
)
type
SavedFileTracker
struct
{
Request
*
http
.
Request
rewrittenFields
map
[
string
]
string
}
func
(
s
*
SavedFileTracker
)
Track
(
fieldName
string
,
localPath
string
)
{
if
s
.
rewrittenFields
==
nil
{
s
.
rewrittenFields
=
make
(
map
[
string
]
string
)
}
s
.
rewrittenFields
[
fieldName
]
=
localPath
}
func
(
s
*
SavedFileTracker
)
Count
()
int
{
return
len
(
s
.
rewrittenFields
)
}
func
(
s
*
SavedFileTracker
)
ProcessFile
(
_
context
.
Context
,
fieldName
string
,
file
*
filestore
.
FileHandler
,
_
*
multipart
.
Writer
)
error
{
s
.
Track
(
fieldName
,
file
.
LocalPath
)
return
nil
}
func
(
s
*
SavedFileTracker
)
ProcessField
(
_
context
.
Context
,
_
string
,
_
*
multipart
.
Writer
)
error
{
return
nil
}
func
(
s
*
SavedFileTracker
)
Finalize
(
_
context
.
Context
)
error
{
if
s
.
rewrittenFields
==
nil
{
return
nil
}
claims
:=
MultipartClaims
{
RewrittenFields
:
s
.
rewrittenFields
,
StandardClaims
:
secret
.
DefaultClaims
}
tokenString
,
err
:=
secret
.
JWTTokenString
(
claims
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"savedFileTracker.Finalize: %v"
,
err
)
}
s
.
Request
.
Header
.
Set
(
RewrittenFieldsHeader
,
tokenString
)
return
nil
}
func
(
s
*
SavedFileTracker
)
Name
()
string
{
return
"accelerate"
}
internal/upload/saved_file_tracker_test.go
0 → 100644
View file @
9e79e5ba
package
upload
import
(
"context"
jwt
"github.com/dgrijalva/jwt-go"
"net/http"
"testing"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func
TestSavedFileTracking
(
t
*
testing
.
T
)
{
testhelper
.
ConfigureSecret
()
r
,
err
:=
http
.
NewRequest
(
"PUT"
,
"/url/path"
,
nil
)
require
.
NoError
(
t
,
err
)
tracker
:=
SavedFileTracker
{
Request
:
r
}
require
.
Equal
(
t
,
"accelerate"
,
tracker
.
Name
())
file
:=
&
filestore
.
FileHandler
{}
ctx
:=
context
.
Background
()
tracker
.
ProcessFile
(
ctx
,
"test"
,
file
,
nil
)
require
.
Equal
(
t
,
1
,
tracker
.
Count
())
tracker
.
Finalize
(
ctx
)
jwtToken
,
err
:=
jwt
.
Parse
(
r
.
Header
.
Get
(
RewrittenFieldsHeader
),
testhelper
.
ParseJWT
)
require
.
NoError
(
t
,
err
)
rewrittenFields
:=
jwtToken
.
Claims
.
(
jwt
.
MapClaims
)[
"rewritten_fields"
]
.
(
map
[
string
]
interface
{})
require
.
Equal
(
t
,
1
,
len
(
rewrittenFields
))
require
.
Contains
(
t
,
rewrittenFields
,
"test"
)
}
internal/upload/uploads_test.go
View file @
9e79e5ba
...
...
@@ -390,7 +390,7 @@ func TestInvalidFileNames(t *testing.T) {
httpRequest
.
Header
.
Set
(
"Content-Type"
,
writer
.
FormDataContentType
())
response
:=
httptest
.
NewRecorder
()
HandleFileUploads
(
response
,
httpRequest
,
nilHandler
,
&
api
.
Response
{
TempPath
:
tempPath
},
&
savedFileTracker
{
r
equest
:
httpRequest
})
HandleFileUploads
(
response
,
httpRequest
,
nilHandler
,
&
api
.
Response
{
TempPath
:
tempPath
},
&
SavedFileTracker
{
R
equest
:
httpRequest
})
testhelper
.
AssertResponseCode
(
t
,
response
,
testCase
.
code
)
}
}
...
...
upload_test.go
View file @
9e79e5ba
...
...
@@ -63,7 +63,7 @@ func TestArtifactsUpload(t *testing.T) {
func
expectSignedRequest
(
t
*
testing
.
T
,
r
*
http
.
Request
)
{
t
.
Helper
()
_
,
err
:=
jwt
.
Parse
(
r
.
Header
.
Get
(
secret
.
RequestHeader
),
p
arseJWT
)
_
,
err
:=
jwt
.
Parse
(
r
.
Header
.
Get
(
secret
.
RequestHeader
),
testhelper
.
P
arseJWT
)
require
.
NoError
(
t
,
err
)
}
...
...
@@ -109,21 +109,6 @@ func signedUploadTestServer(t *testing.T, extraTests func(r *http.Request)) *htt
})
}
func
parseJWT
(
token
*
jwt
.
Token
)
(
interface
{},
error
)
{
// Don't forget to validate the alg is what you expect:
if
_
,
ok
:=
token
.
Method
.
(
*
jwt
.
SigningMethodHMAC
);
!
ok
{
return
nil
,
fmt
.
Errorf
(
"Unexpected signing method: %v"
,
token
.
Header
[
"alg"
])
}
testhelper
.
ConfigureSecret
()
secretBytes
,
err
:=
secret
.
Bytes
()
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"read secret from file: %v"
,
err
)
}
return
secretBytes
,
nil
}
func
TestAcceleratedUpload
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
method
string
...
...
@@ -150,7 +135,7 @@ func TestAcceleratedUpload(t *testing.T) {
expectSignedRequest
(
t
,
r
)
}
jwtToken
,
err
:=
jwt
.
Parse
(
r
.
Header
.
Get
(
upload
.
RewrittenFieldsHeader
),
p
arseJWT
)
jwtToken
,
err
:=
jwt
.
Parse
(
r
.
Header
.
Get
(
upload
.
RewrittenFieldsHeader
),
testhelper
.
P
arseJWT
)
require
.
NoError
(
t
,
err
)
rewrittenFields
:=
jwtToken
.
Claims
.
(
jwt
.
MapClaims
)[
"rewritten_fields"
]
.
(
map
[
string
]
interface
{})
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment