fixes #72, suppose challege headers that don not quote fields (#73)

This commit is contained in:
Daniel Garcia 2018-03-01 11:50:59 -06:00 committed by Jess Frazelle
parent 5208643fa8
commit 5088b3b142
2 changed files with 83 additions and 18 deletions

View file

@ -5,16 +5,13 @@ import (
"net/http"
"net/url"
"regexp"
"strings"
)
var (
authChallengeRegex = regexp.MustCompile(
`^\s*Bearer\s+realm="([^"]+)",service="([^"]+)"\s*$`)
basicRegex = regexp.MustCompile(`^\s*Basic\s+.*$`)
challengeRegex = regexp.MustCompile(
`^\s*Bearer\s+realm="([^"]+)",service="([^"]+)",scope="([^"]+)"\s*$`)
scopeSeparatorRegex = regexp.MustCompile(`\s+`)
bearerRegex = regexp.MustCompile(
`^\s*Bearer\s+(.*)$`)
basicRegex = regexp.MustCompile(`^\s*Basic\s+.*$`)
)
func parseAuthHeader(header http.Header) (*authService, error) {
@ -31,27 +28,41 @@ func parseChallenge(challengeHeader string) (*authService, error) {
return nil, nil
}
match := challengeRegex.FindAllStringSubmatch(challengeHeader, -1)
match := bearerRegex.FindAllStringSubmatch(challengeHeader, -1)
if d := len(match); d != 1 {
return nil, fmt.Errorf("malformed auth challenge header: '%s', %d", challengeHeader, d)
}
parts := strings.Split(strings.TrimSpace(match[0][1]), ",")
if len(match) != 1 {
match = authChallengeRegex.FindAllStringSubmatch(challengeHeader, -1)
if len(match) != 1 {
var realm, service string
var scope []string
for _, s := range parts {
p := strings.SplitN(s, "=", 2)
if len(p) != 2 {
return nil, fmt.Errorf("malformed auth challenge header: '%s'", challengeHeader)
}
key := p[0]
value := strings.TrimSuffix(strings.TrimPrefix(p[1], `"`), `"`)
switch key {
case "realm":
realm = value
case "service":
service = value
case "scope":
scope = strings.Fields(value)
default:
return nil, fmt.Errorf("unknown field in challege header %s: %v", key, challengeHeader)
}
}
parsedRealm, err := url.Parse(match[0][1])
parsedRealm, err := url.Parse(realm)
if err != nil {
return nil, err
}
a := &authService{
Realm: parsedRealm,
Service: match[0][2],
}
if len(match[0]) >= 4 {
a.Scope = scopeSeparatorRegex.Split(match[0][3], -1)
Service: service,
Scope: scope,
}
return a, nil

View file

@ -0,0 +1,54 @@
package registry
import (
"reflect"
"strings"
"testing"
)
type authServiceMock struct {
service string
realm string
scope []string
}
type challengeTestCase struct {
header string
errorString string
value authServiceMock
}
func (asm authServiceMock) equalTo(v *authService) bool {
if asm.service != v.Service {
return false
}
if reflect.DeepEqual(asm.scope, v.Scope) {
return false
}
if asm.realm != v.Realm.String() {
return false
}
return true
}
func Test_parseChallenge(t *testing.T) {
challengeHeaderCases := []challengeTestCase{
{
header: `Bearer realm="https://foobar.com/api/v1/token",service=foobar.com,scope=""`,
value: authServiceMock{
service: "foobar.com",
realm: "https://foobar.com/api/v1/token",
},
},
}
for _, tc := range challengeHeaderCases {
val, err := parseChallenge(tc.header)
if err != nil && !strings.Contains(err.Error(), tc.errorString) {
t.Fatalf("expected error to contain %v, got %s", tc.errorString, err)
}
if !tc.value.equalTo(val) {
t.Fatalf("got %v, expected %v", val, tc.value)
}
}
}