diff --git a/server/bindata.go b/server/bindata.go index 0b4491930492ff71f0f864fc05619fb274c98959..7b071c3dfad361b5b22562c5d9e571abda771605 100644 --- a/server/bindata.go +++ b/server/bindata.go @@ -1173,13 +1173,15 @@ var _templatesLogin_passwordHtml = []byte(`{{template "header" .}} <input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required> + {{if .AccountRecoveryURL}} <p> <small> - <a href="/recovery"> + <a href="{{.AccountRecoveryURL}}"> Forgot your password? </a> </small> </p> + {{end}} <button type="submit" class="btn btn-lg btn-primary btn-block">Login</button> @@ -1198,7 +1200,7 @@ func templatesLogin_passwordHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/login_password.html", size: 1088, mode: os.FileMode(420), modTime: time.Unix(1541234797, 0)} + info := bindataFileInfo{name: "templates/login_password.html", size: 1149, mode: os.FileMode(420), modTime: time.Unix(1542882702, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/server/config.go b/server/config.go index 415c8e18985a20ddbbd958d55711fbc71920c122..d62160a8eefaf9f76d6dcb8ee582876203fe9fb7 100644 --- a/server/config.go +++ b/server/config.go @@ -39,6 +39,7 @@ type Config struct { DeviceManager *device.Config `yaml:"device_manager"` KeyStore *clientutil.BackendConfig `yaml:"keystore"` KeyStoreEnableGroups []string `yaml:"keystore_enable_groups"` + AccountRecoveryURL string `yaml:"account_recovery_url"` allowedServicesRx []*regexp.Regexp } diff --git a/server/http.go b/server/http.go index be96d516eefc0cc6e632d083df18a6ffeeab7d6e..9ee36963d1d8d1ac3bcb38ad518dc6c6cb2ac2c6 100644 --- a/server/http.go +++ b/server/http.go @@ -143,7 +143,9 @@ func New(loginService *LoginService, authClient authclient.Client, config *Confi if err != nil { return nil, err } - s.loginHandler = newLoginHandler(s.loginCallback, devMgr, authClient, config.AuthService, config.U2FAppID, config.URLPrefix, s.tpl, sessionSecrets...) + s.loginHandler = newLoginHandler(s.loginCallback, devMgr, authClient, + config.AuthService, config.U2FAppID, config.URLPrefix, config.AccountRecoveryURL, + s.tpl, sessionSecrets...) return s, nil } diff --git a/server/login.go b/server/login.go index 82b86fc3655c504eb1152d0e4d1e341c112837a9..8a182f1e230883f4614e0695ffbca3cfd8129bb7 100644 --- a/server/login.go +++ b/server/login.go @@ -72,19 +72,20 @@ func init() { type loginCallbackFunc func(http.ResponseWriter, *http.Request, string, string, *auth.UserInfo) error type loginHandler struct { - authClient authclient.Client - authService string - u2fAppID string - urlPrefix string - devMgr *device.Manager - loginCallback loginCallbackFunc - loginSessionStore sessions.Store - tpl *template.Template + authClient authclient.Client + authService string + u2fAppID string + urlPrefix string + devMgr *device.Manager + loginCallback loginCallbackFunc + loginSessionStore sessions.Store + tpl *template.Template + accountRecoveryURL string } // NewLoginHandler will wrap an http.Handler with the login workflow, // invoking it only on successful login. -func newLoginHandler(okHandler loginCallbackFunc, devMgr *device.Manager, authClient authclient.Client, authService, u2fAppID, urlPrefix string, tpl *template.Template, keyPairs ...[]byte) *loginHandler { +func newLoginHandler(okHandler loginCallbackFunc, devMgr *device.Manager, authClient authclient.Client, authService, u2fAppID, urlPrefix, accountRecoveryURL string, tpl *template.Template, keyPairs ...[]byte) *loginHandler { store := sessions.NewCookieStore(keyPairs...) store.Options = &sessions.Options{ HttpOnly: true, @@ -92,14 +93,15 @@ func newLoginHandler(okHandler loginCallbackFunc, devMgr *device.Manager, authCl MaxAge: 0, } return &loginHandler{ - authClient: authClient, - authService: authService, - u2fAppID: u2fAppID, - urlPrefix: strings.TrimRight(urlPrefix, "/"), - devMgr: devMgr, - loginCallback: okHandler, - loginSessionStore: store, - tpl: parseEmbeddedTemplates(), + authClient: authClient, + authService: authService, + u2fAppID: u2fAppID, + urlPrefix: strings.TrimRight(urlPrefix, "/"), + devMgr: devMgr, + loginCallback: okHandler, + loginSessionStore: store, + accountRecoveryURL: accountRecoveryURL, + tpl: parseEmbeddedTemplates(), } } @@ -334,6 +336,7 @@ func (l *loginHandler) makeLoginURL(req *http.Request) string { func (l *loginHandler) executeTemplateToBuffer(req *http.Request, templateName string, data map[string]interface{}) (loginState, []byte, error) { data["CSRFField"] = csrf.TemplateField(req) data["URLPrefix"] = l.urlPrefix + data["AccountRecoveryURL"] = l.accountRecoveryURL var buf bytes.Buffer if err := l.tpl.ExecuteTemplate(&buf, templateName, data); err != nil { return loginStateNone, nil, err diff --git a/server/templates/login_password.html b/server/templates/login_password.html index 78e34e92e0d2aec92e7cc14b7e803abacf2cc848..5b447823d5810c201f8d72c78f39320a9a546987 100644 --- a/server/templates/login_password.html +++ b/server/templates/login_password.html @@ -28,13 +28,15 @@ <input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required> + {{if .AccountRecoveryURL}} <p> <small> - <a href="/recovery"> + <a href="{{.AccountRecoveryURL}}"> Forgot your password? </a> </small> </p> + {{end}} <button type="submit" class="btn btn-lg btn-primary btn-block">Login</button>