mirror of
https://gitlab.com/famedly/conduit.git
synced 2025-06-27 16:35:59 +00:00
impl MSC2965: self-advertise as OIDC authentication provider
This commit is contained in:
parent
a7e6f60b41
commit
c322cbcb79
6 changed files with 125 additions and 2 deletions
|
@ -161,6 +161,7 @@ features = [
|
||||||
"ring-compat",
|
"ring-compat",
|
||||||
"state-res",
|
"state-res",
|
||||||
"unstable-msc2448",
|
"unstable-msc2448",
|
||||||
|
"unstable-msc2965",
|
||||||
"unstable-msc3575",
|
"unstable-msc3575",
|
||||||
]
|
]
|
||||||
git = "https://github.com/ruma/ruma.git"
|
git = "https://github.com/ruma/ruma.git"
|
||||||
|
|
|
@ -13,6 +13,7 @@ mod media;
|
||||||
mod membership;
|
mod membership;
|
||||||
mod message;
|
mod message;
|
||||||
mod openid;
|
mod openid;
|
||||||
|
mod oidc;
|
||||||
mod presence;
|
mod presence;
|
||||||
mod profile;
|
mod profile;
|
||||||
mod push;
|
mod push;
|
||||||
|
@ -73,6 +74,7 @@ pub use unversioned::*;
|
||||||
pub use user_directory::*;
|
pub use user_directory::*;
|
||||||
pub use voip::*;
|
pub use voip::*;
|
||||||
pub use well_known::*;
|
pub use well_known::*;
|
||||||
|
pub use oidc::*;
|
||||||
|
|
||||||
pub const DEVICE_ID_LENGTH: usize = 10;
|
pub const DEVICE_ID_LENGTH: usize = 10;
|
||||||
pub const TOKEN_LENGTH: usize = 32;
|
pub const TOKEN_LENGTH: usize = 32;
|
||||||
|
|
76
src/api/client_server/oidc.rs
Normal file
76
src/api/client_server/oidc.rs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/// Manual implementation of [MSC2965]'s OIDC server discovery.
|
||||||
|
///
|
||||||
|
/// [MSC2965]: https://github.com/matrix-org/matrix-spec-proposals/pull/2965
|
||||||
|
|
||||||
|
use crate::{services, Error, Result, Ruma, RumaResponse};
|
||||||
|
use ruma::serde::Raw;
|
||||||
|
use ruma::api::client::{
|
||||||
|
error::ErrorKind as ClientErrorKind,
|
||||||
|
discovery::get_authorization_server_metadata::{
|
||||||
|
self,
|
||||||
|
msc2965::{
|
||||||
|
AccountManagementAction,
|
||||||
|
AuthorizationServerMetadata,
|
||||||
|
CodeChallengeMethod,
|
||||||
|
GrantType,
|
||||||
|
Prompt,
|
||||||
|
ResponseMode,
|
||||||
|
ResponseType,
|
||||||
|
Response,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// # `GET /_matrix/client/unstable/org.matrix.msc2965/auth_metadata`
|
||||||
|
/// # `GET /_matrix/client/auth_metadata`
|
||||||
|
///
|
||||||
|
/// If `globals.auth.enable_oidc_login` is set, advertise this homeserver's OAuth2 endpoints.
|
||||||
|
/// Otherwise, MSC2965 requires that the homeserver responds with 404/M_UNRECOGNIZED.
|
||||||
|
pub async fn get_auth_metadata(
|
||||||
|
_body: Ruma<get_authorization_server_metadata::msc2965::Request>,
|
||||||
|
) -> Result<RumaResponse<Response>> {
|
||||||
|
let authentication = &services().globals.config.authentication;
|
||||||
|
if ! authentication.enable_oidc_login {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ClientErrorKind::Unknown,
|
||||||
|
"This server doesn't do OIDC authentication."
|
||||||
|
));
|
||||||
|
};
|
||||||
|
// Advertise this homeserver's access URL as the issuer URL.
|
||||||
|
// Unwrap all Url::parse() calls because the issuer URL is validated at startup.
|
||||||
|
let issuer = services().globals.config.well_known.client.as_ref().unwrap();
|
||||||
|
let account_management_uri = authentication
|
||||||
|
.enable_oidc_account_management
|
||||||
|
.then_some(issuer.join("/_matrix/client/unstable/org.matrix.msc2964/account").unwrap());
|
||||||
|
|
||||||
|
let metadata = AuthorizationServerMetadata {
|
||||||
|
issuer: issuer.clone(),
|
||||||
|
authorization_endpoint:
|
||||||
|
issuer.join("/_matrix/client/unstable/org.matrix.msc2964/authorize").unwrap(),
|
||||||
|
device_authorization_endpoint:
|
||||||
|
Some(issuer.join("/_matrix/client/unstable/org.matrix.msc2964/device").unwrap()),
|
||||||
|
token_endpoint:
|
||||||
|
issuer.join("/_matrix/client/unstable/org.matrix.msc2964/token").unwrap(),
|
||||||
|
registration_endpoint:
|
||||||
|
Some(issuer.join("/_matrix/client/unstable/org.matrix.msc2964/device/register").unwrap()),
|
||||||
|
revocation_endpoint:
|
||||||
|
issuer.join("_matrix/client/unstable/org.matrix.msc2964/revoke").unwrap(),
|
||||||
|
response_types_supported: [ResponseType::Code].into(),
|
||||||
|
grant_types_supported: [GrantType::AuthorizationCode, GrantType::RefreshToken].into(),
|
||||||
|
response_modes_supported: [ResponseMode::Fragment, ResponseMode::Query].into(),
|
||||||
|
code_challenge_methods_supported: [CodeChallengeMethod::S256].into(),
|
||||||
|
account_management_uri,
|
||||||
|
account_management_actions_supported: [
|
||||||
|
AccountManagementAction::Profile,
|
||||||
|
AccountManagementAction::SessionView,
|
||||||
|
AccountManagementAction::SessionEnd,
|
||||||
|
].into(),
|
||||||
|
prompt_values_supported: match services().globals.config.allow_registration {
|
||||||
|
| true => vec![Prompt::Create],
|
||||||
|
| false => vec![]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let metadata = Raw::new(&metadata).expect("authorization server metadata should serialize");
|
||||||
|
|
||||||
|
Ok(RumaResponse(Response::new(metadata)))
|
||||||
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
use ruma::api::client::discovery::discover_homeserver::{
|
use ruma::api::client::discovery::discover_homeserver::{
|
||||||
self, HomeserverInfo, SlidingSyncProxyInfo,
|
self,
|
||||||
|
AuthenticationServerInfo,
|
||||||
|
HomeserverInfo,
|
||||||
|
SlidingSyncProxyInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{services, Result, Ruma};
|
use crate::{services, Result, Ruma};
|
||||||
|
@ -11,12 +14,21 @@ pub async fn well_known_client(
|
||||||
_body: Ruma<discover_homeserver::Request>,
|
_body: Ruma<discover_homeserver::Request>,
|
||||||
) -> Result<discover_homeserver::Response> {
|
) -> Result<discover_homeserver::Response> {
|
||||||
let client_url = services().globals.well_known_client();
|
let client_url = services().globals.well_known_client();
|
||||||
|
let authentication = &services().globals.config.authentication;
|
||||||
|
|
||||||
Ok(discover_homeserver::Response {
|
Ok(discover_homeserver::Response {
|
||||||
homeserver: HomeserverInfo {
|
homeserver: HomeserverInfo {
|
||||||
base_url: client_url.clone(),
|
base_url: client_url.clone(),
|
||||||
},
|
},
|
||||||
identity_server: None,
|
identity_server: None,
|
||||||
sliding_sync_proxy: Some(SlidingSyncProxyInfo { url: client_url }),
|
sliding_sync_proxy: Some(SlidingSyncProxyInfo { url: client_url.clone() }),
|
||||||
|
authentication: authentication.enable_oidc_login.then_some(
|
||||||
|
AuthenticationServerInfo::new(
|
||||||
|
client_url.clone(),
|
||||||
|
authentication.enable_oidc_account_management.then_some(
|
||||||
|
format!("{client_url}/account")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ pub struct Config {
|
||||||
pub tracing_flame: bool,
|
pub tracing_flame: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub proxy: ProxyConfig,
|
pub proxy: ProxyConfig,
|
||||||
|
#[serde(default)]
|
||||||
|
pub authentication: AuthenticationConfig,
|
||||||
pub jwt_secret: Option<String>,
|
pub jwt_secret: Option<String>,
|
||||||
#[serde(default = "default_trusted_servers")]
|
#[serde(default = "default_trusted_servers")]
|
||||||
pub trusted_servers: Vec<OwnedServerName>,
|
pub trusted_servers: Vec<OwnedServerName>,
|
||||||
|
@ -115,6 +117,14 @@ pub struct WellKnownConfig {
|
||||||
pub server: Option<OwnedServerName>,
|
pub server: Option<OwnedServerName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Default)]
|
||||||
|
pub struct AuthenticationConfig {
|
||||||
|
#[serde(default = "false_fn")]
|
||||||
|
pub enable_oidc_login: bool,
|
||||||
|
#[serde(default = "false_fn")]
|
||||||
|
pub enable_oidc_account_management: bool,
|
||||||
|
}
|
||||||
|
|
||||||
const DEPRECATED_KEYS: &[&str] = &[
|
const DEPRECATED_KEYS: &[&str] = &[
|
||||||
"cache_capacity",
|
"cache_capacity",
|
||||||
"turn_username",
|
"turn_username",
|
||||||
|
@ -260,6 +270,20 @@ impl fmt::Display for Config {
|
||||||
}),
|
}),
|
||||||
("Well-known server name", well_known_server.as_str()),
|
("Well-known server name", well_known_server.as_str()),
|
||||||
("Well-known client URL", &self.well_known_client()),
|
("Well-known client URL", &self.well_known_client()),
|
||||||
|
("OIDC authentication",
|
||||||
|
if self.authentication.enable_oidc_login {
|
||||||
|
"enabled"
|
||||||
|
} else {
|
||||||
|
"disabled"
|
||||||
|
}
|
||||||
|
),
|
||||||
|
("OIDC account management enabled",
|
||||||
|
if self.authentication.enable_oidc_account_management {
|
||||||
|
"enabled"
|
||||||
|
} else {
|
||||||
|
"disabled"
|
||||||
|
}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut msg: String = "Active config values:\n\n".to_owned();
|
let mut msg: String = "Active config values:\n\n".to_owned();
|
||||||
|
|
|
@ -426,6 +426,14 @@ fn routes(config: &Config) -> Router {
|
||||||
.ruma_route(client_server::get_relating_events_route)
|
.ruma_route(client_server::get_relating_events_route)
|
||||||
.ruma_route(client_server::get_hierarchy_route)
|
.ruma_route(client_server::get_hierarchy_route)
|
||||||
.ruma_route(client_server::well_known_client)
|
.ruma_route(client_server::well_known_client)
|
||||||
|
.route(
|
||||||
|
"/_matrix/client/unstable/org.matrix.msc2965/auth_metadata",
|
||||||
|
get(client_server::get_auth_metadata),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/_matrix/client/auth_metadata",
|
||||||
|
get(client_server::get_auth_metadata),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/_matrix/client/r0/rooms/:room_id/initialSync",
|
"/_matrix/client/r0/rooms/:room_id/initialSync",
|
||||||
get(initial_sync),
|
get(initial_sync),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue