unilim_cas/lib.rs
1//! authentication client for the central authentication service of
2//! [unilim](https://www.unilim.fr), the university of limoges.
3//!
4//! talks to the lemonldap::ng portal at `cas.unilim.fr` and covers the whole
5//! session lifecycle:
6//!
7//! - [`CAS::initialize`] submits credentials and returns a [`PendingAuth`]
8//! holding the 2fa challenge.
9//! - [`PendingAuth`] solves the challenge with an email code or a totp code,
10//! then [`PendingAuth::finish`] establishes the session.
11//! - [`CAS::restore`] brings back a persisted session without solving 2fa
12//! again.
13//! - [`CAS::service`] returns a ticket url for one of the supported
14//! [`Services`].
15//! - [`CAS::authorize`], [`CAS::tokenize`] and [`CAS::userinfo`] handle the
16//! oauth2 flow of the portal.
17//!
18//! # quick start
19//!
20//! ```no_run
21//! use unilim_cas::CAS;
22//!
23//! # async fn quick_start() -> unilim_cas::Result<()> {
24//! // on first login, solve the 2fa challenge manually.
25//! let mut auth = CAS::initialize("username", "password").await?;
26//!
27//! if !auth.solved {
28//! if auth.is_totp_available {
29//! auth.solve_with_totp("123456").await?;
30//! }
31//! else if auth.is_email_available {
32//! auth.send_email_code().await?;
33//! auth.solve_with_email_code("123456").await?;
34//! }
35//! }
36//!
37//! let cas = auth.finish().await?;
38//!
39//! // store `cas.connection` and `cas.key` somewhere safe, then restore
40//! // later without any 2fa prompt.
41//! let cas = CAS::restore("username", "password", &cas.connection, &cas.key).await?;
42//! # Ok(())
43//! # }
44//! ```
45//!
46//! # session model
47//!
48//! an established [`CAS`] session is made of three strings:
49//!
50//! - [`CAS::cookie`], the `lemonldap` session cookie sent on every request.
51//! - [`CAS::connection`], the `llngconnection` persistence cookie obtained
52//! by registering the browser.
53//! - [`CAS::key`], the totp secret answering the browser check during
54//! [`CAS::restore`].
55//!
56//! the session cookie expires quickly, so store the other two for the long
57//! term.
58//!
59//! # features
60//!
61//! - `client`, the default, provides the native client documented here. http
62//! goes through [rikka](https://docs.rs/rikka), so it also runs on
63//! `wasm32`.
64//! - `wasm` only provides the `unilim_cas::wasm` module, extern declarations
65//! of the `@unilim/cas` js classes for packages receiving the session from
66//! javascript. pulls no client code and only compiles on `wasm32`.
67
68#[cfg(feature = "client")]
69mod native;
70#[cfg(feature = "client")]
71pub use native::*;
72
73#[cfg(all(target_arch = "wasm32", feature = "npm"))]
74mod npm;
75
76#[cfg(all(target_arch = "wasm32", feature = "wasm"))]
77pub mod wasm;