feat(sdk): Support logging in using SSO with an identity provider

This commit is contained in:
Damir Jelić
2022-02-23 10:27:07 +01:00

View File

@@ -55,6 +55,7 @@ use ruma::{
sync::sync_events,
uiaa::{AuthData, UserIdentifier},
},
session::sso_login_with_provider::v3 as sso_login_with_provider,
unversioned::{discover_homeserver, get_supported_versions},
},
error::FromHttpResponseError,
@@ -743,12 +744,23 @@ impl Client {
/// * `redirect_url` - The URL that will receive a `loginToken` after a
/// successful SSO login.
///
/// * `idp_id` - The optional ID of the identity provider to login with.
///
/// [`login_with_token`]: #method.login_with_token
pub async fn get_sso_login_url(&self, redirect_url: &str) -> Result<String> {
pub async fn get_sso_login_url(
&self,
redirect_url: &str,
idp_id: Option<&str>,
) -> Result<String> {
let homeserver = self.homeserver().await;
let request = sso_login::Request::new(redirect_url)
.try_into_http_request::<Vec<u8>>(homeserver.as_str(), SendAccessToken::None);
let request = if let Some(id) = idp_id {
sso_login_with_provider::Request::new(id, redirect_url)
.try_into_http_request::<Vec<u8>>(homeserver.as_str(), SendAccessToken::None)
} else {
sso_login::Request::new(redirect_url)
.try_into_http_request::<Vec<u8>>(homeserver.as_str(), SendAccessToken::None)
};
match request {
Ok(req) => Ok(req.uri().to_string()),
@@ -876,6 +888,8 @@ impl Client {
/// associated with the device_id. Only necessary the first time you login
/// with this device_id. It can be changed later.
///
/// * `idp_id` - The optional ID of the identity provider to login with.
///
/// # Example
/// ```no_run
/// # use matrix_sdk::Client;
@@ -894,7 +908,8 @@ impl Client {
/// None,
/// None,
/// None,
/// Some("My app")
/// Some("My app"),
/// None,
/// )
/// .await
/// .unwrap();
@@ -915,6 +930,7 @@ impl Client {
server_response: Option<&str>,
device_id: Option<&str>,
initial_device_display_name: Option<&str>,
idp_id: Option<&str>,
) -> Result<login::Response>
where
C: Future<Output = Result<()>>,
@@ -1007,7 +1023,7 @@ impl Client {
tokio::spawn(server);
let sso_url = self.get_sso_login_url(redirect_url.as_str()).await?;
let sso_url = self.get_sso_login_url(redirect_url.as_str(), idp_id).await?;
match use_sso_login_url(sso_url).await {
Ok(t) => t,
@@ -1067,7 +1083,7 @@ impl Client {
/// # let login_token = "token";
/// # block_on(async {
/// let client = Client::new(homeserver).await.unwrap();
/// let sso_url = client.get_sso_login_url(redirect_url);
/// let sso_url = client.get_sso_login_url(redirect_url, None);
///
/// // Let the user authenticate at the SSO URL
/// // Receive the loginToken param at redirect_url
@@ -2499,7 +2515,10 @@ pub(crate) mod test {
let homeserver = Url::from_str(&mockito::server_url()).unwrap();
let client = Client::new(homeserver).await.unwrap();
let idp = crate::client::get_login_types::IdentityProvider::new(
"some-id".to_string(),
"idp-name".to_string(),
);
client
.login_with_sso(
|sso_url| async move {
@@ -2519,6 +2538,7 @@ pub(crate) mod test {
None,
None,
None,
Some(&idp.id),
)
.await
.unwrap();
@@ -2547,7 +2567,7 @@ pub(crate) mod test {
.any(|flow| matches!(flow, LoginType::Sso(_)));
assert!(can_sso);
let sso_url = client.get_sso_login_url("http://127.0.0.1:3030").await;
let sso_url = client.get_sso_login_url("http://127.0.0.1:3030", None).await;
assert!(sso_url.is_ok());
let _m = mock("POST", "/_matrix/client/r0/login")