Profile modify

This commit is contained in:
Alex Auvolat 2020-02-09 17:35:16 +01:00
parent ebb7553cc8
commit 6297981c3b
3 changed files with 181 additions and 11 deletions

120
main.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"fmt"
"crypto/rand" "crypto/rand"
"crypto/tls" "crypto/tls"
"encoding/base64" "encoding/base64"
@ -92,6 +93,7 @@ func main() {
http.HandleFunc("/", handleHome) http.HandleFunc("/", handleHome)
http.HandleFunc("/logout", handleLogout) http.HandleFunc("/logout", handleLogout)
http.HandleFunc("/profile", handleProfile)
staticfiles := http.FileServer(http.Dir("static")) staticfiles := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", staticfiles)) http.Handle("/static/", http.StripPrefix("/static/", staticfiles))
@ -108,6 +110,12 @@ type LoginInfo struct {
Password string Password string
} }
type LoginStatus struct {
Info *LoginInfo
conn *ldap.Conn
UserEntry *ldap.Entry
}
func logRequest(handler http.Handler) http.Handler { func logRequest(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL) log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL)
@ -115,7 +123,7 @@ func logRequest(handler http.Handler) http.Handler {
}) })
} }
func checkLogin(w http.ResponseWriter, r *http.Request) *LoginInfo { func checkLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
session, err := store.Get(r, SESSION_NAME) session, err := store.Get(r, SESSION_NAME)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@ -125,17 +133,65 @@ func checkLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
username, ok := session.Values["login_username"] username, ok := session.Values["login_username"]
password, ok2 := session.Values["login_password"] password, ok2 := session.Values["login_password"]
user_dn, ok3 := session.Values["login_dn"] user_dn, ok3 := session.Values["login_dn"]
if !(ok && ok2 && ok3) {
return handleLogin(w, r)
}
return &LoginInfo{ var login_info *LoginInfo
if !(ok && ok2 && ok3) {
login_info = handleLogin(w, r)
if login_info == nil {
return nil
}
} else {
login_info = &LoginInfo{
DN: user_dn.(string), DN: user_dn.(string),
Username: username.(string), Username: username.(string),
Password: password.(string), Password: password.(string),
} }
} }
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)
}
searchRequest := ldap.NewSearchRequest(
login_info.DN,
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf("(&(objectClass=organizationalPerson))"),
[]string{"dn", "displayname", "givenname", "sn", "mail"},
nil)
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("Multiple entries: %#v", sr.Entries), http.StatusInternalServerError)
return nil
}
return &LoginStatus{
Info: login_info,
conn: l,
UserEntry: sr.Entries[0],
}
}
func ldapOpen(w http.ResponseWriter) *ldap.Conn { func ldapOpen(w http.ResponseWriter) *ldap.Conn {
l, err := ldap.DialURL(config.LdapServerAddr) l, err := ldap.DialURL(config.LdapServerAddr)
if err != nil { if err != nil {
@ -248,3 +304,57 @@ func handleLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
return nil return nil
} }
} }
type ProfileTplData struct {
Status *LoginStatus
ErrorMessage string
Success bool
Mail string
DisplayName string
GivenName string
Surname string
}
func handleProfile(w http.ResponseWriter, r *http.Request) {
templateProfile := template.Must(template.ParseFiles("templates/layout.html", "templates/profile.html"))
login := checkLogin(w, r)
if login == nil {
return
}
data := &ProfileTplData{
Status: login,
ErrorMessage: "",
Success: false,
}
if r.Method == "POST" {
r.ParseForm()
data.Mail = strings.Join(r.Form["mail"], "")
data.DisplayName = strings.Join(r.Form["display_name"], "")
data.GivenName = strings.Join(r.Form["given_name"], "")
data.Surname = strings.Join(r.Form["surname"], "")
modify_request := ldap.NewModifyRequest(login.Info.DN, nil)
modify_request.Replace("mail", []string{data.Mail})
modify_request.Replace("displayname", []string{data.DisplayName})
modify_request.Replace("givenname", []string{data.GivenName})
modify_request.Replace("sn", []string{data.Surname})
err := login.conn.Modify(modify_request)
if err != nil {
data.ErrorMessage = err.Error()
} else {
data.Success = true
}
} else {
data.Mail = login.UserEntry.GetAttributeValue("mail")
data.DisplayName = login.UserEntry.GetAttributeValue("displayname")
data.GivenName = login.UserEntry.GetAttributeValue("givenname")
data.Surname = login.UserEntry.GetAttributeValue("sn")
}
templateProfile.Execute(w, data)
}

