Skip to content

Commit 0dac508

Browse files
zecakehpixlwave
andauthored
experimental: Expose an OpenID Connect API
Co-authored-by: Doug <[email protected]> Signed-off-by: Kévin Commaille <[email protected]>
1 parent 758c3f7 commit 0dac508

File tree

15 files changed

+3412
-44
lines changed

15 files changed

+3412
-44
lines changed

Cargo.lock

Lines changed: 887 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/matrix-sdk/Cargo.toml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ appservice = ["ruma/appservice-api-s"]
4242
image-proc = ["dep:image"]
4343
image-rayon = ["image-proc", "image?/jpeg_rayon"]
4444

45+
experimental-oidc = [
46+
"ruma/unstable-msc2967",
47+
"dep:chrono",
48+
"dep:language-tags",
49+
"dep:mas-oidc-client",
50+
"dep:rand",
51+
"dep:tower",
52+
]
4553
experimental-sliding-sync = [
4654
"matrix-sdk-base/experimental-sliding-sync",
4755
"reqwest/gzip",
@@ -58,6 +66,7 @@ async-trait = { workspace = true }
5866
bytes = "1.1.0"
5967
bytesize = "1.1"
6068
cfg-vis = "0.3.0"
69+
chrono = { version = "0.4.23", optional = true }
6170
dashmap = { workspace = true }
6271
event-listener = "2.5.2"
6372
eyeball = { workspace = true }
@@ -67,8 +76,9 @@ eyre = { version = "0.6.8", optional = true }
6776
futures-core = { workspace = true }
6877
futures-util = { workspace = true }
6978
http = { workspace = true }
70-
imbl = { version = "2.0.0", features = ["serde"] }
7179
hyper = { version = "0.14.20", features = ["http1", "http2", "server"], optional = true }
80+
imbl = { version = "2.0.0", features = ["serde"] }
81+
language-tags = { version = "0.3.2", optional = true }
7282
matrix-sdk-base = { version = "0.6.0", path = "../matrix-sdk-base", default_features = false }
7383
matrix-sdk-common = { version = "0.6.0", path = "../matrix-sdk-common" }
7484
matrix-sdk-indexeddb = { version = "0.2.0", path = "../matrix-sdk-indexeddb", default-features = false, optional = true }
@@ -107,6 +117,11 @@ features = [
107117
]
108118
optional = true
109119

120+
[dependencies.mas-oidc-client]
121+
git = "https://github.com/matrix-org/matrix-authentication-service"
122+
rev = "4280045b24bc71ef1fa100c0a046ed15e6e20748"
123+
optional = true
124+
110125
[target.'cfg(target_arch = "wasm32")'.dependencies]
111126
gloo-timers = { version = "0.2.6", features = ["futures"] }
112127
reqwest = { version = "0.11.10", default_features = false }

crates/matrix-sdk/src/authentication.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,19 @@
1515
use matrix_sdk_base::SessionMeta;
1616

1717
use crate::matrix_auth::{self, MatrixAuth, MatrixAuthData};
18+
#[cfg(feature = "experimental-oidc")]
19+
use crate::oidc::{self, Oidc, OidcAuthData};
1820

1921
/// An enum over all the possible authentication APIs.
2022
#[derive(Debug, Clone)]
2123
#[non_exhaustive]
2224
pub enum AuthApi {
2325
/// The native Matrix authentication API.
2426
Matrix(MatrixAuth),
27+
28+
/// The OpenID Connect API.
29+
#[cfg(feature = "experimental-oidc")]
30+
Oidc(Oidc),
2531
}
2632

2733
/// A user session using one of the available authentication APIs.
@@ -30,20 +36,28 @@ pub enum AuthApi {
3036
pub enum AuthSession {
3137
/// A session using the native Matrix authentication API.
3238
Matrix(matrix_auth::Session),
39+
40+
/// A session using the OpenID Connect API.
41+
#[cfg(feature = "experimental-oidc")]
42+
Oidc(oidc::FullSession),
3343
}
3444

3545
impl AuthSession {
3646
/// Get the matrix user information of this session.
3747
pub fn meta(&self) -> &SessionMeta {
3848
match self {
3949
AuthSession::Matrix(session) => &session.meta,
50+
#[cfg(feature = "experimental-oidc")]
51+
AuthSession::Oidc(session) => &session.user.meta,
4052
}
4153
}
4254

4355
/// Get the access token of this session.
4456
pub fn access_token(&self) -> &str {
4557
match self {
4658
AuthSession::Matrix(session) => &session.tokens.access_token,
59+
#[cfg(feature = "experimental-oidc")]
60+
AuthSession::Oidc(session) => &session.user.tokens.access_token,
4761
}
4862
}
4963
}
@@ -54,23 +68,47 @@ impl From<matrix_auth::Session> for AuthSession {
5468
}
5569
}
5670

71+
#[cfg(feature = "experimental-oidc")]
72+
impl From<oidc::FullSession> for AuthSession {
73+
fn from(session: oidc::FullSession) -> Self {
74+
Self::Oidc(session)
75+
}
76+
}
77+
5778
/// Data for an authentication API.
58-
#[derive(Clone, Debug)]
79+
#[derive(Debug)]
5980
pub(crate) enum AuthData {
6081
/// Data for the native Matrix authentication API.
6182
Matrix(MatrixAuthData),
83+
/// Data for the OpenID Connect API.
84+
#[cfg(feature = "experimental-oidc")]
85+
Oidc(OidcAuthData),
6286
}
6387

6488
impl AuthData {
6589
pub(crate) fn as_matrix(&self) -> Option<&MatrixAuthData> {
6690
match self {
6791
AuthData::Matrix(d) => Some(d),
92+
#[cfg(feature = "experimental-oidc")]
93+
_ => None,
6894
}
6995
}
7096

71-
pub(crate) fn access_token(&self) -> String {
97+
#[cfg(feature = "experimental-oidc")]
98+
pub(crate) fn as_oidc(&self) -> Option<&OidcAuthData> {
7299
match self {
73-
AuthData::Matrix(d) => d.tokens.get().access_token,
100+
AuthData::Oidc(d) => Some(d),
101+
_ => None,
74102
}
75103
}
104+
105+
pub(crate) fn access_token(&self) -> Option<String> {
106+
let token = match self {
107+
AuthData::Matrix(d) => d.tokens.get().access_token,
108+
#[cfg(feature = "experimental-oidc")]
109+
AuthData::Oidc(d) => d.tokens.get()?.get().access_token,
110+
};
111+
112+
Some(token)
113+
}
76114
}

crates/matrix-sdk/src/client/mod.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ use url::Url;
7474

7575
#[cfg(feature = "e2e-encryption")]
7676
use crate::encryption::Encryption;
77+
#[cfg(feature = "experimental-oidc")]
78+
use crate::oidc::Oidc;
7779
use crate::{
7880
authentication::AuthData,
7981
config::RequestConfig,
@@ -141,12 +143,12 @@ pub(crate) struct ClientInner {
141143
/// The URL of the homeserver to connect to.
142144
homeserver: RwLock<Url>,
143145
/// The authentication server info discovered from the homeserver.
144-
authentication_server_info: Option<AuthenticationServerInfo>,
146+
pub(crate) authentication_server_info: Option<AuthenticationServerInfo>,
145147
/// The sliding sync proxy that is trusted by the homeserver.
146148
#[cfg(feature = "experimental-sliding-sync")]
147149
sliding_sync_proxy: StdRwLock<Option<Url>>,
148150
/// The underlying HTTP client.
149-
http_client: HttpClient,
151+
pub(crate) http_client: HttpClient,
150152
/// User session data.
151153
base_client: BaseClient,
152154
/// The Matrix versions the server supports (well-known ones only)
@@ -477,7 +479,7 @@ impl Client {
477479
///
478480
/// Will be `None` if the client has not been logged in.
479481
pub fn access_token(&self) -> Option<String> {
480-
Some(self.inner.auth_data.get()?.access_token())
482+
self.inner.auth_data.get()?.access_token()
481483
}
482484

483485
/// Access the authentication API used to log in this client.
@@ -486,6 +488,8 @@ impl Client {
486488
pub fn auth_api(&self) -> Option<AuthApi> {
487489
match self.inner.auth_data.get()? {
488490
AuthData::Matrix(_) => Some(AuthApi::Matrix(self.matrix_auth())),
491+
#[cfg(feature = "experimental-oidc")]
492+
AuthData::Oidc(_) => Some(AuthApi::Oidc(self.oidc())),
489493
}
490494
}
491495

@@ -498,6 +502,8 @@ impl Client {
498502
pub fn session(&self) -> Option<AuthSession> {
499503
match self.auth_api()? {
500504
AuthApi::Matrix(api) => api.session().map(Into::into),
505+
#[cfg(feature = "experimental-oidc")]
506+
AuthApi::Oidc(api) => api.full_session().map(Into::into),
501507
}
502508
}
503509

@@ -527,6 +533,12 @@ impl Client {
527533
Media::new(self.clone())
528534
}
529535

536+
/// Access the OpenID Connect API of the client.
537+
#[cfg(feature = "experimental-oidc")]
538+
pub fn oidc(&self) -> Oidc {
539+
Oidc::new(self.clone())
540+
}
541+
530542
/// Register a handler for a specific event type.
531543
///
532544
/// The handler is a function or closure with one or more arguments. The
@@ -942,6 +954,8 @@ impl Client {
942954
let session = session.into();
943955
match session {
944956
AuthSession::Matrix(s) => self.matrix_auth().restore_session(s).await,
957+
#[cfg(feature = "experimental-oidc")]
958+
AuthSession::Oidc(s) => self.oidc().restore_session(s).await,
945959
}
946960
}
947961

@@ -959,6 +973,10 @@ impl Client {
959973
AuthApi::Matrix(a) => {
960974
a.refresh_access_token().await?;
961975
}
976+
#[cfg(feature = "experimental-oidc")]
977+
AuthApi::Oidc(api) => {
978+
api.refresh_access_token().await?;
979+
}
962980
}
963981

964982
Ok(())

crates/matrix-sdk/src/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,11 @@ pub enum Error {
257257
#[error("The internal client state is inconsistent.")]
258258
InconsistentState,
259259

260+
/// An error occurred interacting with the OpenID Connect API.
261+
#[cfg(feature = "experimental-oidc")]
262+
#[error(transparent)]
263+
Oidc(#[from] crate::oidc::OidcError),
264+
260265
/// An other error was raised
261266
/// this might happen because encryption was enabled on the base-crate
262267
/// but not here and that raised.
@@ -423,6 +428,11 @@ pub enum RefreshTokenError {
423428
/// An error occurred interacting with the native Matrix authentication API.
424429
#[error(transparent)]
425430
MatrixAuth(Arc<HttpError>),
431+
432+
/// An error occurred interacting with the OpenID Connect API.
433+
#[cfg(feature = "experimental-oidc")]
434+
#[error(transparent)]
435+
Oidc(#[from] Arc<crate::oidc::OidcError>),
426436
}
427437

428438
/// Errors that can occur when manipulating push notification settings.

crates/matrix-sdk/src/http_client/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,28 @@ async fn response_to_http_response(
239239

240240
Ok(http_builder.body(body).expect("Can't construct a response using the given body"))
241241
}
242+
243+
#[cfg(feature = "experimental-oidc")]
244+
impl tower::Service<http::Request<Bytes>> for HttpClient {
245+
type Response = http::Response<Bytes>;
246+
type Error = tower::BoxError;
247+
type Future = futures_core::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
248+
249+
fn poll_ready(
250+
&mut self,
251+
_cx: &mut std::task::Context<'_>,
252+
) -> std::task::Poll<Result<(), Self::Error>> {
253+
std::task::Poll::Ready(Ok(()))
254+
}
255+
256+
fn call(&mut self, req: http::Request<Bytes>) -> Self::Future {
257+
let inner = self.inner.clone();
258+
259+
let fut = async move {
260+
native::send_request(&inner, &req, DEFAULT_REQUEST_TIMEOUT, Default::default())
261+
.await
262+
.map_err(Into::into)
263+
};
264+
Box::pin(fut)
265+
}
266+
}

crates/matrix-sdk/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ mod http_client;
4040
pub mod matrix_auth;
4141
pub mod media;
4242
pub mod notification_settings;
43+
#[cfg(feature = "experimental-oidc")]
44+
pub mod oidc;
4345
pub mod room;
4446
pub mod sync;
4547

crates/matrix-sdk/src/matrix_auth/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ impl MatrixAuth {
561561
}
562562

563563
/// Set the current session tokens
564-
fn set_session_tokens(&self, tokens: SessionTokens) {
564+
pub(crate) fn set_session_tokens(&self, tokens: SessionTokens) {
565565
if let Some(auth_data) = self.client.inner.auth_data.get() {
566566
let Some(data) = auth_data.as_matrix() else {
567567
panic!("Cannot call native Matrix authentication API after logging in with another API");

0 commit comments

Comments
 (0)