update oauth to use oauth2 library

Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
yxxhero 2021-08-11 13:50:43 +08:00 committed by Gaius
parent c3bf4a3d6f
commit cb126da5d9
No known key found for this signature in database
GPG Key ID: 8B4E5D1290FA2FFB
4 changed files with 164 additions and 24 deletions

View File

@ -1 +1,59 @@
package oauth package oauth
import (
"encoding/json"
"io/ioutil"
"net/http"
"golang.org/x/oauth2"
"golang.org/x/oauth2/github"
"gorm.io/gorm"
)
type githubOauth2 struct {
baseOauth2
}
func NewGithubOauth2(name string, clientID string, clientSecret string, db *gorm.DB) (Oauther, error) {
oa := &githubOauth2{}
oa.Name = name
oa.Config = &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"},
Endpoint: github.Endpoint,
}
oa.UserInfoURL = "https://api.github.com/user"
redirectURL, err := oa.GetRediectURL(db)
if err != nil {
return nil, err
}
oa.Config.RedirectURL = redirectURL
return oa, nil
}
func (oa *githubOauth2) GetOauthUserInfo(token string) (*oauth2User, error) {
req, err := http.NewRequest("GET", oa.UserInfoURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "token"+" "+token)
response, err := (&http.Client{}).Do(req)
if err != nil {
return nil, err
}
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
u := oauth2User{}
err = json.Unmarshal(contents, &u)
if err != nil {
return nil, err
}
return &u, nil
}

View File