View File

@ -1,17 +1,32 @@
{{define "title"}}Guichet{{end}} {{define "title"}}{{end}}
{{define "body"}} {{define "body"}}
<div class="alert alert-success"> <div class="alert alert-success">
Bienvenue, <strong>{{ .Username }}</strong> ! <div class="d-flex">
<span>Bienvenue, <strong>{{ .UserEntry.GetAttributeValue "givenname" }}</strong> !</span>
<a class="ml-auto btn btn-sm btn-dark" href="/logout">Se déconnecter</a>
</div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
Gérer mon compte Mon compte
</div> </div>
<div class="list-group list-group-flush"> <div class="list-group list-group-flush">
<a class="list-group-item list-group-item-action" href="/">Test</a> <a class="list-group-item list-group-item-action" href="/profile">Modifier mon profil</a>
<a class="list-group-item list-group-item-action" href="/logout">Se déconnecter</a> <a class="list-group-item list-group-item-action" href="/passwd">Modifier mon mot de passe</a>
<a class="list-group-item list-group-item-action" href="/invite">Inviter quelqu'un</a>
</div>
</div>
<div class="card mt-3">
<div class="card-header">
Administration
</div>
<div class="list-group list-group-flush">
<a class="list-group-item list-group-item-action" href="/admin/users">Utilisateurs</a>
<a class="list-group-item list-group-item-action" href="/admin/groups">Groupes</a>
<a class="list-group-item list-group-item-action" href="/admin/ldap">Explorateur LDAP</a>
</div> </div>
</div> </div>

45
templates/profile.html Normal file
View File

@ -0,0 +1,45 @@
{{define "title"}}Profile |{{end}}
{{define "body"}}
<h4>Modifier mon profil</h4>
<form method="POST">
{{if .ErrorMessage}}
<div class="alert alert-danger">Impossible de se connecter.
<div style="font-size: 0.8em">{{ .ErrorMessage }}</div>
</div>
{{end}}
{{if .Success}}
<div class="alert alert-success">
<div class="d-flex">
<span>Profil enregistré.</span>
<a class="ml-auto btn btn-sm btn-info" href="/">Retour</a>
</div>
</div>
{{end}}
<div class="form-group">
<label>Nom d'utilisateur:</label>
<input type="text" disabled="true" class="form-control" value="{{ .Status.Info.Username }}" />
</div>
<div class="form-group">
<label for="mail">Adresse e-mail:</label>
<input type="text" id="mail" name="mail" class="form-control" value="{{ .Mail }}" />
</div>
<div class="form-group">
<label for="display_name">Nom complet:</label>
<input type="text" id="display_name" name="display_name" class="form-control" value="{{ .DisplayName }}" />
</div>
<div class="form-group">
<label for="given_name">Prénom:</label>
<input type="text" id="given_name" name="given_name" class="form-control" value="{{ .GivenName }}" />
</div>
<div class="form-group">
<label for="surname">Nom de famille:</label>
<input type="text" id="surname" name="surname" class="form-control" value="{{ .Surname }}" />
</div>
<div class="d-flex">
<button type="submit" class="btn btn-primary">Enregistrer les modifications</button>
<a class="ml-auto btn btn-danger" href="/">Annuler</a>
</div>
</form>
{{end}}