mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-03 04:10:20 +08:00
feat: add three idp support by goth. (#351)
1. add 3 providers: apple, azuread(v1) and slack. 2. support importing providers from goth. Signed-off-by: 0x2a <stevesough@gmail.com>
This commit is contained in:
254
idp/goth.go
Normal file
254
idp/goth.go
Normal file
@ -0,0 +1,254 @@
|
||||
// Copyright 2021 The casbin 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/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 == "" {
|
||||
user.Username = fmt.Sprintf("%v%v", gothUser.FirstName, gothUser.LastName)
|
||||
}
|
||||
if user.Username == "" {
|
||||
user.Username = gothUser.NickName
|
||||
}
|
||||
|
||||
return &user
|
||||
}
|
Reference in New Issue
Block a user