diff options
author | Alex Auvolat <alex@adnab.me> | 2020-02-09 17:45:22 +0100 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2020-02-09 17:45:22 +0100 |
commit | 27a411fe69cd3d8f669acb76b56d2390efc86deb (patch) | |
tree | 2a4e608f91036271412cd6f154e043f4587f497e | |
parent | 6297981c3bf01f94566ad76dc25b3b76c9c32029 (diff) | |
download | guichet-27a411fe69cd3d8f669acb76b56d2390efc86deb.tar.gz guichet-27a411fe69cd3d8f669acb76b56d2390efc86deb.zip |
Password change
-rw-r--r-- | go.mod | 1 | ||||
-rw-r--r-- | go.sum | 10 | ||||
-rw-r--r-- | main.go | 45 | ||||
-rw-r--r-- | ssha.go | 37 | ||||
-rw-r--r-- | templates/login.html | 1 | ||||
-rw-r--r-- | templates/passwd.html | 37 | ||||
-rw-r--r-- | templates/profile.html | 59 |
7 files changed, 160 insertions, 30 deletions
@@ -6,4 +6,5 @@ require ( github.com/go-ldap/ldap v3.0.3+incompatible github.com/go-ldap/ldap/v3 v3.1.6 github.com/gorilla/sessions v1.2.0 + github.com/sirupsen/logrus v1.4.2 ) @@ -1,3 +1,4 @@ +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-asn1-ber/asn1-ber v1.3.1 h1:gvPdv/Hr++TRFCl0UbPFHC54P9N9jgsRPnmnr419Uck= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk= @@ -8,3 +9,12 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -94,6 +94,7 @@ func main() { http.HandleFunc("/", handleHome) http.HandleFunc("/logout", handleLogout) http.HandleFunc("/profile", handleProfile) + http.HandleFunc("/passwd", handlePasswd) staticfiles := http.FileServer(http.Dir("static")) http.Handle("/static/", http.StripPrefix("/static/", staticfiles)) @@ -358,3 +359,47 @@ func handleProfile(w http.ResponseWriter, r *http.Request) { templateProfile.Execute(w, data) } + +type PasswdTplData struct { + Status *LoginStatus + ErrorMessage string + NoMatchError bool + Success bool +} + +func handlePasswd(w http.ResponseWriter, r *http.Request) { + templatePasswd := template.Must(template.ParseFiles("templates/layout.html", "templates/passwd.html")) + + login := checkLogin(w, r) + if login == nil { + return + } + + data := &PasswdTplData{ + Status: login, + ErrorMessage: "", + Success: false, + } + + if r.Method == "POST" { + r.ParseForm() + + password := strings.Join(r.Form["password"], "") + password2 := strings.Join(r.Form["password2"], "") + + if password2 != password { + data.NoMatchError = true + } else { + modify_request := ldap.NewModifyRequest(login.Info.DN, nil) + modify_request.Replace("userpassword", []string{SSHAEncode([]byte(password))}) + err := login.conn.Modify(modify_request) + if err != nil { + data.ErrorMessage = err.Error() + } else { + data.Success = true + } + } + } + + templatePasswd.Execute(w, data) +} @@ -0,0 +1,37 @@ +package main + +import ( + "crypto/rand" + "crypto/sha1" + "encoding/base64" + "fmt" + + log "github.com/sirupsen/logrus" +) + +// Encode encodes the []byte of raw password +func SSHAEncode(rawPassPhrase []byte) string { + hash := makeSSHAHash(rawPassPhrase, makeSalt()) + b64 := base64.StdEncoding.EncodeToString(hash) + return fmt.Sprintf("{ssha}%s", b64) +} + +// makeSalt make a 32 byte array containing random bytes. +func makeSalt() []byte { + sbytes := make([]byte, 32) + _, err := rand.Read(sbytes) + if err != nil { + log.Panicf("Could not read random bytes: %s", err) + } + return sbytes +} + +// makeSSHAHash make hasing using SHA-1 with salt. This is not the final output though. You need to append {SSHA} string with base64 of this hash. +func makeSSHAHash(passphrase, salt []byte) []byte { + sha := sha1.New() + sha.Write(passphrase) + sha.Write(salt) + + h := sha.Sum(nil) + return append(h, salt...) +} diff --git a/templates/login.html b/templates/login.html index 0801884..ed4d358 100644 --- a/templates/login.html +++ b/templates/login.html @@ -1,6 +1,7 @@ {{define "title"}}{{end}} {{define "body"}} +<h4>S'identifier</h4> <form method="POST"> {{if .ErrorMessage}} diff --git a/templates/passwd.html b/templates/passwd.html new file mode 100644 index 0000000..7dffcb8 --- /dev/null +++ b/templates/passwd.html @@ -0,0 +1,37 @@ +{{define "title"}}Mot de passe |{{end}} + +{{define "body"}} +<h4>Modifier mon mot de passe</h4> + + {{if .ErrorMessage}} + <div class="alert alert-danger">Impossible d'effectuer la modification. + <div style="font-size: 0.8em">{{ .ErrorMessage }}</div> + </div> + {{end}} + {{if .Success}} + <div class="alert alert-success"> + Nouveau mot de passe enregistré. + </div> + <a class="ml-auto btn btn-info" href="/">Retour</a> + {{else}} + <form method="POST"> + <div class="form-group"> + <label for="password">Nouveau mot de passe :</label> + <input type="password" id="password" name="password" class="form-control" /> + </div> + <div class="form-group"> + <label for="password2">Répéter le mot de passe :</label> + <input type="password" id="password2" name="password2" class="form-control" /> + </div> + {{if .NoMatchError}} + <div class="alert alert-warning"> + Les deux mots de passe entrés ne correspondent pas. + </div> + {{end}} + <div class="d-flex"> + <button type="submit" class="btn btn-primary">Changer de mot de passe</button> + <a class="ml-auto btn btn-danger" href="/">Annuler</a> + </div> + </form> + {{end}} +{{end}} diff --git a/templates/profile.html b/templates/profile.html index 24556fa..d2ff632 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -3,43 +3,42 @@ {{define "body"}} <h4>Modifier mon profil</h4> -<form method="POST"> {{if .ErrorMessage}} - <div class="alert alert-danger">Impossible de se connecter. + <div class="alert alert-danger">Impossible d'effectuer la modification. <div style="font-size: 0.8em">{{ .ErrorMessage }}</div> </div> {{end}} {{if .Success}} <div class="alert alert-success"> + Profil enregistré. + </div> + <a class="ml-auto btn btn-info" href="/">Retour</a> + {{else}} + <form method="POST"> + <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"> - <span>Profil enregistré.</span> - <a class="ml-auto btn btn-sm btn-info" href="/">Retour</a> + <button type="submit" class="btn btn-primary">Enregistrer les modifications</button> + <a class="ml-auto btn btn-danger" href="/">Annuler</a> </div> - </div> + </form> {{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}} |