split headers.Authenticate and headers.Authorization (#523)

This commit is contained in:
Alessandro Ros
2024-02-22 13:19:31 +01:00
committed by GitHub
parent c93d5c54d9
commit c10f7aaedb
21 changed files with 369 additions and 424 deletions

View File

@@ -13,14 +13,37 @@ type Authorization struct {
// authentication method
Method AuthMethod
// basic user
//
// Basic authentication fields
//
// user
BasicUser string
// basic password
// password
BasicPass string
// digest values
DigestValues Authenticate
//
// Digest authentication fields
//
// username
Username string
// realm
Realm string
// nonce
Nonce string
// URI
URI string
// response
Response string
// response
Opaque *string
}
// Unmarshal decodes an Authorization header.
@@ -35,12 +58,24 @@ func (h *Authorization) Unmarshal(v base.HeaderValue) error {
v0 := v[0]
switch {
case strings.HasPrefix(v0, "Basic "):
i := strings.IndexByte(v0, ' ')
if i < 0 {
return fmt.Errorf("unable to split between method and keys (%v)", v0)
}
method, v0 := v0[:i], v0[i+1:]
switch method {
case "Basic":
h.Method = AuthBasic
v0 = v0[len("Basic "):]
case "Digest":
h.Method = AuthDigest
default:
return fmt.Errorf("invalid method (%s)", method)
}
if h.Method == AuthBasic {
tmp, err := base64.StdEncoding.DecodeString(v0)
if err != nil {
return fmt.Errorf("invalid value")
@@ -52,20 +87,50 @@ func (h *Authorization) Unmarshal(v base.HeaderValue) error {
}
h.BasicUser, h.BasicPass = tmp2[0], tmp2[1]
case strings.HasPrefix(v0, "Digest "):
h.Method = AuthDigest
var vals Authenticate
err := vals.Unmarshal(base.HeaderValue{v0})
} else { // digest
kvs, err := keyValParse(v0, ',')
if err != nil {
return err
}
h.DigestValues = vals
realmReceived := false
usernameReceived := false
nonceReceived := false
uriReceived := false
responseReceived := false
default:
return fmt.Errorf("invalid authorization header")
for k, rv := range kvs {
v := rv
switch k {
case "realm":
h.Realm = v
realmReceived = true
case "username":
h.Username = v
usernameReceived = true
case "nonce":
h.Nonce = v
nonceReceived = true
case "uri":
h.URI = v
uriReceived = true
case "response":
h.Response = v
responseReceived = true
case "opaque":
h.Opaque = &v
}
}
if !realmReceived || !usernameReceived || !nonceReceived || !uriReceived || !responseReceived {
return fmt.Errorf("one or more digest fields are missing")
}
}
return nil
@@ -73,13 +138,18 @@ func (h *Authorization) Unmarshal(v base.HeaderValue) error {
// Marshal encodes an Authorization header.
func (h Authorization) Marshal() base.HeaderValue {
switch h.Method {
case AuthBasic:
response := base64.StdEncoding.EncodeToString([]byte(h.BasicUser + ":" + h.BasicPass))
return base.HeaderValue{"Basic " + response}
default: // AuthDigest
return h.DigestValues.Marshal()
if h.Method == AuthBasic {
return base.HeaderValue{"Basic " +
base64.StdEncoding.EncodeToString([]byte(h.BasicUser+":"+h.BasicPass))}
}
ret := "Digest " +
"username=\"" + h.Username + "\", realm=\"" + h.Realm + "\", " +
"nonce=\"" + h.Nonce + "\", uri=\"" + h.URI + "\", response=\"" + h.Response + "\""
if h.Opaque != nil {
ret += ", opaque=\"" + *h.Opaque + "\""
}
return base.HeaderValue{ret}
}