Skip to content

Commit aefac78

Browse files
committed
fix parser
1 parent b38e25b commit aefac78

File tree

6 files changed

+76
-73
lines changed

6 files changed

+76
-73
lines changed

modules/auth/httpauth/httpauth.go

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,38 @@ import (
1010
"code.gitea.io/gitea/modules/util"
1111
)
1212

13-
func ParseAuthorizationHeaderBasic(header string) (string, string, bool) {
14-
parts := strings.Fields(header)
15-
if len(parts) != 2 {
16-
return "", "", false
17-
}
18-
if !util.AsciiEqualFold(parts[0], "basic") {
19-
return "", "", false
20-
}
21-
s, err := base64.StdEncoding.DecodeString(parts[1])
22-
if err != nil {
23-
return "", "", false
24-
}
25-
if u, p, ok := strings.Cut(string(s), ":"); ok {
26-
return u, p, true
27-
}
28-
return "", "", false
13+
type BasicAuth struct {
14+
Username, Password string
15+
}
16+
17+
type BearerToken struct {
18+
Token string
19+
}
20+
21+
type ParsedAuthorizationHeader struct {
22+
BasicAuth *BasicAuth
23+
BearerToken *BearerToken
2924
}
3025

31-
func ParseAuthorizationHeaderBearerToken(header string) (string, bool) {
26+
func ParseAuthorizationHeader(header string) (ret ParsedAuthorizationHeader, _ bool) {
3227
parts := strings.Fields(header)
3328
if len(parts) != 2 {
34-
return "", false
29+
return ret, false
3530
}
36-
if util.AsciiEqualFold(parts[0], "token") || util.AsciiEqualFold(parts[0], "bearer") {
37-
return parts[1], true
31+
if util.AsciiEqualFold(parts[0], "basic") {
32+
s, err := base64.StdEncoding.DecodeString(parts[1])
33+
if err != nil {
34+
return ret, false
35+
}
36+
u, p, ok := strings.Cut(string(s), ":")
37+
if !ok {
38+
return ret, false
39+
}
40+
ret.BasicAuth = &BasicAuth{Username: u, Password: p}
41+
return ret, true
42+
} else if util.AsciiEqualFold(parts[0], "token") || util.AsciiEqualFold(parts[0], "bearer") {
43+
ret.BearerToken = &BearerToken{Token: parts[1]}
44+
return ret, true
3845
}
39-
return "", false
46+
return ret, false
4047
}

modules/auth/httpauth/httpauth_test.go

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,33 @@ import (
1111
)
1212

1313
func TestParseAuthorizationHeader(t *testing.T) {
14-
t.Run("Basic", func(t *testing.T) {
15-
cases := []struct {
16-
headerValue string
17-
user, pass string
18-
ok bool
19-
}{
20-
{"", "", "", false},
21-
{"?", "", "", false},
22-
{"foo", "", "", false},
23-
{"Basic ?", "", "", false},
24-
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo")), "", "", false},
25-
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), "foo", "bar", true},
26-
{"basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), "foo", "bar", true},
27-
}
28-
for _, c := range cases {
29-
user, pass, ok := ParseAuthorizationHeaderBasic(c.headerValue)
30-
assert.Equal(t, c.ok, ok, "header %q", c.headerValue)
31-
assert.Equal(t, c.user, user, "header %q", c.headerValue)
32-
assert.Equal(t, c.pass, pass, "header %q", c.headerValue)
33-
}
34-
})
35-
t.Run("BearerToken", func(t *testing.T) {
36-
cases := []struct {
37-
headerValue string
38-
expected string
39-
ok bool
40-
}{
41-
{"", "", false},
42-
{"?", "", false},
43-
{"any value", "", false},
44-
{"token value", "value", true},
45-
{"Token value", "value", true},
46-
{"bearer value", "value", true},
47-
{"Bearer value", "value", true},
48-
{"Bearer wrong value", "", false},
49-
}
50-
for _, c := range cases {
51-
token, ok := ParseAuthorizationHeaderBearerToken(c.headerValue)
52-
assert.Equal(t, c.ok, ok, "header %q", c.headerValue)
53-
assert.Equal(t, c.expected, token, "header %q", c.headerValue)
54-
}
55-
})
14+
type parsed = ParsedAuthorizationHeader
15+
type basic = BasicAuth
16+
type bearer = BearerToken
17+
cases := []struct {
18+
headerValue string
19+
expected parsed
20+
ok bool
21+
}{
22+
{"", parsed{}, false},
23+
{"?", parsed{}, false},
24+
{"foo", parsed{}, false},
25+
{"any value", parsed{}, false},
26+
27+
{"Basic ?", parsed{}, false},
28+
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo")), parsed{}, false},
29+
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), parsed{BasicAuth: &basic{"foo", "bar"}}, true},
30+
{"basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), parsed{BasicAuth: &basic{"foo", "bar"}}, true},
31+
32+
{"token value", parsed{BearerToken: &bearer{"value"}}, true},
33+
{"Token value", parsed{BearerToken: &bearer{"value"}}, true},
34+
{"bearer value", parsed{BearerToken: &bearer{"value"}}, true},
35+
{"Bearer value", parsed{BearerToken: &bearer{"value"}}, true},
36+
{"Bearer wrong value", parsed{}, false},
37+
}
38+
for _, c := range cases {
39+
ret, ok := ParseAuthorizationHeader(c.headerValue)
40+
assert.Equal(t, c.ok, ok, "header %q", c.headerValue)
41+
assert.Equal(t, c.expected, ret, "header %q", c.headerValue)
42+
}
5643
}

routers/web/auth/oauth2_provider.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ func InfoOAuth(ctx *context.Context) {
106106

107107
var accessTokenScope auth.AccessTokenScope
108108
if auHead := ctx.Req.Header.Get("Authorization"); auHead != "" {
109-
if headerAuthToken, ok := httpauth.ParseAuthorizationHeaderBearerToken(auHead); ok {
110-
accessTokenScope, _ = auth_service.GetOAuthAccessTokenScopeAndUserID(ctx, headerAuthToken)
109+
if parsed, ok := httpauth.ParseAuthorizationHeader(auHead); ok && parsed.BearerToken != nil {
110+
accessTokenScope, _ = auth_service.GetOAuthAccessTokenScopeAndUserID(ctx, parsed.BearerToken.Token)
111111
}
112112
}
113113

@@ -128,7 +128,8 @@ func InfoOAuth(ctx *context.Context) {
128128
func IntrospectOAuth(ctx *context.Context) {
129129
clientIDValid := false
130130
authHeader := ctx.Req.Header.Get("Authorization")
131-
if clientID, clientSecret, ok := httpauth.ParseAuthorizationHeaderBasic(authHeader); ok {
131+
if parsed, ok := httpauth.ParseAuthorizationHeader(authHeader); ok && parsed.BasicAuth != nil {
132+
clientID, clientSecret := parsed.BasicAuth.Username, parsed.BasicAuth.Password
132133
app, err := auth.GetOAuth2ApplicationByClientID(ctx, clientID)
133134
if err != nil && !auth.IsErrOauthClientIDInvalid(err) {
134135
// this is likely a database error; log it and respond without details
@@ -456,14 +457,15 @@ func AccessTokenOAuth(ctx *context.Context) {
456457
// 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
457458
if form.ClientID == "" || form.ClientSecret == "" {
458459
if authHeader := ctx.Req.Header.Get("Authorization"); authHeader != "" {
459-
clientID, clientSecret, ok := httpauth.ParseAuthorizationHeaderBasic(authHeader)
460-
if !ok {
460+
parsed, ok := httpauth.ParseAuthorizationHeader(authHeader)
461+
if !ok || parsed.BasicAuth == nil {
461462
handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
462463
ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidRequest,
463464
ErrorDescription: "cannot parse basic auth header",
464465
})
465466
return
466467
}
468+
clientID, clientSecret := parsed.BasicAuth.Username, parsed.BasicAuth.Password
467469
// validate that any fields present in the form match the Basic auth header
468470
if form.ClientID != "" && form.ClientID != clientID {
469471
handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{

services/auth/basic.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
5757
if authHeader == "" {
5858
return nil, nil
5959
}
60-
uname, passwd, _ := httpauth.ParseAuthorizationHeaderBasic(authHeader)
60+
parsed, ok := httpauth.ParseAuthorizationHeader(authHeader)
61+
if !ok || parsed.BasicAuth == nil {
62+
return nil, nil
63+
}
64+
uname, passwd := parsed.BasicAuth.Username, parsed.BasicAuth.Password
6165

6266
// Check if username or password is a token
6367
isUsernameToken := len(passwd) == 0 || passwd == "x-oauth-basic"

services/auth/oauth2.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ func parseToken(req *http.Request) (string, bool) {
9898

9999
// check header token
100100
if auHead := req.Header.Get("Authorization"); auHead != "" {
101-
return httpauth.ParseAuthorizationHeaderBearerToken(auHead)
101+
parsed, ok := httpauth.ParseAuthorizationHeader(auHead)
102+
if ok && parsed.BearerToken != nil {
103+
return parsed.BearerToken.Token, true
104+
}
102105
}
103106
return "", false
104107
}

services/lfs/server.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -595,11 +595,11 @@ func parseToken(ctx stdCtx.Context, authorization string, target *repo_model.Rep
595595
if authorization == "" {
596596
return nil, errors.New("no token")
597597
}
598-
token, ok := httpauth.ParseAuthorizationHeaderBearerToken(authorization)
599-
if !ok {
598+
parsed, ok := httpauth.ParseAuthorizationHeader(authorization)
599+
if !ok || parsed.BearerToken == nil {
600600
return nil, errors.New("token not found")
601601
}
602-
return handleLFSToken(ctx, token, target, mode)
602+
return handleLFSToken(ctx, parsed.BearerToken.Token, target, mode)
603603
}
604604

605605
func requireAuth(ctx *context.Context) {

0 commit comments

Comments
 (0)