Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add setting to force login through openid #21851

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

tiltingpenguin
Copy link

This PR aims to add a setting that skips the normal login and redirects automatically to the openID login/the configured openID provider

The desired behavior can be observed at https://gitea.opensuse.org/

Fixes #21741

@techknowlogick techknowlogick added type/enhancement An improvement of existing functionality topic/authentication labels Nov 17, 2022
@techknowlogick techknowlogick added this to the 1.19.0 milestone Nov 17, 2022
@techknowlogick
Copy link
Member

Hey! Thanks for this PR! For approach I'd suggest perhaps using a flag in the auth settings rather than a hardcoded URL/setting this in app.ini.

Perhaps a checkbox on this page, for "force login via this auth" (or something like that).
image
and since all auth providers are loaded on this page (to add the links on this page) you could loop through them and check for bool.

If this is not enough details on the direction I am suggesting please let me know and I can provide additional details :)

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Nov 17, 2022
@tiltingpenguin
Copy link
Author

Hey @techknowlogick
I'm currently a bit stuck trying to save and read my setting from the templates. I tried to imitate the SkipLocal2FA setting but I couldn't find how it was done there. Do you have any tips maybe?

if checkForceOAuth(ctx) {
return
}

orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! Thank you so much!! Are you able to re-use this GetActiveOAuth2Providers call, to reduce the duplication of DB calls?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that but sadly the map of Providers that GetActiveOAuth2Providers returns is a different object that doesn't contain all the Source attributes, including my ForceOAuth parameter

@techknowlogick
Copy link
Member

@tiltingpenguin, ah just saw your comment after making my comment. Yeah, let me get an example of what you could use for saving that setting.

@tiltingpenguin
Copy link
Author

Hey @techknowlogick , any update on this?

@tiltingpenguin
Copy link
Author

The reason for the setting not being saved turned out to be the variable naming in the templates

@techknowlogick techknowlogick marked this pull request as ready for review January 16, 2023 19:51
Copy link
Member

@techknowlogick techknowlogick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again <3

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Jan 16, 2023
@tiltingpenguin
Copy link
Author

I don't think it's quite ready yet, I probably have a bug in which OAuth app I redirect to and it might be better to not just redirect to the first one with the setting and instead check if multiple OAuth providers are forced

brechtvl pushed a commit to blender/gitea that referenced this pull request Jan 30, 2023
This PR aims to add a setting that skips the normal login and redirects
automatically to the openID login/the configured openID provider

The desired behavior can be observed at https://gitea.opensuse.org/

BLENDER NOTE: this is is PR go-gitea#21851, in the hope that this will be merged
upstream.
@brechtvl
Copy link
Contributor

At Blender we also need this functionality, so thanks!

We still wanted a way to skip the redirect. This commit adds ?noredirect=true for that. Feel free to fold it into this PR if you want, or if not I will send a follow up PR after this lands.
blender/gitea@979a48c

@brechtvl
Copy link
Contributor

brechtvl commented Feb 1, 2023

So in testing this I don't understand why this involves creating an application. Those are meant to give third-party application access to user accounts on Gitea., but what we want to do is the other way around.

Is there any reason the redirect URL is not just the same URL found on the /user/login page when the force oauth option is off? That would work without having to create an application.

@techknowlogick
Copy link
Member

@brechtvl Im not sure what you mean, you should only need to create an auth source in the admin dashboard and then check the box. Are you able to describe the flow you are seeing in terms of URLs and redirects?

