diff --git a/routers/api/packages/nuget/auth.go b/routers/api/packages/nuget/auth.go index ce7df0ce0a..8248453e74 100644 --- a/routers/api/packages/nuget/auth.go +++ b/routers/api/packages/nuget/auth.go @@ -6,43 +6,21 @@ package nuget import ( "net/http" - auth_model "code.gitea.io/gitea/models/auth" 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" ) var _ auth.Method = &Auth{} -type Auth struct{} +type Auth struct { + basicAuth auth.Basic +} func (a *Auth) Name() string { 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) { - token, err := auth_model.GetAccessTokenBySHA(req.Context(), req.Header.Get("X-NuGet-ApiKey")) - if err != nil { - 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 + // ref: https://docs.microsoft.com/en-us/nuget/api/package-publish-resource#request-parameters + return a.basicAuth.VerifyAuthToken(req, w, store, sess, req.Header.Get("X-NuGet-ApiKey")) } diff --git a/services/auth/basic.go b/services/auth/basic.go index 51613870c9..de5c7730cc 100644 --- a/services/auth/basic.go +++ b/services/auth/basic.go @@ -40,25 +40,21 @@ func (b *Basic) Name() string { return BasicMethodName } -// 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) { +func (b *Basic) parseAuthBasic(req *http.Request) (ret struct{ authToken, uname, passwd string }) { // 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 detector := newAuthPathDetector(req) if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isArchivePath() && !detector.isGitRawOrAttachOrLFSPath() { - return nil, nil + return ret } authHeader := req.Header.Get("Authorization") if authHeader == "" { - return nil, nil + return ret } parsed, ok := httpauth.ParseAuthorizationHeader(authHeader) if !ok || parsed.BasicAuth == nil { - return nil, nil + return ret } 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 { 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 _, uid := GetOAuthAccessTokenScopeAndUserID(req.Context(), authToken) if uid != 0 { @@ -120,6 +121,23 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore store.GetData()["LoginMethod"] = ActionTokenMethodName 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 { return nil, nil