reg/registry/authchallenge.go
Pat Gavlin 65b2c0329d Use a distinguished error value for basic auth. (#120)
Rather than returning an error that requires pattern-matching from
`parseChallenge` when the challenge header requires basic
authentication, return a distinguished error value. This makes checking
for this error a bit easier.

This commit also updates the check in `r.Headers` to use the new error
value and adds a couple of regression tests.
2018-07-26 14:13:58 -07:00

74 lines
1.6 KiB
Go

package registry
import (
"errors"
"fmt"
"net/http"
"net/url"
"regexp"
"strings"
)
var (
bearerRegex = regexp.MustCompile(
`^\s*Bearer\s+(.*)$`)
basicRegex = regexp.MustCompile(`^\s*Basic\s+.*$`)
// ErrBasicAuth indicates that the repository requires basic rather than token authentication.
ErrBasicAuth = errors.New("basic auth required")
)
func parseAuthHeader(header http.Header) (*authService, error) {
ch, err := parseChallenge(header.Get("www-authenticate"))
if err != nil {
return nil, err
}
return ch, nil
}
func parseChallenge(challengeHeader string) (*authService, error) {
if basicRegex.MatchString(challengeHeader) {
return nil, ErrBasicAuth
}
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.SplitN(strings.TrimSpace(match[0][1]), ",", 3)
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(realm)
if err != nil {
return nil, err
}
a := &authService{
Realm: parsedRealm,
Service: service,
Scope: scope,
}
return a, nil
}