for _, source := range authSources {
if forced, ok := source.Cfg.(auth_service.ForceOAuth); ok && forced.IsOAuthForced() {
OAuthList = append(OAuthList, source.ID)
app, err := auth.GetOAuth2ApplicationByID(ctx, OAuthList[0])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it looks up an application to get the redirect URL, not an authentication source.

@brechtvl
Copy link
Contributor

brechtvl commented Feb 1, 2023

To get this working you have to go to the "Applications" tab, create an application and then fill in the appropriate redirect URL. I only understood this from reading the code.

@tiltingpenguin
Copy link
Author

So what you mean is that the OAuth Application where I'm getting the redirect URL from is not the same as the OAuth source? I might have gotten this wrong but in my testing with openID it worked without configuring anything but the authentication source.

@zeripath
Copy link
Contributor

zeripath commented Feb 2, 2023

Hmm... I'm guessing here that what you actually want to do is to disable login with username/password.

In which case this seems like the wrong thing to do as it is hacking around the inability to do that.

@techknowlogick
Copy link
Member

@zeripath in the case of Blender (and also my personal use) there is a default provider that should be used for the majority of users, so login link would take you through that flow, but then for the one or two local accounts that is what the query string option to show form would be used for.

In the case of people misunderstanding that this would block local logins, for the querystring option I've asked that documentation be added.

@techknowlogick
Copy link
Member

@brechtvl ah, I was testing from a non-fresh DB. Thanks for that info.

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Feb 2, 2023

@techknowlogick I do not know why it could be approved now. At least, I can see some code-level problems:

  • There should be only en-US translation.
  • The naming of var OAuthList []int64 is wrong.
  • There is OAuthList = append(OAuthList, source.ID) but it's not used later?
  • The IsOAuthForced seems unnecessary, you can just cast the source to oauth2.Source and access its ForceOAuth.
  • Some errors are silently ignored.

And I guess there would be some design problems:

  • If I understand correctly, this PR just makes all requests from GET SignIn to be redirected to the OAuth2 auth? How could a local account (maybe the first and default site admin) login then?
  • Is this approach a general one and how does this approach work with other sources (maybe SAML in the future)?

@tiltingpenguin
Copy link
Author

tiltingpenguin commented Feb 2, 2023

@wxiaoguang To address some of your concerns

  • I can take out the german translation, I just thought it would help
  • What would you suggest I name this list then?
  • I am using this list to collect all auth sources that have this option enabled. It's true that I'm currently defaulting to the first one but since there is the possibility to enable it for more than one source I think it is good to include for when we decide how to handle this case
  • I'll remove the Interface then
  • I see one error where I just return and login proceeds like normal, I will fix this

About the design:

  • The goal of this PR is to give the option of basically disabling local users and just allow authentication through one OAuth. You are right that this would also make login for the default admin account more difficult. I'll think about how to solve this
  • I haven't thought much about other authentication sources since the use case for me (gitea.opensuse.org) is just OAuth/openID. If there is demand I can try to also implement it for other sources but this would take time and not be a high priority for me

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Feb 3, 2023

Thanks for the detailed explanations 👍

My opinions are:

About code-level:

  • About translation: Other translations will be done by the translation system, so PRs should only contain en-US ones, otherwise other language changes will be overwritten and lost.
  • About OAuthList: the local variable naming style should be camelCase in Go. But I think the using for it is not proper in the for loop. Each loop, you just append IDs to id then always use the first, I think it equals to just use the first matched auth source, then no extra variable is needed.

About design:

TBH I haven't thought about the details carefully.

Just share some here:

  • Since the purpose of this PR is not disabling the local login completely, the local login should still appear on the UI somewhere.

    • Disabling and Hiding are different.
    • Disabling means that no one can ever use local login anymore
    • But after this PR, username/password are still available in all cases, it just hides the local login.
    • IMO the purpose of this PR is "guiding users to use Xxx auth source by default"
  • About the UI:

    • Adding "no_redirect" query parameter to the /user/login to skip the redirection seems working, but it looks somewhat hacky (at least, from my opinion)
    • A brief idea in my mind is that the login UI should be refactored together, using a tab/menu/radio-list to switch the login methods (auth sources). As long as an auth source is not disabled, it should be on the login UI.
  • About other possible auth sources:

    • Maybe it really needs an interface for the auth source, like IsPreferredLoginMethod or IsDefaultLoginMethod (ok, the naming is long, just for example...). Then the UI can render that method as the default one on the login page.

@tiltingpenguin
Copy link
Author

Yes, the goal is to guide users to an auth source by default. But in the case of oauth that makes it difficult without just redirecting the user. For our use case we mostly wanted to cut out the extra step of having the local login displayed and so the automatic redirect was the first approach.

While I agree that having a different option for the admin than to manually change the url I don't really see a better way that doesn't involve refactoring the whole login page like you mentioned. And to be honest doing that is way out of my scope and I don't really have the time to implement that. I don't mind adapting the PR though and if you have some proposal that would bring this feature to an acceptable level for you (within reasonable effort) I will try to do that.

@wxiaoguang
Copy link
Contributor

@techknowlogick what's your opinion?

@wxiaoguang
Copy link
Contributor

ping

@techknowlogick
Copy link
Member

@wxiaoguang thank you as always for your thorough reviews. And thank you @tiltingpenguin for your patience as the review on this continues.

What about instead of redirecting the login route, the login link itself would change destination to the preferred provider? That way there is no issue with the querystring, and multiple auth providers are still available.

@tiltingpenguin
Copy link
Author

That sounds like a good solution to me. If nothing speaks against it I will go and implement that then

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Feb 20, 2023

Is this approach a general one and how does this approach work with other sources (maybe SAML in the future)?

Finally, the SAML request comes.

So it really needs a general approach.

@tiltingpenguin
Copy link
Author

I don't have any experience with SAML so for now I would prefer just supporting OAuth with this option and maybe implement SAML support later

Comment on lines +148 to +158
var OAuthList []int64

for _, source := range authSources {
if forced, ok := source.Cfg.(auth_service.ForceOAuth); ok && forced.IsOAuthForced() {
OAuthList = append(OAuthList, source.ID)
app, err := auth.GetOAuth2ApplicationByID(ctx, OAuthList[0])
if err != nil {
return false
}
url := app.PrimaryRedirectURI()
ctx.Redirect(url)
Copy link
Contributor

@brechtvl brechtvl Feb 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference, we simplified like this to avoid involving the application unnecessarily.

Suggested change
var OAuthList []int64
for _, source := range authSources {
if forced, ok := source.Cfg.(auth_service.ForceOAuth); ok && forced.IsOAuthForced() {
OAuthList = append(OAuthList, source.ID)
app, err := auth.GetOAuth2ApplicationByID(ctx, OAuthList[0])
if err != nil {
return false
}
url := app.PrimaryRedirectURI()
ctx.Redirect(url)
for _, source := range authSources {
if forced, ok := source.Cfg.(auth_service.ForceOAuth); ok && forced.IsOAuthForced() {
ctx.Redirect(setting.AppSubURL + "/user/oauth2/" + source.Name)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least for my test case (openID) this doesn't work because you still land on the local login page

@yardenshoham yardenshoham modified the milestones: 1.19.0, 1.20.0 Feb 22, 2023
@yardenshoham yardenshoham added the outdated/backport/v1.19 This PR should be backported to Gitea 1.19 label Feb 22, 2023
@delvh delvh added the modifies/cli PR changes something on the CLI, i.e. gitea doctor or gitea admin label Apr 11, 2023
@wxiaoguang wxiaoguang removed the outdated/backport/v1.19 This PR should be backported to Gitea 1.19 label May 10, 2023
@wxiaoguang wxiaoguang removed this from the 1.20.0 milestone May 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm/need 1 This PR needs approval from one additional maintainer to be merged. modifies/cli PR changes something on the CLI, i.e. gitea doctor or gitea admin topic/authentication type/enhancement An improvement of existing functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add option to make sign-in button link to oauth provider
8 participants