Skip to content

Commit

Permalink
Initial addition of two-factor authentication support
Browse files Browse the repository at this point in the history
  • Loading branch information
minecrafter committed Mar 9, 2016
1 parent 0c9a616 commit 5cd2997
Show file tree
Hide file tree
Showing 14 changed files with 1,230 additions and 911 deletions.
6 changes: 6 additions & 0 deletions cmd/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ func runWeb(ctx *cli.Context) {
m.Post("/sign_up", bindIgnErr(auth.RegisterForm{}), user.SignUpPost)
m.Get("/reset_password", user.ResetPasswd)
m.Post("/reset_password", user.ResetPasswdPost)
m.Get("/twofa", user.TwoFactor)
m.Post("/twofa", bindIgnErr(auth.TwoFactorForm{}), user.TwoFactorPost)
}, reqSignOut)

m.Group("/user/settings", func() {
Expand All @@ -231,6 +233,10 @@ func runWeb(ctx *cli.Context) {
Post(bindIgnErr(auth.NewAccessTokenForm{}), user.SettingsApplicationsPost)
m.Post("/applications/delete", user.SettingsDeleteApplication)
m.Route("/delete", "GET,POST", user.SettingsDelete)
m.Get("/twofa", user.SettingsTwoFactor)
m.Combo("/twofa/enroll").Get(user.SettingsEnrollTwoFactor).
Post(user.SettingsEnrollTwoFactorPost)
m.Post("/twofa/disable", user.SettingsDisableTwoFactor)
}, reqSignIn, func(ctx *middleware.Context) {
ctx.Data["PageIsUserSettings"] = true
})
Expand Down
23 changes: 23 additions & 0 deletions conf/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ reset_password = Reset Your Password
invalid_code = Sorry, your confirmation code has expired or not valid.
reset_password_helper = Click here to reset your password
password_too_short = Password length cannot be less then 6.
two_factor = Two-factor authentication
two_factor_code = Please enter the two-factor authentication code on your phone.
two_factor_attempt = Submit code
two_factor_failure = The submitted code is incorrect.

[mail]
activate_account = Please activate your account
Expand Down Expand Up @@ -333,6 +337,25 @@ confirm_delete_account = Confirm Deletion
delete_account_title = Account Deletion
delete_account_desc = This account is going to be deleted permanently, do you want to continue?
two_factor = Two-factor authentication
two_factor_description = Two-factor authentication helps protect your account from unauthorized access.
two_factor_active = Two-factor authentication is currently enabled.
two_factor_deactivate = Deactivate two-factor authentication
two_factor_not_active = Two-factor authentication is currently disabled.
two_factor_do_enroll = Enable two-factor authentication
deactivate_two_factor_desc = Deactivating two-factor authentication makes your account less secure. You must confirm this action by entering your password.
two_factor_deactivated = Two-factor authentication has been disabled for your account.
confirm_deactivate_two_factor = Disable two-factor authentication
two_factor_enroll = Enrolling in two-factor authentication
two_factor_scan_qr = Scan the QR code
two_factor_secret = Or enter the secret manually
two_factor_enter_code = Once you have added the secret to your device, enter the code from your device below and click "Verify code".
two_factor_verify_code = Verify code
two_factor_enroll_success = You have successfully enabled two-factor authentication on your account.
two_factor_enroll_error_code = It seems you have entered your code incorrectly. Try again.
two_factor_already_active_error = Your account already has two-factor authentication enabled.
two_factor_not_active_error = Your account already does not have two-factor authentication enabled.
[repo]
owner = Owner
repo_name = Repository Name
Expand Down
13 changes: 13 additions & 0 deletions models/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,19 @@ func (err ErrAuthenticationNotExist) Error() string {
return fmt.Sprintf("authentication does not exist [id: %d]", err.ID)
}

type ErrTwoFactorNotExist struct {
UID int64
}

func IsErrTwoFactorNotExist(err error) bool {
_, ok := err.(ErrTwoFactorNotExist)
return ok
}

func (err ErrTwoFactorNotExist) Error() string {
return fmt.Sprintf("two factor does not exist [uid: %d]", err.UID)
}

// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
Expand Down
2 changes: 1 addition & 1 deletion models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func init() {
new(Mirror), new(Release), new(LoginSource), new(Webhook),
new(UpdateTask), new(HookTask),
new(Team), new(OrgUser), new(TeamUser), new(TeamRepo),
new(Notice), new(EmailAddress))
new(Notice), new(EmailAddress), new(TwoFactor))

gonicNames := []string{"SSL"}
for _, name := range gonicNames {
Expand Down
48 changes: 48 additions & 0 deletions models/two_factor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2016 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
"time"
)

// TwoFactor represents a stored two-factor authentication secret.
type TwoFactor struct {
ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"UNIQUE"`
Secret string `xorm:"UNIQUE VARCHAR(16)"`
Created time.Time `xorm:"CREATED"`
Updated time.Time
}

// NewTwoFactor creates a new two factor token.
func NewTwoFactor(t *TwoFactor) error {
_, err := x.Insert(t)
return err
}

// GetTwoFactorByUID returns two factor token by given user ID.
func GetTwoFactorByUID(uid int64) (*TwoFactor, error) {
t := &TwoFactor{UID: uid}
has, err := x.Get(t)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTwoFactorNotExist{uid}
}
return t, nil
}

// UpdateTwoFactorupdates information of two factor token.
func UpdateTwoFactor(t *TwoFactor) error {
_, err := x.Id(t.ID).AllCols().Update(t)
return err
}

// DeleteTwoFactorByID deletes two faactor token by given ID.
func DeleteTwoFactorByID(id int64) error {
_, err := x.Id(id).Delete(new(TwoFactor))
return err
}
53 changes: 53 additions & 0 deletions models/two_factor_backup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2016 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
"time"
)

// TwoFactorBackup represents a stored two-factor authentication backup code.
type TwoFactorBackup struct {
ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"UNIQUE"`
Code string `xorm:"UNIQUE VARCHAR(16)"`
Created time.Time `xorm:"CREATED"`
Updated time.Time
Burnt bool
}

// NewTwoFactorBackup creates a new two factor token.
func NewTwoFactorBackup(t *TwoFactorBackup) error {
_, err := x.Insert(t)
return err
}

// BurnTwoFactorBackupCode will try to "burn" a two-factor authentication backup code.
func BurnTwoFactorBackupCode(uid int64, code string) error {
t := &TwoFactorBackup{UID: uid, Code: code, Burnt: false}
has, err := x.Get(t)
if err != nil {
return err
} else if !has {
return nil, ErrTwoFactorNotExist{uid}
}

// Now we burn the backup code
t.Burnt = true
return UpdateTwoFactorBackup(t)
}

// UpdateTwoFactorBackup updates information of two factor token.
func UpdateTwoFactorBackup(t *TwoFactorBackup) error {
_, err := x.Id(t.ID).AllCols().Update(t)
return err
}

// DeleteTwoFactorCodesFromUser deletes two factor authentication backup codes from a user.
func DeleteTwoFactorCodesFromUser(uid int64) error {
deleteBy := &TwoFactorBackup{UID: uid}
_, err := x.Delete(deleteBy)
return err
}
8 changes: 8 additions & 0 deletions modules/auth/user_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,11 @@ type NewAccessTokenForm struct {
func (f *NewAccessTokenForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

type TwoFactorForm struct {
Code string `form:"code" binding:"Required"`
}

func (f *TwoFactorForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
Loading

0 comments on commit 5cd2997

Please sign in to comment.