From bddae8a5e287e9df55c10e18e94b4f97d89a977f Mon Sep 17 00:00:00 2001 From: nkrapp Date: Thu, 17 Nov 2022 17:21:27 +0100 Subject: [PATCH 1/6] add force openID login option --- .../doc/advanced/config-cheat-sheet.en-us.md | 1 + modules/setting/service.go | 2 ++ routers/web/auth/auth.go | 16 ++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 05cedeb63ddd..087ec3b57130 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -547,6 +547,7 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o OpenID URI's to permit. - `BLACKLISTED_URIS`: **\**: If non-empty, list of POSIX regex patterns matching OpenID URI's to block. +- `FORCE_OPENID`: **false**: Skip login page and always link to OpenID ## OAuth2 Client (`oauth2_client`) diff --git a/modules/setting/service.go b/modules/setting/service.go index 10e389995032..e2f4e9730c91 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -70,6 +70,7 @@ var Service = struct { // OpenID settings EnableOpenIDSignIn bool EnableOpenIDSignUp bool + ForceOpenID bool OpenIDWhitelist []*regexp.Regexp OpenIDBlacklist []*regexp.Regexp @@ -186,6 +187,7 @@ func newService() { sec = Cfg.Section("openid") Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock) Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(!Service.DisableRegistration && Service.EnableOpenIDSignIn) + Service.ForceOpenID = sec.Key("FORCE_OPENID").MustBool(false) pats := sec.Key("WHITELISTED_URIS").Strings(" ") if len(pats) != 0 { Service.OpenIDWhitelist = make([]*regexp.Regexp, len(pats)) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 8a4c12d57b57..4006b0be8e9a 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -146,10 +146,26 @@ func checkAutoLogin(ctx *context.Context) bool { return false } +func checkForceOpenID(ctx *context.Context) bool { + // Check forced OpenID login + forced := setting.Service.ForceOpenID + + if forced && setting.Service.EnableOpenIDSignIn { + ctx.RedirectToFirst(setting.AppSubURL + "/user/login/openid") + return true + } + return false +} + // SignIn render sign in page func SignIn(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("sign_in") + // Check forced OpenID login + if checkForceOpenID(ctx) { + return + } + // Check auto-login if checkAutoLogin(ctx) { return From 50163beabc4c0ff1022e6cf80a19f0cc0f7f50f8 Mon Sep 17 00:00:00 2001 From: nkrapp Date: Wed, 23 Nov 2022 17:13:06 +0100 Subject: [PATCH 2/6] move setting location to admin page --- cmd/admin.go | 4 +++ .../doc/advanced/config-cheat-sheet.en-us.md | 1 - modules/setting/service.go | 2 -- options/locale/locale_de-DE.ini | 2 ++ options/locale/locale_en-US.ini | 2 ++ routers/web/admin/auths.go | 1 + routers/web/auth/auth.go | 27 ++++++++++++------- services/auth/source/oauth2/source.go | 1 + services/forms/auth_form.go | 1 + templates/admin/auth/edit.tmpl | 7 +++++ templates/admin/auth/source/oauth.tmpl | 7 +++++ 11 files changed, 42 insertions(+), 13 deletions(-) diff --git a/cmd/admin.go b/cmd/admin.go index 2cf63d384abe..6b39f9af958a 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -826,6 +826,7 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source { CustomURLMapping: customURLMapping, IconURL: c.String("icon-url"), SkipLocalTwoFA: c.Bool("skip-local-2fa"), + ForceOAuth: c.Bool("force-configured-oauth"), Scopes: c.StringSlice("scopes"), RequiredClaimName: c.String("required-claim-name"), RequiredClaimValue: c.String("required-claim-value"), @@ -914,6 +915,9 @@ func runUpdateOauth(c *cli.Context) error { if c.IsSet("restricted-group") { oAuth2Config.RestrictedGroup = c.String("restricted-group") } + if c.IsSet("force-oauth") { + oAuth2Config.ForceOAuth = c.BoolT("force-oauth") + } // update custom URL mapping customURLMapping := &oauth2.CustomURLMapping{} diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 087ec3b57130..05cedeb63ddd 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -547,7 +547,6 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o OpenID URI's to permit. - `BLACKLISTED_URIS`: **\**: If non-empty, list of POSIX regex patterns matching OpenID URI's to block. -- `FORCE_OPENID`: **false**: Skip login page and always link to OpenID ## OAuth2 Client (`oauth2_client`) diff --git a/modules/setting/service.go b/modules/setting/service.go index e2f4e9730c91..10e389995032 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -70,7 +70,6 @@ var Service = struct { // OpenID settings EnableOpenIDSignIn bool EnableOpenIDSignUp bool - ForceOpenID bool OpenIDWhitelist []*regexp.Regexp OpenIDBlacklist []*regexp.Regexp @@ -187,7 +186,6 @@ func newService() { sec = Cfg.Section("openid") Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock) Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(!Service.DisableRegistration && Service.EnableOpenIDSignIn) - Service.ForceOpenID = sec.Key("FORCE_OPENID").MustBool(false) pats := sec.Key("WHITELISTED_URIS").Strings(" ") if len(pats) != 0 { Service.OpenIDWhitelist = make([]*regexp.Regexp, len(pats)) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index ec2e6ba50ab1..b310cc414f20 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -2663,6 +2663,8 @@ auths.oauth2_profileURL=Profil-URL auths.oauth2_emailURL=E-Mail-URL auths.skip_local_two_fa=Lokale 2FA überspringen auths.skip_local_two_fa_helper=Leer lassen bedeutet, dass lokale User die 2FA immer noch bestehen müssen, um sich anzumelden +auths.force_oauth=Anmelden durch diese Quelle erzwingen +auths.force_oauth_helper=Setzen um Anmeldungen automatisch auf diesen OAuth Anbieter umzuleiten auths.oauth2_tenant=Inhaber auths.oauth2_scopes=Zusätzliche Bereiche auths.oauth2_required_claim_name=Benötigter Claim-Name diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ba647771e30f..953c169055b4 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2680,6 +2680,8 @@ auths.oauth2_profileURL = Profile URL auths.oauth2_emailURL = Email URL auths.skip_local_two_fa = Skip local 2FA auths.skip_local_two_fa_helper = Leaving unset means local users with 2FA set will still have to pass 2FA to log on +auths.force_oauth = Force login via this authentication +auths.force_oauth_helper = Set this to automatically redirect sign in to this OAuth provider auths.oauth2_tenant = Tenant auths.oauth2_scopes = Additional Scopes auths.oauth2_required_claim_name = Required Claim Name diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index b79b31755596..def195aef43f 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -205,6 +205,7 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source { GroupClaimName: form.Oauth2GroupClaimName, RestrictedGroup: form.Oauth2RestrictedGroup, AdminGroup: form.Oauth2AdminGroup, + ForceOAuth: form.ForceOAuth, } } diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 4006b0be8e9a..c9ceb2c42b34 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -146,14 +146,21 @@ func checkAutoLogin(ctx *context.Context) bool { return false } -func checkForceOpenID(ctx *context.Context) bool { - // Check forced OpenID login - forced := setting.Service.ForceOpenID +func checkForceOAuth(ctx *context.Context) bool { + // Check if authentication is forced to OAuth - if forced && setting.Service.EnableOpenIDSignIn { - ctx.RedirectToFirst(setting.AppSubURL + "/user/login/openid") - return true + authSources, err := auth.GetActiveOAuth2ProviderSources() + if err != nil { + return false + } + + for _, source := range authSources { + if source.Cfg.(*oauth2.Source).ForceOAuth { + ctx.RedirectToFirst(setting.AppSubURL + "/user/login/openid") + return true + } } + return false } @@ -161,13 +168,13 @@ func checkForceOpenID(ctx *context.Context) bool { func SignIn(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("sign_in") - // Check forced OpenID login - if checkForceOpenID(ctx) { + // Check auto-login + if checkAutoLogin(ctx) { return } - // Check auto-login - if checkAutoLogin(ctx) { + // Check if authentication is forced to OAuth + if checkForceOAuth(ctx) { return } diff --git a/services/auth/source/oauth2/source.go b/services/auth/source/oauth2/source.go index 457686ba1fd4..e4f79985854a 100644 --- a/services/auth/source/oauth2/source.go +++ b/services/auth/source/oauth2/source.go @@ -24,6 +24,7 @@ type Source struct { OpenIDConnectAutoDiscoveryURL string CustomURLMapping *CustomURLMapping IconURL string + ForceOAuth bool `json:",omitempty"` Scopes []string RequiredClaimName string diff --git a/services/forms/auth_form.go b/services/forms/auth_form.go index 9064be2cca38..6720f93f0ebd 100644 --- a/services/forms/auth_form.go +++ b/services/forms/auth_form.go @@ -60,6 +60,7 @@ type AuthenticationForm struct { Oauth2Key string Oauth2Secret string OpenIDConnectAutoDiscoveryURL string + ForceOAuth bool Oauth2UseCustomURL bool Oauth2TokenURL string Oauth2AuthURL string diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl index bf9d53152c2e..9fc44fa7db02 100644 --- a/templates/admin/auth/edit.tmpl +++ b/templates/admin/auth/edit.tmpl @@ -299,6 +299,13 @@

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

