mirror of https://github.com/go-gitea/gitea
parent
5ac876a728
commit
a584ba7ed2
@ -0,0 +1,113 @@ |
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package auth |
||||
|
||||
import ( |
||||
"net/http" |
||||
"strings" |
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth" |
||||
user_model "code.gitea.io/gitea/models/user" |
||||
"code.gitea.io/gitea/modules/base" |
||||
"code.gitea.io/gitea/modules/log" |
||||
"code.gitea.io/gitea/modules/timeutil" |
||||
"code.gitea.io/gitea/modules/web/middleware" |
||||
) |
||||
|
||||
// Ensure the struct implements the interface.
|
||||
var ( |
||||
_ Method = &AccessToken{} |
||||
) |
||||
|
||||
// BasicMethodName is the constant name of the basic authentication method
|
||||
const ( |
||||
AccessTokenMethodName = "access_token" |
||||
) |
||||
|
||||
// AccessToken implements the Auth interface and authenticates requests (API requests
|
||||
// only) by looking for access token
|
||||
type AccessToken struct{} |
||||
|
||||
// Name represents the name of auth method
|
||||
func (b *AccessToken) Name() string { |
||||
return AccessTokenMethodName |
||||
} |
||||
|
||||
// Match returns true if the request matched AccessToken requirements
|
||||
// TODO: remove path check once AccessToken will not be a global middleware but only
|
||||
// for specific routes
|
||||
func (b *AccessToken) Match(req *http.Request) bool { |
||||
if !middleware.IsAPIPath(req) && !isContainerPath(req) && !isAttachmentDownload(req) && !isGitRawOrAttachOrLFSPath(req) { |
||||
return false |
||||
} |
||||
baHead := req.Header.Get("Authorization") |
||||
if baHead == "" { |
||||
return false |
||||
} |
||||
auths := strings.SplitN(baHead, " ", 2) |
||||
if len(auths) != 2 || (strings.ToLower(auths[0]) != "basic") { |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
// Verify extracts and validates Basic data (username and password/token) from the
|
||||
// "Authorization" header of the request and returns the corresponding user object for that
|
||||
// name/token on successful validation.
|
||||
// Returns nil if header is empty or validation fails.
|
||||
func (b *AccessToken) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { |
||||
// Basic authentication should only fire on API, Download or on Git or LFSPaths
|
||||
if !middleware.IsAPIPath(req) && !isContainerPath(req) && !isAttachmentDownload(req) && !isGitRawOrAttachOrLFSPath(req) { |
||||
return nil, nil |
||||
} |
||||
|
||||
baHead := req.Header.Get("Authorization") |
||||
if len(baHead) == 0 { |
||||
return nil, nil |
||||
} |
||||
|
||||
auths := strings.SplitN(baHead, " ", 2) |
||||
if len(auths) != 2 || (strings.ToLower(auths[0]) != "basic") { |
||||
return nil, nil |
||||
} |
||||
|
||||
uname, passwd, _ := base.BasicAuthDecode(auths[1]) |
||||
|
||||
// Check if username or password is a token
|
||||
isUsernameToken := len(passwd) == 0 || passwd == "x-oauth-basic" |
||||
// Assume username is token
|
||||
authToken := uname |
||||
if !isUsernameToken { |
||||
log.Trace("Basic Authorization: Attempting login for: %s", uname) |
||||
// Assume password is token
|
||||
authToken = passwd |
||||
} else { |
||||
log.Trace("Basic Authorization: Attempting login with username as token") |
||||
} |
||||
|
||||
// check personal access token
|
||||
token, err := auth_model.GetAccessTokenBySHA(req.Context(), authToken) |
||||
if err == nil { |
||||
log.Trace("Basic Authorization: Valid AccessToken for user[%d]", token.UID) |
||||
u, err := user_model.GetUserByID(req.Context(), token.UID) |
||||
if err != nil { |
||||
log.Error("GetUserByID: %v", err) |
||||
return nil, err |
||||
} |
||||
|
||||
token.UpdatedUnix = timeutil.TimeStampNow() |
||||
if err = auth_model.UpdateAccessToken(req.Context(), token); err != nil { |
||||
log.Error("UpdateAccessToken: %v", err) |
||||
} |
||||
|
||||
store.GetData()["LoginMethod"] = AccessTokenMethodName |
||||
store.GetData()["IsApiToken"] = true |
||||
store.GetData()["ApiTokenScope"] = token.Scope |
||||
return u, nil |
||||
} else if !auth_model.IsErrAccessTokenNotExist(err) && !auth_model.IsErrAccessTokenEmpty(err) { |
||||
log.Error("GetAccessTokenBySha: %v", err) |
||||
} |
||||
|
||||
return nil, nil |
||||
} |
Loading…
Reference in new issue