2021-07-24 12:16:34 +02:00
|
|
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
2022-11-27 19:20:29 +01:00
|
|
|
// SPDX-License-Identifier: MIT
|
2017-02-22 08:14:37 +01:00
|
|
|
|
|
|
|
package oauth2
|
|
|
|
|
|
|
|
import (
|
2023-10-14 10:37:24 +02:00
|
|
|
"context"
|
2021-11-24 10:49:20 +01:00
|
|
|
"errors"
|
2023-06-13 12:51:02 +02:00
|
|
|
"fmt"
|
|
|
|
"html"
|
|
|
|
"html/template"
|
2020-08-31 00:55:01 +02:00
|
|
|
"net/url"
|
2021-07-24 12:16:34 +02:00
|
|
|
"sort"
|
2017-03-03 09:21:31 +01:00
|
|
|
|
2022-01-02 14:12:35 +01:00
|
|
|
"code.gitea.io/gitea/models/auth"
|
2023-11-24 04:49:41 +01:00
|
|
|
"code.gitea.io/gitea/models/db"
|
2017-02-22 08:14:37 +01:00
|
|
|
"code.gitea.io/gitea/modules/log"
|
2024-03-02 16:42:31 +01:00
|
|
|
"code.gitea.io/gitea/modules/optional"
|
2017-03-03 09:21:31 +01:00
|
|
|
"code.gitea.io/gitea/modules/setting"
|
|
|
|
|
2017-02-22 08:14:37 +01:00
|
|
|
"github.com/markbates/goth"
|
|
|
|
)
|
|
|
|
|
2021-08-06 03:11:08 +02:00
|
|
|
// Provider is an interface for describing a single OAuth2 provider
|
|
|
|
type Provider interface {
|
|
|
|
Name() string
|
|
|
|
DisplayName() string
|
2023-09-19 23:47:13 +02:00
|
|
|
IconHTML(size int) template.HTML
|
2021-08-06 03:11:08 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-06-08 18:35:29 +02:00
|
|
|
// AuthSourceProvider provides a provider for an AuthSource. Multiple auth sources could use the same registered GothProvider
|
2023-06-13 12:51:02 +02:00
|
|
|
// So each auth source should have its own DisplayName and IconHTML for display.
|
2023-06-08 18:35:29 +02:00
|
|
|
// The Name is the GothProvider's name, to help to find the GothProvider to sign in.
|
|
|
|
// The DisplayName is the auth source config's name, site admin set it on the admin page, the IconURL can also be set there.
|
|
|
|
type AuthSourceProvider struct {
|
2021-08-06 03:11:08 +02:00
|
|
|
GothProvider
|
2023-06-08 18:35:29 +02:00
|
|
|
sourceName, iconURL string
|
2021-08-06 03:11:08 +02:00
|
|
|
}
|
|
|
|
|
2023-06-08 18:35:29 +02:00
|
|
|
func (p *AuthSourceProvider) Name() string {
|
|
|
|
return p.GothProvider.Name()
|
2021-08-06 03:11:08 +02:00
|
|
|
}
|
|
|
|
|
2023-06-08 18:35:29 +02:00
|
|
|
func (p *AuthSourceProvider) DisplayName() string {
|
|
|
|
return p.sourceName
|
|
|
|
}
|
|
|
|
|
2023-09-19 23:47:13 +02:00
|
|
|
func (p *AuthSourceProvider) IconHTML(size int) template.HTML {
|
2023-06-08 18:35:29 +02:00
|
|
|
if p.iconURL != "" {
|
Migrate margin and padding helpers to tailwind (#30043)
This will conclude the refactor of 1:1 class replacements to tailwind,
except `gt-hidden`. Commands ran:
```bash
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-0#tw-$1$2-0#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-1#tw-$1$2-0.5#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-2#tw-$1$2-1#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-3#tw-$1$2-2#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-4#tw-$1$2-4#g' {web_src/js,templates,routers,services}/**/*
perl -p -i -e 's#gt-(p|m)([lrtbxy])?-5#tw-$1$2-8#g' {web_src/js,templates,routers,services}/**/*
```
(cherry picked from commit 68ec9b48592fe88765bcc3a73093d43c98b315de)
Conflicts:
routers/web/repo/view.go
templates/base/head_navbar.tmpl
templates/repo/code/recently_pushed_new_branches.tmpl
templates/repo/diff/box.tmpl
templates/repo/diff/compare.tmpl
templates/repo/diff/conversation.tmpl
templates/repo/header.tmpl
templates/repo/issue/filter_list.tmpl
templates/repo/issue/view_content/conversation.tmpl
templates/repo/issue/view_content/sidebar.tmpl
templates/repo/settings/options.tmpl
templates/repo/view_file.tmpl
templates/shared/user/blocked_users.tmpl
templates/status/500.tmpl
web_src/js/components/DashboardRepoList.vue
resolved by prefering Forgejo version and applying the
commands to all files
2024-03-24 17:42:49 +01:00
|
|
|
img := fmt.Sprintf(`<img class="tw-object-contain tw-mr-2" width="%d" height="%d" src="%s" alt="%s">`,
|
2023-09-19 23:47:13 +02:00
|
|
|
size,
|
|
|
|
size,
|
2023-06-13 12:51:02 +02:00
|
|
|
html.EscapeString(p.iconURL), html.EscapeString(p.DisplayName()),
|
|
|
|
)
|
|
|
|
return template.HTML(img)
|
2021-08-06 03:11:08 +02:00
|
|
|
}
|
2023-09-19 23:47:13 +02:00
|
|
|
return p.GothProvider.IconHTML(size)
|
2021-07-24 12:16:34 +02:00
|
|
|
}
|
2017-02-22 08:14:37 +01:00
|
|
|
|
2021-07-24 12:16:34 +02:00
|
|
|
// Providers contains the map of registered OAuth2 providers in Gitea (based on goth)
|
2022-01-02 14:12:35 +01:00
|
|
|
// key is used to map the OAuth2Provider with the goth provider type (also in AuthSource.OAuth2Config.Provider)
|
2021-07-24 12:16:34 +02:00
|
|
|
// value is used to store display data
|
2021-08-06 03:11:08 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-11-03 02:41:00 +01:00
|
|
|
// GetSupportedOAuth2Providers returns the map of unconfigured OAuth2 providers
|
2021-08-06 03:11:08 +02:00
|
|
|
// key is used as technical name (like in the callbackURL)
|
|
|
|
// values to display
|
2023-11-03 02:41:00 +01:00
|
|
|
func GetSupportedOAuth2Providers() []Provider {
|
2021-08-06 03:11:08 +02:00
|
|
|
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
|
2017-05-01 15:26:53 +02:00
|
|
|
}
|
|
|
|
|
2023-11-03 02:41:00 +01:00
|
|
|
func CreateProviderFromSource(source *auth.Source) (Provider, error) {
|
|
|
|
oauth2Cfg, ok := source.Cfg.(*Source)
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("invalid OAuth2 source config: %v", oauth2Cfg)
|
|
|
|
}
|
|
|
|
gothProv := gothProviders[oauth2Cfg.Provider]
|
|
|
|
return &AuthSourceProvider{GothProvider: gothProv, sourceName: source.Name, iconURL: oauth2Cfg.IconURL}, nil
|
|
|
|
}
|
2017-02-22 08:14:37 +01:00
|
|
|
|
2023-11-03 02:41:00 +01:00
|
|
|
// GetOAuth2Providers returns the list of configured OAuth2 providers
|
2024-03-02 16:42:31 +01:00
|
|
|
func GetOAuth2Providers(ctx context.Context, isActive optional.Option[bool]) ([]Provider, error) {
|
2023-11-24 04:49:41 +01:00
|
|
|
authSources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{
|
2023-11-03 02:41:00 +01:00
|
|
|
IsActive: isActive,
|
|
|
|
LoginType: auth.OAuth2,
|
|
|
|
})
|
2018-04-29 08:09:24 +02:00
|
|
|
if err != nil {
|
2023-11-03 02:41:00 +01:00
|
|
|
return nil, err
|
2017-02-22 08:14:37 +01:00
|
|
|
}
|
|
|
|
|
2023-11-03 02:41:00 +01:00
|
|
|
providers := make([]Provider, 0, len(authSources))
|
2022-01-02 14:12:35 +01:00
|
|
|
for _, source := range authSources {
|
2023-11-03 02:41:00 +01:00
|
|
|
provider, err := CreateProviderFromSource(source)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2021-07-24 12:16:34 +02:00
|
|
|
}
|
2023-11-03 02:41:00 +01:00
|
|
|
providers = append(providers, provider)
|
2017-02-22 08:14:37 +01:00
|
|
|
}
|
|
|
|
|
2023-11-03 02:41:00 +01:00
|
|
|
sort.Slice(providers, func(i, j int) bool {
|
|
|
|
return providers[i].Name() < providers[j].Name()
|
|
|
|
})
|
2017-02-22 08:14:37 +01:00
|
|
|
|
2023-11-03 02:41:00 +01:00
|
|
|
return providers, nil
|
2017-02-22 08:14:37 +01:00
|
|
|
}
|
|
|
|
|
2021-08-06 03:11:08 +02:00
|
|
|
// RegisterProviderWithGothic register a OAuth2 provider in goth lib
|
|
|
|
func RegisterProviderWithGothic(providerName string, source *Source) error {
|
|
|
|
provider, err := createProvider(providerName, source)
|
2017-02-22 08:14:37 +01:00
|
|
|
|
2017-05-01 15:26:53 +02:00
|
|
|
if err == nil && provider != nil {
|
2021-07-29 19:53:18 +02:00
|
|
|
gothRWMutex.Lock()
|
|
|
|
defer gothRWMutex.Unlock()
|
|
|
|
|
2017-02-22 08:14:37 +01:00
|
|
|
goth.UseProviders(provider)
|
|
|
|
}
|
2017-05-01 15:26:53 +02:00
|
|
|
|
|
|
|
return err
|
2017-02-22 08:14:37 +01:00
|
|
|
}
|
|
|
|
|
2021-08-06 03:11:08 +02:00
|
|
|
// RemoveProviderFromGothic removes the given OAuth2 provider from the goth lib
|
|
|
|
func RemoveProviderFromGothic(providerName string) {
|
2021-07-29 19:53:18 +02:00
|
|
|
gothRWMutex.Lock()
|
|
|
|
defer gothRWMutex.Unlock()
|
|
|
|
|
2017-02-22 08:14:37 +01:00
|
|
|
delete(goth.GetProviders(), providerName)
|
|
|
|
}
|
|
|
|
|
2020-12-24 20:47:17 +01:00
|
|
|
// ClearProviders clears all OAuth2 providers from the goth lib
|
|
|
|
func ClearProviders() {
|
2021-07-29 19:53:18 +02:00
|
|
|
gothRWMutex.Lock()
|
|
|
|
defer gothRWMutex.Unlock()
|
|
|
|
|
2020-12-24 20:47:17 +01:00
|
|
|
goth.ClearProviders()
|
|
|
|
}
|
|
|
|
|
2023-06-08 18:35:29 +02:00
|
|
|
var ErrAuthSourceNotActivated = errors.New("auth source is not activated")
|
2021-11-24 10:49:20 +01:00
|
|
|
|
2017-02-22 08:14:37 +01:00
|
|
|
// used to create different types of goth providers
|
2021-08-06 03:11:08 +02:00
|
|
|
func createProvider(providerName string, source *Source) (goth.Provider, error) {
|
2020-08-31 00:55:01 +02:00
|
|
|
callbackURL := setting.AppURL + "user/oauth2/" + url.PathEscape(providerName) + "/callback"
|
2017-02-22 08:14:37 +01:00
|
|
|
|
|
|
|
var provider goth.Provider
|
2017-05-01 15:26:53 +02:00
|
|
|
var err error
|
2017-02-22 08:14:37 +01:00
|
|
|
|
2021-08-06 03:11:08 +02:00
|
|
|
p, ok := gothProviders[source.Provider]
|
|
|
|
if !ok {
|
2023-06-08 18:35:29 +02:00
|
|
|
return nil, ErrAuthSourceNotActivated
|
2021-08-06 03:11:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
provider, err = p.CreateGothProvider(providerName, callbackURL, source)
|
|
|
|
if err != nil {
|
|
|
|
return provider, err
|
2017-02-22 08:14:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// always set the name if provider is created so we can support multiple setups of 1 provider
|
2017-05-01 15:26:53 +02:00
|
|
|
if err == nil && provider != nil {
|
2017-02-22 08:14:37 +01:00
|
|
|
provider.SetName(providerName)
|
|
|
|
}
|
|
|
|
|
2017-05-01 15:26:53 +02:00
|
|
|
return provider, err
|
|
|
|
}
|