Add getting or creating a third party user
This commit is contained in:
parent
52d9c25125
commit
0c382f2ee6
|
@ -233,7 +233,6 @@ auth:
|
|||
# A list of enabled providers
|
||||
providers:
|
||||
# The name of the provider as it will appear in the frontend.
|
||||
# **If you change this after users already authenticated with this provider, users will loose access to their accounts!**
|
||||
- name:
|
||||
# The auth url to send users to if they want to authenticate using OpenID Connect.
|
||||
authurl:
|
||||
|
|
1
go.mod
1
go.mod
|
@ -30,6 +30,7 @@ require (
|
|||
github.com/d4l3k/messagediff v1.2.1 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0
|
||||
github.com/fzipp/gocyclo v0.3.1
|
||||
github.com/gabriel-vasile/mimetype v1.1.1
|
||||
github.com/getsentry/sentry-go v0.7.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -140,6 +140,8 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1
|
|||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0 h1:90Ly+6UfUypEF6vvvW5rQIv9opIL8CbmW9FT20LDQoY=
|
||||
github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0/go.mod h1:V+Qd57rJe8gd4eiGzZyg4h54VLHmYVVw54iMnlAMrF8=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type user20201025195822 struct {
|
||||
Issuer string `xorm:"text null" json:"-"`
|
||||
Subject string `xorm:"text null" json:"-"`
|
||||
}
|
||||
|
||||
func (user20201025195822) TableName() string {
|
||||
return "user"
|
||||
}
|
||||
|
||||
func init() {
|
||||
migrations = append(migrations, &xormigrate.Migration{
|
||||
ID: "20201025195822",
|
||||
Description: "",
|
||||
Migrate: func(tx *xorm.Engine) error {
|
||||
err := tx.Sync2(user20201025195822{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Cols("issuer").Update(&user20201025195822{Issuer: "local"})
|
||||
return err
|
||||
},
|
||||
Rollback: func(tx *xorm.Engine) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
|
@ -20,9 +20,12 @@ import (
|
|||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"context"
|
||||
"encoding/json"
|
||||
petname "github.com/dustinkirkland/golang-petname"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
|
@ -55,6 +58,10 @@ type claims struct {
|
|||
PreferredUsername string `json:"preferred_username"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
}
|
||||
|
||||
func getKeyFromName(name string) string {
|
||||
reg, _ := regexp.Compile("[^a-z0-9]+")
|
||||
return reg.ReplaceAllString(strings.ToLower(name), "")
|
||||
|
@ -194,6 +201,51 @@ func HandleCallback(c echo.Context) error {
|
|||
return apiv1.NewUserAuthTokenResponse(u, c)
|
||||
}
|
||||
|
||||
func getOrCreateUser() (u *user.User, err error) {
|
||||
func getOrCreateUser(cl *claims, issuer, subject string) (u *user.User, err error) {
|
||||
// Check if the user exists for that issuer and subject
|
||||
u, err = user.GetUser(&user.User{
|
||||
Issuer: issuer,
|
||||
Subject: subject,
|
||||
})
|
||||
if err != nil && !user.IsErrUserDoesNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If no user exists, create one with the preferred username if it is not already taken
|
||||
if user.IsErrUserDoesNotExist(err) {
|
||||
uu := &user.User{
|
||||
Username: cl.PreferredUsername,
|
||||
Email: cl.Email,
|
||||
IsActive: true,
|
||||
Issuer: issuer,
|
||||
Subject: subject,
|
||||
}
|
||||
|
||||
u, err = user.CreateUser(uu)
|
||||
if err != nil && !user.IsErrUsernameExists(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If their preferred username is already taken, create some random one from the email and subject
|
||||
if user.IsErrUsernameExists(err) {
|
||||
uu.Username = petname.Generate(3, "-")
|
||||
u, err = user.CreateUser(uu)
|
||||
}
|
||||
} else {
|
||||
// If it exists, check if the email address changed and change it if not
|
||||
if cl.Email != u.Email {
|
||||
u.Email = cl.Email
|
||||
u, err = user.UpdateUser(&user.User{
|
||||
ID: u.ID,
|
||||
Email: cl.Email,
|
||||
Issuer: issuer,
|
||||
Subject: subject,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ type User struct {
|
|||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id"`
|
||||
// The username of the user. Is always unique.
|
||||
Username string `xorm:"varchar(250) not null unique" json:"username" valid:"length(1|250)" minLength:"1" maxLength:"250"`
|
||||
Password string `xorm:"varchar(250) not null" json:"-"`
|
||||
Password string `xorm:"varchar(250) null" json:"-"`
|
||||
// The user's email address.
|
||||
Email string `xorm:"varchar(250) null" json:"email,omitempty" valid:"email,length(0|250)" maxLength:"250"`
|
||||
IsActive bool `xorm:"null" json:"-"`
|
||||
|
@ -60,6 +60,10 @@ type User struct {
|
|||
AvatarProvider string `xorm:"varchar(255) null" json:"-"`
|
||||
AvatarFileID int64 `xorn:"null" json:"-"`
|
||||
|
||||
// Issuer and Subject contain the issuer and subject from the source the user authenticated with.
|
||||
Issuer string `xorm:"text null" json:"-"`
|
||||
Subject string `xorm:"text null" json:"-"`
|
||||
|
||||
// A timestamp when this task was created. You cannot change this value.
|
||||
Created time.Time `xorm:"created not null" json:"created"`
|
||||
// A timestamp when this task was last updated. You cannot change this value.
|
||||
|
@ -248,7 +252,17 @@ func CreateUser(user *User) (newUser *User, err error) {
|
|||
|
||||
// Check if the user already existst with that email
|
||||
exists = true
|
||||
_, err = GetUser(&User{Email: newUser.Email})
|
||||
userToCheck := &User{
|
||||
Email: newUser.Email,
|
||||
Issuer: newUser.Issuer,
|
||||
Subject: newUser.Subject,
|
||||
}
|
||||
|
||||
if newUser.Issuer == "local" {
|
||||
userToCheck.Email = ""
|
||||
}
|
||||
|
||||
_, err = GetUser(userToCheck)
|
||||
if err != nil {
|
||||
if IsErrUserDoesNotExist(err) {
|
||||
exists = false
|
||||
|
@ -260,14 +274,16 @@ func CreateUser(user *User) (newUser *User, err error) {
|
|||
return &User{}, ErrUserEmailExists{newUser.ID, newUser.Email}
|
||||
}
|
||||
|
||||
// Hash the password
|
||||
newUser.Password, err = hashPassword(user.Password)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
if newUser.Issuer == "local" {
|
||||
// Hash the password
|
||||
newUser.Password, err = hashPassword(user.Password)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
}
|
||||
|
||||
newUser.IsActive = true
|
||||
if config.MailerEnabled.GetBool() {
|
||||
if config.MailerEnabled.GetBool() && newUser.Issuer == "local" {
|
||||
// The new user should not be activated until it confirms his mail address
|
||||
newUser.IsActive = false
|
||||
// Generate a confirm token
|
||||
|
@ -340,7 +356,11 @@ func UpdateUser(user *User) (updatedUser *User, err error) {
|
|||
if user.Email == "" {
|
||||
user.Email = theUser.Email
|
||||
} else {
|
||||
uu, err := getUser(&User{Email: user.Email}, true)
|
||||
uu, err := getUser(&User{
|
||||
Email: user.Email,
|
||||
Issuer: user.Issuer,
|
||||
Subject: user.Subject,
|
||||
}, true)
|
||||
if err != nil && !IsErrUserDoesNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue