summaryrefslogtreecommitdiffstats
path: root/services/auth/source/oauth2/providers.go
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2021-08-06 02:11:08 +0100
committerGitHub <noreply@github.com>2021-08-05 21:11:08 -0400
commitab9bb54144f136bbbba2ce2e94fd88c0be0ee1cf (patch)
treef8b283e33e70cbc3d827879c4774de2b41450ab0 /services/auth/source/oauth2/providers.go
parent7e7006e00d8d0d5ce4c871685d421269049e4b39 (diff)
downloadgitea-ab9bb54144f136bbbba2ce2e94fd88c0be0ee1cf.tar.gz
gitea-ab9bb54144f136bbbba2ce2e94fd88c0be0ee1cf.zip
Add microsoft oauth2 providers (#16544)
* Clean up oauth2 providers Signed-off-by: Andrew Thornton <art27@cantab.net> * Add AzureAD, AzureADv2, MicrosoftOnline OAuth2 providers Signed-off-by: Andrew Thornton <art27@cantab.net> * Apply suggestions from code review * remove unused Scopes Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Diffstat (limited to 'services/auth/source/oauth2/providers.go')
-rw-r--r--services/auth/source/oauth2/providers.go252
1 files changed, 75 insertions, 177 deletions
diff --git a/services/auth/source/oauth2/providers.go b/services/auth/source/oauth2/providers.go
index 8df8d62961..2196e30492 100644
--- a/services/auth/source/oauth2/providers.go
+++ b/services/auth/source/oauth2/providers.go
@@ -13,80 +13,72 @@ import (
"code.gitea.io/gitea/modules/setting"
"github.com/markbates/goth"
- "github.com/markbates/goth/providers/bitbucket"
- "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/mastodon"
- "github.com/markbates/goth/providers/nextcloud"
- "github.com/markbates/goth/providers/openidConnect"
- "github.com/markbates/goth/providers/twitter"
- "github.com/markbates/goth/providers/yandex"
)
-// Provider describes the display values of a single OAuth2 provider
-type Provider struct {
- Name string
- DisplayName string
- Image string
- CustomURLMapping *CustomURLMapping
+// Provider is an interface for describing a single OAuth2 provider
+type Provider interface {
+ Name() string
+ DisplayName() string
+ Image() string
+ CustomURLSettings() *CustomURLSettings
+}
+
+// GothProviderCreator provides a function to create a goth.Provider
+type GothProviderCreator interface {
+ CreateGothProvider(providerName, callbackURL string, source *Source) (goth.Provider, error)
+}
+
+// GothProvider is an interface for describing a single OAuth2 provider
+type GothProvider interface {
+ Provider
+ GothProviderCreator
+}
+
+// ImagedProvider provide an overrided image setting for the provider
+type ImagedProvider struct {
+ GothProvider
+ image string
+}
+
+// Image returns the image path for this provider
+func (i *ImagedProvider) Image() string {
+ return i.image
+}
+
+// NewImagedProvider is a constructor function for the ImagedProvider
+func NewImagedProvider(image string, provider GothProvider) *ImagedProvider {
+ return &ImagedProvider{
+ GothProvider: provider,
+ image: image,
+ }
}
// Providers contains the map of registered OAuth2 providers in Gitea (based on goth)
// key is used to map the OAuth2Provider with the goth provider type (also in LoginSource.OAuth2Config.Provider)
// value is used to store display data
-var Providers = map[string]Provider{
- "bitbucket": {Name: "bitbucket", DisplayName: "Bitbucket", Image: "/assets/img/auth/bitbucket.png"},
- "dropbox": {Name: "dropbox", DisplayName: "Dropbox", Image: "/assets/img/auth/dropbox.png"},
- "facebook": {Name: "facebook", DisplayName: "Facebook", Image: "/assets/img/auth/facebook.png"},
- "github": {
- Name: "github", DisplayName: "GitHub", Image: "/assets/img/auth/github.png",
- CustomURLMapping: &CustomURLMapping{
- TokenURL: github.TokenURL,
- AuthURL: github.AuthURL,
- ProfileURL: github.ProfileURL,
- EmailURL: github.EmailURL,
- },
- },
- "gitlab": {
- Name: "gitlab", DisplayName: "GitLab", Image: "/assets/img/auth/gitlab.png",
- CustomURLMapping: &CustomURLMapping{
- TokenURL: gitlab.TokenURL,
- AuthURL: gitlab.AuthURL,
- ProfileURL: gitlab.ProfileURL,
- },
- },
- "gplus": {Name: "gplus", DisplayName: "Google", Image: "/assets/img/auth/google.png"},
- "openidConnect": {Name: "openidConnect", DisplayName: "OpenID Connect", Image: "/assets/img/auth/openid_connect.svg"},
- "twitter": {Name: "twitter", DisplayName: "Twitter", Image: "/assets/img/auth/twitter.png"},
- "discord": {Name: "discord", DisplayName: "Discord", Image: "/assets/img/auth/discord.png"},
- "gitea": {
- Name: "gitea", DisplayName: "Gitea", Image: "/assets/img/auth/gitea.png",
- CustomURLMapping: &CustomURLMapping{
- TokenURL: gitea.TokenURL,
- AuthURL: gitea.AuthURL,
- ProfileURL: gitea.ProfileURL,
- },
- },
- "nextcloud": {
- Name: "nextcloud", DisplayName: "Nextcloud", Image: "/assets/img/auth/nextcloud.png",
- CustomURLMapping: &CustomURLMapping{
- TokenURL: nextcloud.TokenURL,
- AuthURL: nextcloud.AuthURL,
- ProfileURL: nextcloud.ProfileURL,
- },
- },
- "yandex": {Name: "yandex", DisplayName: "Yandex", Image: "/assets/img/auth/yandex.png"},
- "mastodon": {
- Name: "mastodon", DisplayName: "Mastodon", Image: "/assets/img/auth/mastodon.png",
- CustomURLMapping: &CustomURLMapping{
- AuthURL: mastodon.InstanceURL,
- },
- },
+var gothProviders = map[string]GothProvider{}
+
+// RegisterGothProvider registers a GothProvider
+func RegisterGothProvider(provider GothProvider) {
+ if _, has := gothProviders[provider.Name()]; has {
+ log.Fatal("Duplicate oauth2provider type provided: %s", provider.Name())
+ }
+ gothProviders[provider.Name()] = provider
+}
+
+// GetOAuth2Providers returns the map of unconfigured OAuth2 providers
+// key is used as technical name (like in the callbackURL)
+// values to display
+func GetOAuth2Providers() []Provider {
+ providers := make([]Provider, 0, len(gothProviders))
+
+ for _, provider := range gothProviders {
+ providers = append(providers, provider)
+ }
+ sort.Slice(providers, func(i, j int) bool {
+ return providers[i].Name() < providers[j].Name()
+ })
+ return providers
}
// GetActiveOAuth2Providers returns the map of configured active OAuth2 providers
@@ -103,9 +95,9 @@ func GetActiveOAuth2Providers() ([]string, map[string]Provider, error) {
var orderedKeys []string
providers := make(map[string]Provider)
for _, source := range loginSources {
- prov := Providers[source.Cfg.(*Source).Provider]
+ prov := gothProviders[source.Cfg.(*Source).Provider]
if source.Cfg.(*Source).IconURL != "" {
- prov.Image = source.Cfg.(*Source).IconURL
+ prov = &ImagedProvider{prov, source.Cfg.(*Source).IconURL}
}
providers[source.Name] = prov
orderedKeys = append(orderedKeys, source.Name)
@@ -116,9 +108,9 @@ func GetActiveOAuth2Providers() ([]string, map[string]Provider, error) {
return orderedKeys, providers, nil
}
-// RegisterProvider register a OAuth2 provider in goth lib
-func RegisterProvider(providerName, providerType, clientID, clientSecret, openIDConnectAutoDiscoveryURL string, customURLMapping *CustomURLMapping) error {
- provider, err := createProvider(providerName, providerType, clientID, clientSecret, openIDConnectAutoDiscoveryURL, customURLMapping)
+// RegisterProviderWithGothic register a OAuth2 provider in goth lib
+func RegisterProviderWithGothic(providerName string, source *Source) error {
+ provider, err := createProvider(providerName, source)
if err == nil && provider != nil {
gothRWMutex.Lock()
@@ -130,8 +122,8 @@ func RegisterProvider(providerName, providerType, clientID, clientSecret, openID
return err
}
-// RemoveProvider removes the given OAuth2 provider from the goth lib
-func RemoveProvider(providerName string) {
+// RemoveProviderFromGothic removes the given OAuth2 provider from the goth lib
+func RemoveProviderFromGothic(providerName string) {
gothRWMutex.Lock()
defer gothRWMutex.Unlock()
@@ -147,114 +139,20 @@ func ClearProviders() {
}
// used to create different types of goth providers
-func createProvider(providerName, providerType, clientID, clientSecret, openIDConnectAutoDiscoveryURL string, customURLMapping *CustomURLMapping) (goth.Provider, error) {
+func createProvider(providerName string, source *Source) (goth.Provider, error) {
callbackURL := setting.AppURL + "user/oauth2/" + url.PathEscape(providerName) + "/callback"
var provider goth.Provider
var err error
- switch providerType {
- case "bitbucket":
- provider = bitbucket.New(clientID, clientSecret, callbackURL, "account")
- case "dropbox":
- provider = dropbox.New(clientID, clientSecret, callbackURL)
- case "facebook":
- provider = facebook.New(clientID, clientSecret, callbackURL, "email")
- case "github":
- authURL := github.AuthURL
- tokenURL := github.TokenURL
- profileURL := github.ProfileURL
- emailURL := github.EmailURL
- if customURLMapping != nil {
- if len(customURLMapping.AuthURL) > 0 {
- authURL = customURLMapping.AuthURL
- }
- if len(customURLMapping.TokenURL) > 0 {
- tokenURL = customURLMapping.TokenURL
- }
- if len(customURLMapping.ProfileURL) > 0 {
- profileURL = customURLMapping.ProfileURL
- }
- if len(customURLMapping.EmailURL) > 0 {
- emailURL = customURLMapping.EmailURL
- }
- }
- scopes := []string{}
- if setting.OAuth2Client.EnableAutoRegistration {
- scopes = append(scopes, "user:email")
- }
- provider = github.NewCustomisedURL(clientID, clientSecret, callbackURL, authURL, tokenURL, profileURL, emailURL, scopes...)
- case "gitlab":
- authURL := gitlab.AuthURL
- tokenURL := gitlab.TokenURL
- profileURL := gitlab.ProfileURL
- if customURLMapping != nil {
- if len(customURLMapping.AuthURL) > 0 {
- authURL = customURLMapping.AuthURL
- }
- if len(customURLMapping.TokenURL) > 0 {
- tokenURL = customURLMapping.TokenURL
- }
- if len(customURLMapping.ProfileURL) > 0 {
- profileURL = customURLMapping.ProfileURL
- }
- }
- provider = gitlab.NewCustomisedURL(clientID, clientSecret, callbackURL, authURL, tokenURL, profileURL, "read_user")
- case "gplus": // named gplus due to legacy gplus -> google migration (Google killed Google+). This ensures old connections still work
- scopes := []string{"email"}
- if setting.OAuth2Client.UpdateAvatar || setting.OAuth2Client.EnableAutoRegistration {
- scopes = append(scopes, "profile")
- }
- provider = google.New(clientID, clientSecret, callbackURL, scopes...)
- case "openidConnect":
- if provider, err = openidConnect.New(clientID, clientSecret, callbackURL, openIDConnectAutoDiscoveryURL, setting.OAuth2Client.OpenIDConnectScopes...); err != nil {
- log.Warn("Failed to create OpenID Connect Provider with name '%s' with url '%s': %v", providerName, openIDConnectAutoDiscoveryURL, err)
- }
- case "twitter":
- provider = twitter.NewAuthenticate(clientID, clientSecret, callbackURL)
- case "discord":
- provider = discord.New(clientID, clientSecret, callbackURL, discord.ScopeIdentify, discord.ScopeEmail)
- case "gitea":
- authURL := gitea.AuthURL
- tokenURL := gitea.TokenURL
- profileURL := gitea.ProfileURL
- if customURLMapping != nil {
- if len(customURLMapping.AuthURL) > 0 {
- authURL = customURLMapping.AuthURL
- }
- if len(customURLMapping.TokenURL) > 0 {
- tokenURL = customURLMapping.TokenURL
- }
- if len(customURLMapping.ProfileURL) > 0 {
- profileURL = customURLMapping.ProfileURL
- }
- }
- provider = gitea.NewCustomisedURL(clientID, clientSecret, callbackURL, authURL, tokenURL, profileURL)
- case "nextcloud":
- authURL := nextcloud.AuthURL
- tokenURL := nextcloud.TokenURL
- profileURL := nextcloud.ProfileURL
- if customURLMapping != nil {
- if len(customURLMapping.AuthURL) > 0 {
- authURL = customURLMapping.AuthURL
- }
- if len(customURLMapping.TokenURL) > 0 {
- tokenURL = customURLMapping.TokenURL
- }
- if len(customURLMapping.ProfileURL) > 0 {
- profileURL = customURLMapping.ProfileURL
- }
- }
- provider = nextcloud.NewCustomisedURL(clientID, clientSecret, callbackURL, authURL, tokenURL, profileURL)
- case "yandex":
- // See https://tech.yandex.com/passport/doc/dg/reference/response-docpage/
- provider = yandex.New(clientID, clientSecret, callbackURL, "login:email", "login:info", "login:avatar")
- case "mastodon":
- instanceURL := mastodon.InstanceURL
- if customURLMapping != nil && len(customURLMapping.AuthURL) > 0 {
- instanceURL = customURLMapping.AuthURL
- }
- provider = mastodon.NewCustomisedURL(clientID, clientSecret, callbackURL, instanceURL)
+ p, ok := gothProviders[source.Provider]
+ if !ok {
+ return nil, models.ErrLoginSourceNotActived
+ }
+
+ provider, err = p.CreateGothProvider(providerName, callbackURL, source)
+ if err != nil {
+ return provider, err
}
// always set the name if provider is created so we can support multiple setups of 1 provider