mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-13 11:05:46 +02:00
Refactor Nuget Auth to reuse Basic Auth Token Validation (#36558)
* Implicitly handle Actions Task Token for Nuget Api Keys * Support same tokens as Basic Auth in Nuget Api Key Header --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
daf0483ef2
commit
f65df2a69b
@ -6,43 +6,21 @@ package nuget
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
|
||||||
"code.gitea.io/gitea/services/auth"
|
"code.gitea.io/gitea/services/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ auth.Method = &Auth{}
|
var _ auth.Method = &Auth{}
|
||||||
|
|
||||||
type Auth struct{}
|
type Auth struct {
|
||||||
|
basicAuth auth.Basic
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Auth) Name() string {
|
func (a *Auth) Name() string {
|
||||||
return "nuget"
|
return "nuget"
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/nuget/api/package-publish-resource#request-parameters
|
|
||||||
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) {
|
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) {
|
||||||
token, err := auth_model.GetAccessTokenBySHA(req.Context(), req.Header.Get("X-NuGet-ApiKey"))
|
// ref: https://docs.microsoft.com/en-us/nuget/api/package-publish-resource#request-parameters
|
||||||
if err != nil {
|
return a.basicAuth.VerifyAuthToken(req, w, store, sess, req.Header.Get("X-NuGet-ApiKey"))
|
||||||
if !(auth_model.IsErrAccessTokenNotExist(err) || auth_model.IsErrAccessTokenEmpty(err)) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := user_model.GetUserByID(req.Context(), token.UID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
token.UpdatedUnix = timeutil.TimeStampNow()
|
|
||||||
if err := auth_model.UpdateAccessToken(req.Context(), token); err != nil {
|
|
||||||
log.Error("UpdateAccessToken: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store.GetData()["IsApiToken"] = true
|
|
||||||
store.GetData()["ApiToken"] = token
|
|
||||||
|
|
||||||
return u, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,25 +40,21 @@ func (b *Basic) Name() string {
|
|||||||
return BasicMethodName
|
return BasicMethodName
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify extracts and validates Basic data (username and password/token) from the
|
func (b *Basic) parseAuthBasic(req *http.Request) (ret struct{ authToken, uname, passwd string }) {
|
||||||
// "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 *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
|
|
||||||
// Basic authentication should only fire on API, Feed, Download, Archives or on Git or LFSPaths
|
// Basic authentication should only fire on API, Feed, Download, Archives or on Git or LFSPaths
|
||||||
// Not all feed (rss/atom) clients feature the ability to add cookies or headers, so we need to allow basic auth for feeds
|
// Not all feed (rss/atom) clients feature the ability to add cookies or headers, so we need to allow basic auth for feeds
|
||||||
detector := newAuthPathDetector(req)
|
detector := newAuthPathDetector(req)
|
||||||
if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isArchivePath() && !detector.isGitRawOrAttachOrLFSPath() {
|
if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isArchivePath() && !detector.isGitRawOrAttachOrLFSPath() {
|
||||||
return nil, nil
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
authHeader := req.Header.Get("Authorization")
|
authHeader := req.Header.Get("Authorization")
|
||||||
if authHeader == "" {
|
if authHeader == "" {
|
||||||
return nil, nil
|
return ret
|
||||||
}
|
}
|
||||||
parsed, ok := httpauth.ParseAuthorizationHeader(authHeader)
|
parsed, ok := httpauth.ParseAuthorizationHeader(authHeader)
|
||||||
if !ok || parsed.BasicAuth == nil {
|
if !ok || parsed.BasicAuth == nil {
|
||||||
return nil, nil
|
return ret
|
||||||
}
|
}
|
||||||
uname, passwd := parsed.BasicAuth.Username, parsed.BasicAuth.Password
|
uname, passwd := parsed.BasicAuth.Username, parsed.BasicAuth.Password
|
||||||
|
|
||||||
@ -73,7 +69,12 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
|
|||||||
} else {
|
} else {
|
||||||
log.Trace("Basic Authorization: Attempting login with username as token")
|
log.Trace("Basic Authorization: Attempting login with username as token")
|
||||||
}
|
}
|
||||||
|
ret.authToken, ret.uname, ret.passwd = authToken, uname, passwd
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyAuthToken only the access token provided as parameter, used by other auth methods that want to reuse access token verification logic
|
||||||
|
func (b *Basic) VerifyAuthToken(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore, authToken string) (*user_model.User, error) {
|
||||||
// get oauth2 token's user's ID
|
// get oauth2 token's user's ID
|
||||||
_, uid := GetOAuthAccessTokenScopeAndUserID(req.Context(), authToken)
|
_, uid := GetOAuthAccessTokenScopeAndUserID(req.Context(), authToken)
|
||||||
if uid != 0 {
|
if uid != 0 {
|
||||||
@ -120,6 +121,23 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
|
|||||||
store.GetData()["LoginMethod"] = ActionTokenMethodName
|
store.GetData()["LoginMethod"] = ActionTokenMethodName
|
||||||
return user_model.NewActionsUserWithTaskID(task.ID), nil
|
return user_model.NewActionsUserWithTaskID(task.ID), nil
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
|
||||||
|
parseBasicRet := b.parseAuthBasic(req)
|
||||||
|
authToken, uname, passwd := parseBasicRet.authToken, parseBasicRet.uname, parseBasicRet.passwd
|
||||||
|
if authToken == "" && uname == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
u, err := b.VerifyAuthToken(req, w, store, sess, authToken)
|
||||||
|
if u != nil || err != nil {
|
||||||
|
return u, err
|
||||||
|
}
|
||||||
|
|
||||||
if !setting.Service.EnableBasicAuth {
|
if !setting.Service.EnableBasicAuth {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user