mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-22 18:25:47 +08:00
231 lines
7.1 KiB
Go
231 lines
7.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 (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"golang.org/x/oauth2"
|
|
)
|
|
|
|
type GitlabIdProvider struct {
|
|
Client *http.Client
|
|
Config *oauth2.Config
|
|
}
|
|
|
|
func NewGitlabIdProvider(clientId string, clientSecret string, redirectUrl string) *GitlabIdProvider {
|
|
idp := &GitlabIdProvider{}
|
|
|
|
config := idp.getConfig(clientId, clientSecret, redirectUrl)
|
|
idp.Config = config
|
|
|
|
return idp
|
|
}
|
|
|
|
func (idp *GitlabIdProvider) SetHttpClient(client *http.Client) {
|
|
idp.Client = client
|
|
}
|
|
|
|
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
|
func (idp *GitlabIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
|
endpoint := oauth2.Endpoint{
|
|
TokenURL: "https://gitlab.com/oauth/token",
|
|
}
|
|
|
|
config := &oauth2.Config{
|
|
Scopes: []string{"read_user+profile"},
|
|
Endpoint: endpoint,
|
|
ClientID: clientId,
|
|
ClientSecret: clientSecret,
|
|
RedirectURL: redirectUrl,
|
|
}
|
|
|
|
return config
|
|
}
|
|
|
|
type GitlabProviderToken struct {
|
|
AccessToken string `json:"access_token"`
|
|
TokenType string `json:"token_type"`
|
|
ExpiresIn int `json:"expires_in"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
CreatedAt int `json:"created_at"`
|
|
}
|
|
|
|
// GetToken use code get access_token (*operation of getting code ought to be done in front)
|
|
// get more detail via: https://docs.gitlab.com/ee/api/oauth2.html
|
|
func (idp *GitlabIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|
params := url.Values{}
|
|
params.Add("grant_type", "authorization_code")
|
|
params.Add("client_id", idp.Config.ClientID)
|
|
params.Add("client_secret", idp.Config.ClientSecret)
|
|
params.Add("code", code)
|
|
params.Add("redirect_uri", idp.Config.RedirectURL)
|
|
|
|
accessTokenUrl := fmt.Sprintf("%s?%s", idp.Config.Endpoint.TokenURL, params.Encode())
|
|
resp, err := idp.Client.Post(accessTokenUrl, "application/json;charset=UTF-8", nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
gtoken := &GitlabProviderToken{}
|
|
if err = json.Unmarshal(data, gtoken); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// gtoken.ExpiresIn always returns 0, so we set Expiry=7200 to avoid verification errors.
|
|
token := &oauth2.Token{
|
|
AccessToken: gtoken.AccessToken,
|
|
TokenType: gtoken.TokenType,
|
|
RefreshToken: gtoken.RefreshToken,
|
|
Expiry: time.Unix(time.Now().Unix()+int64(7200), 0),
|
|
}
|
|
|
|
return token, nil
|
|
}
|
|
|
|
/*
|
|
{
|
|
"id":5162115,
|
|
"name":"shiluo",
|
|
"username":"shiluo",
|
|
"state":"active",
|
|
"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/5162115/avatar.png",
|
|
"web_url":"https://gitlab.com/shiluo",
|
|
"created_at":"2019-12-23T02:50:10.348Z",
|
|
"bio":"",
|
|
"bio_html":"",
|
|
"location":"China",
|
|
"public_email":"silo1999@163.com",
|
|
"skype":"",
|
|
"linkedin":"",
|
|
"twitter":"",
|
|
"website_url":"",
|
|
"organization":"",
|
|
"job_title":"",
|
|
"pronouns":null,
|
|
"bot":false,
|
|
"work_information":null,
|
|
"followers":0,
|
|
"following":0,
|
|
"last_sign_in_at":"2019-12-26T13:24:42.941Z",
|
|
"confirmed_at":"2019-12-23T02:52:10.778Z",
|
|
"last_activity_on":"2021-08-19",
|
|
"email":"silo1999@163.com",
|
|
"theme_id":1,
|
|
"color_scheme_id":1,
|
|
"projects_limit":100000,
|
|
"current_sign_in_at":"2021-08-19T09:46:46.004Z",
|
|
"identities":[
|
|
{
|
|
"provider":"github",
|
|
"extern_uid":"51157931",
|
|
"saml_provider_id":null
|
|
}
|
|
],
|
|
"can_create_group":true,
|
|
"can_create_project":true,
|
|
"two_factor_enabled":false,
|
|
"external":false,
|
|
"private_profile":false,
|
|
"commit_email":"silo1999@163.com",
|
|
"shared_runners_minutes_limit":null,
|
|
"extra_shared_runners_minutes_limit":null
|
|
}
|
|
*/
|
|
|
|
type GitlabUserInfo struct {
|
|
Id int `json:"id"`
|
|
Name string `json:"name"`
|
|
Username string `json:"username"`
|
|
State string `json:"state"`
|
|
AvatarUrl string `json:"avatar_url"`
|
|
WebUrl string `json:"web_url"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
Bio string `json:"bio"`
|
|
BioHtml string `json:"bio_html"`
|
|
Location string `json:"location"`
|
|
PublicEmail string `json:"public_email"`
|
|
Skype string `json:"skype"`
|
|
Linkedin string `json:"linkedin"`
|
|
Twitter string `json:"twitter"`
|
|
WebsiteUrl string `json:"website_url"`
|
|
Organization string `json:"organization"`
|
|
JobTitle string `json:"job_title"`
|
|
Pronouns interface{} `json:"pronouns"`
|
|
Bot bool `json:"bot"`
|
|
WorkInformation interface{} `json:"work_information"`
|
|
Followers int `json:"followers"`
|
|
Following int `json:"following"`
|
|
LastSignInAt time.Time `json:"last_sign_in_at"`
|
|
ConfirmedAt time.Time `json:"confirmed_at"`
|
|
LastActivityOn string `json:"last_activity_on"`
|
|
Email string `json:"email"`
|
|
ThemeId int `json:"theme_id"`
|
|
ColorSchemeId int `json:"color_scheme_id"`
|
|
ProjectsLimit int `json:"projects_limit"`
|
|
CurrentSignInAt time.Time `json:"current_sign_in_at"`
|
|
Identities []struct {
|
|
Provider string `json:"provider"`
|
|
ExternUid string `json:"extern_uid"`
|
|
SamlProviderId interface{} `json:"saml_provider_id"`
|
|
} `json:"identities"`
|
|
CanCreateGroup bool `json:"can_create_group"`
|
|
CanCreateProject bool `json:"can_create_project"`
|
|
TwoFactorEnabled bool `json:"two_factor_enabled"`
|
|
External bool `json:"external"`
|
|
PrivateProfile bool `json:"private_profile"`
|
|
CommitEmail string `json:"commit_email"`
|
|
SharedRunnersMinutesLimit interface{} `json:"shared_runners_minutes_limit"`
|
|
ExtraSharedRunnersMinutesLimit interface{} `json:"extra_shared_runners_minutes_limit"`
|
|
}
|
|
|
|
// GetUserInfo use GitlabProviderToken gotten before return GitlabUserInfo
|
|
func (idp *GitlabIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
|
resp, err := idp.Client.Get("https://gitlab.com/api/v4/user?access_token=" + token.AccessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
guser := GitlabUserInfo{}
|
|
if err = json.Unmarshal(data, &guser); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
userInfo := UserInfo{
|
|
Id: strconv.Itoa(guser.Id),
|
|
Username: guser.Username,
|
|
DisplayName: guser.Name,
|
|
AvatarUrl: guser.AvatarUrl,
|
|
Email: guser.Email,
|
|
}
|
|
return &userInfo, nil
|
|
}
|