mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-04 22:57:34 -04:00
fix parser
This commit is contained in:
parent
b38e25b96b
commit
aefac78df7
@ -10,31 +10,38 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
func ParseAuthorizationHeaderBasic(header string) (string, string, bool) {
|
||||
parts := strings.Fields(header)
|
||||
if len(parts) != 2 {
|
||||
return "", "", false
|
||||
}
|
||||
if !util.AsciiEqualFold(parts[0], "basic") {
|
||||
return "", "", false
|
||||
}
|
||||
s, err := base64.StdEncoding.DecodeString(parts[1])
|
||||
if err != nil {
|
||||
return "", "", false
|
||||
}
|
||||
if u, p, ok := strings.Cut(string(s), ":"); ok {
|
||||
return u, p, true
|
||||
}
|
||||
return "", "", false
|
||||
type BasicAuth struct {
|
||||
Username, Password string
|
||||
}
|
||||
|
||||
func ParseAuthorizationHeaderBearerToken(header string) (string, bool) {
|
||||
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 "", false
|
||||
return ret, false
|
||||
}
|
||||
if util.AsciiEqualFold(parts[0], "token") || util.AsciiEqualFold(parts[0], "bearer") {
|
||||
return parts[1], true
|
||||
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 "", false
|
||||
return ret, false
|
||||
}
|
||||
|
@ -11,46 +11,33 @@ import (
|
||||
)
|
||||
|
||||
func TestParseAuthorizationHeader(t *testing.T) {
|
||||
t.Run("Basic", func(t *testing.T) {
|
||||
cases := []struct {
|
||||
headerValue string
|
||||
user, pass string
|
||||
ok bool
|
||||
}{
|
||||
{"", "", "", false},
|
||||
{"?", "", "", false},
|
||||
{"foo", "", "", false},
|
||||
{"Basic ?", "", "", false},
|
||||
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo")), "", "", false},
|
||||
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), "foo", "bar", true},
|
||||
{"basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), "foo", "bar", true},
|
||||
}
|
||||
for _, c := range cases {
|
||||
user, pass, ok := ParseAuthorizationHeaderBasic(c.headerValue)
|
||||
assert.Equal(t, c.ok, ok, "header %q", c.headerValue)
|
||||
assert.Equal(t, c.user, user, "header %q", c.headerValue)
|
||||
assert.Equal(t, c.pass, pass, "header %q", c.headerValue)
|
||||
}
|
||||
})
|
||||
t.Run("BearerToken", func(t *testing.T) {
|
||||
cases := []struct {
|
||||
headerValue string
|
||||
expected string
|
||||
ok bool
|
||||
}{
|
||||
{"", "", false},
|
||||
{"?", "", false},
|
||||
{"any value", "", false},
|
||||
{"token value", "value", true},
|
||||
{"Token value", "value", true},
|
||||
{"bearer value", "value", true},
|
||||
{"Bearer value", "value", true},
|
||||
{"Bearer wrong value", "", false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
token, ok := ParseAuthorizationHeaderBearerToken(c.headerValue)
|
||||
assert.Equal(t, c.ok, ok, "header %q", c.headerValue)
|
||||
assert.Equal(t, c.expected, token, "header %q", c.headerValue)
|
||||
}
|
||||
})
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ func InfoOAuth(ctx *context.Context) {
|
||||
|
||||
var accessTokenScope auth.AccessTokenScope
|
||||
if auHead := ctx.Req.Header.Get("Authorization"); auHead != "" {
|
||||
if headerAuthToken, ok := httpauth.ParseAuthorizationHeaderBearerToken(auHead); ok {
|
||||
accessTokenScope, _ = auth_service.GetOAuthAccessTokenScopeAndUserID(ctx, headerAuthToken)
|
||||
if parsed, ok := httpauth.ParseAuthorizationHeader(auHead); ok && parsed.BearerToken != nil {
|
||||
accessTokenScope, _ = auth_service.GetOAuthAccessTokenScopeAndUserID(ctx, parsed.BearerToken.Token)
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +128,8 @@ func InfoOAuth(ctx *context.Context) {
|
||||
func IntrospectOAuth(ctx *context.Context) {
|
||||
clientIDValid := false
|
||||
authHeader := ctx.Req.Header.Get("Authorization")
|
||||
if clientID, clientSecret, ok := httpauth.ParseAuthorizationHeaderBasic(authHeader); ok {
|
||||
if parsed, ok := httpauth.ParseAuthorizationHeader(authHeader); ok && parsed.BasicAuth != nil {
|
||||
clientID, clientSecret := parsed.BasicAuth.Username, parsed.BasicAuth.Password
|
||||
app, err := auth.GetOAuth2ApplicationByClientID(ctx, clientID)
|
||||
if err != nil && !auth.IsErrOauthClientIDInvalid(err) {
|
||||
// this is likely a database error; log it and respond without details
|
||||
@ -456,14 +457,15 @@ func AccessTokenOAuth(ctx *context.Context) {
|
||||
// if there is no ClientID or ClientSecret in the request body, fill these fields by the Authorization header and ensure the provided field matches the Authorization header
|
||||
if form.ClientID == "" || form.ClientSecret == "" {
|
||||
if authHeader := ctx.Req.Header.Get("Authorization"); authHeader != "" {
|
||||
clientID, clientSecret, ok := httpauth.ParseAuthorizationHeaderBasic(authHeader)
|
||||
if !ok {
|
||||
parsed, ok := httpauth.ParseAuthorizationHeader(authHeader)
|
||||
if !ok || parsed.BasicAuth == nil {
|
||||
handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
|
||||
ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidRequest,
|
||||
ErrorDescription: "cannot parse basic auth header",
|
||||
})
|
||||
return
|
||||
}
|
||||
clientID, clientSecret := parsed.BasicAuth.Username, parsed.BasicAuth.Password
|
||||
// validate that any fields present in the form match the Basic auth header
|
||||
if form.ClientID != "" && form.ClientID != clientID {
|
||||
handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
|
||||
|
@ -57,7 +57,11 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
|
||||
if authHeader == "" {
|
||||
return nil, nil
|
||||
}
|
||||
uname, passwd, _ := httpauth.ParseAuthorizationHeaderBasic(authHeader)
|
||||
parsed, ok := httpauth.ParseAuthorizationHeader(authHeader)
|
||||
if !ok || parsed.BasicAuth == nil {
|
||||
return nil, nil
|
||||
}
|
||||
uname, passwd := parsed.BasicAuth.Username, parsed.BasicAuth.Password
|
||||
|
||||
// Check if username or password is a token
|
||||
isUsernameToken := len(passwd) == 0 || passwd == "x-oauth-basic"
|
||||
|
@ -98,7 +98,10 @@ func parseToken(req *http.Request) (string, bool) {
|
||||
|
||||
// check header token
|
||||
if auHead := req.Header.Get("Authorization"); auHead != "" {
|
||||
return httpauth.ParseAuthorizationHeaderBearerToken(auHead)
|
||||
parsed, ok := httpauth.ParseAuthorizationHeader(auHead)
|
||||
if ok && parsed.BearerToken != nil {
|
||||
return parsed.BearerToken.Token, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
@ -595,11 +595,11 @@ func parseToken(ctx stdCtx.Context, authorization string, target *repo_model.Rep
|
||||
if authorization == "" {
|
||||
return nil, errors.New("no token")
|
||||
}
|
||||
token, ok := httpauth.ParseAuthorizationHeaderBearerToken(authorization)
|
||||
if !ok {
|
||||
parsed, ok := httpauth.ParseAuthorizationHeader(authorization)
|
||||
if !ok || parsed.BearerToken == nil {
|
||||
return nil, errors.New("token not found")
|
||||
}
|
||||
return handleLFSToken(ctx, token, target, mode)
|
||||
return handleLFSToken(ctx, parsed.BearerToken.Token, target, mode)
|
||||
}
|
||||
|
||||
func requireAuth(ctx *context.Context) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user