diff options
author | Jonas Franz <info@jonasfranz.software> | 2018-05-19 16:12:37 +0200 |
---|---|---|
committer | Lauris BH <lauris@nix.lv> | 2018-05-19 17:12:37 +0300 |
commit | 951309f76aab22e3742e8872bf0642fcea2570ae (patch) | |
tree | 041e43fcc393d0ca07e4e274b28c1938e6604780 /routers/user/setting | |
parent | f933bcdfeef359d8d9592dc0cf0aea244963e23c (diff) | |
download | gitea-951309f76aab22e3742e8872bf0642fcea2570ae.tar.gz gitea-951309f76aab22e3742e8872bf0642fcea2570ae.zip |
Add support for FIDO U2F (#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>
Diffstat (limited to 'routers/user/setting')
-rw-r--r-- | routers/user/setting/security.go | 8 | ||||
-rw-r--r-- | routers/user/setting/security_u2f.go | 99 |
2 files changed, 107 insertions, 0 deletions
diff --git a/routers/user/setting/security.go b/routers/user/setting/security.go index 5346f349ff..860730303f 100644 --- a/routers/user/setting/security.go +++ b/routers/user/setting/security.go @@ -33,6 +33,14 @@ func Security(ctx *context.Context) { } } ctx.Data["TwofaEnrolled"] = enrolled + if enrolled { + ctx.Data["U2FRegistrations"], err = models.GetU2FRegistrationsByUID(ctx.User.ID) + if err != nil { + ctx.ServerError("GetU2FRegistrationsByUID", err) + return + } + ctx.Data["RequireU2F"] = true + } tokens, err := models.ListAccessTokens(ctx.User.ID) if err != nil { diff --git a/routers/user/setting/security_u2f.go b/routers/user/setting/security_u2f.go new file mode 100644 index 0000000000..c1d6eab967 --- /dev/null +++ b/routers/user/setting/security_u2f.go @@ -0,0 +1,99 @@ +// 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 setting + +import ( + "errors" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/auth" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" + + "github.com/tstranex/u2f" +) + +// U2FRegister initializes the u2f registration procedure +func U2FRegister(ctx *context.Context, form auth.U2FRegistrationForm) { + if form.Name == "" { + ctx.Error(409) + return + } + challenge, err := u2f.NewChallenge(setting.U2F.AppID, setting.U2F.TrustedFacets) + if err != nil { + ctx.ServerError("NewChallenge", err) + return + } + err = ctx.Session.Set("u2fChallenge", challenge) + if err != nil { + ctx.ServerError("Session.Set", err) + return + } + regs, err := models.GetU2FRegistrationsByUID(ctx.User.ID) + if err != nil { + ctx.ServerError("GetU2FRegistrationsByUID", err) + return + } + for _, reg := range regs { + if reg.Name == form.Name { + ctx.Error(409, "Name already taken") + return + } + } + ctx.Session.Set("u2fName", form.Name) + ctx.JSON(200, u2f.NewWebRegisterRequest(challenge, regs.ToRegistrations())) +} + +// U2FRegisterPost receives the response of the security key +func U2FRegisterPost(ctx *context.Context, response u2f.RegisterResponse) { + challSess := ctx.Session.Get("u2fChallenge") + u2fName := ctx.Session.Get("u2fName") + if challSess == nil || u2fName == nil { + ctx.ServerError("U2FRegisterPost", errors.New("not in U2F session")) + return + } + challenge := challSess.(*u2f.Challenge) + name := u2fName.(string) + config := &u2f.Config{ + // Chrome 66+ doesn't return the device's attestation + // certificate by default. + SkipAttestationVerify: true, + } + reg, err := u2f.Register(response, *challenge, config) + if err != nil { + ctx.ServerError("u2f.Register", err) + return + } + if _, err = models.CreateRegistration(ctx.User, name, reg); err != nil { + ctx.ServerError("u2f.Register", err) + return + } + ctx.Status(200) +} + +// U2FDelete deletes an security key by id +func U2FDelete(ctx *context.Context, form auth.U2FDeleteForm) { + reg, err := models.GetU2FRegistrationByID(form.ID) + if err != nil { + if models.IsErrU2FRegistrationNotExist(err) { + ctx.Status(200) + return + } + ctx.ServerError("GetU2FRegistrationByID", err) + return + } + if reg.UserID != ctx.User.ID { + ctx.Status(401) + return + } + if err := models.DeleteRegistration(reg); err != nil { + ctx.ServerError("DeleteRegistration", err) + return + } + ctx.JSON(200, map[string]interface{}{ + "redirect": setting.AppSubURL + "/user/settings/security", + }) + return +} |