You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

276 lines
6.6 KiB

10 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package auth
  5. import (
  6. "reflect"
  7. "strings"
  8. "time"
  9. "github.com/Unknwon/com"
  10. "github.com/go-macaron/binding"
  11. "github.com/go-macaron/session"
  12. "gopkg.in/macaron.v1"
  13. "github.com/gogits/gogs/models"
  14. "github.com/gogits/gogs/modules/base"
  15. "github.com/gogits/gogs/modules/log"
  16. "github.com/gogits/gogs/modules/setting"
  17. "github.com/gogits/gogs/modules/uuid"
  18. )
  19. func IsAPIPath(url string) bool {
  20. return strings.HasPrefix(url, "/api/")
  21. }
  22. // SignedInID returns the id of signed in user.
  23. func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
  24. if !models.HasEngine {
  25. return 0
  26. }
  27. // Check access token.
  28. if IsAPIPath(ctx.Req.URL.Path) {
  29. tokenSHA := ctx.Query("token")
  30. if len(tokenSHA) == 0 {
  31. // Well, check with header again.
  32. auHead := ctx.Req.Header.Get("Authorization")
  33. if len(auHead) > 0 {
  34. auths := strings.Fields(auHead)
  35. if len(auths) == 2 && auths[0] == "token" {
  36. tokenSHA = auths[1]
  37. }
  38. }
  39. }
  40. // Let's see if token is valid.
  41. if len(tokenSHA) > 0 {
  42. t, err := models.GetAccessTokenBySHA(tokenSHA)
  43. if err != nil {
  44. if models.IsErrAccessTokenNotExist(err) {
  45. log.Error(4, "GetAccessTokenBySHA: %v", err)
  46. }
  47. return 0
  48. }
  49. t.Updated = time.Now()
  50. if err = models.UpdateAccessToken(t); err != nil {
  51. log.Error(4, "UpdateAccessToken: %v", err)
  52. }
  53. return t.UID
  54. }
  55. }
  56. uid := sess.Get("uid")
  57. if uid == nil {
  58. return 0
  59. }
  60. if id, ok := uid.(int64); ok {
  61. if _, err := models.GetUserByID(id); err != nil {
  62. if !models.IsErrUserNotExist(err) {
  63. log.Error(4, "GetUserById: %v", err)
  64. }
  65. return 0
  66. }
  67. return id
  68. }
  69. return 0
  70. }
  71. // SignedInUser returns the user object of signed user.
  72. // It returns a bool value to indicate whether user uses basic auth or not.
  73. func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) {
  74. if !models.HasEngine {
  75. return nil, false
  76. }
  77. uid := SignedInID(ctx, sess)
  78. if uid <= 0 {
  79. if setting.Service.EnableReverseProxyAuth {
  80. webAuthUser := ctx.Req.Header.Get(setting.ReverseProxyAuthUser)
  81. if len(webAuthUser) > 0 {
  82. u, err := models.GetUserByName(webAuthUser)
  83. if err != nil {
  84. if !models.IsErrUserNotExist(err) {
  85. log.Error(4, "GetUserByName: %v", err)
  86. return nil, false
  87. }
  88. // Check if enabled auto-registration.
  89. if setting.Service.EnableReverseProxyAutoRegister {
  90. u := &models.User{
  91. Name: webAuthUser,
  92. Email: uuid.NewV4().String() + "@localhost",
  93. Passwd: webAuthUser,
  94. IsActive: true,
  95. }
  96. if err = models.CreateUser(u); err != nil {
  97. // FIXME: should I create a system notice?
  98. log.Error(4, "CreateUser: %v", err)
  99. return nil, false
  100. } else {
  101. return u, false
  102. }
  103. }
  104. }
  105. return u, false
  106. }
  107. }
  108. // Check with basic auth.
  109. baHead := ctx.Req.Header.Get("Authorization")
  110. if len(baHead) > 0 {
  111. auths := strings.Fields(baHead)
  112. if len(auths) == 2 && auths[0] == "Basic" {
  113. uname, passwd, _ := base.BasicAuthDecode(auths[1])
  114. u, err := models.UserSignIn(uname, passwd)
  115. if err != nil {
  116. if !models.IsErrUserNotExist(err) {
  117. log.Error(4, "UserSignIn: %v", err)
  118. }
  119. return nil, false
  120. }
  121. return u, true
  122. }
  123. }
  124. return nil, false
  125. }
  126. u, err := models.GetUserByID(uid)
  127. if err != nil {
  128. log.Error(4, "GetUserById: %v", err)
  129. return nil, false
  130. }
  131. return u, false
  132. }
  133. type Form interface {
  134. binding.Validator
  135. }
  136. func init() {
  137. binding.SetNameMapper(com.ToSnakeCase)
  138. }
  139. // AssignForm assign form values back to the template data.
  140. func AssignForm(form interface{}, data map[string]interface{}) {
  141. typ := reflect.TypeOf(form)
  142. val := reflect.ValueOf(form)
  143. if typ.Kind() == reflect.Ptr {
  144. typ = typ.Elem()
  145. val = val.Elem()
  146. }
  147. for i := 0; i < typ.NumField(); i++ {
  148. field := typ.Field(i)
  149. fieldName := field.Tag.Get("form")
  150. // Allow ignored fields in the struct
  151. if fieldName == "-" {
  152. continue
  153. } else if len(fieldName) == 0 {
  154. fieldName = com.ToSnakeCase(field.Name)
  155. }
  156. data[fieldName] = val.Field(i).Interface()
  157. }
  158. }
  159. func getRuleBody(field reflect.StructField, prefix string) string {
  160. for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
  161. if strings.HasPrefix(rule, prefix) {
  162. return rule[len(prefix) : len(rule)-1]
  163. }
  164. }
  165. return ""
  166. }
  167. func GetSize(field reflect.StructField) string {
  168. return getRuleBody(field, "Size(")
  169. }
  170. func GetMinSize(field reflect.StructField) string {
  171. return getRuleBody(field, "MinSize(")
  172. }
  173. func GetMaxSize(field reflect.StructField) string {
  174. return getRuleBody(field, "MaxSize(")
  175. }
  176. func GetInclude(field reflect.StructField) string {
  177. return getRuleBody(field, "Include(")
  178. }
  179. // FIXME: struct contains a struct
  180. func validateStruct(obj interface{}) binding.Errors {
  181. return nil
  182. }
  183. func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaron.Locale) binding.Errors {
  184. if errs.Len() == 0 {
  185. return errs
  186. }
  187. data["HasError"] = true
  188. AssignForm(f, data)
  189. typ := reflect.TypeOf(f)
  190. val := reflect.ValueOf(f)
  191. if typ.Kind() == reflect.Ptr {
  192. typ = typ.Elem()
  193. val = val.Elem()
  194. }
  195. for i := 0; i < typ.NumField(); i++ {
  196. field := typ.Field(i)
  197. fieldName := field.Tag.Get("form")
  198. // Allow ignored fields in the struct
  199. if fieldName == "-" {
  200. continue
  201. }
  202. if errs[0].FieldNames[0] == field.Name {
  203. data["Err_"+field.Name] = true
  204. trName := field.Tag.Get("locale")
  205. if len(trName) == 0 {
  206. trName = l.Tr("form." + field.Name)
  207. } else {
  208. trName = l.Tr(trName)
  209. }
  210. switch errs[0].Classification {
  211. case binding.ERR_REQUIRED:
  212. data["ErrorMsg"] = trName + l.Tr("form.require_error")
  213. case binding.ERR_ALPHA_DASH:
  214. data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
  215. case binding.ERR_ALPHA_DASH_DOT:
  216. data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
  217. case binding.ERR_SIZE:
  218. data["ErrorMsg"] = trName + l.Tr("form.size_error", GetSize(field))
  219. case binding.ERR_MIN_SIZE:
  220. data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field))
  221. case binding.ERR_MAX_SIZE:
  222. data["ErrorMsg"] = trName + l.Tr("form.max_size_error", GetMaxSize(field))
  223. case binding.ERR_EMAIL:
  224. data["ErrorMsg"] = trName + l.Tr("form.email_error")
  225. case binding.ERR_URL:
  226. data["ErrorMsg"] = trName + l.Tr("form.url_error")
  227. case binding.ERR_INCLUDE:
  228. data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field))
  229. default:
  230. data["ErrorMsg"] = l.Tr("form.unknown_error") + " " + errs[0].Classification
  231. }
  232. return errs
  233. }
  234. }
  235. return errs
  236. }