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.

login_source.go 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package models
  6. import (
  7. "reflect"
  8. "strconv"
  9. "code.gitea.io/gitea/modules/log"
  10. "code.gitea.io/gitea/modules/timeutil"
  11. "xorm.io/xorm"
  12. "xorm.io/xorm/convert"
  13. )
  14. // LoginType represents an login type.
  15. type LoginType int
  16. // Note: new type must append to the end of list to maintain compatibility.
  17. const (
  18. LoginNoType LoginType = iota
  19. LoginPlain // 1
  20. LoginLDAP // 2
  21. LoginSMTP // 3
  22. LoginPAM // 4
  23. LoginDLDAP // 5
  24. LoginOAuth2 // 6
  25. LoginSSPI // 7
  26. )
  27. // String returns the string name of the LoginType
  28. func (typ LoginType) String() string {
  29. return LoginNames[typ]
  30. }
  31. // Int returns the int value of the LoginType
  32. func (typ LoginType) Int() int {
  33. return int(typ)
  34. }
  35. // LoginNames contains the name of LoginType values.
  36. var LoginNames = map[LoginType]string{
  37. LoginLDAP: "LDAP (via BindDN)",
  38. LoginDLDAP: "LDAP (simple auth)", // Via direct bind
  39. LoginSMTP: "SMTP",
  40. LoginPAM: "PAM",
  41. LoginOAuth2: "OAuth2",
  42. LoginSSPI: "SPNEGO with SSPI",
  43. }
  44. // LoginConfig represents login config as far as the db is concerned
  45. type LoginConfig interface {
  46. convert.Conversion
  47. }
  48. // SkipVerifiable configurations provide a IsSkipVerify to check if SkipVerify is set
  49. type SkipVerifiable interface {
  50. IsSkipVerify() bool
  51. }
  52. // HasTLSer configurations provide a HasTLS to check if TLS can be enabled
  53. type HasTLSer interface {
  54. HasTLS() bool
  55. }
  56. // UseTLSer configurations provide a HasTLS to check if TLS is enabled
  57. type UseTLSer interface {
  58. UseTLS() bool
  59. }
  60. // SSHKeyProvider configurations provide ProvidesSSHKeys to check if they provide SSHKeys
  61. type SSHKeyProvider interface {
  62. ProvidesSSHKeys() bool
  63. }
  64. // RegisterableSource configurations provide RegisterSource which needs to be run on creation
  65. type RegisterableSource interface {
  66. RegisterSource() error
  67. UnregisterSource() error
  68. }
  69. // LoginSourceSettable configurations can have their loginSource set on them
  70. type LoginSourceSettable interface {
  71. SetLoginSource(*LoginSource)
  72. }
  73. // RegisterLoginTypeConfig register a config for a provided type
  74. func RegisterLoginTypeConfig(typ LoginType, exemplar LoginConfig) {
  75. if reflect.TypeOf(exemplar).Kind() == reflect.Ptr {
  76. // Pointer:
  77. registeredLoginConfigs[typ] = func() LoginConfig {
  78. return reflect.New(reflect.ValueOf(exemplar).Elem().Type()).Interface().(LoginConfig)
  79. }
  80. return
  81. }
  82. // Not a Pointer
  83. registeredLoginConfigs[typ] = func() LoginConfig {
  84. return reflect.New(reflect.TypeOf(exemplar)).Elem().Interface().(LoginConfig)
  85. }
  86. }
  87. var registeredLoginConfigs = map[LoginType]func() LoginConfig{}
  88. // LoginSource represents an external way for authorizing users.
  89. type LoginSource struct {
  90. ID int64 `xorm:"pk autoincr"`
  91. Type LoginType
  92. Name string `xorm:"UNIQUE"`
  93. IsActive bool `xorm:"INDEX NOT NULL DEFAULT false"`
  94. IsSyncEnabled bool `xorm:"INDEX NOT NULL DEFAULT false"`
  95. Cfg convert.Conversion `xorm:"TEXT"`
  96. CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
  97. UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
  98. }
  99. // Cell2Int64 converts a xorm.Cell type to int64,
  100. // and handles possible irregular cases.
  101. func Cell2Int64(val xorm.Cell) int64 {
  102. switch (*val).(type) {
  103. case []uint8:
  104. log.Trace("Cell2Int64 ([]uint8): %v", *val)
  105. v, _ := strconv.ParseInt(string((*val).([]uint8)), 10, 64)
  106. return v
  107. }
  108. return (*val).(int64)
  109. }
  110. // BeforeSet is invoked from XORM before setting the value of a field of this object.
  111. func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
  112. if colName == "type" {
  113. typ := LoginType(Cell2Int64(val))
  114. constructor, ok := registeredLoginConfigs[typ]
  115. if !ok {
  116. return
  117. }
  118. source.Cfg = constructor()
  119. if settable, ok := source.Cfg.(LoginSourceSettable); ok {
  120. settable.SetLoginSource(source)
  121. }
  122. }
  123. }
  124. // TypeName return name of this login source type.
  125. func (source *LoginSource) TypeName() string {
  126. return LoginNames[source.Type]
  127. }
  128. // IsLDAP returns true of this source is of the LDAP type.
  129. func (source *LoginSource) IsLDAP() bool {
  130. return source.Type == LoginLDAP
  131. }
  132. // IsDLDAP returns true of this source is of the DLDAP type.
  133. func (source *LoginSource) IsDLDAP() bool {
  134. return source.Type == LoginDLDAP
  135. }
  136. // IsSMTP returns true of this source is of the SMTP type.
  137. func (source *LoginSource) IsSMTP() bool {
  138. return source.Type == LoginSMTP
  139. }
  140. // IsPAM returns true of this source is of the PAM type.
  141. func (source *LoginSource) IsPAM() bool {
  142. return source.Type == LoginPAM
  143. }
  144. // IsOAuth2 returns true of this source is of the OAuth2 type.
  145. func (source *LoginSource) IsOAuth2() bool {
  146. return source.Type == LoginOAuth2
  147. }
  148. // IsSSPI returns true of this source is of the SSPI type.
  149. func (source *LoginSource) IsSSPI() bool {
  150. return source.Type == LoginSSPI
  151. }
  152. // HasTLS returns true of this source supports TLS.
  153. func (source *LoginSource) HasTLS() bool {
  154. hasTLSer, ok := source.Cfg.(HasTLSer)
  155. return ok && hasTLSer.HasTLS()
  156. }
  157. // UseTLS returns true of this source is configured to use TLS.
  158. func (source *LoginSource) UseTLS() bool {
  159. useTLSer, ok := source.Cfg.(UseTLSer)
  160. return ok && useTLSer.UseTLS()
  161. }
  162. // SkipVerify returns true if this source is configured to skip SSL
  163. // verification.
  164. func (source *LoginSource) SkipVerify() bool {
  165. skipVerifiable, ok := source.Cfg.(SkipVerifiable)
  166. return ok && skipVerifiable.IsSkipVerify()
  167. }
  168. // CreateLoginSource inserts a LoginSource in the DB if not already
  169. // existing with the given name.
  170. func CreateLoginSource(source *LoginSource) error {
  171. has, err := x.Where("name=?", source.Name).Exist(new(LoginSource))
  172. if err != nil {
  173. return err
  174. } else if has {
  175. return ErrLoginSourceAlreadyExist{source.Name}
  176. }
  177. // Synchronization is only available with LDAP for now
  178. if !source.IsLDAP() {
  179. source.IsSyncEnabled = false
  180. }
  181. _, err = x.Insert(source)
  182. if err != nil {
  183. return err
  184. }
  185. if !source.IsActive {
  186. return nil
  187. }
  188. if settable, ok := source.Cfg.(LoginSourceSettable); ok {
  189. settable.SetLoginSource(source)
  190. }
  191. registerableSource, ok := source.Cfg.(RegisterableSource)
  192. if !ok {
  193. return nil
  194. }
  195. err = registerableSource.RegisterSource()
  196. if err != nil {
  197. // remove the LoginSource in case of errors while registering configuration
  198. if _, err := x.Delete(source); err != nil {
  199. log.Error("CreateLoginSource: Error while wrapOpenIDConnectInitializeError: %v", err)
  200. }
  201. }
  202. return err
  203. }
  204. // LoginSources returns a slice of all login sources found in DB.
  205. func LoginSources() ([]*LoginSource, error) {
  206. auths := make([]*LoginSource, 0, 6)
  207. return auths, x.Find(&auths)
  208. }
  209. // LoginSourcesByType returns all sources of the specified type
  210. func LoginSourcesByType(loginType LoginType) ([]*LoginSource, error) {
  211. sources := make([]*LoginSource, 0, 1)
  212. if err := x.Where("type = ?", loginType).Find(&sources); err != nil {
  213. return nil, err
  214. }
  215. return sources, nil
  216. }
  217. // AllActiveLoginSources returns all active sources
  218. func AllActiveLoginSources() ([]*LoginSource, error) {
  219. sources := make([]*LoginSource, 0, 5)
  220. if err := x.Where("is_active = ?", true).Find(&sources); err != nil {
  221. return nil, err
  222. }
  223. return sources, nil
  224. }
  225. // ActiveLoginSources returns all active sources of the specified type
  226. func ActiveLoginSources(loginType LoginType) ([]*LoginSource, error) {
  227. sources := make([]*LoginSource, 0, 1)
  228. if err := x.Where("is_active = ? and type = ?", true, loginType).Find(&sources); err != nil {
  229. return nil, err
  230. }
  231. return sources, nil
  232. }
  233. // IsSSPIEnabled returns true if there is at least one activated login
  234. // source of type LoginSSPI
  235. func IsSSPIEnabled() bool {
  236. if !HasEngine {
  237. return false
  238. }
  239. sources, err := ActiveLoginSources(LoginSSPI)
  240. if err != nil {
  241. log.Error("ActiveLoginSources: %v", err)
  242. return false
  243. }
  244. return len(sources) > 0
  245. }
  246. // GetLoginSourceByID returns login source by given ID.
  247. func GetLoginSourceByID(id int64) (*LoginSource, error) {
  248. source := new(LoginSource)
  249. if id == 0 {
  250. source.Cfg = registeredLoginConfigs[LoginNoType]()
  251. // Set this source to active
  252. // FIXME: allow disabling of db based password authentication in future
  253. source.IsActive = true
  254. return source, nil
  255. }
  256. has, err := x.ID(id).Get(source)
  257. if err != nil {
  258. return nil, err
  259. } else if !has {
  260. return nil, ErrLoginSourceNotExist{id}
  261. }
  262. return source, nil
  263. }
  264. // UpdateSource updates a LoginSource record in DB.
  265. func UpdateSource(source *LoginSource) error {
  266. var originalLoginSource *LoginSource
  267. if source.IsOAuth2() {
  268. // keep track of the original values so we can restore in case of errors while registering OAuth2 providers
  269. var err error
  270. if originalLoginSource, err = GetLoginSourceByID(source.ID); err != nil {
  271. return err
  272. }
  273. }
  274. _, err := x.ID(source.ID).AllCols().Update(source)
  275. if err != nil {
  276. return err
  277. }
  278. if !source.IsActive {
  279. return nil
  280. }
  281. if settable, ok := source.Cfg.(LoginSourceSettable); ok {
  282. settable.SetLoginSource(source)
  283. }
  284. registerableSource, ok := source.Cfg.(RegisterableSource)
  285. if !ok {
  286. return nil
  287. }
  288. err = registerableSource.RegisterSource()
  289. if err != nil {
  290. // restore original values since we cannot update the provider it self
  291. if _, err := x.ID(source.ID).AllCols().Update(originalLoginSource); err != nil {
  292. log.Error("UpdateSource: Error while wrapOpenIDConnectInitializeError: %v", err)
  293. }
  294. }
  295. return err
  296. }
  297. // DeleteSource deletes a LoginSource record in DB.
  298. func DeleteSource(source *LoginSource) error {
  299. count, err := x.Count(&User{LoginSource: source.ID})
  300. if err != nil {
  301. return err
  302. } else if count > 0 {
  303. return ErrLoginSourceInUse{source.ID}
  304. }
  305. count, err = x.Count(&ExternalLoginUser{LoginSourceID: source.ID})
  306. if err != nil {
  307. return err
  308. } else if count > 0 {
  309. return ErrLoginSourceInUse{source.ID}
  310. }
  311. if registerableSource, ok := source.Cfg.(RegisterableSource); ok {
  312. if err := registerableSource.UnregisterSource(); err != nil {
  313. return err
  314. }
  315. }
  316. _, err = x.ID(source.ID).Delete(new(LoginSource))
  317. return err
  318. }
  319. // CountLoginSources returns number of login sources.
  320. func CountLoginSources() int64 {
  321. count, _ := x.Count(new(LoginSource))
  322. return count
  323. }