@ -1,23 +1,28 @@
package oauth package oauth
import ( import (
"golang.org/x/oauth2"
"golang.org/x/oauth2/google" "golang.org/x/oauth2/google"
"gorm.io/gorm"
) )
type googleOauth2 struct { type googleOauth2 struct {
oauth2 baseOauth2
} }
func NewGoogle(name string, clientID string, clientSecret string, scopes string, authURL string, tokenURL string, db *gorm.DB) (*oauth, error) { func NewGoogleOauth2(name string, clientID string, clientSecret string, db *gorm.DB) (Oauther, error) {
oa := &googleOauth2{ oa := &googleOauth2{}
Name: name, oa.Name = name
Config: &oauth2.Config{ oa.Config = &oauth2.Config{
ClientID: clientID, ClientID: clientID,
ClientSecret: clientSecret, ClientSecret: clientSecret,
Scopes: strings.Split(scopes, ","), Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
Endpoint: google. "https://www.googleapis.com/auth/userinfo.email"},
}, Endpoint: google.Endpoint,
} }
oa.UserInfoURL = "https://www.googleapis.com/oauth2/v2/userinfo"
redirectURL, err := oa.GetRediectURL(db) redirectURL, err := oa.GetRediectURL(db)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,29 +1,42 @@
package oauth package oauth
import ( import (
"context"
"encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil"
"net/http"
"strings" "strings"
"d7y.io/dragonfly/v2/manager/model" "d7y.io/dragonfly/v2/manager/model"
"golang.org/x/crypto/bcrypt"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"gorm.io/gorm" "gorm.io/gorm"
) )
type oauth2 struct { type baseOauth2 struct {
Name string Name string
UserInfoURL string UserInfoURL string
Config *oauth2.Config Config *oauth2.Config
} }
type oauth2User struct {
Name string `json:"name"`
Email string `json:"email"`
}
// oauth interface // oauth interface
type Oauther interface { type Oauther interface {
GetRediectURL(*gorm.DB) (string, error) GetRediectURL(*gorm.DB) (string, error)
GetOauthUserInfo(string) (*model.User, error) GetOauthUserInfo(string) (*oauth2User, error)
ExchangeUserByCode(string, *gorm.DB) (*model.User, error)
AuthCodeURL(string) string
} }
func NewOauth(name string, clientID string, clientSecret string, scopes string, authURL string, tokenURL string, db *gorm.DB) (*oauth, error) { func NewBaseOauth2(name string, clientID string, clientSecret string, scopes string, authURL string, tokenURL string, db *gorm.DB) (Oauther, error) {
oa := &oauth2{ oa := &baseOauth2{
Name: name, Name: name,
Config: &oauth2.Config{ Config: &oauth2.Config{
ClientID: clientID, ClientID: clientID,
@ -43,7 +56,7 @@ func NewOauth(name string, clientID string, clientSecret string, scopes string,
return oa, nil return oa, nil
} }
func (o *oauth2) GetRediectURL(db *gorm.DB) (string, error) { func (oa *baseOauth2) GetRediectURL(db *gorm.DB) (string, error) {
s := model.Settings{} s := model.Settings{}
if err := db.First(&s, model.Settings{ if err := db.First(&s, model.Settings{
@ -51,10 +64,74 @@ func (o *oauth2) GetRediectURL(db *gorm.DB) (string, error) {
}).Error; err != nil { }).Error; err != nil {
return "", err return "", err
} }
return fmt.Sprintf("%s/api/v1/oauth/%s/sigin", s.Value, o.Name), nil return fmt.Sprintf("%s/api/v1/oauth/%s/sigin", s.Value, oa.Name), nil
} }
func (o *oauth2) GetOauthUserInfo(code string) (*model.User, error) { func (oa *baseOauth2) AuthCodeURL(state string) string {
user := model.User{} return oa.Config.AuthCodeURL(state)
return &user, nil }
func (oa *baseOauth2) GetOauthUserInfo(token string) (*oauth2User, error) {
response, err := http.Get(fmt.Sprintf("%s?access_token=%s", oa.UserInfoURL, token))
if err != nil {
return nil, err
}
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
u := oauth2User{}
err = json.Unmarshal(contents, &u)
if err != nil {
return nil, err
}
return &u, nil
}
func (oa *baseOauth2) ExchangeUserByCode(code string, db *gorm.DB) (*model.User, error) {
token, err := oa.Config.Exchange(context.Background(), code)
if err != nil {
return nil, err
}
if oa.UserInfoURL == "" {
return nil, errors.New("UserInfoURL is empty")
}
u, err := oa.GetOauthUserInfo(token.AccessToken)
if err != nil {
return nil, err
}
if u.Name == "admin" {
return nil, errors.New("admin is not allowed to login by oauth")
}
encryptedPasswordBytes, err := bcrypt.GenerateFromPassword([]byte("Dragonfly2"), bcrypt.MinCost)
if err != nil {
return nil, err
}
var userCount int64
if err := db.Model(model.User{}).Where("name = ?", u.Name).Count(&userCount).Error; err != nil {
return nil, err
}
if userCount <= 0 {
user := model.User{
EncryptedPassword: string(encryptedPasswordBytes),
Name: u.Name,
Email: u.Email,
}
if err := db.Create(&user).Error; err != nil {
return nil, err
}
return &user, nil
} else {
user := model.User{}
if err := db.Model(model.User{}).Where("name = ?", u.Name).First(&user).Error; err != nil {
return nil, err
}
return &user, nil
}
} }

View File

@ -95,11 +95,11 @@ func (s *rest) OauthSignin(name string) (string, error) {
return "", err return "", err
} }
o, err := oauth.NewOauth(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db) o, err := oauth.NewBaseOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
if err != nil { if err != nil {
return "", err return "", err
} }
return o.Config.AuthCodeURL("state"), nil return o.AuthCodeURL("state"), nil
} }
func (s *rest) OauthCallback(name, code string) (*model.User, error) { func (s *rest) OauthCallback(name, code string) (*model.User, error) {
@ -108,11 +108,11 @@ func (s *rest) OauthCallback(name, code string) (*model.User, error) {
return nil, err return nil, err
} }
o, err := oauth.NewOauth(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db) o, err := oauth.NewBaseOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
if err != nil { if err != nil {
return nil, err return nil, err
} }
user, err := o.GetOauthUserInfo(code) user, err := o.ExchangeUserByCode(code, s.db)
if err != nil { if err != nil {
return nil, err return nil, err
} }