gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package auth
  5. import (
  6. "errors"
  7. "net/http"
  8. actions_model "code.gitea.io/gitea/models/actions"
  9. auth_model "code.gitea.io/gitea/models/auth"
  10. user_model "code.gitea.io/gitea/models/user"
  11. "code.gitea.io/gitea/modules/auth/httpauth"
  12. "code.gitea.io/gitea/modules/log"
  13. "code.gitea.io/gitea/modules/setting"
  14. "code.gitea.io/gitea/modules/timeutil"
  15. "code.gitea.io/gitea/modules/util"
  16. )
  17. // Ensure the struct implements the interface.
  18. var (
  19. _ Method = &Basic{}
  20. )
  21. // BasicMethodName is the constant name of the basic authentication method
  22. const (
  23. BasicMethodName = "basic"
  24. AccessTokenMethodName = "access_token"
  25. OAuth2TokenMethodName = "oauth2_token"
  26. ActionTokenMethodName = "action_token"
  27. )
  28. // Basic implements the Auth interface and authenticates requests (API requests
  29. // only) by looking for Basic authentication data or "x-oauth-basic" token in the "Authorization"
  30. // header.
  31. type Basic struct{}
  32. // Name represents the name of auth method
  33. func (b *Basic) Name() string {
  34. return BasicMethodName
  35. }
  36. // Verify extracts and validates Basic data (username and password/token) from the
  37. // "Authorization" header of the request and returns the corresponding user object for that
  38. // name/token on successful validation.
  39. // Returns nil if header is empty or validation fails.
  40. func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
  41. // Basic authentication should only fire on API, Feed, Download, Archives or on Git or LFSPaths
  42. // Not all feed (rss/atom) clients feature the ability to add cookies or headers, so we need to allow basic auth for feeds
  43. detector := newAuthPathDetector(req)
  44. if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isArchivePath() && !detector.isGitRawOrAttachOrLFSPath() {
  45. return nil, nil
  46. }
  47. authHeader := req.Header.Get("Authorization")
  48. if authHeader == "" {
  49. return nil, nil
  50. }
  51. parsed, ok := httpauth.ParseAuthorizationHeader(authHeader)
  52. if !ok || parsed.BasicAuth == nil {
  53. return nil, nil
  54. }
  55. uname, passwd := parsed.BasicAuth.Username, parsed.BasicAuth.Password
  56. // Check if username or password is a token
  57. isUsernameToken := len(passwd) == 0 || passwd == "x-oauth-basic"
  58. // Assume username is token
  59. authToken := uname
  60. if !isUsernameToken {
  61. log.Trace("Basic Authorization: Attempting login for: %s", uname)
  62. // Assume password is token
  63. authToken = passwd
  64. } else {
  65. log.Trace("Basic Authorization: Attempting login with username as token")
  66. }
  67. // get oauth2 token's user's ID
  68. _, uid := GetOAuthAccessTokenScopeAndUserID(req.Context(), authToken)
  69. if uid != 0 {
  70. log.Trace("Basic Authorization: Valid OAuthAccessToken for user[%d]", uid)
  71. u, err := user_model.GetUserByID(req.Context(), uid)
  72. if err != nil {
  73. log.Error("GetUserByID: %v", err)
  74. return nil, err
  75. }
  76. store.GetData()["LoginMethod"] = OAuth2TokenMethodName
  77. store.GetData()["IsApiToken"] = true
  78. return u, nil
  79. }
  80. // check personal access token
  81. token, err := auth_model.GetAccessTokenBySHA(req.Context(), authToken)
  82. if err == nil {
  83. log.Trace("Basic Authorization: Valid AccessToken for user[%d]", uid)
  84. u, err := user_model.GetUserByID(req.Context(), token.UID)
  85. if err != nil {
  86. log.Error("GetUserByID: %v", err)
  87. return nil, err
  88. }
  89. token.UpdatedUnix = timeutil.TimeStampNow()
  90. if err = auth_model.UpdateAccessToken(req.Context(), token); err != nil {
  91. log.Error("UpdateAccessToken: %v", err)
  92. }
  93. store.GetData()["LoginMethod"] = AccessTokenMethodName
  94. store.GetData()["IsApiToken"] = true
  95. store.GetData()["ApiTokenScope"] = token.Scope
  96. return u, nil
  97. } else if !auth_model.IsErrAccessTokenNotExist(err) && !auth_model.IsErrAccessTokenEmpty(err) {
  98. log.Error("GetAccessTokenBySha: %v", err)
  99. }
  100. // check task token
  101. task, err := actions_model.GetRunningTaskByToken(req.Context(), authToken)
  102. if err == nil && task != nil {
  103. log.Trace("Basic Authorization: Valid AccessToken for task[%d]", task.ID)
  104. store.GetData()["LoginMethod"] = ActionTokenMethodName
  105. store.GetData()["IsActionsToken"] = true
  106. store.GetData()["ActionsTaskID"] = task.ID
  107. return user_model.NewActionsUser(), nil
  108. }
  109. if !setting.Service.EnableBasicAuth {
  110. return nil, nil
  111. }
  112. log.Trace("Basic Authorization: Attempting SignIn for %s", uname)
  113. u, source, err := UserSignIn(req.Context(), uname, passwd)
  114. if err != nil {
  115. if !user_model.IsErrUserNotExist(err) {
  116. log.Error("UserSignIn: %v", err)
  117. }
  118. return nil, err
  119. }
  120. if !source.TwoFactorShouldSkip() {
  121. // Check if the user has WebAuthn registration
  122. hasWebAuthn, err := auth_model.HasWebAuthnRegistrationsByUID(req.Context(), u.ID)
  123. if err != nil {
  124. return nil, err
  125. }
  126. if hasWebAuthn {
  127. return nil, errors.New("basic authorization is not allowed while WebAuthn enrolled")
  128. }
  129. if err := validateTOTP(req, u); err != nil {
  130. return nil, err
  131. }
  132. }
  133. store.GetData()["LoginMethod"] = BasicMethodName
  134. log.Trace("Basic Authorization: Logged in user %-v", u)
  135. return u, nil
  136. }
  137. func validateTOTP(req *http.Request, u *user_model.User) error {
  138. twofa, err := auth_model.GetTwoFactorByUID(req.Context(), u.ID)
  139. if err != nil {
  140. if auth_model.IsErrTwoFactorNotEnrolled(err) {
  141. // No 2FA enrollment for this user
  142. return nil
  143. }
  144. return err
  145. }
  146. if ok, err := twofa.ValidateTOTP(req.Header.Get("X-Gitea-OTP")); err != nil {
  147. return err
  148. } else if !ok {
  149. return util.NewInvalidArgumentErrorf("invalid provided OTP")
  150. }
  151. return nil
  152. }
  153. func GetAccessScope(store DataStore) auth_model.AccessTokenScope {
  154. if v, ok := store.GetData()["ApiTokenScope"]; ok {
  155. return v.(auth_model.AccessTokenScope)
  156. }
  157. switch store.GetData()["LoginMethod"] {
  158. case OAuth2TokenMethodName:
  159. fallthrough
  160. case BasicMethodName, AccessTokenMethodName:
  161. return auth_model.AccessTokenScopeAll
  162. case ActionTokenMethodName:
  163. fallthrough
  164. default:
  165. return ""
  166. }
  167. }