aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-02-09 17:45:22 +0100
committerAlex Auvolat <alex@adnab.me>2020-02-09 17:45:22 +0100
commit27a411fe69cd3d8f669acb76b56d2390efc86deb (patch)
tree2a4e608f91036271412cd6f154e043f4587f497e
parent6297981c3bf01f94566ad76dc25b3b76c9c32029 (diff)
downloadguichet-27a411fe69cd3d8f669acb76b56d2390efc86deb.tar.gz
guichet-27a411fe69cd3d8f669acb76b56d2390efc86deb.zip
Password change
-rw-r--r--go.mod1
-rw-r--r--go.sum10
-rw-r--r--main.go45
-rw-r--r--ssha.go37
-rw-r--r--templates/login.html1
-rw-r--r--templates/passwd.html37
-rw-r--r--templates/profile.html59
7 files changed, 160 insertions, 30 deletions
diff --git a/go.mod b/go.mod
index 76d92ca..ab70c69 100644
--- a/go.mod
+++ b/go.mod
@@ -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
)
diff --git a/go.sum b/go.sum
index b9d3f98..a0b62e4 100644
--- a/go.sum
+++ b/go.sum
@@ -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=
diff --git a/main.go b/main.go
index aa2bad7..cac2948 100644
--- a/main.go
+++ b/main.go
@@ -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)
+}
diff --git a/ssha.go b/ssha.go
new file mode 100644
index 0000000..fb7f3d8
--- /dev/null
+++ b/ssha.go
@@ -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}}