mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-15 12:27:59 +00:00
fa8f191812
* feat: v2alpha user service idp endpoints * feat: v2alpha user service intent endpoints * begin idp intents (callback) * some cleanup * runnable idp authentication * cleanup * proto cleanup * retrieve idp info * improve success and failure handling * some unit tests * grpc unit tests * add permission check AddUserIDPLink * feat: v2alpha intent writemodel refactoring * feat: v2alpha intent writemodel refactoring * feat: v2alpha intent writemodel refactoring * provider from write model * fix idp type model and add integration tests * proto cleanup * fix integration test * add missing import * add more integration tests * auth url test * feat: v2alpha intent writemodel refactoring * remove unused functions * check token on RetrieveIdentityProviderInformation * feat: v2alpha intent writemodel refactoring * fix TestServer_RetrieveIdentityProviderInformation * fix test * i18n and linting * feat: v2alpha intent review changes --------- Co-authored-by: Livio Spring <livio.a@gmail.com> Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
191 lines
6.8 KiB
Go
191 lines
6.8 KiB
Go
package github
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
|
|
"golang.org/x/oauth2"
|
|
"golang.org/x/text/language"
|
|
|
|
"github.com/zitadel/zitadel/internal/domain"
|
|
"github.com/zitadel/zitadel/internal/idp"
|
|
"github.com/zitadel/zitadel/internal/idp/providers/oauth"
|
|
)
|
|
|
|
const (
|
|
authURL = "https://github.com/login/oauth/authorize"
|
|
tokenURL = "https://github.com/login/oauth/access_token"
|
|
profileURL = "https://api.github.com/user"
|
|
name = "GitHub"
|
|
)
|
|
|
|
var _ idp.Provider = (*Provider)(nil)
|
|
|
|
// New creates a GitHub.com provider using the [oauth.Provider] (OAuth 2.0 generic provider)
|
|
func New(clientID, secret, callbackURL string, scopes []string, options ...oauth.ProviderOpts) (*Provider, error) {
|
|
return NewCustomURL(name, clientID, secret, callbackURL, authURL, tokenURL, profileURL, scopes, options...)
|
|
}
|
|
|
|
// NewCustomURL creates a GitHub provider using the [oauth.Provider] (OAuth 2.0 generic provider)
|
|
// with custom endpoints, e.g. GitHub Enterprise server
|
|
func NewCustomURL(name, clientID, secret, callbackURL, authURL, tokenURL, profileURL string, scopes []string, options ...oauth.ProviderOpts) (*Provider, error) {
|
|
rp, err := oauth.New(
|
|
newConfig(clientID, secret, callbackURL, authURL, tokenURL, scopes),
|
|
name,
|
|
profileURL,
|
|
func() idp.User {
|
|
return new(User)
|
|
},
|
|
options...,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Provider{
|
|
Provider: rp,
|
|
}, nil
|
|
}
|
|
|
|
// Provider is the [idp.Provider] implementation for GitHub
|
|
type Provider struct {
|
|
*oauth.Provider
|
|
}
|
|
|
|
func newConfig(clientID, secret, callbackURL, authURL, tokenURL string, scopes []string) *oauth2.Config {
|
|
c := &oauth2.Config{
|
|
ClientID: clientID,
|
|
ClientSecret: secret,
|
|
RedirectURL: callbackURL,
|
|
Endpoint: oauth2.Endpoint{
|
|
AuthURL: authURL,
|
|
TokenURL: tokenURL,
|
|
},
|
|
Scopes: scopes,
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
// User is a representation of the authenticated GitHub user and implements the [idp.User] interface
|
|
// https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-the-authenticated-user
|
|
type User 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 domain.EmailAddress `json:"email"`
|
|
Hireable bool `json:"hireable"`
|
|
Bio string `json:"bio"`
|
|
TwitterUsername string `json:"twitter_username"`
|
|
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"`
|
|
TwoFactorAuthentication bool `json:"two_factor_authentication"`
|
|
Plan struct {
|
|
Name string `json:"name"`
|
|
Space int `json:"space"`
|
|
PrivateRepos int `json:"private_repos"`
|
|
Collaborators int `json:"collaborators"`
|
|
} `json:"plan"`
|
|
}
|
|
|
|
// GetID is an implementation of the [idp.User] interface.
|
|
func (u *User) GetID() string {
|
|
return strconv.Itoa(u.ID)
|
|
}
|
|
|
|
// GetFirstName is an implementation of the [idp.User] interface.
|
|
// It returns an empty string because GitHub does not provide the user's firstname.
|
|
func (u *User) GetFirstName() string {
|
|
return ""
|
|
}
|
|
|
|
// GetLastName is an implementation of the [idp.User] interface.
|
|
// It returns an empty string because GitHub does not provide the user's lastname.
|
|
func (u *User) GetLastName() string {
|
|
// GitHub does not provide the user's lastname
|
|
return ""
|
|
}
|
|
|
|
// GetDisplayName is an implementation of the [idp.User] interface.
|
|
func (u *User) GetDisplayName() string {
|
|
return u.Name
|
|
}
|
|
|
|
// GetNickname is an implementation of the [idp.User] interface
|
|
// returning the login name of the GitHub user.
|
|
func (u *User) GetNickname() string {
|
|
return u.Login
|
|
}
|
|
|
|
// GetPreferredUsername is an implementation of the [idp.User] interface
|
|
// returning the login name of the GitHub user.
|
|
func (u *User) GetPreferredUsername() string {
|
|
return u.Login
|
|
}
|
|
|
|
// GetEmail is an implementation of the [idp.User] interface.
|
|
func (u *User) GetEmail() domain.EmailAddress {
|
|
return u.Email
|
|
}
|
|
|
|
// IsEmailVerified is an implementation of the [idp.User] interface.
|
|
// It returns true because GitHub validates emails themselves.
|
|
func (u *User) IsEmailVerified() bool {
|
|
return true
|
|
}
|
|
|
|
// GetPhone is an implementation of the [idp.User] interface.
|
|
// It returns an empty string because GitHub does not provide the user's phone.
|
|
func (u *User) GetPhone() domain.PhoneNumber {
|
|
return ""
|
|
}
|
|
|
|
// IsPhoneVerified is an implementation of the [idp.User] interface
|
|
// it returns false because GitHub does not provide the user's phone
|
|
func (u *User) IsPhoneVerified() bool {
|
|
return false
|
|
}
|
|
|
|
// GetPreferredLanguage is an implementation of the [idp.User] interface.
|
|
// It returns [language.Und] because GitHub does not provide the user's language.
|
|
func (u *User) GetPreferredLanguage() language.Tag {
|
|
return language.Und
|
|
}
|
|
|
|
// GetProfile is an implementation of the [idp.User] interface.
|
|
func (u *User) GetProfile() string {
|
|
return u.HtmlUrl
|
|
}
|
|
|
|
// GetAvatarURL is an implementation of the [idp.User] interface.
|
|
func (u *User) GetAvatarURL() string {
|
|
return u.AvatarUrl
|
|
}
|