aboutsummaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2021-12-14 08:37:11 +0000
committerGitHub <noreply@github.com>2021-12-14 16:37:11 +0800
commit0981ec30c3d5218939d44fc2f40725b0b4a03684 (patch)
tree5479fb309f9800310cf2268d493e1cd33abfeac6 /services
parentb4782e24d2821bbb5647eff2eaf5c338e92324db (diff)
downloadgitea-0981ec30c3d5218939d44fc2f40725b0b4a03684.tar.gz
gitea-0981ec30c3d5218939d44fc2f40725b0b4a03684.zip
Add Option to synchronize Admin & Restricted states from OIDC/OAuth2 along with Setting Scopes (#16766)
* Add setting to OAuth handlers to override local 2FA settings This PR adds a setting to OAuth and OpenID login sources to allow the source to override local 2FA requirements. Fix #13939 Signed-off-by: Andrew Thornton <art27@cantab.net> * Fix regression from #16544 Signed-off-by: Andrew Thornton <art27@cantab.net> * Add scopes settings Signed-off-by: Andrew Thornton <art27@cantab.net> * fix trace logging in auth_openid Signed-off-by: Andrew Thornton <art27@cantab.net> * add required claim options Signed-off-by: Andrew Thornton <art27@cantab.net> * Move UpdateExternalUser to externalaccount Signed-off-by: Andrew Thornton <art27@cantab.net> * Allow OAuth2/OIDC to set Admin/Restricted status Signed-off-by: Andrew Thornton <art27@cantab.net> * Allow use of the same group claim name for the prohibit login value Signed-off-by: Andrew Thornton <art27@cantab.net> * fixup! Move UpdateExternalUser to externalaccount * as per wxiaoguang Signed-off-by: Andrew Thornton <art27@cantab.net> * add label back in Signed-off-by: Andrew Thornton <art27@cantab.net> * adjust localisation Signed-off-by: Andrew Thornton <art27@cantab.net> * placate lint Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Diffstat (limited to 'services')
-rw-r--r--services/auth/source/oauth2/providers_custom.go32
-rw-r--r--services/auth/source/oauth2/providers_openid.go7
-rw-r--r--services/auth/source/oauth2/providers_simple.go5
-rw-r--r--services/auth/source/oauth2/source.go9
-rw-r--r--services/externalaccount/link.go29
-rw-r--r--services/externalaccount/user.go26
-rw-r--r--services/forms/auth_form.go6
7 files changed, 93 insertions, 21 deletions
diff --git a/services/auth/source/oauth2/providers_custom.go b/services/auth/source/oauth2/providers_custom.go
index f2cff131f4..c3ebdf9df0 100644
--- a/services/auth/source/oauth2/providers_custom.go
+++ b/services/auth/source/oauth2/providers_custom.go
@@ -17,7 +17,7 @@ import (
)
// CustomProviderNewFn creates a goth.Provider using a custom url mapping
-type CustomProviderNewFn func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error)
+type CustomProviderNewFn func(clientID, secret, callbackURL string, custom *CustomURLMapping, scopes []string) (goth.Provider, error)
// CustomProvider is a GothProvider that has CustomURL features
type CustomProvider struct {
@@ -35,7 +35,7 @@ func (c *CustomProvider) CustomURLSettings() *CustomURLSettings {
func (c *CustomProvider) CreateGothProvider(providerName, callbackURL string, source *Source) (goth.Provider, error) {
custom := c.customURLSettings.OverrideWith(source.CustomURLMapping)
- return c.newFn(source.ClientID, source.ClientSecret, callbackURL, custom)
+ return c.newFn(source.ClientID, source.ClientSecret, callbackURL, custom, source.Scopes)
}
// NewCustomProvider is a constructor function for custom providers
@@ -60,8 +60,7 @@ func init() {
ProfileURL: availableAttribute(github.ProfileURL),
EmailURL: availableAttribute(github.EmailURL),
},
- func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) {
- scopes := []string{}
+ func(clientID, secret, callbackURL string, custom *CustomURLMapping, scopes []string) (goth.Provider, error) {
if setting.OAuth2Client.EnableAutoRegistration {
scopes = append(scopes, "user:email")
}
@@ -73,8 +72,9 @@ func init() {
AuthURL: availableAttribute(gitlab.AuthURL),
TokenURL: availableAttribute(gitlab.TokenURL),
ProfileURL: availableAttribute(gitlab.ProfileURL),
- }, func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) {
- return gitlab.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL, "read_user"), nil
+ }, func(clientID, secret, callbackURL string, custom *CustomURLMapping, scopes []string) (goth.Provider, error) {
+ scopes = append(scopes, "read_user")
+ return gitlab.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL, scopes...), nil
}))
RegisterGothProvider(NewCustomProvider(
@@ -83,8 +83,8 @@ func init() {
AuthURL: requiredAttribute(gitea.AuthURL),
ProfileURL: requiredAttribute(gitea.ProfileURL),
},
- func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) {
- return gitea.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL), nil
+ func(clientID, secret, callbackURL string, custom *CustomURLMapping, scopes []string) (goth.Provider, error) {
+ return gitea.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL, scopes...), nil
}))
RegisterGothProvider(NewCustomProvider(
@@ -93,25 +93,31 @@ func init() {
AuthURL: requiredAttribute(nextcloud.AuthURL),
ProfileURL: requiredAttribute(nextcloud.ProfileURL),
},
- func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) {
- return nextcloud.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL), nil
+ func(clientID, secret, callbackURL string, custom *CustomURLMapping, scopes []string) (goth.Provider, error) {
+ return nextcloud.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL, scopes...), nil
}))
RegisterGothProvider(NewCustomProvider(
"mastodon", "Mastodon", &CustomURLSettings{
AuthURL: requiredAttribute(mastodon.InstanceURL),
},
- func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) {
- return mastodon.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL), nil
+ func(clientID, secret, callbackURL string, custom *CustomURLMapping, scopes []string) (goth.Provider, error) {
+ return mastodon.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, scopes...), nil
}))
RegisterGothProvider(NewCustomProvider(
"azureadv2", "Azure AD v2", &CustomURLSettings{
Tenant: requiredAttribute("organizations"),
},
- func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) {
+ func(clientID, secret, callbackURL string, custom *CustomURLMapping, scopes []string) (goth.Provider, error) {
+ azureScopes := make([]azureadv2.ScopeType, len(scopes))
+ for i, scope := range scopes {
+ azureScopes[i] = azureadv2.ScopeType(scope)
+ }
+
return azureadv2.New(clientID, secret, callbackURL, azureadv2.ProviderOptions{
Tenant: azureadv2.TenantType(custom.Tenant),
+ Scopes: azureScopes,
}), nil
},
))
diff --git a/services/auth/source/oauth2/providers_openid.go b/services/auth/source/oauth2/providers_openid.go
index 7c3836503c..838311b4a1 100644
--- a/services/auth/source/oauth2/providers_openid.go
+++ b/services/auth/source/oauth2/providers_openid.go
@@ -33,7 +33,12 @@ func (o *OpenIDProvider) Image() string {
// CreateGothProvider creates a GothProvider from this Provider
func (o *OpenIDProvider) CreateGothProvider(providerName, callbackURL string, source *Source) (goth.Provider, error) {
- provider, err := openidConnect.New(source.ClientID, source.ClientSecret, callbackURL, source.OpenIDConnectAutoDiscoveryURL, setting.OAuth2Client.OpenIDConnectScopes...)
+ scopes := setting.OAuth2Client.OpenIDConnectScopes
+ if len(scopes) == 0 {
+ scopes = append(scopes, source.Scopes...)
+ }
+
+ provider, err := openidConnect.New(source.ClientID, source.ClientSecret, callbackURL, source.OpenIDConnectAutoDiscoveryURL, scopes...)
if err != nil {
log.Warn("Failed to create OpenID Connect Provider with name '%s' with url '%s': %v", providerName, source.OpenIDConnectAutoDiscoveryURL, err)
}
diff --git a/services/auth/source/oauth2/providers_simple.go b/services/auth/source/oauth2/providers_simple.go
index 5a7062e6c3..a4d61eb2f3 100644
--- a/services/auth/source/oauth2/providers_simple.go
+++ b/services/auth/source/oauth2/providers_simple.go
@@ -31,7 +31,10 @@ type SimpleProvider struct {
// CreateGothProvider creates a GothProvider from this Provider
func (c *SimpleProvider) CreateGothProvider(providerName, callbackURL string, source *Source) (goth.Provider, error) {
- return c.newFn(source.ClientID, source.ClientSecret, callbackURL, c.scopes...), nil
+ scopes := make([]string, len(c.scopes)+len(source.Scopes))
+ copy(scopes, c.scopes)
+ copy(scopes[len(c.scopes):], source.Scopes)
+ return c.newFn(source.ClientID, source.ClientSecret, callbackURL, scopes...), nil
}
// NewSimpleProvider is a constructor function for simple providers
diff --git a/services/auth/source/oauth2/source.go b/services/auth/source/oauth2/source.go
index bedaed7ef3..68ff08d1ee 100644
--- a/services/auth/source/oauth2/source.go
+++ b/services/auth/source/oauth2/source.go
@@ -24,7 +24,14 @@ type Source struct {
OpenIDConnectAutoDiscoveryURL string
CustomURLMapping *CustomURLMapping
IconURL string
- SkipLocalTwoFA bool `json:",omitempty"`
+
+ Scopes []string
+ RequiredClaimName string
+ RequiredClaimValue string
+ GroupClaimName string
+ AdminGroup string
+ RestrictedGroup string
+ SkipLocalTwoFA bool `json:",omitempty"`
// reference to the loginSource
loginSource *login.Source
diff --git a/services/externalaccount/link.go b/services/externalaccount/link.go
new file mode 100644
index 0000000000..e71a37090f
--- /dev/null
+++ b/services/externalaccount/link.go
@@ -0,0 +1,29 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package externalaccount
+
+import (
+ "fmt"
+
+ user_model "code.gitea.io/gitea/models/user"
+ "github.com/markbates/goth"
+)
+
+// Store represents a thing that stores things
+type Store interface {
+ Get(interface{}) interface{}
+ Set(interface{}, interface{}) error
+ Release() error
+}
+
+// LinkAccountFromStore links the provided user with a stored external user
+func LinkAccountFromStore(store Store, user *user_model.User) error {
+ gothUser := store.Get("linkAccountGothUser")
+ if gothUser == nil {
+ return fmt.Errorf("not in LinkAccount session")
+ }
+
+ return LinkAccountToUser(user, gothUser.(goth.User))
+}
diff --git a/services/externalaccount/user.go b/services/externalaccount/user.go
index f7280e90e4..8fd0680a1f 100644
--- a/services/externalaccount/user.go
+++ b/services/externalaccount/user.go
@@ -15,14 +15,12 @@ import (
"github.com/markbates/goth"
)
-// LinkAccountToUser link the gothUser to the user
-func LinkAccountToUser(user *user_model.User, gothUser goth.User) error {
+func toExternalLoginUser(user *user_model.User, gothUser goth.User) (*user_model.ExternalLoginUser, error) {
loginSource, err := login.GetActiveOAuth2LoginSourceByName(gothUser.Provider)
if err != nil {
- return err
+ return nil, err
}
-
- externalLoginUser := &user_model.ExternalLoginUser{
+ return &user_model.ExternalLoginUser{
ExternalID: gothUser.UserID,
UserID: user.ID,
LoginSourceID: loginSource.ID,
@@ -40,6 +38,14 @@ func LinkAccountToUser(user *user_model.User, gothUser goth.User) error {
AccessTokenSecret: gothUser.AccessTokenSecret,
RefreshToken: gothUser.RefreshToken,
ExpiresAt: gothUser.ExpiresAt,
+ }, nil
+}
+
+// LinkAccountToUser link the gothUser to the user
+func LinkAccountToUser(user *user_model.User, gothUser goth.User) error {
+ externalLoginUser, err := toExternalLoginUser(user, gothUser)
+ if err != nil {
+ return err
}
if err := user_model.LinkExternalToUser(user, externalLoginUser); err != nil {
@@ -62,3 +68,13 @@ func LinkAccountToUser(user *user_model.User, gothUser goth.User) error {
return nil
}
+
+// UpdateExternalUser updates external user's information
+func UpdateExternalUser(user *user_model.User, gothUser goth.User) error {
+ externalLoginUser, err := toExternalLoginUser(user, gothUser)
+ if err != nil {
+ return err
+ }
+
+ return user_model.UpdateExternalUserByExternalID(externalLoginUser)
+}
diff --git a/services/forms/auth_form.go b/services/forms/auth_form.go
index 2c6966d266..d096292601 100644
--- a/services/forms/auth_form.go
+++ b/services/forms/auth_form.go
@@ -67,6 +67,12 @@ type AuthenticationForm struct {
Oauth2EmailURL string
Oauth2IconURL string
Oauth2Tenant string
+ Oauth2Scopes string
+ Oauth2RequiredClaimName string
+ Oauth2RequiredClaimValue string
+ Oauth2GroupClaimName string
+ Oauth2AdminGroup string
+ Oauth2RestrictedGroup string
SkipLocalTwoFA bool
SSPIAutoCreateUsers bool
SSPIAutoActivateUsers bool