You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-06 06:02:40 +03:00
Add support for all authorization request parameters
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
committed by
Quentin Gliech
parent
e430e9d414
commit
c67a00ddd6
@@ -89,7 +89,6 @@ pub(crate) async fn get(
|
|||||||
let data = AuthorizationRequestData {
|
let data = AuthorizationRequestData {
|
||||||
client_id: &provider.client_id,
|
client_id: &provider.client_id,
|
||||||
scope: &provider.scope,
|
scope: &provider.scope,
|
||||||
prompt: None,
|
|
||||||
redirect_uri: &redirect_uri,
|
redirect_uri: &redirect_uri,
|
||||||
code_challenge_methods_supported: metadata.code_challenge_methods_supported.as_deref(),
|
code_challenge_methods_supported: metadata.code_challenge_methods_supported.as_deref(),
|
||||||
};
|
};
|
||||||
@@ -98,6 +97,7 @@ pub(crate) async fn get(
|
|||||||
let (url, data) = mas_oidc_client::requests::authorization_code::build_authorization_url(
|
let (url, data) = mas_oidc_client::requests::authorization_code::build_authorization_url(
|
||||||
metadata.authorization_endpoint().clone(),
|
metadata.authorization_endpoint().clone(),
|
||||||
data,
|
data,
|
||||||
|
None,
|
||||||
&mut rng,
|
&mut rng,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@@ -16,9 +16,12 @@
|
|||||||
//!
|
//!
|
||||||
//! [Authorization Code flow]: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
//! [Authorization Code flow]: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
||||||
|
|
||||||
|
use std::{collections::HashSet, num::NonZeroU32};
|
||||||
|
|
||||||
use base64ct::{Base64UrlUnpadded, Encoding};
|
use base64ct::{Base64UrlUnpadded, Encoding};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use http::header::CONTENT_TYPE;
|
use http::header::CONTENT_TYPE;
|
||||||
|
use language_tags::LanguageTag;
|
||||||
use mas_http::{CatchHttpCodesLayer, FormUrlencodedRequestLayer, JsonResponseLayer};
|
use mas_http::{CatchHttpCodesLayer, FormUrlencodedRequestLayer, JsonResponseLayer};
|
||||||
use mas_iana::oauth::{OAuthAuthorizationEndpointResponseType, PkceCodeChallengeMethod};
|
use mas_iana::oauth::{OAuthAuthorizationEndpointResponseType, PkceCodeChallengeMethod};
|
||||||
use mas_jose::claims::{self, TokenHash};
|
use mas_jose::claims::{self, TokenHash};
|
||||||
@@ -27,7 +30,7 @@ use oauth2_types::{
|
|||||||
prelude::CodeChallengeMethodExt,
|
prelude::CodeChallengeMethodExt,
|
||||||
requests::{
|
requests::{
|
||||||
AccessTokenRequest, AccessTokenResponse, AuthorizationCodeGrant, AuthorizationRequest,
|
AccessTokenRequest, AccessTokenResponse, AuthorizationCodeGrant, AuthorizationRequest,
|
||||||
Prompt, PushedAuthorizationResponse,
|
Display, Prompt, PushedAuthorizationResponse,
|
||||||
},
|
},
|
||||||
scope::Scope,
|
scope::Scope,
|
||||||
};
|
};
|
||||||
@@ -74,9 +77,39 @@ pub struct AuthorizationRequestData<'a> {
|
|||||||
///
|
///
|
||||||
/// It must be one of the redirect URIs provided during registration.
|
/// It must be one of the redirect URIs provided during registration.
|
||||||
pub redirect_uri: &'a Url,
|
pub redirect_uri: &'a Url,
|
||||||
|
}
|
||||||
|
|
||||||
/// Optional hints for the action to be performed.
|
/// Extra parameters to influence the authorization flow.
|
||||||
pub prompt: Option<&'a [Prompt]>,
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct AuthorizationRequestExtraParameters {
|
||||||
|
/// How the Authorization Server should display the authentication and
|
||||||
|
/// consent user interface pages to the End-User.
|
||||||
|
pub display: Option<Display>,
|
||||||
|
|
||||||
|
/// Whether the Authorization Server should prompt the End-User for
|
||||||
|
/// reauthentication and consent.
|
||||||
|
///
|
||||||
|
/// If [`Prompt::None`] is used, it must be the only value.
|
||||||
|
pub prompt: Option<Vec<Prompt>>,
|
||||||
|
|
||||||
|
/// The allowable elapsed time in seconds since the last time the End-User
|
||||||
|
/// was actively authenticated by the OpenID Provider.
|
||||||
|
pub max_age: Option<NonZeroU32>,
|
||||||
|
|
||||||
|
/// End-User's preferred languages and scripts for the user interface.
|
||||||
|
pub ui_locales: Option<Vec<LanguageTag>>,
|
||||||
|
|
||||||
|
/// ID Token previously issued by the Authorization Server being passed as a
|
||||||
|
/// hint about the End-User's current or past authenticated session with the
|
||||||
|
/// Client.
|
||||||
|
pub id_token_hint: Option<String>,
|
||||||
|
|
||||||
|
/// Hint to the Authorization Server about the login identifier the End-User
|
||||||
|
/// might use to log in.
|
||||||
|
pub login_hint: Option<String>,
|
||||||
|
|
||||||
|
/// Requested Authentication Context Class Reference values.
|
||||||
|
pub acr_values: Option<HashSet<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The data necessary to validate a response from the Token endpoint in the
|
/// The data necessary to validate a response from the Token endpoint in the
|
||||||
@@ -108,6 +141,7 @@ struct FullAuthorizationRequest {
|
|||||||
/// Build the authorization request.
|
/// Build the authorization request.
|
||||||
fn build_authorization_request(
|
fn build_authorization_request(
|
||||||
authorization_data: AuthorizationRequestData<'_>,
|
authorization_data: AuthorizationRequestData<'_>,
|
||||||
|
extra_params: Option<AuthorizationRequestExtraParameters>,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
) -> Result<(FullAuthorizationRequest, AuthorizationValidationData), AuthorizationError> {
|
) -> Result<(FullAuthorizationRequest, AuthorizationValidationData), AuthorizationError> {
|
||||||
let AuthorizationRequestData {
|
let AuthorizationRequestData {
|
||||||
@@ -115,8 +149,16 @@ fn build_authorization_request(
|
|||||||
code_challenge_methods_supported,
|
code_challenge_methods_supported,
|
||||||
scope,
|
scope,
|
||||||
redirect_uri,
|
redirect_uri,
|
||||||
prompt,
|
|
||||||
} = authorization_data;
|
} = authorization_data;
|
||||||
|
let AuthorizationRequestExtraParameters {
|
||||||
|
display,
|
||||||
|
prompt,
|
||||||
|
max_age,
|
||||||
|
ui_locales,
|
||||||
|
id_token_hint,
|
||||||
|
login_hint,
|
||||||
|
acr_values,
|
||||||
|
} = extra_params.unwrap_or_default();
|
||||||
let mut scope = scope.clone();
|
let mut scope = scope.clone();
|
||||||
|
|
||||||
// Generate a random CSRF "state" token and a nonce.
|
// Generate a random CSRF "state" token and a nonce.
|
||||||
@@ -156,13 +198,13 @@ fn build_authorization_request(
|
|||||||
state: Some(state.clone()),
|
state: Some(state.clone()),
|
||||||
response_mode: None,
|
response_mode: None,
|
||||||
nonce: Some(nonce.clone()),
|
nonce: Some(nonce.clone()),
|
||||||
display: None,
|
display,
|
||||||
prompt: prompt.map(ToOwned::to_owned),
|
prompt,
|
||||||
max_age: None,
|
max_age,
|
||||||
ui_locales: None,
|
ui_locales,
|
||||||
id_token_hint: None,
|
id_token_hint,
|
||||||
login_hint: None,
|
login_hint,
|
||||||
acr_values: None,
|
acr_values,
|
||||||
request: None,
|
request: None,
|
||||||
request_uri: None,
|
request_uri: None,
|
||||||
registration: None,
|
registration: None,
|
||||||
@@ -214,6 +256,7 @@ fn build_authorization_request(
|
|||||||
pub fn build_authorization_url(
|
pub fn build_authorization_url(
|
||||||
authorization_endpoint: Url,
|
authorization_endpoint: Url,
|
||||||
authorization_data: AuthorizationRequestData<'_>,
|
authorization_data: AuthorizationRequestData<'_>,
|
||||||
|
extra_params: Option<AuthorizationRequestExtraParameters>,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
) -> Result<(Url, AuthorizationValidationData), AuthorizationError> {
|
) -> Result<(Url, AuthorizationValidationData), AuthorizationError> {
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
@@ -222,7 +265,7 @@ pub fn build_authorization_url(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let (authorization_request, validation_data) =
|
let (authorization_request, validation_data) =
|
||||||
build_authorization_request(authorization_data, rng)?;
|
build_authorization_request(authorization_data, extra_params, rng)?;
|
||||||
|
|
||||||
let authorization_query = serde_urlencoded::to_string(authorization_request)?;
|
let authorization_query = serde_urlencoded::to_string(authorization_request)?;
|
||||||
|
|
||||||
@@ -285,7 +328,7 @@ pub fn build_authorization_url(
|
|||||||
///
|
///
|
||||||
/// [Pushed Authorization Request]: https://oauth.net/2/pushed-authorization-requests/
|
/// [Pushed Authorization Request]: https://oauth.net/2/pushed-authorization-requests/
|
||||||
/// [`ClientErrorCode`]: oauth2_types::errors::ClientErrorCode
|
/// [`ClientErrorCode`]: oauth2_types::errors::ClientErrorCode
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines, clippy::too_many_arguments)]
|
||||||
#[tracing::instrument(skip_all, fields(par_endpoint))]
|
#[tracing::instrument(skip_all, fields(par_endpoint))]
|
||||||
pub async fn build_par_authorization_url(
|
pub async fn build_par_authorization_url(
|
||||||
http_service: &HttpService,
|
http_service: &HttpService,
|
||||||
@@ -293,6 +336,7 @@ pub async fn build_par_authorization_url(
|
|||||||
par_endpoint: &Url,
|
par_endpoint: &Url,
|
||||||
authorization_endpoint: Url,
|
authorization_endpoint: Url,
|
||||||
authorization_data: AuthorizationRequestData<'_>,
|
authorization_data: AuthorizationRequestData<'_>,
|
||||||
|
extra_params: Option<AuthorizationRequestExtraParameters>,
|
||||||
now: DateTime<Utc>,
|
now: DateTime<Utc>,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
) -> Result<(Url, AuthorizationValidationData), AuthorizationError> {
|
) -> Result<(Url, AuthorizationValidationData), AuthorizationError> {
|
||||||
@@ -304,7 +348,7 @@ pub async fn build_par_authorization_url(
|
|||||||
let client_id = client_credentials.client_id().to_owned();
|
let client_id = client_credentials.client_id().to_owned();
|
||||||
|
|
||||||
let (authorization_request, validation_data) =
|
let (authorization_request, validation_data) =
|
||||||
build_authorization_request(authorization_data, rng)?;
|
build_authorization_request(authorization_data, extra_params, rng)?;
|
||||||
|
|
||||||
let par_request = http::Request::post(par_endpoint.as_str())
|
let par_request = http::Request::post(par_endpoint.as_str())
|
||||||
.header(CONTENT_TYPE, mime::APPLICATION_WWW_FORM_URLENCODED.as_ref())
|
.header(CONTENT_TYPE, mime::APPLICATION_WWW_FORM_URLENCODED.as_ref())
|
||||||
|
@@ -64,8 +64,8 @@ fn pass_authorization_url() {
|
|||||||
code_challenge_methods_supported: Some(&[PkceCodeChallengeMethod::S256]),
|
code_challenge_methods_supported: Some(&[PkceCodeChallengeMethod::S256]),
|
||||||
scope: &[ScopeToken::Openid].into_iter().collect(),
|
scope: &[ScopeToken::Openid].into_iter().collect(),
|
||||||
redirect_uri: &redirect_uri,
|
redirect_uri: &redirect_uri,
|
||||||
prompt: None,
|
|
||||||
},
|
},
|
||||||
|
None,
|
||||||
&mut rng,
|
&mut rng,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -135,8 +135,8 @@ async fn pass_pushed_authorization_request() {
|
|||||||
code_challenge_methods_supported: Some(&[PkceCodeChallengeMethod::S256]),
|
code_challenge_methods_supported: Some(&[PkceCodeChallengeMethod::S256]),
|
||||||
scope: &[ScopeToken::Openid].into_iter().collect(),
|
scope: &[ScopeToken::Openid].into_iter().collect(),
|
||||||
redirect_uri: &redirect_uri,
|
redirect_uri: &redirect_uri,
|
||||||
prompt: None,
|
|
||||||
},
|
},
|
||||||
|
None,
|
||||||
now(),
|
now(),
|
||||||
&mut rng,
|
&mut rng,
|
||||||
)
|
)
|
||||||
@@ -187,8 +187,8 @@ async fn fail_pushed_authorization_request_404() {
|
|||||||
code_challenge_methods_supported: Some(&[PkceCodeChallengeMethod::S256]),
|
code_challenge_methods_supported: Some(&[PkceCodeChallengeMethod::S256]),
|
||||||
scope: &[ScopeToken::Openid].into_iter().collect(),
|
scope: &[ScopeToken::Openid].into_iter().collect(),
|
||||||
redirect_uri: &redirect_uri,
|
redirect_uri: &redirect_uri,
|
||||||
prompt: None,
|
|
||||||
},
|
},
|
||||||
|
None,
|
||||||
now(),
|
now(),
|
||||||
&mut rng,
|
&mut rng,
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user