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