ext.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. use std::future::Future;
  2. use crate::{
  3. config::Config,
  4. schema::{self, UIDCDatabase},
  5. server::{self, SessionHelper, UIDCRequest},
  6. };
  7. mod generic_oidc;
  8. mod github;
  9. pub trait ExternalAuthenticator {
  10. fn build(db: &UIDCDatabase, config: &Config) -> Option<Self>
  11. where
  12. Self: Sized;
  13. fn register_routes(&'static self, server: &mut tide::Server<server::ServerStateWrapper>);
  14. fn generate_login_url(&self, realm: &str, redirect: &str) -> String;
  15. fn generate_registration_url(&self, realm: &str, redirect: &str) -> String;
  16. fn extract_login_state(&self, req: UIDCRequest) -> impl Future<Output = tide::Response>;
  17. fn handle_registration(&self, _req: UIDCRequest) -> tide::Response {
  18. todo!()
  19. }
  20. fn handle_matching_login(
  21. &self,
  22. req: UIDCRequest,
  23. user: schema::UserID,
  24. redirect: &str,
  25. ) -> tide::Response {
  26. let sh = SessionHelper::new(&req);
  27. let mut lease = req.state().pool.acquire().expect("couldn't get lease");
  28. let Ok((resp, cookie)) = sh.get_or_build_session(&mut lease, &req) else {
  29. return tide::Response::builder(500)
  30. .body("error while building session")
  31. .build();
  32. };
  33. let realm_id = sh.get_realm(&mut lease).unwrap().id();
  34. // remove any existing authentication for this realm just in case
  35. resp.auth
  36. .with(schema::SessionAuth::Realm, realm_id)
  37. .first()
  38. .delete(&mut lease)
  39. .expect("couldn't remove existing authentication");
  40. resp.auth
  41. .insert(
  42. &mut lease,
  43. schema::SessionAuth {
  44. realm: realm_id,
  45. user: Some(user),
  46. pending_user: None,
  47. pending_challenges: vec![].into_serialized(),
  48. },
  49. )
  50. .expect("couldn't insert new authentication");
  51. let mut resp: tide::Response = tide::Redirect::see_other(redirect).into();
  52. if let Some(cookie) = cookie {
  53. resp.insert_cookie(cookie);
  54. }
  55. return resp;
  56. }
  57. fn handle_no_mapping(&self, req: UIDCRequest, redirect: String) -> tide::Response {
  58. let sh = SessionHelper::new(&req);
  59. return sh.render_login_from_auth(
  60. tide::Response::new(200),
  61. redirect,
  62. None,
  63. Some("External user not associated with any local user.".to_string()),
  64. );
  65. }
  66. }
  67. pub use generic_oidc::{OIDCAuthenticator, OIDCConfig};
  68. pub use github::{GithubAuthenticator, GithubConfig};
  69. use microrm::{
  70. prelude::{Insertable, Queryable},
  71. schema::Serializable,
  72. };