mirror of https://github.com/go-gitea/gitea.git
Fix http auth header parsing (#34936)
Using `strings.EqualFold` is wrong in many cases.pull/34922/head^2
parent
8cbec63cc7
commit
d6d643fe86
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package httpauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BasicAuth struct {
|
||||||
|
Username, Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BearerToken struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParsedAuthorizationHeader struct {
|
||||||
|
BasicAuth *BasicAuth
|
||||||
|
BearerToken *BearerToken
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseAuthorizationHeader(header string) (ret ParsedAuthorizationHeader, _ bool) {
|
||||||
|
parts := strings.Fields(header)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return ret, false
|
||||||
|
}
|
||||||
|
if util.AsciiEqualFold(parts[0], "basic") {
|
||||||
|
s, err := base64.StdEncoding.DecodeString(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return ret, false
|
||||||
|
}
|
||||||
|
u, p, ok := strings.Cut(string(s), ":")
|
||||||
|
if !ok {
|
||||||
|
return ret, false
|
||||||
|
}
|
||||||
|
ret.BasicAuth = &BasicAuth{Username: u, Password: p}
|
||||||
|
return ret, true
|
||||||
|
} else if util.AsciiEqualFold(parts[0], "token") || util.AsciiEqualFold(parts[0], "bearer") {
|
||||||
|
ret.BearerToken = &BearerToken{Token: parts[1]}
|
||||||
|
return ret, true
|
||||||
|
}
|
||||||
|
return ret, false
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package httpauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseAuthorizationHeader(t *testing.T) {
|
||||||
|
type parsed = ParsedAuthorizationHeader
|
||||||
|
type basic = BasicAuth
|
||||||
|
type bearer = BearerToken
|
||||||
|
cases := []struct {
|
||||||
|
headerValue string
|
||||||
|
expected parsed
|
||||||
|
ok bool
|
||||||
|
}{
|
||||||
|
{"", parsed{}, false},
|
||||||
|
{"?", parsed{}, false},
|
||||||
|
{"foo", parsed{}, false},
|
||||||
|
{"any value", parsed{}, false},
|
||||||
|
|
||||||
|
{"Basic ?", parsed{}, false},
|
||||||
|
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo")), parsed{}, false},
|
||||||
|
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), parsed{BasicAuth: &basic{"foo", "bar"}}, true},
|
||||||
|
{"basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), parsed{BasicAuth: &basic{"foo", "bar"}}, true},
|
||||||
|
|
||||||
|
{"token value", parsed{BearerToken: &bearer{"value"}}, true},
|
||||||
|
{"Token value", parsed{BearerToken: &bearer{"value"}}, true},
|
||||||
|
{"bearer value", parsed{BearerToken: &bearer{"value"}}, true},
|
||||||
|
{"Bearer value", parsed{BearerToken: &bearer{"value"}}, true},
|
||||||
|
{"Bearer wrong value", parsed{}, false},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
ret, ok := ParseAuthorizationHeader(c.headerValue)
|
||||||
|
assert.Equal(t, c.ok, ok, "header %q", c.headerValue)
|
||||||
|
assert.Equal(t, c.expected, ret, "header %q", c.headerValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue