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

[feature] overhaul the oidc system #961

Merged
merged 6 commits into from
Dec 6, 2022

Conversation

theSuess
Copy link
Contributor

@theSuess theSuess commented Nov 5, 2022

Since I'm very interested in this topic, I've built a draft to implement my feedback on #763, #917 and #309

This is by no means final, and very much intended as a base for further discussions on these issues.

It works by intercepting the first OIDC callback of a user and returns a small page for customizing the username if no matching user is found. The text field is prefilled with the preferred_username claim.

image

It also performs validation and checks the DB for colliding usernames

The biggest open topic IMHO is finding a way to migrate existing OIDC setups to the new ExternalID field. I honestly have no idea what would be the best approach here

Copy link
Contributor

@tsmethurst tsmethurst left a comment

Choose a reason for hiding this comment

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

This is looking pretty tasty IMO. Got a few comments about clarification and stuff. Overall, this looks like it's going in a great direction. I'm glad you bit the bullet and just jumped into it, it's always a nice surprise to get a really good PR like this :)

internal/api/client/auth/callback.go Outdated Show resolved Hide resolved
}

func init() {
gob.Register(&Claims{})
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you explain this? I'm not sure what it does :P

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure: the way I implemented the finalization page, the claim temporarily gets stored in the session. Since the session package uses gob to serialize the struct, we need to register it as serializable. I'm open to cleaner approaches - am not too happy with this as well

cmd/gotosocial/action/admin/account/account.go Outdated Show resolved Hide resolved
@@ -87,6 +87,11 @@ func (c *UserCache) GetByEmail(email string) (*gtsmodel.User, bool) {
return c.cache.GetBy("email", email)
}

// GetByExternalID attempts to fetch a user from the cache by its external id, you will receive a copy for thread-safety
func (c *UserCache) GetByExternalID(id string) (*gtsmodel.User, bool) {
return c.cache.GetBy("external_id", id)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need to be registered with the cache as a lookup @NyaaaWhatsUpDoc ?

@theSuess
Copy link
Contributor Author

I had an idea for a graceful migration path:

  • Introduce a config flag to try matching the email to existing users
  • If a user already exists for a login request but does not have the externalID set, ask the user if they want to link the account
  • If yes, populate the externalID field
  • If not, ask the user to provide a new username

What do you think about this?

@theSuess
Copy link
Contributor Author

I had an idea for a graceful migration path:

* Introduce a config flag to try matching the email to existing users

* If a user already exists for a login request but does _not_ have the externalID set, ask the user if they want to link the account

* If yes, populate the externalID field

* If not, ask the user to provide a new username

What do you think about this?

I've now implemented this (without the step of asking for a new username for now).

With this, we have a migration path for servers already using OIDC

@theSuess theSuess force-pushed the oidc-overhaul branch 2 times, most recently from 98c72e5 to bc87fe7 Compare November 12, 2022 09:28
@tsmethurst
Copy link
Contributor

tsmethurst commented Nov 12, 2022

Heya, apologies for being slow to respond to this, it's been rather a hectic week :')

This looks good to me so far! At least, I don't see any glaring issues, but will have to try it out on gts.superseriousbusiness.org (which uses oidc) to see how it works :)

One thing you missed is adding the new config flag to examples/config.yaml, and also updating the documentation here https://github.com/superseriousbusiness/gotosocial/blob/main/docs/configuration/oidc.md.

Once those things are done, I think you can mark this as ready for review and we can have a proper look through it.

Thank you, this is great work!

@theSuess
Copy link
Contributor Author

No problem, I'm just happy to hack on something not work-related 😁

I've added the docs and example config. I always seem to forget at least one place when adding new config options :D

Also marked this PR as ready 🤞

@theSuess theSuess marked this pull request as ready for review November 12, 2022 14:54
@tsmethurst
Copy link
Contributor

This looks good to me :) @NyaaaWhatsUpDoc do you also wanna review or nah?

@tsmethurst
Copy link
Contributor

hey @theSuess , can you merge main into this or rebase to resolve the merge conflicts? then i'll look at it afresh

@theSuess theSuess force-pushed the oidc-overhaul branch 2 times, most recently from 69681f8 to b382797 Compare November 21, 2022 15:45
@theSuess
Copy link
Contributor Author

Rebased and tested

@NyaaaWhatsUpDoc
Copy link
Member

I'll take a look at this today too :) sorry I managed to miss your notifications on this @tsmethurst

@tsmethurst
Copy link
Contributor

No worries pal :)

@NyaaaWhatsUpDoc
Copy link
Member

I have started to review this, but I have ran out of spoons for the evening, and it is late. I shall get back to it tomorrow evening most likely :)

@tsmethurst
Copy link
Contributor

tsmethurst commented Nov 26, 2022

i suggest we merge this once 0.6.0 is out, so we have time to mess about with it :)

[edit] Also sorry for the constant need for rebases dominik 😬

func (m *Module) FinalizePOSTHandler(c *gin.Context) {
s := sessions.Default(c)

form := &extraInfo{}
Copy link
Member

Choose a reason for hiding this comment

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

Could we get some code comments in here? It's quite a heavy unseparated function block

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've sprinkled in some comments - let me know if something is still unclear

if errWithCode != nil {
m.clearSession(s)
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

if user == nil {
Copy link
Member

Choose a reason for hiding this comment

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

Again this is quite a heavy unseparated function block. I know this is quite nitpicky I'm just a bit of a stickler for readability!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also added some comments here. We could also split this up into its own function, but not sure if that would increase readability by much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants