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

FFI: Expose support for registration through OIDC in the login details. #4169

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion bindings/matrix-sdk-ffi/src/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ use matrix_sdk::{
};
use url::Url;

use crate::client::{Client, SlidingSyncVersion};
use crate::client::{Client, OidcPrompt, SlidingSyncVersion};

#[derive(uniffi::Object)]
pub struct HomeserverLoginDetails {
pub(crate) url: String,
pub(crate) sliding_sync_version: SlidingSyncVersion,
pub(crate) supports_oidc_login: bool,
pub(crate) supported_oidc_prompts: Vec<OidcPrompt>,
pub(crate) supports_password_login: bool,
}

Expand All @@ -46,6 +47,12 @@ impl HomeserverLoginDetails {
self.supports_oidc_login
}

/// The prompts advertised by the authentication issuer for use in the login
/// URL.
pub fn supported_oidc_prompts(&self) -> Vec<OidcPrompt> {
self.supported_oidc_prompts.clone()
}

/// Whether the current homeserver supports the password login flow.
pub fn supports_password_login(&self) -> bool {
self.supports_password_login
Expand Down
43 changes: 41 additions & 2 deletions bindings/matrix-sdk-ffi/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,39 @@ impl Client {
impl Client {
/// Information about login options for the client's homeserver.
pub async fn homeserver_login_details(&self) -> Arc<HomeserverLoginDetails> {
let supports_oidc_login = self.inner.oidc().fetch_authentication_issuer().await.is_ok();
let oidc = self.inner.oidc();
let (supports_oidc_login, supported_oidc_prompts) = match oidc
.fetch_authentication_issuer()
.await
{
Ok(issuer) => match &oidc.given_provider_metadata(&issuer).await {
Ok(metadata) => {
let prompts = metadata
.prompt_values_supported
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't be more efficient / generic to expose the prompt_values_supported list as a list of OidcPrompt?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, I wasn't sure if the concept of OidcPrompts was a bit too much info but if we're happy with that I'll update and at which point, there wouldn't be any custom FFI logic so I would leave all this in the FFI.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmm, the amount of code didn't really change that much, it's basically just the use of Into instead of contains. WDYT @bnjbvr, I wouldn't really consider there to be any custom FFI logic here now as it is just mapping SDK values to FFI values.

Copy link
Member

Choose a reason for hiding this comment

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

If that's sufficient for your needs, that's fine with me. (Please make sure to log errors that are silently swallowed here, for both if let Ok(...) branches.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done in 4829f48

.as_ref()
.map_or_else(Vec::new, |prompts| prompts.iter().map(Into::into).collect());

(true, prompts)
}
Err(error) => {
error!("Failed to fetch OIDC provider metadata: {error}");
(true, Default::default())
}
},
Err(error) => {
error!("Failed to fetch authentication issuer: {error}");
(false, Default::default())
}
};

let supports_password_login = self.supports_password_login().await.ok().unwrap_or(false);
let sliding_sync_version = self.sliding_sync_version();

Arc::new(HomeserverLoginDetails {
url: self.homeserver(),
sliding_sync_version,
supports_oidc_login,
supported_oidc_prompts,
supports_password_login,
})
}
Expand Down Expand Up @@ -1758,7 +1783,7 @@ impl TryFrom<SlidingSyncVersion> for SdkSlidingSyncVersion {
}
}

#[derive(uniffi::Enum)]
#[derive(Clone, uniffi::Enum)]
pub enum OidcPrompt {
/// The Authorization Server must not display any authentication or consent
/// user interface pages.
Expand Down Expand Up @@ -1790,6 +1815,20 @@ pub enum OidcPrompt {
Unknown { value: String },
}

impl From<&SdkOidcPrompt> for OidcPrompt {
fn from(value: &SdkOidcPrompt) -> Self {
match value {
SdkOidcPrompt::None => Self::None,
SdkOidcPrompt::Login => Self::Login,
SdkOidcPrompt::Consent => Self::Consent,
SdkOidcPrompt::SelectAccount => Self::SelectAccount,
SdkOidcPrompt::Create => Self::Create,
SdkOidcPrompt::Unknown(value) => Self::Unknown { value: value.to_owned() },
_ => Self::Unknown { value: value.to_string() },
}
}
}

impl From<OidcPrompt> for SdkOidcPrompt {
fn from(value: OidcPrompt) -> Self {
match value {
Expand Down
Loading