/* * * Copyright 2020 The KubeSphere Authors. * * 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 github import ( "context" "encoding/json" "golang.org/x/oauth2" "gopkg.in/yaml.v3" "io/ioutil" "kubesphere.io/kubesphere/pkg/apiserver/authentication/identityprovider" "kubesphere.io/kubesphere/pkg/apiserver/authentication/oauth" "time" ) const ( UserInfoURL = "https://api.github.com/user" ) type Github struct { // ClientID is the application's ID. ClientID string `json:"clientID" yaml:"clientID"` // ClientSecret is the application's secret. ClientSecret string `json:"-" yaml:"clientSecret"` // Endpoint contains the resource server's token endpoint // URLs. These are constants specific to each server and are // often available via site-specific packages, such as // google.Endpoint or github.Endpoint. Endpoint Endpoint `json:"endpoint" yaml:"endpoint"` // RedirectURL is the URL to redirect users going through // the OAuth flow, after the resource owner's URLs. RedirectURL string `json:"redirectURL" yaml:"redirectURL"` // Scope specifies optional requested permissions. Scopes []string `json:"scopes" yaml:"scopes"` } // Endpoint represents an OAuth 2.0 provider's authorization and token // endpoint URLs. type Endpoint struct { AuthURL string `json:"authURL" yaml:"authURL"` TokenURL string `json:"tokenURL" yaml:"tokenURL"` } type GithubIdentity struct { Login string `json:"login"` ID int `json:"id"` NodeID string `json:"node_id"` AvatarURL string `json:"avatar_url"` GravatarID string `json:"gravatar_id"` URL string `json:"url"` HTMLURL string `json:"html_url"` FollowersURL string `json:"followers_url"` FollowingURL string `json:"following_url"` GistsURL string `json:"gists_url"` StarredURL string `json:"starred_url"` SubscriptionsURL string `json:"subscriptions_url"` OrganizationsURL string `json:"organizations_url"` ReposURL string `json:"repos_url"` EventsURL string `json:"events_url"` ReceivedEventsURL string `json:"received_events_url"` Type string `json:"type"` SiteAdmin bool `json:"site_admin"` Name string `json:"name"` Company string `json:"company"` Blog string `json:"blog"` Location string `json:"location"` Email string `json:"email"` Hireable bool `json:"hireable"` Bio string `json:"bio"` PublicRepos int `json:"public_repos"` PublicGists int `json:"public_gists"` Followers int `json:"followers"` Following int `json:"following"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` PrivateGists int `json:"private_gists"` TotalPrivateRepos int `json:"total_private_repos"` OwnedPrivateRepos int `json:"owned_private_repos"` DiskUsage int `json:"disk_usage"` Collaborators int `json:"collaborators"` } func init() { identityprovider.RegisterOAuthProviderCodec(&Github{}) } func (g *Github) Type() string { return "GitHubIdentityProvider" } func (g *Github) Setup(options *oauth.DynamicOptions) (identityprovider.OAuthProvider, error) { data, err := yaml.Marshal(options) if err != nil { return nil, err } var provider Github err = yaml.Unmarshal(data, &provider) if err != nil { return nil, err } return &provider, nil } func (g GithubIdentity) GetName() string { return g.Login } func (g GithubIdentity) GetEmail() string { return g.Email } func (g *Github) IdentityExchange(code string) (identityprovider.Identity, error) { config := oauth2.Config{ ClientID: g.ClientID, ClientSecret: g.ClientSecret, Endpoint: oauth2.Endpoint{ AuthURL: g.Endpoint.AuthURL, TokenURL: g.Endpoint.TokenURL, AuthStyle: oauth2.AuthStyleAutoDetect, }, RedirectURL: g.RedirectURL, Scopes: g.Scopes, } token, err := config.Exchange(context.Background(), code) if err != nil { return nil, err } resp, err := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(token)).Get(UserInfoURL) if err != nil { return nil, err } data, err := ioutil.ReadAll(resp.Body) defer resp.Body.Close() if err != nil { return nil, err } var githubIdentity GithubIdentity err = json.Unmarshal(data, &githubIdentity) if err != nil { return nil, err } return githubIdentity, nil }