1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-01-10 04:17:59 +02:00

Split 2fa pages apart

- Add a config option to control the authboss.Middleware redirecting
This commit is contained in:
Aaron L 2018-09-03 11:57:25 -07:00
parent 5af4d392ab
commit 4420666f2b
8 changed files with 103 additions and 168 deletions

View File

@ -90,11 +90,12 @@ type Config struct {
// for google authenticator.
TOTP2FAIssuer string
// TwoFactorRedirectOnUnauthed controls whether or not a user is redirected or given
// a 404 when they are unauthenticated. The two factor modules all use authboss.Middleware
// to protect their routes and this is the redirectToLogin parameter in that middleware
// that they pass through.
TwoFactorRedirectOnUnauthed bool
// RoutesRedirectOnUnauthed controls whether or not a user is redirected or given
// a 404 when they are unauthenticated and attempting to access a route that's
// login-protected inside Authboss itself. The otp/twofactor modules all use
// authboss.Middleware to protect their routes and this is the
// redirectToLogin parameter in that middleware that they pass through.
RoutesRedirectOnUnauthed bool
}
Mail struct {

View File

@ -268,13 +268,13 @@ func (h HTTPBodyReader) Read(page string, r *http.Request) (authboss.Validator,
Token: values[FormValueToken],
NewPassword: values[FormValuePassword],
}, nil
case "totp2fa_validate":
case "totp2fa_confirm", "totp2fa_remove", "totp2fa_validate":
return TwoFA{
HTTPFormValidator: HTTPFormValidator{Values: values, Ruleset: rules, ConfirmFields: confirms},
Code: values[FormValueCode],
RecoveryCode: values[FormValueRecoveryCode],
}, nil
case "sms2fa_validate":
case "sms2fa_setup", "sms2fa_remove", "sms2fa_confirm", "sms2fa_validate":
return SMSTwoFA{
HTTPFormValidator: HTTPFormValidator{Values: values, Ruleset: rules, ConfirmFields: confirms},
Code: values[FormValueCode],

View File

@ -75,7 +75,7 @@ func (o *OTP) Init(ab *authboss.Authboss) (err error) {
o.Authboss.Config.Core.Router.Get("/otp/login", o.Authboss.Core.ErrorHandler.Wrap(o.LoginGet))
o.Authboss.Config.Core.Router.Post("/otp/login", o.Authboss.Core.ErrorHandler.Wrap(o.LoginPost))
middleware := authboss.MountedMiddleware(ab, true, true, false, false)
middleware := authboss.MountedMiddleware(ab, true, ab.Config.Modules.RoutesRedirectOnUnauthed, false, false)
o.Authboss.Config.Core.Router.Get("/otp/add", middleware(o.Authboss.Core.ErrorHandler.Wrap(o.AddGet)))
o.Authboss.Config.Core.Router.Post("/otp/add", middleware(o.Authboss.Core.ErrorHandler.Wrap(o.AddPost)))

View File

@ -32,20 +32,20 @@ const (
// Pages
const (
PageSMSValidate = "sms2fa_validate"
PageSMSValidateSuccess = "sms2fa_validate_success"
successSuffix = "_success"
PageSMSConfirm = "sms2fa_confirm"
PageSMSConfirmSuccess = "sms2fa_confirm_success"
PageSMSRemove = "sms2fa_remove"
PageSMSRemoveSuccess = "sms2fa_remove_success"
PageSMSSetup = "sms2fa_setup"
PageSMSValidate = "sms2fa_validate"
)
// Data constants
const (
DataValidateMode = "validate_mode"
DataSMSSecret = SessionSMSSecret
DataSMSPhoneNumber = "sms_phone_number"
dataValidate = "validate"
dataValidateSetup = "setup"
dataValidateConfirm = "confirm"
dataValidateRemove = "remove"
)
const (
@ -88,7 +88,7 @@ type SMS struct {
// SMSValidator abstracts the send code/resend code/submit code workflow
type SMSValidator struct {
*SMS
Action string
Page string
}
// Setup the module
@ -97,25 +97,32 @@ func (s *SMS) Setup() error {
return errors.New("must have SMS.Sender set")
}
middleware := authboss.MountedMiddleware(s.Authboss, true, s.Authboss.Config.Modules.TwoFactorRedirectOnUnauthed, false, false)
middleware := authboss.MountedMiddleware(s.Authboss, true, s.Authboss.Config.Modules.RoutesRedirectOnUnauthed, false, false)
s.Authboss.Core.Router.Get("/2fa/sms/setup", middleware(s.Core.ErrorHandler.Wrap(s.GetSetup)))
s.Authboss.Core.Router.Post("/2fa/sms/setup", middleware(s.Core.ErrorHandler.Wrap(s.PostSetup)))
confirm := &SMSValidator{SMS: s, Action: dataValidateConfirm}
confirm := &SMSValidator{SMS: s, Page: PageSMSConfirm}
s.Authboss.Core.Router.Get("/2fa/sms/confirm", middleware(s.Core.ErrorHandler.Wrap(confirm.Get)))
s.Authboss.Core.Router.Post("/2fa/sms/confirm", middleware(s.Core.ErrorHandler.Wrap(confirm.Post)))
remove := &SMSValidator{SMS: s, Action: dataValidateRemove}
remove := &SMSValidator{SMS: s, Page: PageSMSRemove}
s.Authboss.Core.Router.Get("/2fa/sms/remove", middleware(s.Core.ErrorHandler.Wrap(remove.Get)))
s.Authboss.Core.Router.Post("/2fa/sms/remove", middleware(s.Core.ErrorHandler.Wrap(remove.Post)))
validate := &SMSValidator{SMS: s, Action: dataValidate}
validate := &SMSValidator{SMS: s, Page: PageSMSValidate}
s.Authboss.Core.Router.Get("/2fa/sms/validate", s.Core.ErrorHandler.Wrap(validate.Get))
s.Authboss.Core.Router.Post("/2fa/sms/validate", s.Core.ErrorHandler.Wrap(validate.Post))
s.Authboss.Events.Before(authboss.EventAuth, s.BeforeAuth)
return s.Authboss.Core.ViewRenderer.Load(PageSMSValidate, PageSMSValidateSuccess)
return s.Authboss.Core.ViewRenderer.Load(
PageSMSConfirm,
PageSMSConfirmSuccess,
PageSMSRemove,
PageSMSRemoveSuccess,
PageSMSSetup,
PageSMSValidate,
)
}
// BeforeAuth stores the user's pid in a special temporary session variable
@ -197,18 +204,18 @@ func (s *SMS) GetSetup(w http.ResponseWriter, r *http.Request) error {
return err
}
data := authboss.HTMLData{DataValidateMode: dataValidateSetup}
var data authboss.HTMLData
numberProvider, ok := abUser.(SMSNumberProvider)
if ok {
if val := numberProvider.GetSMSPhoneNumberSeed(); len(val) != 0 {
data[DataSMSPhoneNumber] = val
data = authboss.HTMLData{DataSMSPhoneNumber: val}
}
}
authboss.DelSession(w, SessionSMSSecret)
authboss.DelSession(w, SessionSMSNumber)
return s.Core.Responder.Respond(w, r, http.StatusOK, PageSMSValidate, data)
return s.Core.Responder.Respond(w, r, http.StatusOK, PageSMSSetup, data)
}
// PostSetup adds the phone number provided to the user's session and sends
@ -220,7 +227,7 @@ func (s *SMS) PostSetup(w http.ResponseWriter, r *http.Request) error {
}
user := abUser.(User)
validator, err := s.Authboss.Config.Core.BodyReader.Read(PageSMSValidate, r)
validator, err := s.Authboss.Config.Core.BodyReader.Read(PageSMSSetup, r)
if err != nil {
return err
}
@ -231,9 +238,8 @@ func (s *SMS) PostSetup(w http.ResponseWriter, r *http.Request) error {
if len(number) == 0 {
data := authboss.HTMLData{
authboss.DataValidation: map[string][]string{FormValuePhoneNumber: []string{"must provide a phone number"}},
DataValidateMode: dataValidateSetup,
}
return s.Core.Responder.Respond(w, r, http.StatusOK, PageSMSValidate, data)
return s.Core.Responder.Respond(w, r, http.StatusOK, PageSMSSetup, data)
}
authboss.PutSession(w, SessionSMSNumber, number)
@ -251,8 +257,7 @@ func (s *SMS) PostSetup(w http.ResponseWriter, r *http.Request) error {
// Get shows an empty page typically, this allows us to prompt
// a second time for the action.
func (s *SMSValidator) Get(w http.ResponseWriter, r *http.Request) error {
data := authboss.HTMLData{DataValidateMode: s.Action}
return s.Core.Responder.Respond(w, r, http.StatusOK, PageSMSValidate, data)
return s.Core.Responder.Respond(w, r, http.StatusOK, s.Page, nil)
}
// Post receives a code in the body and validates it, if the code is
@ -273,7 +278,7 @@ func (s *SMSValidator) Post(w http.ResponseWriter, r *http.Request) error {
}
user := abUser.(User)
validator, err := s.Authboss.Config.Core.BodyReader.Read(PageSMSValidate, r)
validator, err := s.Authboss.Config.Core.BodyReader.Read(s.Page, r)
if err != nil {
return err
}
@ -283,7 +288,7 @@ func (s *SMSValidator) Post(w http.ResponseWriter, r *http.Request) error {
inputCode = smsCodeValues.GetCode()
// Only allow recovery codes on login/remove operations
if s.Action == dataValidate || s.Action == dataValidateRemove {
if s.Page == PageSMSValidate || s.Page == PageSMSRemove {
recoveryCode = smsCodeValues.GetRecoveryCode()
}
@ -303,15 +308,15 @@ func (s *SMSValidator) sendCode(w http.ResponseWriter, r *http.Request, user Use
// Get the phone number, when we're confirming the phone number is not
// yet stored in the user but inside the session.
switch s.Action {
case dataValidateConfirm:
switch s.Page {
case PageSMSConfirm:
var ok bool
phoneNumber, ok = authboss.GetSession(r, SessionSMSNumber)
if !ok {
return errors.New("request failed, no sms number present in session")
}
case dataValidate, dataValidateRemove:
case PageSMSValidate, PageSMSRemove:
phoneNumber = user.GetSMSPhoneNumber()
}
@ -319,16 +324,15 @@ func (s *SMSValidator) sendCode(w http.ResponseWriter, r *http.Request, user Use
return errors.Errorf("no phone number was available in PostSendCode for user %s", user.GetPID())
}
data := authboss.HTMLData{DataValidateMode: s.Action}
var data authboss.HTMLData
err := s.SendCodeToUser(w, r, user.GetPID(), phoneNumber)
if err == errSMSRateLimit {
data[authboss.DataErr] = "please wait a few moments before resending SMS code"
data = authboss.HTMLData{authboss.DataErr: "please wait a few moments before resending SMS code"}
} else if err != nil {
return err
}
return s.Core.Responder.Respond(w, r, http.StatusOK, PageSMSValidate, data)
return s.Core.Responder.Respond(w, r, http.StatusOK, s.Page, data)
}
func (s *SMSValidator) validateCode(w http.ResponseWriter, r *http.Request, user User, inputCode, recoveryCode string) error {
@ -362,17 +366,14 @@ func (s *SMSValidator) validateCode(w http.ResponseWriter, r *http.Request, user
logger.Infof("user %s sms 2fa failure (wrong code)", user.GetPID())
data := authboss.HTMLData{
authboss.DataValidation: map[string][]string{FormValueCode: []string{"2fa code was invalid"}},
DataValidateMode: s.Action,
}
return s.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageSMSValidate, data)
return s.Authboss.Core.Responder.Respond(w, r, http.StatusOK, s.Page, data)
}
data := authboss.HTMLData{
DataValidateMode: s.Action,
}
var data authboss.HTMLData
switch s.Action {
case dataValidateConfirm:
switch s.Page {
case PageSMSConfirm:
phoneNumber, ok := authboss.GetSession(r, SessionSMSNumber)
if !ok {
return errors.New("request failed, no sms number present in session")
@ -399,8 +400,8 @@ func (s *SMSValidator) validateCode(w http.ResponseWriter, r *http.Request, user
authboss.DelSession(w, SessionSMSNumber)
logger.Infof("user %s enabled sms 2fa", user.GetPID())
data[twofactor.DataRecoveryCodes] = codes
case dataValidateRemove:
data = authboss.HTMLData{twofactor.DataRecoveryCodes: codes}
case PageSMSRemove:
user.PutSMSPhoneNumber("")
if err := s.Authboss.Config.Storage.Server.Save(r.Context(), user); err != nil {
return err
@ -409,7 +410,7 @@ func (s *SMSValidator) validateCode(w http.ResponseWriter, r *http.Request, user
authboss.DelSession(w, authboss.Session2FA)
logger.Infof("user %s disabled sms 2fa", user.GetPID())
case dataValidate:
case PageSMSValidate:
authboss.PutSession(w, authboss.SessionKey, user.GetPID())
authboss.PutSession(w, authboss.Session2FA, "sms")
@ -430,7 +431,7 @@ func (s *SMSValidator) validateCode(w http.ResponseWriter, r *http.Request, user
return errors.New("unknown action for sms validate")
}
return s.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageSMSValidateSuccess, data)
return s.Authboss.Core.Responder.Respond(w, r, http.StatusOK, s.Page+successSuffix, data)
}
// generateRandomCode for sms auth

View File

@ -242,12 +242,9 @@ func TestGetSetup(t *testing.T) {
t.Error("session sms number should be cleared")
}
if h.responder.Page != PageSMSValidate {
if h.responder.Page != PageSMSSetup {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateSetup {
t.Error("data wrong:", got)
}
if got := h.responder.Data[DataSMSPhoneNumber]; got != "seednumber" {
t.Error("data wrong:", got)
}
@ -271,12 +268,9 @@ func TestPostSetup(t *testing.T) {
t.Error(err)
}
if h.responder.Page != PageSMSValidate {
if h.responder.Page != PageSMSSetup {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateSetup {
t.Error("data wrong:", got)
}
validation := h.responder.Data[authboss.DataValidation].(map[string][]string)
if got := validation[FormValuePhoneNumber][0]; got != "must provide a phone number" {
t.Error("data wrong:", got)
@ -327,26 +321,23 @@ func TestValidatorGet(t *testing.T) {
t.Parallel()
h := testSetup()
validator := &SMSValidator{SMS: h.sms, Action: dataValidateConfirm}
validator := &SMSValidator{SMS: h.sms, Page: PageSMSConfirm}
r, w, _ := h.newHTTP("GET")
if err := validator.Get(w, r); err != nil {
t.Fatal(err)
}
if h.responder.Page != PageSMSValidate {
if h.responder.Page != PageSMSConfirm {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateConfirm {
t.Error("data wrong:", got)
}
}
func TestValidatorPostSend(t *testing.T) {
t.Parallel()
h := testSetup()
validator := &SMSValidator{SMS: h.sms, Action: dataValidate}
validator := &SMSValidator{SMS: h.sms, Page: PageSMSValidate}
r, w, _ := h.newHTTP("POST")
@ -368,7 +359,7 @@ func TestValidatorPostSend(t *testing.T) {
// When action is confirm, it retrieves the phone number from
// the session, not the user.
validator.Action = dataValidateConfirm
validator.Page = PageSMSConfirm
user.SMSPhoneNumber = ""
h.setSession(SessionSMSNumber, "number")
h.loadClientState(w, &r)
@ -382,17 +373,13 @@ func TestValidatorPostSend(t *testing.T) {
}
}
// recovery code, normal code
// user in session, user in pending
// successful code paths for: validate, remove, and confirm
func TestValidatorPostOk(t *testing.T) {
t.Parallel()
t.Run("OkConfirm", func(t *testing.T) {
h := testSetup()
r, w, _ := h.newHTTP("POST")
v := &SMSValidator{SMS: h.sms, Action: dataValidateConfirm}
v := &SMSValidator{SMS: h.sms, Page: PageSMSConfirm}
user := &mocks.User{Email: "test@test.com"}
h.storer.Users[user.Email] = user
@ -412,12 +399,9 @@ func TestValidatorPostOk(t *testing.T) {
// Flush client state
w.WriteHeader(http.StatusOK)
if h.responder.Page != PageSMSValidateSuccess {
if h.responder.Page != PageSMSConfirmSuccess {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateConfirm {
t.Error("data wrong:", got)
}
if got := h.responder.Data[twofactor.DataRecoveryCodes].([]string); len(got) == 0 {
t.Error("recovery codes should have been returned")
}
@ -440,7 +424,7 @@ func TestValidatorPostOk(t *testing.T) {
t.Run("OkRemoveWithRecovery", func(t *testing.T) {
h := testSetup()
r, w, _ := h.newHTTP("POST")
v := &SMSValidator{SMS: h.sms, Action: dataValidateRemove}
v := &SMSValidator{SMS: h.sms, Page: PageSMSRemove}
user := &mocks.User{Email: "test@test.com", SMSPhoneNumber: "number"}
h.storer.Users[user.Email] = user
@ -468,12 +452,9 @@ func TestValidatorPostOk(t *testing.T) {
// Flush client state
w.WriteHeader(http.StatusOK)
if h.responder.Page != PageSMSValidateSuccess {
if h.responder.Page != PageSMSRemoveSuccess {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateRemove {
t.Error("data wrong:", got)
}
if h.session.ClientValues[authboss.Session2FA] != "" {
t.Error("session 2fa should be cleared")
@ -490,7 +471,7 @@ func TestValidatorPostOk(t *testing.T) {
t.Run("OkValidateWithCode", func(t *testing.T) {
h := testSetup()
r, w, _ := h.newHTTP("POST")
v := &SMSValidator{SMS: h.sms, Action: dataValidate}
v := &SMSValidator{SMS: h.sms, Page: PageSMSValidate}
user := &mocks.User{Email: "test@test.com", SMSPhoneNumber: "number"}
h.storer.Users[user.Email] = user
@ -550,7 +531,7 @@ func TestValidatorPostOk(t *testing.T) {
t.Run("FailRemoveCode", func(t *testing.T) {
h := testSetup()
r, w, _ := h.newHTTP("POST")
v := &SMSValidator{SMS: h.sms, Action: dataValidateRemove}
v := &SMSValidator{SMS: h.sms, Page: PageSMSRemove}
user := &mocks.User{Email: "test@test.com"}
h.storer.Users[user.Email] = user
@ -565,12 +546,9 @@ func TestValidatorPostOk(t *testing.T) {
t.Fatal(err)
}
if h.responder.Page != PageSMSValidate {
if h.responder.Page != PageSMSRemove {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateRemove {
t.Error("data wrong:", got)
}
validation := h.responder.Data[authboss.DataValidation].(map[string][]string)
if got := validation[FormValueCode][0]; got != "2fa code was invalid" {
t.Error("data wrong:", got)

View File

@ -29,8 +29,12 @@ const (
// Pages
const (
PageTOTPValidate = "totp2fa_validate"
PageTOTPValidateSuccess = "totp2fa_validate_success"
PageTOTPConfirm = "totp2fa_confirm"
PageTOTPConfirmSuccess = "totp2fa_confirm_success"
PageTOTPRemove = "totp2fa_remove"
PageTOTPRemoveSuccess = "totp2fa_remove_success"
PageTOTPSetup = "totp2fa_setup"
PageTOTPValidate = "totp2fa_validate"
)
// Form value constants
@ -40,13 +44,7 @@ const (
// Data constants
const (
DataValidateMode = "validate_mode"
DataTOTPSecret = SessionTOTPSecret
dataValidate = "validate"
dataValidateSetup = "setup"
dataValidateConfirm = "confirm"
dataValidateRemove = "remove"
DataTOTPSecret = SessionTOTPSecret
)
var (
@ -68,7 +66,7 @@ type TOTP struct {
// Setup the module
func (t *TOTP) Setup() error {
middleware := authboss.MountedMiddleware(t.Authboss, true, t.Authboss.Config.Modules.TwoFactorRedirectOnUnauthed, true, false)
middleware := authboss.MountedMiddleware(t.Authboss, true, t.Authboss.Config.Modules.RoutesRedirectOnUnauthed, true, false)
t.Authboss.Core.Router.Get("/2fa/totp/setup", middleware(t.Core.ErrorHandler.Wrap(t.GetSetup)))
t.Authboss.Core.Router.Post("/2fa/totp/setup", middleware(t.Core.ErrorHandler.Wrap(t.PostSetup)))
@ -85,7 +83,14 @@ func (t *TOTP) Setup() error {
t.Authboss.Events.Before(authboss.EventAuth, t.BeforeAuth)
return t.Authboss.Core.ViewRenderer.Load(PageTOTPValidate, PageTOTPValidateSuccess)
return t.Authboss.Core.ViewRenderer.Load(
PageTOTPSetup,
PageTOTPValidate,
PageTOTPConfirm,
PageTOTPConfirmSuccess,
PageTOTPRemove,
PageTOTPRemoveSuccess,
)
}
// BeforeAuth stores the user's pid in a special temporary session variable
@ -117,8 +122,7 @@ func (t *TOTP) BeforeAuth(w http.ResponseWriter, r *http.Request, handled bool)
// GetSetup shows a screen allows a user to opt in to setting up totp 2fa
func (t *TOTP) GetSetup(w http.ResponseWriter, r *http.Request) error {
authboss.DelSession(w, SessionTOTPSecret)
data := authboss.HTMLData{DataValidateMode: dataValidateSetup}
return t.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
return t.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPSetup, nil)
}
// PostSetup prepares adds a key to the user's session
@ -203,11 +207,8 @@ func (t *TOTP) GetConfirm(w http.ResponseWriter, r *http.Request) error {
return errors.New("request failed, no totp secret present in session")
}
data := authboss.HTMLData{
DataValidateMode: dataValidateConfirm,
DataTOTPSecret: totpSecret,
}
return t.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
data := authboss.HTMLData{DataTOTPSecret: totpSecret}
return t.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPConfirm, data)
}
// PostConfirm finally activates totp if the code matches
@ -223,7 +224,7 @@ func (t *TOTP) PostConfirm(w http.ResponseWriter, r *http.Request) error {
return errors.New("request failed, no totp secret present in session")
}
validator, err := t.Authboss.Config.Core.BodyReader.Read(PageTOTPValidate, r)
validator, err := t.Authboss.Config.Core.BodyReader.Read(PageTOTPConfirm, r)
if err != nil {
return err
}
@ -235,10 +236,9 @@ func (t *TOTP) PostConfirm(w http.ResponseWriter, r *http.Request) error {
if !ok {
data := authboss.HTMLData{
authboss.DataValidation: map[string][]string{FormValueCode: []string{"2fa code was invalid"}},
DataValidateMode: dataValidateConfirm,
DataTOTPSecret: totpSecret,
}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPConfirm, data)
}
codes, err := twofactor.GenerateRecoveryCodes()
@ -263,18 +263,13 @@ func (t *TOTP) PostConfirm(w http.ResponseWriter, r *http.Request) error {
logger := t.RequestLogger(r)
logger.Infof("user %s enabled totp 2fa", user.GetPID())
data := authboss.HTMLData{
twofactor.DataRecoveryCodes: codes,
DataValidateMode: dataValidateConfirm,
}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidateSuccess, data)
data := authboss.HTMLData{twofactor.DataRecoveryCodes: codes}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPConfirmSuccess, data)
}
// GetRemove starts removal
func (t *TOTP) GetRemove(w http.ResponseWriter, r *http.Request) error {
data := authboss.HTMLData{DataValidateMode: dataValidateRemove}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPRemove, nil)
}
// PostRemove removes totp
@ -282,19 +277,15 @@ func (t *TOTP) PostRemove(w http.ResponseWriter, r *http.Request) error {
user, ok, err := t.validate(r)
switch {
case err == errNoTOTPEnabled:
data := authboss.HTMLData{
authboss.DataErr: "totp 2fa not active",
DataValidateMode: dataValidateRemove,
}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
data := authboss.HTMLData{authboss.DataErr: "totp 2fa not active"}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPRemove, data)
case err != nil:
return err
case !ok:
data := authboss.HTMLData{
authboss.DataValidation: map[string][]string{FormValueCode: []string{"2fa code was invalid"}},
DataValidateMode: dataValidateRemove,
}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPRemove, data)
}
authboss.DelSession(w, authboss.Session2FA)
@ -306,14 +297,12 @@ func (t *TOTP) PostRemove(w http.ResponseWriter, r *http.Request) error {
logger := t.RequestLogger(r)
logger.Infof("user %s disabled totp 2fa", user.GetPID())
data := authboss.HTMLData{DataValidateMode: dataValidateRemove}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidateSuccess, data)
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPRemoveSuccess, nil)
}
// GetValidate shows a page to enter a code into
func (t *TOTP) GetValidate(w http.ResponseWriter, r *http.Request) error {
data := authboss.HTMLData{DataValidateMode: dataValidate}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, nil)
}
// PostValidate redirects on success
@ -324,10 +313,7 @@ func (t *TOTP) PostValidate(w http.ResponseWriter, r *http.Request) error {
switch {
case err == errNoTOTPEnabled:
logger.Infof("user %s totp failure (not enabled)", user.GetPID())
data := authboss.HTMLData{
authboss.DataErr: "totp 2fa not active",
DataValidateMode: dataValidate,
}
data := authboss.HTMLData{authboss.DataErr: "totp 2fa not active"}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
case err != nil:
return err
@ -335,7 +321,6 @@ func (t *TOTP) PostValidate(w http.ResponseWriter, r *http.Request) error {
logger.Infof("user %s totp 2fa failure (wrong code)", user.GetPID())
data := authboss.HTMLData{
authboss.DataValidation: map[string][]string{FormValueCode: []string{"2fa code was invalid"}},
DataValidateMode: dataValidate,
}
return t.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageTOTPValidate, data)
}

View File

@ -197,12 +197,9 @@ func TestGetSetup(t *testing.T) {
t.Error("session totp secret should be cleared")
}
if h.responder.Page != PageTOTPValidate {
if h.responder.Page != PageTOTPSetup {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateSetup {
t.Error("data wrong:", got)
}
}
func TestPostSetup(t *testing.T) {
@ -282,12 +279,9 @@ func TestGetConfirm(t *testing.T) {
t.Error(err)
}
if h.responder.Page != PageTOTPValidate {
if h.responder.Page != PageTOTPConfirm {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateConfirm {
t.Error("data wrong:", got)
}
if got := h.responder.Data[DataTOTPSecret]; got != secret {
t.Error("data wrong:", got)
}
@ -334,12 +328,9 @@ func TestPostConfirm(t *testing.T) {
t.Error("session totp secret not deleted")
}
if h.responder.Page != PageTOTPValidateSuccess {
if h.responder.Page != PageTOTPConfirmSuccess {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateConfirm {
t.Error("data wrong:", got)
}
if got := h.responder.Data[twofactor.DataRecoveryCodes].([]string); len(got) == 0 {
t.Error("data wrong:", got)
}
@ -355,12 +346,9 @@ func TestGetRemove(t *testing.T) {
t.Error(err)
}
if h.responder.Page != PageTOTPValidate {
if h.responder.Page != PageTOTPRemove {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateRemove {
t.Error("data wrong:", got)
}
}
func TestPostRemove(t *testing.T) {
@ -386,12 +374,9 @@ func TestPostRemove(t *testing.T) {
t.Fatal(err)
}
if h.responder.Page != PageTOTPValidate {
if h.responder.Page != PageTOTPRemove {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateRemove {
t.Error("data wrong:", got)
}
if got := h.responder.Data[authboss.DataErr]; got != "totp 2fa not active" {
t.Error("data wrong:", got)
}
@ -413,12 +398,9 @@ func TestPostRemove(t *testing.T) {
t.Error(err)
}
if h.responder.Page != PageTOTPValidate {
if h.responder.Page != PageTOTPRemove {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateRemove {
t.Error("data wrong:", got)
}
if got := h.responder.Data[authboss.DataValidation].(map[string][]string); got[FormValueCode][0] != "2fa code was invalid" {
t.Error("data wrong:", got)
}
@ -445,12 +427,9 @@ func TestPostRemove(t *testing.T) {
t.Error(err)
}
if h.responder.Page != PageTOTPValidateSuccess {
if h.responder.Page != PageTOTPRemoveSuccess {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidateRemove {
t.Error("data wrong:", got)
}
// Flush client state
w.WriteHeader(http.StatusOK)
@ -474,9 +453,6 @@ func TestGetValidate(t *testing.T) {
if h.responder.Page != PageTOTPValidate {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidate {
t.Error("data wrong:", got)
}
}
func TestPostValidate(t *testing.T) {
@ -507,9 +483,6 @@ func TestPostValidate(t *testing.T) {
if h.responder.Page != PageTOTPValidate {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidate {
t.Error("data wrong:", got)
}
if got := h.responder.Data[authboss.DataErr]; got != "totp 2fa not active" {
t.Error("data wrong:", got)
}
@ -533,9 +506,6 @@ func TestPostValidate(t *testing.T) {
if h.responder.Page != PageTOTPValidate {
t.Error("page wrong:", h.responder.Page)
}
if got := h.responder.Data[DataValidateMode]; got != dataValidate {
t.Error("data wrong:", got)
}
if got := h.responder.Data[authboss.DataValidation].(map[string][]string); got[FormValueCode][0] != "2fa code was invalid" {
t.Error("data wrong:", got)
}

View File

@ -50,7 +50,7 @@ type Recovery struct {
func (rc *Recovery) Setup() error {
rc.Authboss.Core.ViewRenderer.Load(PageRecovery2FA)
middleware := authboss.MountedMiddleware(rc.Authboss, true, rc.Authboss.Config.Modules.TwoFactorRedirectOnUnauthed, true, false)
middleware := authboss.MountedMiddleware(rc.Authboss, true, rc.Authboss.Config.Modules.RoutesRedirectOnUnauthed, true, false)
rc.Authboss.Core.Router.Get("/2fa/recovery/regen", middleware(rc.Authboss.Core.ErrorHandler.Wrap(rc.GetRegen)))
rc.Authboss.Core.Router.Post("/2fa/recovery/regen", middleware(rc.Authboss.Core.ErrorHandler.Wrap(rc.PostRegen)))