auths.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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 admin
  5. import (
  6. "fmt"
  7. "net/http"
  8. "strings"
  9. "github.com/unknwon/com"
  10. log "unknwon.dev/clog/v2"
  11. "gogs.io/gogs/internal/auth"
  12. "gogs.io/gogs/internal/auth/github"
  13. "gogs.io/gogs/internal/auth/ldap"
  14. "gogs.io/gogs/internal/auth/pam"
  15. "gogs.io/gogs/internal/auth/smtp"
  16. "gogs.io/gogs/internal/conf"
  17. "gogs.io/gogs/internal/context"
  18. "gogs.io/gogs/internal/database"
  19. "gogs.io/gogs/internal/form"
  20. )
  21. const (
  22. AUTHS = "admin/auth/list"
  23. AUTH_NEW = "admin/auth/new"
  24. AUTH_EDIT = "admin/auth/edit"
  25. )
  26. func Authentications(c *context.Context) {
  27. c.Title("admin.authentication")
  28. c.PageIs("Admin")
  29. c.PageIs("AdminAuthentications")
  30. var err error
  31. c.Data["Sources"], err = database.Handle.LoginSources().List(c.Req.Context(), database.ListLoginSourceOptions{})
  32. if err != nil {
  33. c.Error(err, "list login sources")
  34. return
  35. }
  36. c.Data["Total"] = database.Handle.LoginSources().Count(c.Req.Context())
  37. c.Success(AUTHS)
  38. }
  39. type dropdownItem struct {
  40. Name string
  41. Type any
  42. }
  43. var (
  44. authSources = []dropdownItem{
  45. {auth.Name(auth.LDAP), auth.LDAP},
  46. {auth.Name(auth.DLDAP), auth.DLDAP},
  47. {auth.Name(auth.SMTP), auth.SMTP},
  48. {auth.Name(auth.PAM), auth.PAM},
  49. {auth.Name(auth.GitHub), auth.GitHub},
  50. }
  51. securityProtocols = []dropdownItem{
  52. {ldap.SecurityProtocolName(ldap.SecurityProtocolUnencrypted), ldap.SecurityProtocolUnencrypted},
  53. {ldap.SecurityProtocolName(ldap.SecurityProtocolLDAPS), ldap.SecurityProtocolLDAPS},
  54. {ldap.SecurityProtocolName(ldap.SecurityProtocolStartTLS), ldap.SecurityProtocolStartTLS},
  55. }
  56. )
  57. func NewAuthSource(c *context.Context) {
  58. c.Title("admin.auths.new")
  59. c.PageIs("Admin")
  60. c.PageIs("AdminAuthentications")
  61. c.Data["type"] = auth.LDAP
  62. c.Data["CurrentTypeName"] = auth.Name(auth.LDAP)
  63. c.Data["CurrentSecurityProtocol"] = ldap.SecurityProtocolName(ldap.SecurityProtocolUnencrypted)
  64. c.Data["smtp_auth"] = "PLAIN"
  65. c.Data["is_active"] = true
  66. c.Data["is_default"] = true
  67. c.Data["AuthSources"] = authSources
  68. c.Data["SecurityProtocols"] = securityProtocols
  69. c.Data["SMTPAuths"] = smtp.AuthTypes
  70. c.Success(AUTH_NEW)
  71. }
  72. func parseLDAPConfig(f form.Authentication) *ldap.Config {
  73. return &ldap.Config{
  74. Host: f.Host,
  75. Port: f.Port,
  76. SecurityProtocol: ldap.SecurityProtocol(f.SecurityProtocol),
  77. SkipVerify: f.SkipVerify,
  78. BindDN: f.BindDN,
  79. UserDN: f.UserDN,
  80. BindPassword: f.BindPassword,
  81. UserBase: f.UserBase,
  82. AttributeUsername: f.AttributeUsername,
  83. AttributeName: f.AttributeName,
  84. AttributeSurname: f.AttributeSurname,
  85. AttributeMail: f.AttributeMail,
  86. AttributesInBind: f.AttributesInBind,
  87. Filter: f.Filter,
  88. GroupEnabled: f.GroupEnabled,
  89. GroupDN: f.GroupDN,
  90. GroupFilter: f.GroupFilter,
  91. GroupMemberUID: f.GroupMemberUID,
  92. UserUID: f.UserUID,
  93. AdminFilter: f.AdminFilter,
  94. }
  95. }
  96. func parseSMTPConfig(f form.Authentication) *smtp.Config {
  97. return &smtp.Config{
  98. Auth: f.SMTPAuth,
  99. Host: f.SMTPHost,
  100. Port: f.SMTPPort,
  101. AllowedDomains: f.AllowedDomains,
  102. TLS: f.TLS,
  103. SkipVerify: f.SkipVerify,
  104. }
  105. }
  106. func NewAuthSourcePost(c *context.Context, f form.Authentication) {
  107. c.Title("admin.auths.new")
  108. c.PageIs("Admin")
  109. c.PageIs("AdminAuthentications")
  110. c.Data["CurrentTypeName"] = auth.Name(auth.Type(f.Type))
  111. c.Data["CurrentSecurityProtocol"] = ldap.SecurityProtocolName(ldap.SecurityProtocol(f.SecurityProtocol))
  112. c.Data["AuthSources"] = authSources
  113. c.Data["SecurityProtocols"] = securityProtocols
  114. c.Data["SMTPAuths"] = smtp.AuthTypes
  115. hasTLS := false
  116. var config any
  117. switch auth.Type(f.Type) {
  118. case auth.LDAP, auth.DLDAP:
  119. config = parseLDAPConfig(f)
  120. hasTLS = ldap.SecurityProtocol(f.SecurityProtocol) > ldap.SecurityProtocolUnencrypted
  121. case auth.SMTP:
  122. config = parseSMTPConfig(f)
  123. hasTLS = true
  124. case auth.PAM:
  125. config = &pam.Config{
  126. ServiceName: f.PAMServiceName,
  127. }
  128. case auth.GitHub:
  129. config = &github.Config{
  130. APIEndpoint: strings.TrimSuffix(f.GitHubAPIEndpoint, "/") + "/",
  131. SkipVerify: f.SkipVerify,
  132. }
  133. hasTLS = true
  134. default:
  135. c.Status(http.StatusBadRequest)
  136. return
  137. }
  138. c.Data["HasTLS"] = hasTLS
  139. if c.HasError() {
  140. c.Success(AUTH_NEW)
  141. return
  142. }
  143. source, err := database.Handle.LoginSources().Create(c.Req.Context(),
  144. database.CreateLoginSourceOptions{
  145. Type: auth.Type(f.Type),
  146. Name: f.Name,
  147. Activated: f.IsActive,
  148. Default: f.IsDefault,
  149. Config: config,
  150. },
  151. )
  152. if err != nil {
  153. if database.IsErrLoginSourceAlreadyExist(err) {
  154. c.FormErr("Name")
  155. c.RenderWithErr(c.Tr("admin.auths.login_source_exist", f.Name), AUTH_NEW, f)
  156. } else {
  157. c.Error(err, "create login source")
  158. }
  159. return
  160. }
  161. if source.IsDefault {
  162. err = database.Handle.LoginSources().ResetNonDefault(c.Req.Context(), source)
  163. if err != nil {
  164. c.Error(err, "reset non-default login sources")
  165. return
  166. }
  167. }
  168. log.Trace("Authentication created by admin(%s): %s", c.User.Name, f.Name)
  169. c.Flash.Success(c.Tr("admin.auths.new_success", f.Name))
  170. c.Redirect(conf.Server.Subpath + "/admin/auths")
  171. }
  172. func EditAuthSource(c *context.Context) {
  173. c.Title("admin.auths.edit")
  174. c.PageIs("Admin")
  175. c.PageIs("AdminAuthentications")
  176. c.Data["SecurityProtocols"] = securityProtocols
  177. c.Data["SMTPAuths"] = smtp.AuthTypes
  178. source, err := database.Handle.LoginSources().GetByID(c.Req.Context(), c.ParamsInt64(":authid"))
  179. if err != nil {
  180. c.Error(err, "get login source by ID")
  181. return
  182. }
  183. c.Data["Source"] = source
  184. c.Data["HasTLS"] = source.Provider.HasTLS()
  185. c.Success(AUTH_EDIT)
  186. }
  187. func EditAuthSourcePost(c *context.Context, f form.Authentication) {
  188. c.Title("admin.auths.edit")
  189. c.PageIs("Admin")
  190. c.PageIs("AdminAuthentications")
  191. c.Data["SMTPAuths"] = smtp.AuthTypes
  192. source, err := database.Handle.LoginSources().GetByID(c.Req.Context(), c.ParamsInt64(":authid"))
  193. if err != nil {
  194. c.Error(err, "get login source by ID")
  195. return
  196. }
  197. c.Data["Source"] = source
  198. c.Data["HasTLS"] = source.Provider.HasTLS()
  199. if c.HasError() {
  200. c.Success(AUTH_EDIT)
  201. return
  202. }
  203. var provider auth.Provider
  204. switch auth.Type(f.Type) {
  205. case auth.LDAP:
  206. provider = ldap.NewProvider(false, parseLDAPConfig(f))
  207. case auth.DLDAP:
  208. provider = ldap.NewProvider(true, parseLDAPConfig(f))
  209. case auth.SMTP:
  210. provider = smtp.NewProvider(parseSMTPConfig(f))
  211. case auth.PAM:
  212. provider = pam.NewProvider(&pam.Config{
  213. ServiceName: f.PAMServiceName,
  214. })
  215. case auth.GitHub:
  216. provider = github.NewProvider(&github.Config{
  217. APIEndpoint: strings.TrimSuffix(f.GitHubAPIEndpoint, "/") + "/",
  218. SkipVerify: f.SkipVerify,
  219. })
  220. default:
  221. c.Status(http.StatusBadRequest)
  222. return
  223. }
  224. source.Name = f.Name
  225. source.IsActived = f.IsActive
  226. source.IsDefault = f.IsDefault
  227. source.Provider = provider
  228. if err := database.Handle.LoginSources().Save(c.Req.Context(), source); err != nil {
  229. c.Error(err, "update login source")
  230. return
  231. }
  232. if source.IsDefault {
  233. err = database.Handle.LoginSources().ResetNonDefault(c.Req.Context(), source)
  234. if err != nil {
  235. c.Error(err, "reset non-default login sources")
  236. return
  237. }
  238. }
  239. log.Trace("Authentication changed by admin '%s': %d", c.User.Name, source.ID)
  240. c.Flash.Success(c.Tr("admin.auths.update_success"))
  241. c.Redirect(conf.Server.Subpath + "/admin/auths/" + com.ToStr(f.ID))
  242. }
  243. func DeleteAuthSource(c *context.Context) {
  244. id := c.ParamsInt64(":authid")
  245. if err := database.Handle.LoginSources().DeleteByID(c.Req.Context(), id); err != nil {
  246. if database.IsErrLoginSourceInUse(err) {
  247. c.Flash.Error(c.Tr("admin.auths.still_in_used"))
  248. } else {
  249. c.Flash.Error(fmt.Sprintf("DeleteSource: %v", err))
  250. }
  251. c.JSONSuccess(map[string]any{
  252. "redirect": conf.Server.Subpath + "/admin/auths/" + c.Params(":authid"),
  253. })
  254. return
  255. }
  256. log.Trace("Authentication deleted by admin(%s): %d", c.User.Name, id)
  257. c.Flash.Success(c.Tr("admin.auths.deletion_success"))
  258. c.JSONSuccess(map[string]any{
  259. "redirect": conf.Server.Subpath + "/admin/auths",
  260. })
  261. }