forked from go-gitea/gitea
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for FIDO U2F (go-gitea#3971)
* Add support for U2F Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add vendor library Add missing translations Signed-off-by: Jonas Franz <info@jonasfranz.software> * Minor improvements Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add U2F support for Firefox, Chrome (Android) by introducing a custom JS library Add U2F error handling Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add U2F login page to OAuth Signed-off-by: Jonas Franz <info@jonasfranz.software> * Move U2F user settings to a separate file Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add unit tests for u2f model Renamed u2f table name Signed-off-by: Jonas Franz <info@jonasfranz.software> * Fix problems caused by refactoring Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add U2F documentation Signed-off-by: Jonas Franz <info@jonasfranz.software> * Remove not needed console.log-s Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add default values to app.ini.sample Add FIDO U2F to comparison Signed-off-by: Jonas Franz <info@jonasfranz.software>
- Loading branch information
1 parent
f933bcd
commit 951309f
Showing
34 changed files
with
1,599 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
- | ||
id: 1 | ||
name: "U2F Key" | ||
user_id: 1 | ||
counter: 0 | ||
created_unix: 946684800 | ||
updated_unix: 946684800 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package migrations | ||
|
||
import ( | ||
"code.gitea.io/gitea/modules/util" | ||
"github.com/go-xorm/xorm" | ||
) | ||
|
||
func addU2FReg(x *xorm.Engine) error { | ||
type U2FRegistration struct { | ||
ID int64 `xorm:"pk autoincr"` | ||
Name string | ||
UserID int64 `xorm:"INDEX"` | ||
Raw []byte | ||
Counter uint32 | ||
CreatedUnix util.TimeStamp `xorm:"INDEX created"` | ||
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` | ||
} | ||
return x.Sync2(&U2FRegistration{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Copyright 2018 The Gitea 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 ( | ||
"code.gitea.io/gitea/modules/log" | ||
"code.gitea.io/gitea/modules/util" | ||
|
||
"github.com/tstranex/u2f" | ||
) | ||
|
||
// U2FRegistration represents the registration data and counter of a security key | ||
type U2FRegistration struct { | ||
ID int64 `xorm:"pk autoincr"` | ||
Name string | ||
UserID int64 `xorm:"INDEX"` | ||
Raw []byte | ||
Counter uint32 | ||
CreatedUnix util.TimeStamp `xorm:"INDEX created"` | ||
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` | ||
} | ||
|
||
// TableName returns a better table name for U2FRegistration | ||
func (reg U2FRegistration) TableName() string { | ||
return "u2f_registration" | ||
} | ||
|
||
// Parse will convert the db entry U2FRegistration to an u2f.Registration struct | ||
func (reg *U2FRegistration) Parse() (*u2f.Registration, error) { | ||
r := new(u2f.Registration) | ||
return r, r.UnmarshalBinary(reg.Raw) | ||
} | ||
|
||
func (reg *U2FRegistration) updateCounter(e Engine) error { | ||
_, err := e.ID(reg.ID).Cols("counter").Update(reg) | ||
return err | ||
} | ||
|
||
// UpdateCounter will update the database value of counter | ||
func (reg *U2FRegistration) UpdateCounter() error { | ||
return reg.updateCounter(x) | ||
} | ||
|
||
// U2FRegistrationList is a list of *U2FRegistration | ||
type U2FRegistrationList []*U2FRegistration | ||
|
||
// ToRegistrations will convert all U2FRegistrations to u2f.Registrations | ||
func (list U2FRegistrationList) ToRegistrations() []u2f.Registration { | ||
regs := make([]u2f.Registration, len(list)) | ||
for _, reg := range list { | ||
r, err := reg.Parse() | ||
if err != nil { | ||
log.Fatal(4, "parsing u2f registration: %v", err) | ||
continue | ||
} | ||
regs = append(regs, *r) | ||
} | ||
|
||
return regs | ||
} | ||
|
||
func getU2FRegistrationsByUID(e Engine, uid int64) (U2FRegistrationList, error) { | ||
regs := make(U2FRegistrationList, 0) | ||
return regs, e.Where("user_id = ?", uid).Find(®s) | ||
} | ||
|
||
// GetU2FRegistrationByID returns U2F registration by id | ||
func GetU2FRegistrationByID(id int64) (*U2FRegistration, error) { | ||
return getU2FRegistrationByID(x, id) | ||
} | ||
|
||
func getU2FRegistrationByID(e Engine, id int64) (*U2FRegistration, error) { | ||
reg := new(U2FRegistration) | ||
if found, err := e.ID(id).Get(reg); err != nil { | ||
return nil, err | ||
} else if !found { | ||
return nil, ErrU2FRegistrationNotExist{ID: id} | ||
} | ||
return reg, nil | ||
} | ||
|
||
// GetU2FRegistrationsByUID returns all U2F registrations of the given user | ||
func GetU2FRegistrationsByUID(uid int64) (U2FRegistrationList, error) { | ||
return getU2FRegistrationsByUID(x, uid) | ||
} | ||
|
||
func createRegistration(e Engine, user *User, name string, reg *u2f.Registration) (*U2FRegistration, error) { | ||
raw, err := reg.MarshalBinary() | ||
if err != nil { | ||
return nil, err | ||
} | ||
r := &U2FRegistration{ | ||
UserID: user.ID, | ||
Name: name, | ||
Counter: 0, | ||
Raw: raw, | ||
} | ||
_, err = e.InsertOne(r) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return r, nil | ||
} | ||
|
||
// CreateRegistration will create a new U2FRegistration from the given Registration | ||
func CreateRegistration(user *User, name string, reg *u2f.Registration) (*U2FRegistration, error) { | ||
return createRegistration(x, user, name, reg) | ||
} | ||
|
||
// DeleteRegistration will delete U2FRegistration | ||
func DeleteRegistration(reg *U2FRegistration) error { | ||
return deleteRegistration(x, reg) | ||
} | ||
|
||
func deleteRegistration(e Engine, reg *U2FRegistration) error { | ||
_, err := e.Delete(reg) | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package models | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/tstranex/u2f" | ||
) | ||
|
||
func TestGetU2FRegistrationByID(t *testing.T) { | ||
assert.NoError(t, PrepareTestDatabase()) | ||
|
||
res, err := GetU2FRegistrationByID(1) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "U2F Key", res.Name) | ||
|
||
_, err = GetU2FRegistrationByID(342432) | ||
assert.Error(t, err) | ||
assert.True(t, IsErrU2FRegistrationNotExist(err)) | ||
} | ||
|
||
func TestGetU2FRegistrationsByUID(t *testing.T) { | ||
assert.NoError(t, PrepareTestDatabase()) | ||
|
||
res, err := GetU2FRegistrationsByUID(1) | ||
assert.NoError(t, err) | ||
assert.Len(t, res, 1) | ||
assert.Equal(t, "U2F Key", res[0].Name) | ||
} | ||
|
||
func TestU2FRegistration_TableName(t *testing.T) { | ||
assert.Equal(t, "u2f_registration", U2FRegistration{}.TableName()) | ||
} | ||
|
||
func TestU2FRegistration_UpdateCounter(t *testing.T) { | ||
assert.NoError(t, PrepareTestDatabase()) | ||
reg := AssertExistsAndLoadBean(t, &U2FRegistration{ID: 1}).(*U2FRegistration) | ||
reg.Counter = 1 | ||
assert.NoError(t, reg.UpdateCounter()) | ||
AssertExistsIf(t, true, &U2FRegistration{ID: 1, Counter: 1}) | ||
} | ||
|
||
func TestCreateRegistration(t *testing.T) { | ||
assert.NoError(t, PrepareTestDatabase()) | ||
user := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User) | ||
|
||
res, err := CreateRegistration(user, "U2F Created Key", &u2f.Registration{Raw: []byte("Test")}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "U2F Created Key", res.Name) | ||
assert.Equal(t, []byte("Test"), res.Raw) | ||
|
||
AssertExistsIf(t, true, &U2FRegistration{Name: "U2F Created Key", UserID: user.ID}) | ||
} | ||
|
||
func TestDeleteRegistration(t *testing.T) { | ||
assert.NoError(t, PrepareTestDatabase()) | ||
reg := AssertExistsAndLoadBean(t, &U2FRegistration{ID: 1}).(*U2FRegistration) | ||
|
||
assert.NoError(t, DeleteRegistration(reg)) | ||
AssertNotExistsBean(t, &U2FRegistration{ID: 1}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.