mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2025-09-10 19:02:50 +02:00
OIDC: embed user_id in consent
This commit is contained in:
parent
a536bc4c97
commit
c059dbb337
6 changed files with 30 additions and 29 deletions
|
@ -1,7 +1,7 @@
|
||||||
use axum::extract::{Query, State};
|
use axum::extract::{Query, State};
|
||||||
use conduwuit::{Result, err};
|
use conduwuit::{Result, err};
|
||||||
use conduwuit_web::oidc::{
|
use conduwuit_web::oidc::{
|
||||||
AuthorizationQuery, OidcRequest, OidcResponse, oidc_consent_form, oidc_login_form,
|
oidc_consent_form, oidc_login_form, AuthorizationQuery, OidcRequest, OidcResponse,
|
||||||
};
|
};
|
||||||
use oxide_auth::{
|
use oxide_auth::{
|
||||||
endpoint::{OwnerConsent, Solicitation},
|
endpoint::{OwnerConsent, Solicitation},
|
||||||
|
@ -40,25 +40,20 @@ pub(crate) async fn authorize(
|
||||||
|
|
||||||
// Redirect to the login page if no token or token not known.
|
// Redirect to the login page if no token or token not known.
|
||||||
let hostname = services.config.server_name.host();
|
let hostname = services.config.server_name.host();
|
||||||
match oauth.authorization_header() {
|
let Some(token) = oauth.authorization_header() else {
|
||||||
| None => {
|
|
||||||
return Ok(oidc_login_form(hostname, &query));
|
return Ok(oidc_login_form(hostname, &query));
|
||||||
},
|
};
|
||||||
| Some(token) =>
|
|
||||||
if services.users.find_from_token(token).await.is_err() {
|
tracing::debug!("submitting OIDC authorisation for token : {token:#?}");
|
||||||
return Ok(oidc_login_form(hostname, &query));
|
// Get the user id from the token and add it to the query.
|
||||||
},
|
let (owner_id, _) = services.oidc.get_user_for_token(token)?;
|
||||||
}
|
let mut query_with_user_id = query.clone();
|
||||||
// TODO register the device ID ?
|
query_with_user_id.username = Some(owner_id.localpart().to_string());
|
||||||
tracing::debug!(
|
|
||||||
"submitting OIDC authorisation for token : {:#?}",
|
|
||||||
oauth.authorization_header().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
services
|
services
|
||||||
.oidc
|
.oidc
|
||||||
.endpoint()
|
.endpoint()
|
||||||
.with_solicitor(oidc_consent_form(hostname, &query))
|
.with_solicitor(oidc_consent_form(hostname, &query_with_user_id))
|
||||||
.authorization_flow()
|
.authorization_flow()
|
||||||
.execute(oauth)
|
.execute(oauth)
|
||||||
.map_err(|err| err!("authorization failed: {err:?}"))
|
.map_err(|err| err!("authorization failed: {err:?}"))
|
||||||
|
@ -67,10 +62,10 @@ pub(crate) async fn authorize(
|
||||||
/// Whether a user allows their device to access this homeserver's resources.
|
/// Whether a user allows their device to access this homeserver's resources.
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub(crate) struct Allowance {
|
pub(crate) struct Allowance {
|
||||||
allow: Option<bool>,
|
allow: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # `POST /_matrix/client/unstable/org.matrix.msc2964/authorize?allow=[Option<bool>]`
|
/// # `POST /_matrix/client/unstable/org.matrix.msc2964/authorize?allow=[Option<String>]`
|
||||||
///
|
///
|
||||||
/// Authorize the device based on the user's consent. If the user allows
|
/// Authorize the device based on the user's consent. If the user allows
|
||||||
/// it to access their data, the client may request a token at the
|
/// it to access their data, the client may request a token at the
|
||||||
|
@ -80,16 +75,15 @@ pub(crate) async fn authorize_consent(
|
||||||
State(services): State<crate::State>,
|
State(services): State<crate::State>,
|
||||||
oauth: OidcRequest,
|
oauth: OidcRequest,
|
||||||
) -> Result<OidcResponse> {
|
) -> Result<OidcResponse> {
|
||||||
let allowed = allow.unwrap_or(false);
|
tracing::debug!("processing user's consent: {:?} - {:?}", allow, oauth);
|
||||||
tracing::debug!("processing user's consent: {:?} - {:?}", allowed, oauth);
|
|
||||||
|
|
||||||
services
|
services
|
||||||
.oidc
|
.oidc
|
||||||
.endpoint()
|
.endpoint()
|
||||||
.with_solicitor(FnSolicitor(
|
.with_solicitor(FnSolicitor(
|
||||||
move |_: &mut _, solicitation: Solicitation<'_>| match allowed {
|
move |_: &mut _, _: Solicitation<'_>| match allow.clone() {
|
||||||
| false => OwnerConsent::Denied,
|
| None => OwnerConsent::Denied,
|
||||||
| true => OwnerConsent::Authorized(solicitation.pre_grant().client_id.clone()),
|
| Some(user_id) => OwnerConsent::Authorized(user_id),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.authorization_flow()
|
.authorization_flow()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{Result, err, utils::hash::verify_password};
|
use conduwuit::{Result, err, utils::hash::verify_password};
|
||||||
use conduwuit_web::oidc::{
|
use conduwuit_web::oidc::{
|
||||||
AuthorizationQuery, LoginError, LoginQuery, OidcRequest, OidcResponse, oidc_consent_form,
|
LoginError, LoginQuery, OidcRequest, OidcResponse, oidc_consent_form,
|
||||||
};
|
};
|
||||||
use ruma::user_id::UserId;
|
use ruma::user_id::UserId;
|
||||||
|
|
||||||
|
@ -38,14 +38,12 @@ pub(crate) async fn oidc_login(
|
||||||
}
|
}
|
||||||
|
|
||||||
let hostname = services.config.server_name.host();
|
let hostname = services.config.server_name.host();
|
||||||
let authorization_query: AuthorizationQuery = query.into();
|
|
||||||
tracing::info!("logging in {user_id:?}");
|
tracing::info!("logging in {user_id:?}");
|
||||||
tracing::debug!("login {user_id} authorisation query : {authorization_query:#?}");
|
|
||||||
|
|
||||||
services
|
services
|
||||||
.oidc
|
.oidc
|
||||||
.endpoint()
|
.endpoint()
|
||||||
.with_solicitor(oidc_consent_form(hostname, &authorization_query))
|
.with_solicitor(oidc_consent_form(hostname, &query.into()))
|
||||||
.authorization_flow()
|
.authorization_flow()
|
||||||
.execute(request)
|
.execute(request)
|
||||||
.map_err(|err| err!(Request(Unknown("authorisation failed: {err:?}"))))
|
.map_err(|err| err!(Request(Unknown("authorisation failed: {err:?}"))))
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub(crate) struct ConsentPageTemplate<'a> {
|
||||||
nonce: &'a str,
|
nonce: &'a str,
|
||||||
hostname: &'a str,
|
hostname: &'a str,
|
||||||
route: &'a str,
|
route: &'a str,
|
||||||
|
user_id: &'a str,
|
||||||
client_id: &'a str,
|
client_id: &'a str,
|
||||||
client_secret: Option<&'a str>,
|
client_secret: Option<&'a str>,
|
||||||
redirect_uri: &'a str,
|
redirect_uri: &'a str,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use url::Url;
|
||||||
use super::LoginQuery;
|
use super::LoginQuery;
|
||||||
|
|
||||||
/// The set of parameters required for an OIDC authorization request.
|
/// The set of parameters required for an OIDC authorization request.
|
||||||
#[derive(serde::Deserialize, Debug)]
|
#[derive(serde::Deserialize, Debug, Clone)]
|
||||||
pub struct AuthorizationQuery {
|
pub struct AuthorizationQuery {
|
||||||
pub client_id: String,
|
pub client_id: String,
|
||||||
pub client_secret: Option<String>,
|
pub client_secret: Option<String>,
|
||||||
|
@ -14,6 +14,7 @@ pub struct AuthorizationQuery {
|
||||||
pub code_challenge_method: String,
|
pub code_challenge_method: String,
|
||||||
pub response_type: String,
|
pub response_type: String,
|
||||||
pub response_mode: Option<String>,
|
pub response_mode: Option<String>,
|
||||||
|
pub username: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<LoginQuery> for AuthorizationQuery {
|
impl From<LoginQuery> for AuthorizationQuery {
|
||||||
|
@ -28,6 +29,7 @@ impl From<LoginQuery> for AuthorizationQuery {
|
||||||
code_challenge_method,
|
code_challenge_method,
|
||||||
response_type,
|
response_type,
|
||||||
response_mode,
|
response_mode,
|
||||||
|
username,
|
||||||
..
|
..
|
||||||
} = value;
|
} = value;
|
||||||
|
|
||||||
|
@ -41,6 +43,7 @@ impl From<LoginQuery> for AuthorizationQuery {
|
||||||
code_challenge_method,
|
code_challenge_method,
|
||||||
response_type,
|
response_type,
|
||||||
response_mode: Some(response_mode),
|
response_mode: Some(response_mode),
|
||||||
|
username: Some(username),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,12 @@ pub fn oidc_consent_form(hostname: &str, query: &AuthorizationQuery) -> OidcResp
|
||||||
/// Render the html contents of the user consent page.
|
/// Render the html contents of the user consent page.
|
||||||
fn consent_page(hostname: &str, query: &AuthorizationQuery, route: &str, nonce: &str) -> String {
|
fn consent_page(hostname: &str, query: &AuthorizationQuery, route: &str, nonce: &str) -> String {
|
||||||
let response_mode = &query.response_mode.clone().unwrap_or("fragment".to_string());
|
let response_mode = &query.response_mode.clone().unwrap_or("fragment".to_string());
|
||||||
|
let user_id = query.username.clone().expect("user_id in authorization query");
|
||||||
let template = ConsentPageTemplate {
|
let template = ConsentPageTemplate {
|
||||||
nonce,
|
nonce,
|
||||||
hostname,
|
hostname,
|
||||||
route,
|
route,
|
||||||
|
user_id: &encode(&user_id),
|
||||||
client_id: &encode(query.client_id.as_str()),
|
client_id: &encode(query.client_id.as_str()),
|
||||||
client_secret: query.client_secret.as_deref(),
|
client_secret: query.client_secret.as_deref(),
|
||||||
redirect_uri: &encode(query.redirect_uri.as_str()),
|
redirect_uri: &encode(query.redirect_uri.as_str()),
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
'{{ client_id }}' (at {{ redirect_uri }}) is requesting permission for '{{ scope }}'
|
'{{ client_id }}' (at {{ redirect_uri }}) is requesting permission for '{{ scope }}'
|
||||||
</p>
|
</p>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="submit" value="Accept" formaction="{{ route }}?client_id={{ client_id }}{%- if let Some(secret) = client_secret -%}&client_secret={{ secret }}{%- endif -%}&redirect_uri={{ redirect_uri }}&scope={{ scope }}&state={{ state }}&code_challenge={{ code_challenge }}&code_challenge_method={{ code_challenge_method }}&response_type={{ response_type }}&response_mode={{ response_mode }}&allow=true">
|
<input type="submit" value="Accept" formaction="{{ route }}?client_id={{ client_id }}{%- if let Some(secret)
|
||||||
|
= client_secret -%}&client_secret={{ secret }}{%- endif -%}&redirect_uri={{ redirect_uri }}&scope={{ scope
|
||||||
|
}}&state={{ state }}&code_challenge={{ code_challenge }}&code_challenge_method={{ code_challenge_method
|
||||||
|
}}&response_type={{ response_type }}&response_mode={{ response_mode }}&allow={{ user_id }}">
|
||||||
<input type="submit" value="Deny" formaction="{{ route }}?client_id={{ client_id }}{%- if let Some(secret) = client_secret -%}&client_secret={{ secret }}{%- endif -%}&redirect_uri={{ redirect_uri }}&scope={{scope }}&state={{ state }}&code_challenge={{ code_challenge }}&code_challenge_method={{ code_challenge_method }}&response_type={{ response_type }}&response_mode={{ response_mode }}&deny=true">
|
<input type="submit" value="Deny" formaction="{{ route }}?client_id={{ client_id }}{%- if let Some(secret) = client_secret -%}&client_secret={{ secret }}{%- endif -%}&redirect_uri={{ redirect_uri }}&scope={{scope }}&state={{ state }}&code_challenge={{ code_challenge }}&code_challenge_method={{ code_challenge_method }}&response_type={{ response_type }}&response_mode={{ response_mode }}&deny=true">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue