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

Implement logging in via external identity providers #4238

Closed
wants to merge 19 commits into from

Conversation

thepaperpilot
Copy link

@thepaperpilot thepaperpilot commented Dec 8, 2023

Description

Implements #2930. I believe #489 is a duplicate of that issue, and would also be considered implemented by this. Note that this does NOT make lemmy itself an identity provider, and thus does NOT implement #1368.

External auth methods can be added via the admin settings, and then buttons are shown on the login page to use those auth methods instead of "basic" auth (username + password). The implementation supports both OAuth or OIDC auth methods, and can register non-existent users as well (if a new setting is explicitly turned on).

Other frontends that wish to support these external auth methods can use the changes in lemmy-ui as a reference. They'll need to show the buttons to go to the authorization URL with the appropriate redirect URI, and then implement the endpoint at that URI that takes the auth cookie and navigates to the redirect URI param it was passed. Optionally, frontends can also implement the new admin settings.

Future Work

Most of these are not implemented because my understanding is lemmy-ui is getting replaced soon-ish anyways and these are tasks that would take awhile to implement which is probably not worth it imo.

  • Make frontends have convenient presets for common identity providers (like Google, Github, Discord, etc.) that hides the well-known fields (i.e. just show client ID and secret).
  • PKCE support (more secure version of OAuth)
  • If auto-registration is disabled, bring non-existent users to modified version of the signup page where the email is pre-filled and readonly, and the password field is hidden
  • Improve error handling/messaging (for example if an external auth method fails to save due to a non-unique client ID)

Related PRs

Screenshots

image

image

@thepaperpilot
Copy link
Author

Woodpecker is failing but it works for me locally. I'm not totally sure how to handle the error it's giving. Could one of the reviewers help me out?

@Nutomic
Copy link
Member

Nutomic commented Dec 11, 2023

CI seems to fail because there is a mismatch between the sql schema and the db struct defined in crates/db_schema/src/source/external_auth.rs. Try running diesel migration redo to get the exact db state defined in your migration, if that doesnt help wipe the db first.

Anyway we are currently busy preparing for the Lemmy 0.19 release, so this will have to wait a while for review.

/// An external auth view.
pub struct ExternalAuthView {
pub external_auth: ExternalAuth,
}
Copy link
Member

Choose a reason for hiding this comment

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

This view seems totally pointless if it only has one field. Why not move the methods into crates/db_schema?

migrations/2023-11-03-131721_create_external_auth/up.sql Outdated Show resolved Hide resolved
&local_user_view.local_user.password_encrypted,
)
.unwrap_or(false);
let valid: bool = local_user_view.local_user.password_encrypted == ""
Copy link
Member

Choose a reason for hiding this comment

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

Looks like the password field should be nullable/optional then.

crates/db_schema/src/impls/external_auth.rs Outdated Show resolved Hide resolved
crates/api_crud/src/user/create.rs Show resolved Hide resolved
crates/api/src/local_user/oauth_callback.rs Show resolved Hide resolved
return HttpResponse::Found()
.append_header(("Location", "/login?err=internal"))
.finish();
}
Copy link
Member

Choose a reason for hiding this comment

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

Why not use ? for error handling? You can customize the response headers based on the error type in crates/utils/src/error.rs. Or make a helper function and use .map_err(). In any case you shouldnt repeat the same error handling over and over, this isnt Go :P

@dessalines
Copy link
Member

We'll be able to look at this in greater detail after the new year. The failing lint means you need to run cargo +nightly fmt

@thepaperpilot
Copy link
Author

thepaperpilot commented Dec 18, 2023

Thanks! I plan on also addressing the rest of nutomic's feedback, just haven't been rushing since it's way too late to get into this release.

Would it make sense to add that cargo command as a pre commit step?

@dessalines
Copy link
Member

Cool, no rush.

Would it make sense to add that cargo command as a pre commit step?

We used to use Cargo husky to do that (both fmt and clippy), but stopped using it because

  • It couldn't run on nightly
  • Sometimes takes a long time to run clippy
  • It requires you to run cargo test locally to set up the hooks, which a lot of ppl starting new PRs don't do.

So now we just let CI tell you the errors. You can set up your own git pre-commit hook tho.

@@ -23,8 +23,10 @@ lemmy_db_views = { workspace = true, features = ["full"] }
lemmy_db_views_moderator = { workspace = true, features = ["full"] }
lemmy_db_views_actor = { workspace = true, features = ["full"] }
lemmy_api_common = { workspace = true, features = ["full"] }
lemmy_api_crud = { workspace = true }
Copy link
Member

Choose a reason for hiding this comment

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

Dont do this, it will slow down compilation. Instead move anything that you need from api_crud into api_common.

pub client_secret: String,
pub scopes: String,
pub published: DateTime<Utc>,
pub updated: Option<DateTime<Utc>>,
Copy link
Member

Choose a reason for hiding this comment

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

Can you add comments what all these fields mean? Or a link to documentation?

diesel::delete(external_auth.find(external_auth_id))
.execute(conn)
.await
}
Copy link
Member

Choose a reason for hiding this comment

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

You can remove this and rely on the trait impl for delete.

@Nutomic
Copy link
Member

Nutomic commented May 17, 2024

Outdated, feel free to reopen when you work on it again.

@Nutomic Nutomic closed this May 17, 2024
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.

None yet

3 participants