summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Krogh <markus@nordu.net>2018-06-08 14:19:46 +0200
committerMarkus Krogh <markus@nordu.net>2018-06-08 14:19:46 +0200
commit8b7180f770d0cd63c8a3626f35ce6d8c06f54db4 (patch)
tree1fab6ac8a80c7c8020d8cba2678e73b7b9248d03
parent494303236fb55530a0f9e756babf2a79e4267a61 (diff)
Adding basepath and password strength
-rw-r--r--main.go49
-rw-r--r--static/css/main.css5
-rw-r--r--static/js/password_strength.js85
-rw-r--r--templates/change_ssh.html2
-rw-r--r--templates/changepw.html7
-rw-r--r--templates/index.html10
-rw-r--r--templates/layout/base.html6
-rw-r--r--views.go5
8 files changed, 118 insertions, 51 deletions
diff --git a/main.go b/main.go
index 4970e86..7bba68e 100644
--- a/main.go
+++ b/main.go
@@ -17,6 +17,7 @@ type PwmanServer struct {
Krb5Conf string
ChangePwScript string
RemoteUserHeader string
+ BasePath string
}
var pwman *PwmanServer
@@ -24,7 +25,7 @@ var pwman *PwmanServer
const csrf_base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._#%!&:;?+{}[]"
func main() {
- var ldapServer, ldapUser, ldapPassword, pwnedFile, krb5Conf, changePwScript, csrfSecret, serverAddr string
+ var ldapServer, ldapUser, ldapPassword, pwnedFile, krb5Conf, changePwScript, csrfSecret, serverAddr, basePath string
var ldapPort int
var ldapSkipSSLVerify, csrfInsecure, gennerateCsrfKey bool
flag.StringVar(&ldapServer, "ldap-server", "localhost", "the ldap server address")
@@ -37,6 +38,7 @@ func main() {
flag.StringVar(&changePwScript, "changepw-script", "./create-kdc-principal.pl", "Path to the change password script")
flag.StringVar(&csrfSecret, "csrf-secret", "", "Specify csrf 32 char secret")
flag.StringVar(&serverAddr, "address", ":3000", "Server address to listen on")
+ flag.StringVar(&basePath, "base-path", "", "A base path that pwman lives under e.g. /sso")
flag.BoolVar(&csrfInsecure, "csrf-insecure", false, "Allow csrf cookie to be sent over http")
flag.BoolVar(&gennerateCsrfKey, "gennerate-csrf", false, "Gennerate a csrf secret")
flag.Parse()
@@ -58,19 +60,19 @@ func main() {
Krb5Conf: krb5Conf,
ChangePwScript: changePwScript,
RemoteUserHeader: "X-Remote-User",
+ BasePath: basePath,
}
- base_path := "/sso"
v := Views()
mux := http.NewServeMux()
- mux.Handle(base_path+"/", FlashMessage(RemoteUser(v.Index())))
- mux.Handle(base_path+"/sso", FlashMessage(RemoteUser(v.ChangePassword("SSO"))))
- mux.Handle(base_path+"/tacacs", FlashMessage(RemoteUser(v.ChangePassword("TACACS"))))
- mux.Handle(base_path+"/eduroam", FlashMessage(RemoteUser(v.ChangePassword("eduroam"))))
- mux.Handle(base_path+"/pubkeys", FlashMessage(RemoteUser(v.ChangeSSHKeys())))
+ mux.Handle(basePath+"/", http.StripPrefix(basePath, FlashMessage(RemoteUser(v.Index()))))
+ mux.Handle(basePath+"/changepw/sso/", FlashMessage(RemoteUser(v.ChangePassword("SSO"))))
+ mux.Handle(basePath+"/changepw/tacacs/", FlashMessage(RemoteUser(v.ChangePassword("TACACS"))))
+ mux.Handle(basePath+"/changepw/eduroam/", FlashMessage(RemoteUser(v.ChangePassword("eduroam"))))
+ mux.Handle(basePath+"/pubkeys/", FlashMessage(RemoteUser(v.ChangeSSHKeys())))
- mux.Handle(base_path+"/static/", http.StripPrefix(base_path+"/static", http.FileServer(http.Dir("static"))))
+ mux.Handle(basePath+"/static/", http.StripPrefix(basePath+"/static", http.FileServer(http.Dir("static"))))
CSRF := csrf.Protect([]byte(csrfSecret), csrf.Secure(!csrfInsecure))
@@ -95,34 +97,3 @@ func gennerateCsrfSecret() string {
}
return string(b)
}
-
-//type CustomMux struct {
-// base_path string
-// mux *http.ServeMux
-//}
-//
-//func NewCustomMux(base_path string) *CustomMux {
-// return &CustomMux{base_path, http.NewServeMux()}
-//}
-//
-//func (m *CustomMux) Handle(path string, h http.Handler) {
-// m.mux.Handle(path, h)
-//}
-//
-//func (m *CustomMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-// clean_path := filepath.Clean(r.URL.Path)
-// log.Println(clean_path)
-// if !strings.HasPrefix(clean_path, m.base_path) {
-// http.NotFound(w, r)
-// return
-// }
-// r.URL.Path = clean_path[len(m.base_path):]
-// log.Println(clean_path[len(m.base_path):])
-// m.mux.ServeHTTP(w, r)
-//}
-
-//type RemoteUserMux map[string] http.Handler
-//
-//func (m RemoteUserMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-// handler, ok := m[r.URL.Path
-//}
diff --git a/static/css/main.css b/static/css/main.css
index 31caa19..f44e5a6 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -288,3 +288,8 @@ textarea {
background-color: #fff3cd;
border-color: #ffeeba;
}
+
+.password_strength {
+ text-align: right;
+ display: block;
+}
diff --git a/static/js/password_strength.js b/static/js/password_strength.js
new file mode 100644
index 0000000..af0b1c4
--- /dev/null
+++ b/static/js/password_strength.js
@@ -0,0 +1,85 @@
+(function(){
+
+function count(val, rxp){
+ const match = val.match(rxp)
+ return match ? match.length : 0
+}
+
+function passwordStrength(password, options={}) {
+ const opt = Object.assign(options,{
+ "minLength": 10,
+ "minOther": 3,
+ "texts" : [
+ 'Too weak',
+ 'Weak password',
+ 'Normal strength',
+ 'Strong password',
+ 'Very strong password'
+ ]
+ })
+
+
+ const len = password.length
+ if (len < opt["minLength"]) {
+ return opt["texts"][0];
+ }
+
+ const num = count(password, /\d/g),
+ lower = count(password, /[a-z]/g),
+ upper = count(password, /[A-Z]/g),
+ special = len - num - lower - upper,
+ other = num + special
+
+ if (lower == 0 || upper == 0 || other < opt["minOther"]) {
+ return opt["texts"][0];
+ }
+
+ // Strength is just based on password length
+ if (len < 11) {
+ return opt["texts"][1];
+ }else if (len < 13) {
+ return opt["texts"][2];
+ }else if (len < 16) {
+ return opt["texts"][3];
+ }else if (len >= 16) {
+ return opt["texts"][4];
+ }
+
+ // falltrough
+ return opt["texts"][1];
+}
+
+
+// auto setup for data-password-strength
+
+document.querySelectorAll("input[data-password-strength]").forEach( ($elm) => {
+ $elm.addEventListener("keyup", (e) => {
+ const val = $elm.value;
+ if (val.length > 0) {
+ // check if we have a .password_strength beside the field
+ let $info = $elm.parentNode.querySelector(".password_strength")
+ if (!$info) {
+ $info = document.createElement("span");
+ $info.classList.add("password_strength");
+ $elm.parentNode.appendChild($info);
+ }
+ $info.textContent = passwordStrength(val);
+ }
+ }, false)
+})
+
+
+document.querySelectorAll("input[data-same-as]").forEach( ($elm) => {
+ const $target = document.querySelector("#"+$elm.dataset.sameAs)
+ if ($target) {
+ $elm.addEventListener("keyup", (e) => {
+ if ($elm.value != $target.value) {
+ $elm.setCustomValidity("Passwords do not match")
+ }else{
+ $elm.setCustomValidity("");
+ }
+ })
+ }
+});
+
+})();
diff --git a/templates/change_ssh.html b/templates/change_ssh.html
index 96231a7..f87afce 100644
--- a/templates/change_ssh.html
+++ b/templates/change_ssh.html
@@ -27,6 +27,6 @@
</form>
<div class="column full">
- <a href=".">Back</a>
+ <a href="{{.BasePath}}/">Back</a>
</div>
{{ end }}
diff --git a/templates/changepw.html b/templates/changepw.html
index a7c1dc6..207ce7e 100644
--- a/templates/changepw.html
+++ b/templates/changepw.html
@@ -12,10 +12,10 @@
<br>
{{ .CsrfField }}
<label class="form-element-wrapper">New password
- <input type="password" name="new_password" class="form-element form-field" />
+ <input id="new_password" type="password" name="new_password" class="form-element form-field" data-password-strength />
</label>
<label class="form-element-wrapper">Repeat password
- <input type="password" name="new_password_again" class="form-element form-field" />
+ <input type="password" name="new_password_again" class="form-element form-field" data-same-as="new_password" />
</label>
<div class="form-element-wrapper">
<input type="submit" value="Change password" class="form-element form-button" />
@@ -23,6 +23,7 @@
</form>
<div class="column full">
- <a href=".">Back</a>
+ <a href="{{.BasePath}}/">Back</a>
</div>
+ <script src="{{.BasePath}}/static/js/password_strength.js"></script>
{{ end }}
diff --git a/templates/index.html b/templates/index.html
index 218ffe2..afadf8b 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -17,24 +17,24 @@
<h3>Available actions</h3>
<ul class="unstyled">
<li>
- <a href="sso"><span class="item-marker">›</span> Change single sign on (SSO) password</a>
+ <a href="{{$.BasePath}}/changepw/sso/"><span class="item-marker">›</span> Change single sign on (SSO) password</a>
</li>
{{ if .Staff }}
<li>
- <a href="tacacs"><span class="item-marker">›</span> Change TACACS password</a>
+ <a href="{{$.BasePath}}/changepw/tacacs/"><span class="item-marker">›</span> Change TACACS password</a>
</li>
{{ end }}
{{ if .Active }}
<li>
- <a href="eduroam"><span class="item-marker">›</span> Change eduroam password</a>
+ <a href="{{$.BasePath}}/changepw/eduroam/"><span class="item-marker">›</span> Change eduroam password</a>
</li>
{{ end }}
{{ if .Staff }}
<li>
- <a href="pubkeys"><span class="item-marker">›</span> Update your public SSH keys</a>
+ <a href="{{$.BasePath}}/pubkeys/"><span class="item-marker">›</span> Update your public SSH keys</a>
</li>
<li>
- <a href="ideviceconf" rel="external"><span class="item-marker">›</span> Configure eduroam on your iDevice</a>
+ <a href="{{$.BasePath}}/ideviceconf" rel="external"><span class="item-marker">›</span> Configure eduroam on your iDevice</a>
</li>
{{ end }}
</ul>
diff --git a/templates/layout/base.html b/templates/layout/base.html
index f041321..95a1c86 100644
--- a/templates/layout/base.html
+++ b/templates/layout/base.html
@@ -5,14 +5,14 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>{{block "title" .}}SSO Password Manager{{end}}</title>
- <link rel="stylesheet" type="text/css" href="static/css/main.css">
- <link href="static/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
+ <link rel="stylesheet" type="text/css" href="{{.BasePath}}/static/css/main.css">
+ <link href="{{.BasePath}}/static/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
</head>
<body>
<div class="wrapper">
<header>
<div class="container">
- <img src="static/images/nordunet.png" alt="NORDUnet Nordic Gateway for Research and Education">
+ <img src="{{.BasePath}}/static/images/nordunet.png" alt="NORDUnet Nordic Gateway for Research and Education">
</div>
</header>
<div class="container flex-group">
diff --git a/views.go b/views.go
index 6bc915f..a78f8c8 100644
--- a/views.go
+++ b/views.go
@@ -25,6 +25,10 @@ func Views() *views {
func (v *views) Index() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ if req.URL.Path != "/" {
+ http.NotFound(w, req)
+ return
+ }
if _, ok := req.Context().Value("user").(*User); ok {
err := v.templates["index"].ExecuteTemplate(w, "base", NewPageCtx(req))
if err != nil {
@@ -102,6 +106,7 @@ func NewPageCtx(req *http.Request) PageCtx {
"FlashClass": flash_class,
"User": user,
"CsrfField": csrf.TemplateField(req),
+ "BasePath": pwman.BasePath,
}
}