ldap.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. package ldap
  2. import (
  3. "encoding/json"
  4. "log"
  5. "net/http"
  6. "regexp"
  7. "strconv"
  8. auth "imuslab.com/arozos/mod/auth"
  9. "imuslab.com/arozos/mod/auth/ldap/ldapreader"
  10. reg "imuslab.com/arozos/mod/auth/register"
  11. "imuslab.com/arozos/mod/common"
  12. db "imuslab.com/arozos/mod/database"
  13. permission "imuslab.com/arozos/mod/permission"
  14. "imuslab.com/arozos/mod/user"
  15. )
  16. type ldapHandler struct {
  17. ag *auth.AuthAgent
  18. ldapreader *ldapreader.LdapReader
  19. reg *reg.RegisterHandler
  20. coredb *db.Database
  21. permissionHandler *permission.PermissionHandler
  22. userHandler *user.UserHandler
  23. }
  24. type Config struct {
  25. Enabled bool `json:"enabled"`
  26. AutoRedirect bool `json:"auto_redirect"`
  27. BindUsername string `json:"bind_username"`
  28. BindPassword string `json:"bind_password"`
  29. FQDN string `json:"fqdn"`
  30. BaseDN string `json:"base_dn"`
  31. }
  32. type UserAccount struct {
  33. Username string `json:"username"`
  34. Group []string `json:"group"`
  35. EquivGroup []string `json:"equiv_group"`
  36. }
  37. /*
  38. TODO: not sure why auto redirect will keep enable
  39. TODO: stop user to syncorize if the current user will lost admin access
  40. */
  41. //NewLdapHandler xxx
  42. func NewLdapHandler(authAgent *auth.AuthAgent, register *reg.RegisterHandler, coreDb *db.Database, permissionHandler *permission.PermissionHandler, userHandler *user.UserHandler) *ldapHandler {
  43. //ldap handler init
  44. log.Println("Starting LDAP client...")
  45. err := coreDb.NewTable("ldap")
  46. if err != nil {
  47. log.Println("Failed to create LDAP database. Terminating.")
  48. panic(err)
  49. }
  50. //key value to be used for LDAP authentication
  51. BindUsername := readSingleConfig("BindUsername", coreDb)
  52. BindPassword := readSingleConfig("BindPassword", coreDb)
  53. FQDN := readSingleConfig("FQDN", coreDb)
  54. BaseDN := readSingleConfig("BaseDN", coreDb)
  55. LDAPHandler := ldapHandler{
  56. ag: authAgent,
  57. ldapreader: ldapreader.NewLDAPReader(BindUsername, BindPassword, FQDN, BaseDN),
  58. reg: register,
  59. coredb: coreDb,
  60. permissionHandler: permissionHandler,
  61. userHandler: userHandler,
  62. }
  63. return &LDAPHandler
  64. }
  65. func (ldap *ldapHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
  66. //basic components
  67. enabled, err := strconv.ParseBool(ldap.readSingleConfig("enabled"))
  68. if err != nil {
  69. common.SendTextResponse(w, "Invalid config value [key=enabled].")
  70. return
  71. }
  72. autoredirect, err := strconv.ParseBool(ldap.readSingleConfig("autoredirect"))
  73. if err != nil {
  74. common.SendTextResponse(w, "Invalid config value [key=autoredirect].")
  75. return
  76. }
  77. //get the LDAP config from db
  78. BindUsername := ldap.readSingleConfig("BindUsername")
  79. BindPassword := ldap.readSingleConfig("BindPassword")
  80. FQDN := ldap.readSingleConfig("FQDN")
  81. BaseDN := ldap.readSingleConfig("BaseDN")
  82. //marshall it and return
  83. config, err := json.Marshal(Config{
  84. Enabled: enabled,
  85. AutoRedirect: autoredirect,
  86. BindUsername: BindUsername,
  87. BindPassword: BindPassword,
  88. FQDN: FQDN,
  89. BaseDN: BaseDN,
  90. })
  91. if err != nil {
  92. empty, err := json.Marshal(Config{})
  93. if err != nil {
  94. common.SendErrorResponse(w, "Error while marshalling config")
  95. }
  96. common.SendJSONResponse(w, string(empty))
  97. }
  98. common.SendJSONResponse(w, string(config))
  99. }
  100. func (ldap *ldapHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
  101. enabled, err := common.Mv(r, "enabled", true)
  102. if err != nil {
  103. common.SendErrorResponse(w, "enabled field can't be empty")
  104. return
  105. }
  106. autoredirect, err := common.Mv(r, "autoredirect", true)
  107. if err != nil {
  108. common.SendErrorResponse(w, "enabled field can't be empty")
  109. return
  110. }
  111. //allow empty fields if enabled is false
  112. showError := true
  113. if enabled != "true" {
  114. showError = false
  115. }
  116. //four fields to store the LDAP authentication information
  117. BindUsername, err := common.Mv(r, "bind_username", true)
  118. if err != nil {
  119. if showError {
  120. common.SendErrorResponse(w, "bind_username field can't be empty")
  121. return
  122. }
  123. }
  124. BindPassword, err := common.Mv(r, "bind_password", true)
  125. if err != nil {
  126. if showError {
  127. common.SendErrorResponse(w, "bind_password field can't be empty")
  128. return
  129. }
  130. }
  131. FQDN, err := common.Mv(r, "fqdn", true)
  132. if err != nil {
  133. if showError {
  134. common.SendErrorResponse(w, "fqdn field can't be empty")
  135. return
  136. }
  137. }
  138. BaseDN, err := common.Mv(r, "base_dn", true)
  139. if err != nil {
  140. if showError {
  141. common.SendErrorResponse(w, "base_dn field can't be empty")
  142. return
  143. }
  144. }
  145. ldap.coredb.Write("ldap", "enabled", enabled)
  146. ldap.coredb.Write("ldap", "autoredirect", autoredirect)
  147. ldap.coredb.Write("ldap", "BindUsername", BindUsername)
  148. ldap.coredb.Write("ldap", "BindPassword", BindPassword)
  149. ldap.coredb.Write("ldap", "FQDN", FQDN)
  150. ldap.coredb.Write("ldap", "BaseDN", BaseDN)
  151. //update the new authencation infromation
  152. ldap.ldapreader = ldapreader.NewLDAPReader(BindUsername, BindPassword, FQDN, BaseDN)
  153. common.SendOK(w)
  154. }
  155. //@para limit: -1 means unlimited
  156. func (ldap *ldapHandler) getAllUser(limit int) []UserAccount {
  157. var accounts []UserAccount
  158. result, _ := ldap.ldapreader.GetAllUser()
  159. //loop through the result
  160. for i, v := range result {
  161. //check the group belongs
  162. var Group []string
  163. var EquivGroup []string
  164. regexSyntax := regexp.MustCompile("cn=([^,]+),")
  165. for _, v := range v.GetAttributeValues("memberOf") {
  166. groups := regexSyntax.FindStringSubmatch(v)
  167. if len(groups) > 0 {
  168. //check if the LDAP group is already exists in ArOZOS system
  169. if ldap.permissionHandler.GroupExists(groups[1]) {
  170. EquivGroup = append(EquivGroup, groups[1])
  171. }
  172. //LDAP list
  173. Group = append(Group, groups[1])
  174. }
  175. }
  176. if len(EquivGroup) < 1 {
  177. EquivGroup = append(EquivGroup, ldap.reg.DefaultUserGroup)
  178. }
  179. account := UserAccount{
  180. Username: v.GetAttributeValue("uid"),
  181. Group: Group,
  182. EquivGroup: EquivGroup,
  183. }
  184. accounts = append(accounts, account)
  185. if i > limit && limit != -1 {
  186. break
  187. }
  188. }
  189. if len(accounts) > 0 {
  190. return accounts[1:]
  191. } else {
  192. return []UserAccount{}
  193. }
  194. }
  195. func (ldap *ldapHandler) TestConnection(w http.ResponseWriter, r *http.Request) {
  196. //marshall it and return
  197. accountJSON, err := json.Marshal(ldap.getAllUser(10))
  198. if err != nil {
  199. empty, err := json.Marshal(UserAccount{})
  200. if err != nil {
  201. common.SendErrorResponse(w, "Error while marshalling information")
  202. }
  203. common.SendJSONResponse(w, string(empty))
  204. }
  205. common.SendJSONResponse(w, string(accountJSON))
  206. }
  207. func (ldap *ldapHandler) checkCurrUserAdmin(w http.ResponseWriter, r *http.Request) bool {
  208. //check current user is admin and new update will remove it or not
  209. currentLoggedInUser, err := ldap.userHandler.GetUserInfoFromRequest(w, r)
  210. if err != nil {
  211. common.SendErrorResponse(w, "Error while getting user info")
  212. return false
  213. }
  214. ldapCurrUserInfo, err := ldap.ldapreader.GetUser(currentLoggedInUser.Username)
  215. if err != nil {
  216. common.SendErrorResponse(w, "Error while getting user info from LDAP")
  217. return false
  218. }
  219. isAdmin := false
  220. regexSyntax := regexp.MustCompile("cn=([^,]+),")
  221. for _, v := range ldapCurrUserInfo.GetAttributeValues("memberOf") {
  222. groups := regexSyntax.FindStringSubmatch(v)
  223. if len(groups) > 0 {
  224. //check if the LDAP group is already exists in ArOZOS system
  225. if ldap.permissionHandler.GroupExists(groups[1]) {
  226. if ldap.permissionHandler.GetPermissionGroupByName(groups[1]).IsAdmin {
  227. isAdmin = true
  228. }
  229. }
  230. }
  231. }
  232. return isAdmin
  233. }
  234. func (ldap *ldapHandler) SynchronizeUser(w http.ResponseWriter, r *http.Request) {
  235. consistencyCheck := ldap.checkCurrUserAdmin(w, r)
  236. if !consistencyCheck {
  237. common.SendErrorResponse(w, "You will no longer become the admin after synchronizing, synchronize terminated")
  238. return
  239. }
  240. ldapUsersList := ldap.getAllUser(-1)
  241. for _, ldapUser := range ldapUsersList {
  242. //check if user does not exist in system
  243. if !ldap.ag.UserExists(ldapUser.Username) {
  244. //TODO change password
  245. ldap.ag.CreateUserAccount(ldapUser.Username, "P@ssw0rd", ldapUser.EquivGroup)
  246. } else {
  247. //if exists, then check if the user group is the same with ldap's setting
  248. //Get the permission groups by their ids
  249. userinfo, err := ldap.userHandler.GetUserInfoFromUsername(ldapUser.Username)
  250. if err != nil {
  251. common.SendErrorResponse(w, "Error while getting user info")
  252. return
  253. }
  254. newPermissionGroups := ldap.permissionHandler.GetPermissionGroupByNameList(ldapUser.EquivGroup)
  255. //Set the user's permission to these groups
  256. userinfo.SetUserPermissionGroup(newPermissionGroups)
  257. }
  258. }
  259. common.SendOK(w)
  260. }