From e4cc8e9db38476889666f690af7afc34ab0d0c6f Mon Sep 17 00:00:00 2001 From: Chris Mann Date: Fri, 21 Jul 2023 06:23:03 +0200 Subject: [PATCH] Front-End Stuff --- Makefile | 2 +- main.go | 354 ++----------------------------------------------------- utils.go | 17 +-- 3 files changed, 16 insertions(+), 357 deletions(-) diff --git a/Makefile b/Makefile index db11b2d..a00d9ff 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ BIN=guichet -SRC=main.go ssha.go profile.go admin.go invite.go directory.go utils.go picture.go +SRC=main.go ssha.go profile.go admin.go invite.go directory.go utils.go picture.go login.go config.go DOCKER=lxpz/guichet_amd64 all: $(BIN) diff --git a/main.go b/main.go index f80235e..ddd0587 100644 --- a/main.go +++ b/main.go @@ -1,16 +1,23 @@ +/* +Guichet provides a user-management system around an LDAP Directory + +Oriniated with deuxfleurs.fr and advanced by resdigita.com +*/ package main import ( "crypto/rand" "crypto/tls" - "encoding/json" + + // "encoding/json" "flag" - "fmt" + // "fmt" "html/template" - "io/ioutil" + // "io/ioutil" "log" "net/http" - "os" + + // "os" "strings" "github.com/go-ldap/ldap/v3" @@ -18,52 +25,6 @@ import ( "github.com/gorilla/sessions" ) -type ConfigFile struct { - HttpBindAddr string `json:"http_bind_addr"` - LdapServerAddr string `json:"ldap_server_addr"` - LdapTLS bool `json:"ldap_tls"` - - BaseDN string `json:"base_dn"` - UserBaseDN string `json:"user_base_dn"` - UserNameAttr string `json:"user_name_attr"` - GroupBaseDN string `json:"group_base_dn"` - GroupNameAttr string `json:"group_name_attr"` - - MailingBaseDN string `json:"mailing_list_base_dn"` - MailingNameAttr string `json:"mailing_list_name_attr"` - MailingGuestsBaseDN string `json:"mailing_list_guest_user_base_dn"` - - InvitationBaseDN string `json:"invitation_base_dn"` - InvitationNameAttr string `json:"invitation_name_attr"` - InvitedMailFormat string `json:"invited_mail_format"` - InvitedAutoGroups []string `json:"invited_auto_groups"` - - WebAddress string `json:"web_address"` - MailFrom string `json:"mail_from"` - SMTPServer string `json:"smtp_server"` - SMTPUsername string `json:"smtp_username"` - SMTPPassword string `json:"smtp_password"` - - AdminAccount string `json:"admin_account"` - GroupCanInvite string `json:"group_can_invite"` - GroupCanAdmin string `json:"group_can_admin"` - - S3AdminEndpoint string `json:"s3_admin_endpoint"` - S3AdminToken string `json:"s3_admin_token"` - - S3Endpoint string `json:"s3_endpoint"` - S3AccessKey string `json:"s3_access_key"` - S3SecretKey string `json:"s3_secret_key"` - S3Region string `json:"s3_region"` - S3Bucket string `json:"s3_bucket"` - - Org string `json:"org"` -} - -var configFlag = flag.String("config", "./config.json", "Configuration file path") - -var config *ConfigFile - const SESSION_NAME = "guichet_session" var staticPath = "./static" @@ -71,43 +32,6 @@ var templatePath = "./templates" var store sessions.Store = nil -func readConfig() ConfigFile { - // Default configuration values for certain fields - config_file := ConfigFile{ - HttpBindAddr: ":9991", - LdapServerAddr: "ldap://127.0.0.1:389", - - UserNameAttr: "uid", - GroupNameAttr: "gid", - - InvitationNameAttr: "cn", - InvitedAutoGroups: []string{}, - - Org: "ResDigita", - } - - _, err := os.Stat(*configFlag) - if os.IsNotExist(err) { - log.Fatalf("Could not find Guichet configuration file at %s. Please create this file, for exemple starting with config.json.exemple and customizing it for your deployment.", *configFlag) - } - - if err != nil { - log.Fatal(err) - } - - bytes, err := ioutil.ReadFile(*configFlag) - if err != nil { - log.Fatal(err) - } - - err = json.Unmarshal(bytes, &config_file) - if err != nil { - log.Fatal(err) - } - - return config_file -} - func getTemplate(name string) *template.Template { return template.Must(template.New("layout.html").Funcs(template.FuncMap{ "contains": strings.Contains, @@ -167,31 +91,6 @@ func main() { } } -type LoginInfo struct { - Username string - DN string - Password string -} - -type LoginStatus struct { - Info *LoginInfo - conn *ldap.Conn - UserEntry *ldap.Entry - CanAdmin bool - CanInvite bool -} - -func (login *LoginStatus) WelcomeName() string { - ret := login.UserEntry.GetAttributeValue("givenname") - if ret == "" { - ret = login.UserEntry.GetAttributeValue("displayname") - } - if ret == "" { - ret = login.Info.Username - } - return ret -} - func logRequest(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL) @@ -199,142 +98,6 @@ func logRequest(handler http.Handler) http.Handler { }) } -func checkLogin(w http.ResponseWriter, r *http.Request) *LoginStatus { - var login_info *LoginInfo - - session, err := store.Get(r, SESSION_NAME) - if err == nil { - username, ok := session.Values["login_username"] - password, ok2 := session.Values["login_password"] - user_dn, ok3 := session.Values["login_dn"] - - if ok && ok2 && ok3 { - login_info = &LoginInfo{ - DN: user_dn.(string), - Username: username.(string), - Password: password.(string), - } - } - } - - if login_info == nil { - login_info = handleLogin(w, r) - if login_info == nil { - return nil - } - } - - l := ldapOpen(w) - if l == nil { - return nil - } - - err = l.Bind(login_info.DN, login_info.Password) - if err != nil { - delete(session.Values, "login_username") - delete(session.Values, "login_password") - delete(session.Values, "login_dn") - - err = session.Save(r, w) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return nil - } - return checkLogin(w, r) - } - - loginStatus := &LoginStatus{ - Info: login_info, - conn: l, - } - - requestKind := "(objectClass=organizationalPerson)" - if strings.EqualFold(login_info.DN, config.AdminAccount) { - requestKind = "(objectclass=*)" - } - searchRequest := ldap.NewSearchRequest( - login_info.DN, - ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false, - requestKind, - []string{ - "dn", - "displayname", - "givenname", - "sn", - "mail", - "cn", - "memberof", - "description", - "garage_s3_access_key", - }, - nil) -// FIELD_NAME_DIRECTORY_VISIBILITY, -// FIELD_NAME_PROFILE_PICTURE, - - sr, err := l.Search(searchRequest) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return nil - } - - if len(sr.Entries) != 1 { - http.Error(w, fmt.Sprintf("Unable to find entry for %s", login_info.DN), http.StatusInternalServerError) - return nil - } - - loginStatus.UserEntry = sr.Entries[0] - - loginStatus.CanAdmin = strings.EqualFold(loginStatus.Info.DN, config.AdminAccount) - loginStatus.CanInvite = false - - groups := []EntryName{} - searchRequest = ldap.NewSearchRequest( - config.GroupBaseDN, - ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, - fmt.Sprintf("(&(objectClass=groupOfNames)(member=%s))",login_info.DN), - []string{"dn", "displayName", "cn", "description"}, - nil) - // // log.Printf(fmt.Sprintf("708: %v",searchRequest)) - sr, err = l.Search(searchRequest) - // if err != nil { - // http.Error(w, err.Error(), http.StatusInternalServerError) - // return - // } - //// log.Printf(fmt.Sprintf("303: %v",sr.Entries)) - for _, ent := range sr.Entries { - // log.Printf(fmt.Sprintf("305: %v",ent.DN)) - groups = append(groups, EntryName{ - DN: ent.DN, - Name: ent.GetAttributeValue("cn"), - }) - // log.Printf(fmt.Sprintf("310: %v",config.GroupCanInvite)) - if config.GroupCanInvite != "" && strings.EqualFold(ent.DN, config.GroupCanInvite) { - loginStatus.CanInvite = true - } - // log.Printf(fmt.Sprintf("314: %v",config.GroupCanAdmin)) - if config.GroupCanAdmin != "" && strings.EqualFold(ent.DN, config.GroupCanAdmin) { - loginStatus.CanAdmin = true - } - } - - - - // for _, attr := range loginStatus.UserEntry.Attributes { - // if strings.EqualFold(attr.Name, "memberof") { - // for _, group := range attr.Values { - // if config.GroupCanInvite != "" && strings.EqualFold(group, config.GroupCanInvite) { - // loginStatus.CanInvite = true - // } - // if config.GroupCanAdmin != "" && strings.EqualFold(group, config.GroupCanAdmin) { - // loginStatus.CanAdmin = true - // } - // } - // } - // } - - return loginStatus -} - func ldapOpen(w http.ResponseWriter) *ldap.Conn { l, err := ldap.DialURL(config.LdapServerAddr) if err != nil { @@ -358,7 +121,7 @@ func ldapOpen(w http.ResponseWriter) *ldap.Conn { type HomePageData struct { Login *LoginStatus BaseDN string - Org string + Org string } func handleHome(w http.ResponseWriter, r *http.Request) { @@ -372,99 +135,8 @@ func handleHome(w http.ResponseWriter, r *http.Request) { data := &HomePageData{ Login: login, BaseDN: config.BaseDN, - Org: config.Org, + Org: config.Org, } templateHome.Execute(w, data) } - -func handleLogout(w http.ResponseWriter, r *http.Request) { - session, err := store.Get(r, SESSION_NAME) - if err != nil { - session, _ = store.New(r, SESSION_NAME) - } - - delete(session.Values, "login_username") - delete(session.Values, "login_password") - delete(session.Values, "login_dn") - - err = session.Save(r, w) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - http.Redirect(w, r, "/", http.StatusFound) -} - -type LoginFormData struct { - Username string - WrongUser bool - WrongPass bool - ErrorMessage string -} - -func handleLogin(w http.ResponseWriter, r *http.Request) *LoginInfo { - templateLogin := getTemplate("login.html") - - if r.Method == "GET" { - templateLogin.Execute(w, LoginFormData{}) - return nil - } else if r.Method == "POST" { - r.ParseForm() - - username := strings.Join(r.Form["username"], "") - password := strings.Join(r.Form["password"], "") - user_dn := fmt.Sprintf("%s=%s,%s", config.UserNameAttr, username, config.UserBaseDN) - if strings.EqualFold(username, config.AdminAccount) { - user_dn = username - } - - l := ldapOpen(w) - if l == nil { - return nil - } - - err := l.Bind(user_dn, password) - if err != nil { - data := &LoginFormData{ - Username: username, - } - if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) { - data.WrongPass = true - } else if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) { - data.WrongUser = true - } else { - data.ErrorMessage = err.Error() - } - templateLogin.Execute(w, data) - return nil - } - - // Successfully logged in, save it to session - session, err := store.Get(r, SESSION_NAME) - if err != nil { - session, _ = store.New(r, SESSION_NAME) - } - - session.Values["login_username"] = username - session.Values["login_password"] = password - session.Values["login_dn"] = user_dn - - err = session.Save(r, w) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return nil - } - - return &LoginInfo{ - DN: user_dn, - Username: username, - Password: password, - } - } else { - http.Error(w, "Unsupported method", http.StatusBadRequest) - return nil - } -} - diff --git a/utils.go b/utils.go index 3eab69e..974b8cf 100644 --- a/utils.go +++ b/utils.go @@ -4,22 +4,9 @@ import ( "fmt" "log" - "github.com/go-ldap/ldap/v3" - // "bytes" - // "crypto/rand" - - // "encoding/hex" - // "fmt" - // "html/template" - // "log" - // "net/http" - // "regexp" - // "strings" - // "github.com/emersion/go-sasl" - // "github.com/emersion/go-smtp" - // "github.com/gorilla/mux" - // "golang.org/x/crypto/argon2" "math/rand" + + "github.com/go-ldap/ldap/v3" ) type NewUser struct {