mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 02:35:49 +08:00
272 lines
8.1 KiB
Go
272 lines
8.1 KiB
Go
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package idp
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/casdoor/casdoor/util"
|
|
"github.com/markbates/goth"
|
|
"github.com/markbates/goth/providers/amazon"
|
|
"github.com/markbates/goth/providers/apple"
|
|
"github.com/markbates/goth/providers/azuread"
|
|
"github.com/markbates/goth/providers/bitbucket"
|
|
"github.com/markbates/goth/providers/digitalocean"
|
|
"github.com/markbates/goth/providers/discord"
|
|
"github.com/markbates/goth/providers/dropbox"
|
|
"github.com/markbates/goth/providers/facebook"
|
|
"github.com/markbates/goth/providers/gitea"
|
|
"github.com/markbates/goth/providers/github"
|
|
"github.com/markbates/goth/providers/gitlab"
|
|
"github.com/markbates/goth/providers/google"
|
|
"github.com/markbates/goth/providers/heroku"
|
|
"github.com/markbates/goth/providers/instagram"
|
|
"github.com/markbates/goth/providers/kakao"
|
|
"github.com/markbates/goth/providers/line"
|
|
"github.com/markbates/goth/providers/linkedin"
|
|
"github.com/markbates/goth/providers/microsoftonline"
|
|
"github.com/markbates/goth/providers/paypal"
|
|
"github.com/markbates/goth/providers/salesforce"
|
|
"github.com/markbates/goth/providers/shopify"
|
|
"github.com/markbates/goth/providers/slack"
|
|
"github.com/markbates/goth/providers/tumblr"
|
|
"github.com/markbates/goth/providers/twitter"
|
|
"github.com/markbates/goth/providers/yahoo"
|
|
"github.com/markbates/goth/providers/yandex"
|
|
"github.com/markbates/goth/providers/zoom"
|
|
"golang.org/x/oauth2"
|
|
)
|
|
|
|
type GothIdProvider struct {
|
|
Provider goth.Provider
|
|
Session goth.Session
|
|
}
|
|
|
|
func NewGothIdProvider(providerType string, clientId string, clientSecret string, redirectUrl string) *GothIdProvider {
|
|
var idp GothIdProvider
|
|
switch providerType {
|
|
case "Amazon":
|
|
idp = GothIdProvider{
|
|
Provider: amazon.New(clientId, clientSecret, redirectUrl),
|
|
Session: &amazon.Session{},
|
|
}
|
|
case "Apple":
|
|
idp = GothIdProvider{
|
|
Provider: apple.New(clientId, clientSecret, redirectUrl, nil),
|
|
Session: &apple.Session{},
|
|
}
|
|
case "AzureAD":
|
|
idp = GothIdProvider{
|
|
Provider: azuread.New(clientId, clientSecret, redirectUrl, nil),
|
|
Session: &azuread.Session{},
|
|
}
|
|
case "Bitbucket":
|
|
idp = GothIdProvider{
|
|
Provider: bitbucket.New(clientId, clientSecret, redirectUrl),
|
|
Session: &bitbucket.Session{},
|
|
}
|
|
case "DigitalOcean":
|
|
idp = GothIdProvider{
|
|
Provider: digitalocean.New(clientId, clientSecret, redirectUrl),
|
|
Session: &digitalocean.Session{},
|
|
}
|
|
case "Discord":
|
|
idp = GothIdProvider{
|
|
Provider: discord.New(clientId, clientSecret, redirectUrl),
|
|
Session: &discord.Session{},
|
|
}
|
|
case "Dropbox":
|
|
idp = GothIdProvider{
|
|
Provider: dropbox.New(clientId, clientSecret, redirectUrl),
|
|
Session: &dropbox.Session{},
|
|
}
|
|
case "Facebook":
|
|
idp = GothIdProvider{
|
|
Provider: facebook.New(clientId, clientSecret, redirectUrl),
|
|
Session: &facebook.Session{},
|
|
}
|
|
case "Gitea":
|
|
idp = GothIdProvider{
|
|
Provider: gitea.New(clientId, clientSecret, redirectUrl),
|
|
Session: &gitea.Session{},
|
|
}
|
|
case "GitHub":
|
|
idp = GothIdProvider{
|
|
Provider: github.New(clientId, clientSecret, redirectUrl),
|
|
Session: &github.Session{},
|
|
}
|
|
case "GitLab":
|
|
idp = GothIdProvider{
|
|
Provider: gitlab.New(clientId, clientSecret, redirectUrl),
|
|
Session: &gitlab.Session{},
|
|
}
|
|
case "Google":
|
|
idp = GothIdProvider{
|
|
Provider: google.New(clientId, clientSecret, redirectUrl),
|
|
Session: &google.Session{},
|
|
}
|
|
case "Heroku":
|
|
idp = GothIdProvider{
|
|
Provider: heroku.New(clientId, clientSecret, redirectUrl),
|
|
Session: &heroku.Session{},
|
|
}
|
|
case "Instagram":
|
|
idp = GothIdProvider{
|
|
Provider: instagram.New(clientId, clientSecret, redirectUrl),
|
|
Session: &instagram.Session{},
|
|
}
|
|
case "Kakao":
|
|
idp = GothIdProvider{
|
|
Provider: kakao.New(clientId, clientSecret, redirectUrl),
|
|
Session: &kakao.Session{},
|
|
}
|
|
case "Linkedin":
|
|
idp = GothIdProvider{
|
|
Provider: linkedin.New(clientId, clientSecret, redirectUrl),
|
|
Session: &linkedin.Session{},
|
|
}
|
|
case "Line":
|
|
idp = GothIdProvider{
|
|
Provider: line.New(clientId, clientSecret, redirectUrl),
|
|
Session: &line.Session{},
|
|
}
|
|
case "MicrosoftOnline":
|
|
idp = GothIdProvider{
|
|
Provider: microsoftonline.New(clientId, clientSecret, redirectUrl),
|
|
Session: µsoftonline.Session{},
|
|
}
|
|
case "Paypal":
|
|
idp = GothIdProvider{
|
|
Provider: paypal.New(clientId, clientSecret, redirectUrl),
|
|
Session: &paypal.Session{},
|
|
}
|
|
case "SalesForce":
|
|
idp = GothIdProvider{
|
|
Provider: salesforce.New(clientId, clientSecret, redirectUrl),
|
|
Session: &salesforce.Session{},
|
|
}
|
|
case "Shopify":
|
|
idp = GothIdProvider{
|
|
Provider: shopify.New(clientId, clientSecret, redirectUrl),
|
|
Session: &shopify.Session{},
|
|
}
|
|
case "Slack":
|
|
idp = GothIdProvider{
|
|
Provider: slack.New(clientId, clientSecret, redirectUrl),
|
|
Session: &slack.Session{},
|
|
}
|
|
case "Tumblr":
|
|
idp = GothIdProvider{
|
|
Provider: tumblr.New(clientId, clientSecret, redirectUrl),
|
|
Session: &tumblr.Session{},
|
|
}
|
|
case "Twitter":
|
|
idp = GothIdProvider{
|
|
Provider: twitter.New(clientId, clientSecret, redirectUrl),
|
|
Session: &twitter.Session{},
|
|
}
|
|
case "Yahoo":
|
|
idp = GothIdProvider{
|
|
Provider: yahoo.New(clientId, clientSecret, redirectUrl),
|
|
Session: &yahoo.Session{},
|
|
}
|
|
case "Yandex":
|
|
idp = GothIdProvider{
|
|
Provider: yandex.New(clientId, clientSecret, redirectUrl),
|
|
Session: &yandex.Session{},
|
|
}
|
|
case "Zoom":
|
|
idp = GothIdProvider{
|
|
Provider: zoom.New(clientId, clientSecret, redirectUrl),
|
|
Session: &zoom.Session{},
|
|
}
|
|
}
|
|
|
|
return &idp
|
|
}
|
|
|
|
//Goth's idp all implement the Client method, but since the goth.Provider interface does not provide to modify idp's client method, reflection is required
|
|
func (idp *GothIdProvider) SetHttpClient(client *http.Client) {
|
|
idpClient := reflect.ValueOf(idp.Provider).Elem().FieldByName("HTTPClient")
|
|
idpClient.Set(reflect.ValueOf(client))
|
|
}
|
|
|
|
func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|
var expireAt time.Time
|
|
//Need to construct variables supported by goth
|
|
//to call the function to obtain accessToken
|
|
value := url.Values{}
|
|
value.Add("code", code)
|
|
accessToken, err := idp.Session.Authorize(idp.Provider, value)
|
|
//Get ExpiresAt's value
|
|
valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt")
|
|
if valueOfExpire.IsValid() {
|
|
expireAt = valueOfExpire.Interface().(time.Time)
|
|
}
|
|
token := oauth2.Token{
|
|
AccessToken: accessToken,
|
|
Expiry: expireAt,
|
|
}
|
|
return &token, err
|
|
}
|
|
|
|
func (idp *GothIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
|
gothUser, err := idp.Provider.FetchUser(idp.Session)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return getUser(gothUser), nil
|
|
}
|
|
|
|
func getUser(gothUser goth.User) *UserInfo {
|
|
user := UserInfo{
|
|
Id: gothUser.UserID,
|
|
Username: gothUser.Name,
|
|
DisplayName: gothUser.NickName,
|
|
Email: gothUser.Email,
|
|
AvatarUrl: gothUser.AvatarURL,
|
|
}
|
|
//Some idp return an empty Name
|
|
//so construct the Name with firstname and lastname or nickname
|
|
if user.Username == "" {
|
|
if gothUser.FirstName != "" && gothUser.LastName != "" {
|
|
user.Username = getName(gothUser.FirstName, gothUser.LastName)
|
|
} else {
|
|
user.Username = gothUser.NickName
|
|
}
|
|
}
|
|
if user.DisplayName == "" {
|
|
if gothUser.FirstName != "" && gothUser.LastName != "" {
|
|
user.DisplayName = getName(gothUser.FirstName, gothUser.LastName)
|
|
} else {
|
|
user.DisplayName = user.Username
|
|
}
|
|
}
|
|
|
|
return &user
|
|
}
|
|
|
|
func getName(firstName, lastName string) string {
|
|
if util.IsChinese(firstName) || util.IsChinese(lastName) {
|
|
return fmt.Sprintf("%s%s", lastName, firstName)
|
|
} else {
|
|
return fmt.Sprintf("%s %s", firstName, lastName)
|
|
}
|
|
}
|