+
+
+ + +

{{.locale.Tr "admin.auths.force_oauth_helper"}}

+
+
diff --git a/templates/admin/auth/source/oauth.tmpl b/templates/admin/auth/source/oauth.tmpl index 166373a32489..b61651f6422c 100644 --- a/templates/admin/auth/source/oauth.tmpl +++ b/templates/admin/auth/source/oauth.tmpl @@ -35,6 +35,13 @@

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

+
+
+ + +

{{.locale.Tr "admin.auths.force_oauth_helper"}}

+
+
From 12357152300480d97cba39bce8ca6afa2d2a6bc2 Mon Sep 17 00:00:00 2001 From: nkrapp Date: Thu, 5 Jan 2023 15:07:36 +0100 Subject: [PATCH 3/6] Add cli flag --- cmd/admin.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/admin.go b/cmd/admin.go index 6b39f9af958a..0ad30d28eac0 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -363,6 +363,10 @@ var ( Value: "", Usage: "Group Claim value for restricted users", }, + cli.BoolFlag{ + Name: "force-oauth", + Usage: "set to force all logins to the configured oauth provider", + }, } microcmdAuthUpdateOauth = cli.Command{ @@ -826,7 +830,7 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source { CustomURLMapping: customURLMapping, IconURL: c.String("icon-url"), SkipLocalTwoFA: c.Bool("skip-local-2fa"), - ForceOAuth: c.Bool("force-configured-oauth"), + ForceOAuth: c.Bool("force-oauth"), Scopes: c.StringSlice("scopes"), RequiredClaimName: c.String("required-claim-name"), RequiredClaimValue: c.String("required-claim-value"), From f4224c5c78fea7591ad7c80031ab924697da7388 Mon Sep 17 00:00:00 2001 From: nkrapp Date: Thu, 5 Jan 2023 15:09:37 +0100 Subject: [PATCH 4/6] Update variable names and documentation --- docs/content/doc/usage/command-line.en-us.md | 2 ++ options/locale/locale_de-DE.ini | 4 ++-- options/locale/locale_en-US.ini | 4 ++-- templates/admin/auth/edit.tmpl | 6 +++--- templates/admin/auth/source/oauth.tmpl | 6 +++--- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index 5f05bc4c3be3..eaa5ebdf2119 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -130,6 +130,7 @@ Admin operations: - `--custom-email-url`: Use a custom Email URL (option for GitHub). - `--icon-url`: Custom icon URL for OAuth2 login source. - `--skip-local-2fa`: Allow source to override local 2FA. (Optional) + - `--force-oauth`: Automatically redirect sign in to this OAuth provider (Optional) - `--scopes`: Additional scopes to request for this OAuth2 source. (Optional) - `--required-claim-name`: Claim name that has to be set to allow users to login with this source. (Optional) - `--required-claim-value`: Claim value that has to be set to allow users to login with this source. (Optional) @@ -153,6 +154,7 @@ Admin operations: - `--custom-email-url`: Use a custom Email URL (option for GitHub). - `--icon-url`: Custom icon URL for OAuth2 login source. - `--skip-local-2fa`: Allow source to override local 2FA. (Optional) + - `--force-oauth`: Automatically redirect sign in to this OAuth provider (Optional) - `--scopes`: Additional scopes to request for this OAuth2 source. - `--required-claim-name`: Claim name that has to be set to allow users to login with this source. (Optional) - `--required-claim-value`: Claim value that has to be set to allow users to login with this source. (Optional) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index b310cc414f20..274c381c7531 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -2663,8 +2663,8 @@ auths.oauth2_profileURL=Profil-URL auths.oauth2_emailURL=E-Mail-URL auths.skip_local_two_fa=Lokale 2FA überspringen auths.skip_local_two_fa_helper=Leer lassen bedeutet, dass lokale User die 2FA immer noch bestehen müssen, um sich anzumelden -auths.force_oauth=Anmelden durch diese Quelle erzwingen -auths.force_oauth_helper=Setzen um Anmeldungen automatisch auf diesen OAuth Anbieter umzuleiten +auths.force_o_auth=Anmelden durch diese Quelle erzwingen +auths.force_o_auth_helper=Setzen um Anmeldungen automatisch auf diesen OAuth Anbieter umzuleiten auths.oauth2_tenant=Inhaber auths.oauth2_scopes=Zusätzliche Bereiche auths.oauth2_required_claim_name=Benötigter Claim-Name diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 953c169055b4..d09614afa79f 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2680,8 +2680,8 @@ auths.oauth2_profileURL = Profile URL auths.oauth2_emailURL = Email URL auths.skip_local_two_fa = Skip local 2FA auths.skip_local_two_fa_helper = Leaving unset means local users with 2FA set will still have to pass 2FA to log on -auths.force_oauth = Force login via this authentication -auths.force_oauth_helper = Set this to automatically redirect sign in to this OAuth provider +auths.force_o_auth = Force login via this authentication +auths.force_o_auth_helper = Set this to automatically redirect sign in to this OAuth provider auths.oauth2_tenant = Tenant auths.oauth2_scopes = Additional Scopes auths.oauth2_required_claim_name = Required Claim Name diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl index 9fc44fa7db02..f7c104bf08f9 100644 --- a/templates/admin/auth/edit.tmpl +++ b/templates/admin/auth/edit.tmpl @@ -301,9 +301,9 @@
- - -

{{.locale.Tr "admin.auths.force_oauth_helper"}}

+ + +

{{.locale.Tr "admin.auths.force_o_auth_helper"}}

diff --git a/templates/admin/auth/source/oauth.tmpl b/templates/admin/auth/source/oauth.tmpl index b61651f6422c..535c0473e4f5 100644 --- a/templates/admin/auth/source/oauth.tmpl +++ b/templates/admin/auth/source/oauth.tmpl @@ -37,9 +37,9 @@
- - -

{{.locale.Tr "admin.auths.force_oauth_helper"}}

+ + +

{{.locale.Tr "admin.auths.force_o_auth_helper"}}

From d20b362ba044bea9440c84197dd95d8ded127167 Mon Sep 17 00:00:00 2001 From: nkrapp Date: Thu, 5 Jan 2023 15:10:32 +0100 Subject: [PATCH 5/6] Add proper redirect and improve readability --- routers/web/admin/auths.go | 2 +- routers/web/auth/auth.go | 10 ++++++++-- services/auth/interface.go | 4 ++++ services/auth/source/oauth2/source_authenticate.go | 4 ++++ services/forms/auth_form.go | 2 +- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index def195aef43f..1f83afb682bf 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -202,10 +202,10 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source { RequiredClaimName: form.Oauth2RequiredClaimName, RequiredClaimValue: form.Oauth2RequiredClaimValue, SkipLocalTwoFA: form.SkipLocalTwoFA, + ForceOAuth: form.ForceOAuth, GroupClaimName: form.Oauth2GroupClaimName, RestrictedGroup: form.Oauth2RestrictedGroup, AdminGroup: form.Oauth2AdminGroup, - ForceOAuth: form.ForceOAuth, } } diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index c9ceb2c42b34..ae0417e5a2f2 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -155,8 +155,14 @@ func checkForceOAuth(ctx *context.Context) bool { } for _, source := range authSources { - if source.Cfg.(*oauth2.Source).ForceOAuth { - ctx.RedirectToFirst(setting.AppSubURL + "/user/login/openid") + if forced, ok := source.Cfg.(auth_service.ForceOAuth); ok && forced.IsOAuthForced() { + fmt.Println(source.Cfg) + app, err := auth.GetOAuth2ApplicationByID(ctx, 1) + if err != nil { + return false + } + url := app.PrimaryRedirectURI() + ctx.Redirect(url) return true } } diff --git a/services/auth/interface.go b/services/auth/interface.go index ecc9ad2ca6b8..faf1e010c7ab 100644 --- a/services/auth/interface.go +++ b/services/auth/interface.go @@ -59,6 +59,10 @@ type LocalTwoFASkipper interface { IsSkipLocalTwoFA() bool } +type ForceOAuth interface { + IsOAuthForced() bool +} + // SynchronizableSource represents a source that can synchronize users type SynchronizableSource interface { Sync(ctx context.Context, updateExisting bool) error diff --git a/services/auth/source/oauth2/source_authenticate.go b/services/auth/source/oauth2/source_authenticate.go index fdc18411a75d..908bbdbb548f 100644 --- a/services/auth/source/oauth2/source_authenticate.go +++ b/services/auth/source/oauth2/source_authenticate.go @@ -14,5 +14,9 @@ func (source *Source) Authenticate(user *user_model.User, login, password string return db.Authenticate(user, login, password) } +func (source *Source) IsOAuthForced() bool { + return source.ForceOAuth +} + // NB: Oauth2 does not implement LocalTwoFASkipper for password authentication // as its password authentication drops to db authentication diff --git a/services/forms/auth_form.go b/services/forms/auth_form.go index 6720f93f0ebd..5458905e86ad 100644 --- a/services/forms/auth_form.go +++ b/services/forms/auth_form.go @@ -60,7 +60,6 @@ type AuthenticationForm struct { Oauth2Key string Oauth2Secret string OpenIDConnectAutoDiscoveryURL string - ForceOAuth bool Oauth2UseCustomURL bool Oauth2TokenURL string Oauth2AuthURL string @@ -75,6 +74,7 @@ type AuthenticationForm struct { Oauth2AdminGroup string Oauth2RestrictedGroup string SkipLocalTwoFA bool + ForceOAuth bool SSPIAutoCreateUsers bool SSPIAutoActivateUsers bool SSPIStripDomainNames bool From c7cfdcc42332ab03842b41aa862b7f8ff4621e79 Mon Sep 17 00:00:00 2001 From: nkrapp Date: Tue, 17 Jan 2023 15:03:41 +0100 Subject: [PATCH 6/6] Redirect to first forced OAuth --- routers/web/auth/auth.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 74f1c3a99404..8871193b2856 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -145,10 +145,12 @@ func checkForceOAuth(ctx *context.Context) bool { return false } + var OAuthList []int64 + for _, source := range authSources { if forced, ok := source.Cfg.(auth_service.ForceOAuth); ok && forced.IsOAuthForced() { - fmt.Println(source.Cfg) - app, err := auth.GetOAuth2ApplicationByID(ctx, 1) + OAuthList = append(OAuthList, source.ID) + app, err := auth.GetOAuth2ApplicationByID(ctx, OAuthList[0]) if err != nil { return false }