|
@@ -1,18 +1,14 @@
|
|
|
package ldap
|
|
|
|
|
|
import (
|
|
|
- "encoding/json"
|
|
|
"log"
|
|
|
- "net/http"
|
|
|
"regexp"
|
|
|
- "strconv"
|
|
|
|
|
|
"github.com/go-ldap/ldap"
|
|
|
auth "imuslab.com/arozos/mod/auth"
|
|
|
"imuslab.com/arozos/mod/auth/ldap/ldapreader"
|
|
|
"imuslab.com/arozos/mod/auth/oauth2/syncdb"
|
|
|
reg "imuslab.com/arozos/mod/auth/register"
|
|
|
- "imuslab.com/arozos/mod/common"
|
|
|
db "imuslab.com/arozos/mod/database"
|
|
|
permission "imuslab.com/arozos/mod/permission"
|
|
|
"imuslab.com/arozos/mod/time/nightly"
|
|
@@ -86,95 +82,6 @@ func NewLdapHandler(authAgent *auth.AuthAgent, register *reg.RegisterHandler, co
|
|
|
return &LDAPHandler
|
|
|
}
|
|
|
|
|
|
-func (ldap *ldapHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
|
|
|
- //basic components
|
|
|
- enabled, err := strconv.ParseBool(ldap.readSingleConfig("enabled"))
|
|
|
- if err != nil {
|
|
|
- common.SendTextResponse(w, "Invalid config value [key=enabled].")
|
|
|
- return
|
|
|
- }
|
|
|
- //get the LDAP config from db
|
|
|
- BindUsername := ldap.readSingleConfig("BindUsername")
|
|
|
- BindPassword := ldap.readSingleConfig("BindPassword")
|
|
|
- FQDN := ldap.readSingleConfig("FQDN")
|
|
|
- BaseDN := ldap.readSingleConfig("BaseDN")
|
|
|
-
|
|
|
- //marshall it and return
|
|
|
- config, err := json.Marshal(Config{
|
|
|
- Enabled: enabled,
|
|
|
- BindUsername: BindUsername,
|
|
|
- BindPassword: BindPassword,
|
|
|
- FQDN: FQDN,
|
|
|
- BaseDN: BaseDN,
|
|
|
- })
|
|
|
- if err != nil {
|
|
|
- empty, err := json.Marshal(Config{})
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, "Error while marshalling config")
|
|
|
- }
|
|
|
- common.SendJSONResponse(w, string(empty))
|
|
|
- }
|
|
|
- common.SendJSONResponse(w, string(config))
|
|
|
-}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
|
|
|
- //receive the parameter
|
|
|
- enabled, err := common.Mv(r, "enabled", true)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, "enabled field can't be empty")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- //allow empty fields if enabled is false
|
|
|
- showError := true
|
|
|
- if enabled != "true" {
|
|
|
- showError = false
|
|
|
- }
|
|
|
-
|
|
|
- //four fields to store the LDAP authentication information
|
|
|
- BindUsername, err := common.Mv(r, "bind_username", true)
|
|
|
- if err != nil {
|
|
|
- if showError {
|
|
|
- common.SendErrorResponse(w, "bind_username field can't be empty")
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
- BindPassword, err := common.Mv(r, "bind_password", true)
|
|
|
- if err != nil {
|
|
|
- if showError {
|
|
|
- common.SendErrorResponse(w, "bind_password field can't be empty")
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
- FQDN, err := common.Mv(r, "fqdn", true)
|
|
|
- if err != nil {
|
|
|
- if showError {
|
|
|
- common.SendErrorResponse(w, "fqdn field can't be empty")
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
- BaseDN, err := common.Mv(r, "base_dn", true)
|
|
|
- if err != nil {
|
|
|
- if showError {
|
|
|
- common.SendErrorResponse(w, "base_dn field can't be empty")
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //write the data back to db
|
|
|
- ldap.coredb.Write("ldap", "enabled", enabled)
|
|
|
- ldap.coredb.Write("ldap", "BindUsername", BindUsername)
|
|
|
- ldap.coredb.Write("ldap", "BindPassword", BindPassword)
|
|
|
- ldap.coredb.Write("ldap", "FQDN", FQDN)
|
|
|
- ldap.coredb.Write("ldap", "BaseDN", BaseDN)
|
|
|
-
|
|
|
- //update the new authencation infromation
|
|
|
- ldap.ldapreader = ldapreader.NewLDAPReader(BindUsername, BindPassword, FQDN, BaseDN)
|
|
|
-
|
|
|
- //return ok
|
|
|
- common.SendOK(w)
|
|
|
-}
|
|
|
-
|
|
|
//@para limit: -1 means unlimited
|
|
|
func (ldap *ldapHandler) getAllUser(limit int) ([]UserAccount, int, error) {
|
|
|
//read the user account from ldap, if limit is -1 then it will read all USERS
|
|
@@ -230,316 +137,3 @@ func (ldap *ldapHandler) convertGroup(ldapUser *ldap.Entry) UserAccount {
|
|
|
}
|
|
|
return account
|
|
|
}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) TestConnection(w http.ResponseWriter, r *http.Request) {
|
|
|
- //marshall it and return the connection status
|
|
|
- userList, totalLength, err := ldap.getAllUser(10)
|
|
|
- if err != nil {
|
|
|
- errMessage, err := json.Marshal(syncorizeUserReturnInterface{Error: err.Error()})
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, "{\"error\":\"Error while marshalling information\"}")
|
|
|
- return
|
|
|
- }
|
|
|
- common.SendJSONResponse(w, string(errMessage))
|
|
|
- return
|
|
|
- }
|
|
|
- returnJSON := syncorizeUserReturnInterface{Userinfo: userList, Length: len(userList), TotalLength: totalLength, Error: ""}
|
|
|
- accountJSON, err := json.Marshal(returnJSON)
|
|
|
- if err != nil {
|
|
|
- errMessage, err := json.Marshal(syncorizeUserReturnInterface{Error: err.Error()})
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, "{\"error\":\"Error while marshalling information\"}")
|
|
|
- return
|
|
|
- }
|
|
|
- common.SendJSONResponse(w, string(errMessage))
|
|
|
- return
|
|
|
- }
|
|
|
- common.SendJSONResponse(w, string(accountJSON))
|
|
|
-}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) checkCurrUserAdmin(w http.ResponseWriter, r *http.Request) bool {
|
|
|
- //check current user is admin and new update will remove it or not
|
|
|
- currentLoggedInUser, err := ldap.userHandler.GetUserInfoFromRequest(w, r)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, "Error while getting user info")
|
|
|
- return false
|
|
|
- }
|
|
|
- ldapCurrUserInfo, err := ldap.ldapreader.GetUser(currentLoggedInUser.Username)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, "Error while getting user info from LDAP")
|
|
|
- return false
|
|
|
- }
|
|
|
- isAdmin := false
|
|
|
- //get the croups out from LDAP group list
|
|
|
- regexSyntax := regexp.MustCompile("cn=([^,]+),")
|
|
|
- for _, v := range ldapCurrUserInfo.GetAttributeValues("memberOf") {
|
|
|
- //loop through all memberOf's array
|
|
|
- groups := regexSyntax.FindStringSubmatch(v)
|
|
|
- //if after regex there is still groups exists
|
|
|
- if len(groups) > 0 {
|
|
|
- //check if the LDAP group is already exists in ArOZOS system
|
|
|
- if ldap.permissionHandler.GroupExists(groups[1]) {
|
|
|
- if ldap.permissionHandler.GetPermissionGroupByName(groups[1]).IsAdmin {
|
|
|
- isAdmin = true
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return isAdmin
|
|
|
-}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) SynchronizeUser(w http.ResponseWriter, r *http.Request) {
|
|
|
- //check if suer is admin before executing the command
|
|
|
- //if user is admin then check if user will lost him/her's admin access
|
|
|
- consistencyCheck := ldap.checkCurrUserAdmin(w, r)
|
|
|
- if !consistencyCheck {
|
|
|
- common.SendErrorResponse(w, "You will no longer become the admin after synchronizing, synchronize terminated")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- err := ldap.SynchronizeUserFromLDAP()
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- common.SendOK(w)
|
|
|
-}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) NightlySync() {
|
|
|
- err := ldap.SynchronizeUserFromLDAP()
|
|
|
- log.Println(err)
|
|
|
-}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) SynchronizeUserFromLDAP() error {
|
|
|
- //check if suer is admin before executing the command
|
|
|
- //if user is admin then check if user will lost him/her's admin access
|
|
|
- ldapUsersList, _, err := ldap.getAllUser(-1)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- for _, ldapUser := range ldapUsersList {
|
|
|
- //check if user exist in system
|
|
|
- if ldap.ag.UserExists(ldapUser.Username) {
|
|
|
- //if exists, then check if the user group is the same with ldap's setting
|
|
|
- //Get the permission groups by their ids
|
|
|
- userinfo, err := ldap.userHandler.GetUserInfoFromUsername(ldapUser.Username)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- newPermissionGroups := ldap.permissionHandler.GetPermissionGroupByNameList(ldapUser.EquivGroup)
|
|
|
- //Set the user's permission to these groups
|
|
|
- userinfo.SetUserPermissionGroup(newPermissionGroups)
|
|
|
- }
|
|
|
- }
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-//LOGIN related function
|
|
|
-//functions basically same as arozos's original function
|
|
|
-func (ldap *ldapHandler) HandleLoginPage(w http.ResponseWriter, r *http.Request) {
|
|
|
- checkLDAPenabled := ldap.readSingleConfig("enabled")
|
|
|
- if checkLDAPenabled == "false" {
|
|
|
- common.SendTextResponse(w, "LDAP not enabled.")
|
|
|
- return
|
|
|
- }
|
|
|
- //load the template from file and inject necessary variables
|
|
|
- red, _ := common.Mv(r, "redirect", false)
|
|
|
-
|
|
|
- //Append the redirection addr into the template
|
|
|
- imgsrc := "./web/" + ldap.iconSystem
|
|
|
- if !common.FileExists(imgsrc) {
|
|
|
- imgsrc = "./web/img/public/auth_icon.png"
|
|
|
- }
|
|
|
- imageBase64, _ := common.LoadImageAsBase64(imgsrc)
|
|
|
- parsedPage, err := common.Templateload("web/login.system", map[string]interface{}{
|
|
|
- "redirection_addr": red,
|
|
|
- "usercount": strconv.Itoa(ldap.ag.GetUserCounts()),
|
|
|
- "service_logo": imageBase64,
|
|
|
- "login_addr": "system/auth/ldap/login",
|
|
|
- })
|
|
|
- if err != nil {
|
|
|
- panic("Error. Unable to parse login page. Is web directory data exists?")
|
|
|
- }
|
|
|
- w.Header().Add("Content-Type", "text/html; charset=UTF-8")
|
|
|
- w.Write([]byte(parsedPage))
|
|
|
-}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) HandleNewPasswordPage(w http.ResponseWriter, r *http.Request) {
|
|
|
- checkLDAPenabled := ldap.readSingleConfig("enabled")
|
|
|
- if checkLDAPenabled == "false" {
|
|
|
- common.SendTextResponse(w, "LDAP not enabled.")
|
|
|
- return
|
|
|
- }
|
|
|
- //get the parameter from the request
|
|
|
- acc, err := common.Mv(r, "username", false)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- displayname, err := common.Mv(r, "displayname", false)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- key, err := common.Mv(r, "authkey", false)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- //init the web interface
|
|
|
- imgsrc := "./web/" + ldap.iconSystem
|
|
|
- if !common.FileExists(imgsrc) {
|
|
|
- imgsrc = "./web/img/public/auth_icon.png"
|
|
|
- }
|
|
|
- imageBase64, _ := common.LoadImageAsBase64(imgsrc)
|
|
|
- template, err := common.Templateload("system/ldap/newPasswordTemplate.html", map[string]interface{}{
|
|
|
- "vendor_logo": imageBase64,
|
|
|
- "username": acc,
|
|
|
- "display_name": displayname,
|
|
|
- "key": key,
|
|
|
- })
|
|
|
- if err != nil {
|
|
|
- log.Fatal(err)
|
|
|
- }
|
|
|
- w.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
|
|
- w.Write([]byte(template))
|
|
|
-}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) HandleLogin(w http.ResponseWriter, r *http.Request) {
|
|
|
- checkLDAPenabled := ldap.readSingleConfig("enabled")
|
|
|
- if checkLDAPenabled == "false" {
|
|
|
- common.SendTextResponse(w, "LDAP not enabled.")
|
|
|
- return
|
|
|
- }
|
|
|
- //Get username from request using POST mode
|
|
|
- username, err := common.Mv(r, "username", true)
|
|
|
- if err != nil {
|
|
|
- //Username not defined
|
|
|
- log.Println("[System Auth] Someone trying to login with username: " + username)
|
|
|
- //Write to log
|
|
|
- ldap.ag.Logger.LogAuth(r, false)
|
|
|
- common.SendErrorResponse(w, "Username not defined or empty.")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- //Get password from request using POST mode
|
|
|
- password, err := common.Mv(r, "password", true)
|
|
|
- if err != nil {
|
|
|
- //Password not defined
|
|
|
- ldap.ag.Logger.LogAuth(r, false)
|
|
|
- common.SendErrorResponse(w, "Password not defined or empty.")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- //Get rememberme settings
|
|
|
- rememberme := false
|
|
|
- rmbme, _ := common.Mv(r, "rmbme", true)
|
|
|
- if rmbme == "true" {
|
|
|
- rememberme = true
|
|
|
- }
|
|
|
-
|
|
|
- //Check the database and see if this user is in the database
|
|
|
- passwordCorrect, err := ldap.ldapreader.Authenticate(username, password)
|
|
|
- if err != nil {
|
|
|
- ldap.ag.Logger.LogAuth(r, false)
|
|
|
- common.SendErrorResponse(w, "Unable to connect to LDAP server")
|
|
|
- log.Println("LDAP Authentication error, " + err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- //The database contain this user information. Check its password if it is correct
|
|
|
- if passwordCorrect {
|
|
|
- //Password correct
|
|
|
- //if user not exist then redirect to create pwd screen
|
|
|
- if !ldap.ag.UserExists(username) {
|
|
|
- authkey := ldap.syncdb.Store(username)
|
|
|
- common.SendJSONResponse(w, "{\"redirect\":\"system/auth/ldap/newPassword?username="+username+"&displayname="+username+"&authkey="+authkey+"\"}")
|
|
|
- } else {
|
|
|
- // Set user as authenticated
|
|
|
- ldap.ag.LoginUserByRequest(w, r, username, rememberme)
|
|
|
- //Print the login message to console
|
|
|
- log.Println(username + " logged in.")
|
|
|
- ldap.ag.Logger.LogAuth(r, true)
|
|
|
- common.SendOK(w)
|
|
|
- }
|
|
|
- } else {
|
|
|
- //Password incorrect
|
|
|
- log.Println(username + " has entered an invalid username or password")
|
|
|
- common.SendErrorResponse(w, "Invalid username or password")
|
|
|
- ldap.ag.Logger.LogAuth(r, false)
|
|
|
- return
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func (ldap *ldapHandler) HandleSetPassword(w http.ResponseWriter, r *http.Request) {
|
|
|
- checkLDAPenabled := ldap.readSingleConfig("enabled")
|
|
|
- if checkLDAPenabled == "false" {
|
|
|
- common.SendTextResponse(w, "LDAP not enabled.")
|
|
|
- return
|
|
|
- }
|
|
|
- //get paramters from request
|
|
|
- username, err := common.Mv(r, "username", true)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- password, err := common.Mv(r, "password", true)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- authkey, err := common.Mv(r, "authkey", true)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- //check if the input key matches the database's username
|
|
|
- isValid := ldap.syncdb.Read(authkey) == username
|
|
|
- ldap.syncdb.Delete(authkey) // remove the key, aka key is one time use only
|
|
|
- //if db data match the username, proceed
|
|
|
- if isValid {
|
|
|
- //if not exists
|
|
|
- if !ldap.ag.UserExists(username) {
|
|
|
- //get the user from ldap server
|
|
|
- ldapUser, err := ldap.ldapreader.GetUser(username)
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, err.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- //convert the ldap usergroup to arozos usergroup
|
|
|
- convertedInfo := ldap.convertGroup(ldapUser)
|
|
|
- //create user account and login
|
|
|
- ldap.ag.CreateUserAccount(username, password, convertedInfo.EquivGroup)
|
|
|
- ldap.ag.Logger.LogAuth(r, true)
|
|
|
- ldap.ag.LoginUserByRequest(w, r, username, false)
|
|
|
- common.SendOK(w)
|
|
|
- return
|
|
|
- } else {
|
|
|
- //if exist then return error
|
|
|
- common.SendErrorResponse(w, "User exists, please contact the system administrator if you believe this is an error.")
|
|
|
- return
|
|
|
- }
|
|
|
- } else {
|
|
|
- common.SendErrorResponse(w, "Improper key detected")
|
|
|
- log.Println(r.RemoteAddr + " attempted to use invaild key to create new user but failed")
|
|
|
- return
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//CheckOAuth check if oauth is enabled
|
|
|
-func (ldap *ldapHandler) HandleCheckLDAP(w http.ResponseWriter, r *http.Request) {
|
|
|
- enabledB := false
|
|
|
- enabled := ldap.readSingleConfig("enabled")
|
|
|
- if enabled == "true" {
|
|
|
- enabledB = true
|
|
|
- }
|
|
|
-
|
|
|
- type returnFormat struct {
|
|
|
- Enabled bool `json:"enabled"`
|
|
|
- }
|
|
|
- json, err := json.Marshal(returnFormat{Enabled: enabledB})
|
|
|
- if err != nil {
|
|
|
- common.SendErrorResponse(w, "Error occurred while marshalling JSON response")
|
|
|
- }
|
|
|
- common.SendJSONResponse(w, string(json))
|
|
|
-}
|