You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Fix the authorization grant template
It previously relied on the client being in the authorization grant, which is not the case anymore. This commit also adds a test to ensure we're not breaking this template in the future.
This commit is contained in:
@ -19,6 +19,11 @@ use mas_iana::oauth::PkceCodeChallengeMethod;
|
|||||||
use oauth2_types::{
|
use oauth2_types::{
|
||||||
pkce::{CodeChallengeError, CodeChallengeMethodExt},
|
pkce::{CodeChallengeError, CodeChallengeMethodExt},
|
||||||
requests::ResponseMode,
|
requests::ResponseMode,
|
||||||
|
scope::{Scope, OPENID, PROFILE},
|
||||||
|
};
|
||||||
|
use rand::{
|
||||||
|
distributions::{Alphanumeric, DistString},
|
||||||
|
RngCore,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
@ -146,7 +151,7 @@ pub struct AuthorizationGrant {
|
|||||||
pub code: Option<AuthorizationCode>,
|
pub code: Option<AuthorizationCode>,
|
||||||
pub client_id: Ulid,
|
pub client_id: Ulid,
|
||||||
pub redirect_uri: Url,
|
pub redirect_uri: Url,
|
||||||
pub scope: oauth2_types::scope::Scope,
|
pub scope: Scope,
|
||||||
pub state: Option<String>,
|
pub state: Option<String>,
|
||||||
pub nonce: Option<String>,
|
pub nonce: Option<String>,
|
||||||
pub max_age: Option<NonZeroU32>,
|
pub max_age: Option<NonZeroU32>,
|
||||||
@ -190,4 +195,25 @@ impl AuthorizationGrant {
|
|||||||
self.stage = self.stage.cancel(canceld_at)?;
|
self.stage = self.stage.cancel(canceld_at)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sample(now: DateTime<Utc>, rng: &mut impl RngCore) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Ulid::from_datetime_with_source(now.into(), rng),
|
||||||
|
stage: AuthorizationGrantStage::Pending,
|
||||||
|
code: Some(AuthorizationCode {
|
||||||
|
code: Alphanumeric.sample_string(rng, 10),
|
||||||
|
pkce: None,
|
||||||
|
}),
|
||||||
|
client_id: Ulid::from_datetime_with_source(now.into(), rng),
|
||||||
|
redirect_uri: Url::parse("http://localhost:8080").unwrap(),
|
||||||
|
scope: Scope::from_iter([OPENID, PROFILE]),
|
||||||
|
state: Some(Alphanumeric.sample_string(rng, 10)),
|
||||||
|
nonce: Some(Alphanumeric.sample_string(rng, 10)),
|
||||||
|
max_age: None,
|
||||||
|
response_mode: ResponseMode::Query,
|
||||||
|
response_type_id_token: false,
|
||||||
|
created_at: now,
|
||||||
|
requires_consent: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,14 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use mas_iana::{
|
use mas_iana::{
|
||||||
jose::JsonWebSignatureAlg,
|
jose::JsonWebSignatureAlg,
|
||||||
oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
|
oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
|
||||||
};
|
};
|
||||||
use mas_jose::jwk::PublicJsonWebKeySet;
|
use mas_jose::jwk::PublicJsonWebKeySet;
|
||||||
use oauth2_types::requests::GrantType;
|
use oauth2_types::requests::GrantType;
|
||||||
|
use rand::RngCore;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
@ -120,4 +122,56 @@ impl Client {
|
|||||||
_ => Err(InvalidRedirectUriError::NotAllowed),
|
_ => Err(InvalidRedirectUriError::NotAllowed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn samples(now: DateTime<Utc>, rng: &mut impl RngCore) -> Vec<Client> {
|
||||||
|
vec![
|
||||||
|
// A client with all the URIs set
|
||||||
|
Self {
|
||||||
|
id: Ulid::from_datetime_with_source(now.into(), rng),
|
||||||
|
client_id: "client1".to_owned(),
|
||||||
|
encrypted_client_secret: None,
|
||||||
|
redirect_uris: vec![
|
||||||
|
Url::parse("https://client1.example.com/redirect").unwrap(),
|
||||||
|
Url::parse("https://client1.example.com/redirect2").unwrap(),
|
||||||
|
],
|
||||||
|
response_types: vec![OAuthAuthorizationEndpointResponseType::Code],
|
||||||
|
grant_types: vec![GrantType::AuthorizationCode, GrantType::RefreshToken],
|
||||||
|
contacts: vec!["foo@client1.example.com".to_owned()],
|
||||||
|
client_name: Some("Client 1".to_owned()),
|
||||||
|
client_uri: Some(Url::parse("https://client1.example.com").unwrap()),
|
||||||
|
logo_uri: Some(Url::parse("https://client1.example.com/logo.png").unwrap()),
|
||||||
|
tos_uri: Some(Url::parse("https://client1.example.com/tos").unwrap()),
|
||||||
|
policy_uri: Some(Url::parse("https://client1.example.com/policy").unwrap()),
|
||||||
|
initiate_login_uri: Some(
|
||||||
|
Url::parse("https://client1.example.com/initiate-login").unwrap(),
|
||||||
|
),
|
||||||
|
token_endpoint_auth_method: Some(OAuthClientAuthenticationMethod::None),
|
||||||
|
token_endpoint_auth_signing_alg: None,
|
||||||
|
id_token_signed_response_alg: None,
|
||||||
|
userinfo_signed_response_alg: None,
|
||||||
|
jwks: None,
|
||||||
|
},
|
||||||
|
// Another client without any URIs set
|
||||||
|
Self {
|
||||||
|
id: Ulid::from_datetime_with_source(now.into(), rng),
|
||||||
|
client_id: "client2".to_owned(),
|
||||||
|
encrypted_client_secret: None,
|
||||||
|
redirect_uris: vec![Url::parse("https://client2.example.com/redirect").unwrap()],
|
||||||
|
response_types: vec![OAuthAuthorizationEndpointResponseType::Code],
|
||||||
|
grant_types: vec![GrantType::AuthorizationCode, GrantType::RefreshToken],
|
||||||
|
contacts: vec!["foo@client2.example.com".to_owned()],
|
||||||
|
client_name: None,
|
||||||
|
client_uri: None,
|
||||||
|
logo_uri: None,
|
||||||
|
tos_uri: None,
|
||||||
|
policy_uri: None,
|
||||||
|
initiate_login_uri: None,
|
||||||
|
token_endpoint_auth_method: None,
|
||||||
|
token_endpoint_auth_signing_alg: None,
|
||||||
|
id_token_signed_response_alg: None,
|
||||||
|
userinfo_signed_response_alg: None,
|
||||||
|
jwks: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ use axum::{
|
|||||||
use axum_extra::extract::PrivateCookieJar;
|
use axum_extra::extract::PrivateCookieJar;
|
||||||
use hyper::StatusCode;
|
use hyper::StatusCode;
|
||||||
use mas_axum_utils::SessionInfoExt;
|
use mas_axum_utils::SessionInfoExt;
|
||||||
use mas_data_model::{AuthorizationGrant, BrowserSession};
|
use mas_data_model::{AuthorizationGrant, BrowserSession, Client};
|
||||||
use mas_keystore::Encrypter;
|
use mas_keystore::Encrypter;
|
||||||
use mas_policy::PolicyFactory;
|
use mas_policy::PolicyFactory;
|
||||||
use mas_router::{PostAuthAction, Route};
|
use mas_router::{PostAuthAction, Route};
|
||||||
@ -47,6 +47,9 @@ pub enum RouteError {
|
|||||||
|
|
||||||
#[error("authorization grant is not in a pending state")]
|
#[error("authorization grant is not in a pending state")]
|
||||||
NotPending,
|
NotPending,
|
||||||
|
|
||||||
|
#[error("failed to load client")]
|
||||||
|
NoSuchClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoResponse for RouteError {
|
impl IntoResponse for RouteError {
|
||||||
@ -62,8 +65,8 @@ impl IntoResponse for RouteError {
|
|||||||
"authorization grant not in a pending state",
|
"authorization grant not in a pending state",
|
||||||
)
|
)
|
||||||
.into_response(),
|
.into_response(),
|
||||||
RouteError::Internal(e) => {
|
RouteError::Internal(_) | Self::NoSuchClient => {
|
||||||
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response()
|
(StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +115,13 @@ pub(crate) async fn get(
|
|||||||
return Ok((cookie_jar, mas_router::Login::and_then(continue_grant).go()).into_response());
|
return Ok((cookie_jar, mas_router::Login::and_then(continue_grant).go()).into_response());
|
||||||
};
|
};
|
||||||
|
|
||||||
match complete(rng, clock, grant, session, &policy_factory, repo).await {
|
let client = repo
|
||||||
|
.oauth2_client()
|
||||||
|
.lookup(grant.client_id)
|
||||||
|
.await?
|
||||||
|
.ok_or(RouteError::NoSuchClient)?;
|
||||||
|
|
||||||
|
match complete(rng, clock, grant, client, session, &policy_factory, repo).await {
|
||||||
Ok(params) => {
|
Ok(params) => {
|
||||||
let res = callback_destination.go(&templates, params).await?;
|
let res = callback_destination.go(&templates, params).await?;
|
||||||
Ok((cookie_jar, res).into_response())
|
Ok((cookie_jar, res).into_response())
|
||||||
@ -128,7 +137,6 @@ pub(crate) async fn get(
|
|||||||
}
|
}
|
||||||
Err(GrantCompletionError::NotPending) => Err(RouteError::NotPending),
|
Err(GrantCompletionError::NotPending) => Err(RouteError::NotPending),
|
||||||
Err(GrantCompletionError::Internal(e)) => Err(RouteError::Internal(e)),
|
Err(GrantCompletionError::Internal(e)) => Err(RouteError::Internal(e)),
|
||||||
Err(e) => Err(RouteError::Internal(e.into())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,9 +156,6 @@ pub enum GrantCompletionError {
|
|||||||
|
|
||||||
#[error("denied by the policy")]
|
#[error("denied by the policy")]
|
||||||
PolicyViolation,
|
PolicyViolation,
|
||||||
|
|
||||||
#[error("failed to load client")]
|
|
||||||
NoSuchClient,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_from_error_for_route!(GrantCompletionError: mas_storage::RepositoryError);
|
impl_from_error_for_route!(GrantCompletionError: mas_storage::RepositoryError);
|
||||||
@ -163,6 +168,7 @@ pub(crate) async fn complete(
|
|||||||
mut rng: BoxRng,
|
mut rng: BoxRng,
|
||||||
clock: BoxClock,
|
clock: BoxClock,
|
||||||
grant: AuthorizationGrant,
|
grant: AuthorizationGrant,
|
||||||
|
client: Client,
|
||||||
browser_session: BrowserSession,
|
browser_session: BrowserSession,
|
||||||
policy_factory: &PolicyFactory,
|
policy_factory: &PolicyFactory,
|
||||||
mut repo: BoxRepository,
|
mut repo: BoxRepository,
|
||||||
@ -181,19 +187,13 @@ pub(crate) async fn complete(
|
|||||||
// Run through the policy
|
// Run through the policy
|
||||||
let mut policy = policy_factory.instantiate().await?;
|
let mut policy = policy_factory.instantiate().await?;
|
||||||
let res = policy
|
let res = policy
|
||||||
.evaluate_authorization_grant(&grant, &browser_session.user)
|
.evaluate_authorization_grant(&grant, &client, &browser_session.user)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !res.valid() {
|
if !res.valid() {
|
||||||
return Err(GrantCompletionError::PolicyViolation);
|
return Err(GrantCompletionError::PolicyViolation);
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = repo
|
|
||||||
.oauth2_client()
|
|
||||||
.lookup(grant.client_id)
|
|
||||||
.await?
|
|
||||||
.ok_or(GrantCompletionError::NoSuchClient)?;
|
|
||||||
|
|
||||||
let current_consent = repo
|
let current_consent = repo
|
||||||
.oauth2_client()
|
.oauth2_client()
|
||||||
.get_consent_for_user(&client, &browser_session.user)
|
.get_consent_for_user(&client, &browser_session.user)
|
||||||
|
@ -341,6 +341,7 @@ pub(crate) async fn get(
|
|||||||
rng,
|
rng,
|
||||||
clock,
|
clock,
|
||||||
grant,
|
grant,
|
||||||
|
client,
|
||||||
user_session,
|
user_session,
|
||||||
&policy_factory,
|
&policy_factory,
|
||||||
repo,
|
repo,
|
||||||
@ -372,10 +373,7 @@ pub(crate) async fn get(
|
|||||||
Err(GrantCompletionError::Internal(e)) => {
|
Err(GrantCompletionError::Internal(e)) => {
|
||||||
return Err(RouteError::Internal(e))
|
return Err(RouteError::Internal(e))
|
||||||
}
|
}
|
||||||
Err(
|
Err(e @ GrantCompletionError::NotPending) => {
|
||||||
e @ (GrantCompletionError::NotPending
|
|
||||||
| GrantCompletionError::NoSuchClient),
|
|
||||||
) => {
|
|
||||||
// This should never happen
|
// This should never happen
|
||||||
return Err(RouteError::Internal(Box::new(e)));
|
return Err(RouteError::Internal(Box::new(e)));
|
||||||
}
|
}
|
||||||
@ -388,6 +386,7 @@ pub(crate) async fn get(
|
|||||||
rng,
|
rng,
|
||||||
clock,
|
clock,
|
||||||
grant,
|
grant,
|
||||||
|
client,
|
||||||
user_session,
|
user_session,
|
||||||
&policy_factory,
|
&policy_factory,
|
||||||
repo,
|
repo,
|
||||||
@ -413,10 +412,7 @@ pub(crate) async fn get(
|
|||||||
Err(GrantCompletionError::Internal(e)) => {
|
Err(GrantCompletionError::Internal(e)) => {
|
||||||
return Err(RouteError::Internal(e))
|
return Err(RouteError::Internal(e))
|
||||||
}
|
}
|
||||||
Err(
|
Err(e @ GrantCompletionError::NotPending) => {
|
||||||
e @ (GrantCompletionError::NotPending
|
|
||||||
| GrantCompletionError::NoSuchClient),
|
|
||||||
) => {
|
|
||||||
// This should never happen
|
// This should never happen
|
||||||
return Err(RouteError::Internal(Box::new(e)));
|
return Err(RouteError::Internal(Box::new(e)));
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,12 @@ pub(crate) async fn get(
|
|||||||
.await?
|
.await?
|
||||||
.ok_or(RouteError::GrantNotFound)?;
|
.ok_or(RouteError::GrantNotFound)?;
|
||||||
|
|
||||||
|
let client = repo
|
||||||
|
.oauth2_client()
|
||||||
|
.lookup(grant.client_id)
|
||||||
|
.await?
|
||||||
|
.ok_or(RouteError::NoSuchClient)?;
|
||||||
|
|
||||||
if !matches!(grant.stage, AuthorizationGrantStage::Pending) {
|
if !matches!(grant.stage, AuthorizationGrantStage::Pending) {
|
||||||
return Err(RouteError::GrantNotPending);
|
return Err(RouteError::GrantNotPending);
|
||||||
}
|
}
|
||||||
@ -106,11 +112,11 @@ pub(crate) async fn get(
|
|||||||
|
|
||||||
let mut policy = policy_factory.instantiate().await?;
|
let mut policy = policy_factory.instantiate().await?;
|
||||||
let res = policy
|
let res = policy
|
||||||
.evaluate_authorization_grant(&grant, &session.user)
|
.evaluate_authorization_grant(&grant, &client, &session.user)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if res.valid() {
|
if res.valid() {
|
||||||
let ctx = ConsentContext::new(grant)
|
let ctx = ConsentContext::new(grant, client)
|
||||||
.with_session(session)
|
.with_session(session)
|
||||||
.with_csrf(csrf_token.form_value());
|
.with_csrf(csrf_token.form_value());
|
||||||
|
|
||||||
@ -118,7 +124,7 @@ pub(crate) async fn get(
|
|||||||
|
|
||||||
Ok((cookie_jar, Html(content)).into_response())
|
Ok((cookie_jar, Html(content)).into_response())
|
||||||
} else {
|
} else {
|
||||||
let ctx = PolicyViolationContext::new(grant)
|
let ctx = PolicyViolationContext::new(grant, client)
|
||||||
.with_session(session)
|
.with_session(session)
|
||||||
.with_csrf(csrf_token.form_value());
|
.with_csrf(csrf_token.form_value());
|
||||||
|
|
||||||
@ -167,21 +173,21 @@ pub(crate) async fn post(
|
|||||||
return Ok((cookie_jar, login.go()).into_response());
|
return Ok((cookie_jar, login.go()).into_response());
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut policy = policy_factory.instantiate().await?;
|
|
||||||
let res = policy
|
|
||||||
.evaluate_authorization_grant(&grant, &session.user)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if !res.valid() {
|
|
||||||
return Err(RouteError::PolicyViolation);
|
|
||||||
}
|
|
||||||
|
|
||||||
let client = repo
|
let client = repo
|
||||||
.oauth2_client()
|
.oauth2_client()
|
||||||
.lookup(grant.client_id)
|
.lookup(grant.client_id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(RouteError::NoSuchClient)?;
|
.ok_or(RouteError::NoSuchClient)?;
|
||||||
|
|
||||||
|
let mut policy = policy_factory.instantiate().await?;
|
||||||
|
let res = policy
|
||||||
|
.evaluate_authorization_grant(&grant, &client, &session.user)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !res.valid() {
|
||||||
|
return Err(RouteError::PolicyViolation);
|
||||||
|
}
|
||||||
|
|
||||||
// Do not consent for the "urn:matrix:org.matrix.msc2967.client:device:*" scope
|
// Do not consent for the "urn:matrix:org.matrix.msc2967.client:device:*" scope
|
||||||
let scope_without_device = grant
|
let scope_without_device = grant
|
||||||
.scope
|
.scope
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
#![allow(clippy::missing_errors_doc)]
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
|
||||||
use mas_data_model::{AuthorizationGrant, User};
|
use mas_data_model::{AuthorizationGrant, Client, User};
|
||||||
use oauth2_types::registration::VerifiedClientMetadata;
|
use oauth2_types::registration::VerifiedClientMetadata;
|
||||||
use opa_wasm::Runtime;
|
use opa_wasm::Runtime;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -246,6 +246,7 @@ impl Policy {
|
|||||||
skip_all,
|
skip_all,
|
||||||
fields(
|
fields(
|
||||||
data.authorization_grant.id = %authorization_grant.id,
|
data.authorization_grant.id = %authorization_grant.id,
|
||||||
|
data.client.id = %client.id,
|
||||||
data.user.id = %user.id,
|
data.user.id = %user.id,
|
||||||
),
|
),
|
||||||
err,
|
err,
|
||||||
@ -253,12 +254,14 @@ impl Policy {
|
|||||||
pub async fn evaluate_authorization_grant(
|
pub async fn evaluate_authorization_grant(
|
||||||
&mut self,
|
&mut self,
|
||||||
authorization_grant: &AuthorizationGrant,
|
authorization_grant: &AuthorizationGrant,
|
||||||
|
client: &Client,
|
||||||
user: &User,
|
user: &User,
|
||||||
) -> Result<EvaluationResult, EvaluationError> {
|
) -> Result<EvaluationResult, EvaluationError> {
|
||||||
let authorization_grant = serde_json::to_value(authorization_grant)?;
|
let authorization_grant = serde_json::to_value(authorization_grant)?;
|
||||||
let user = serde_json::to_value(user)?;
|
let user = serde_json::to_value(user)?;
|
||||||
let input = serde_json::json!({
|
let input = serde_json::json!({
|
||||||
"authorization_grant": authorization_grant,
|
"authorization_grant": authorization_grant,
|
||||||
|
"client": client,
|
||||||
"user": user,
|
"user": user,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use mas_data_model::{
|
use mas_data_model::{
|
||||||
AuthorizationGrant, BrowserSession, CompatSsoLogin, CompatSsoLoginState, UpstreamOAuthLink,
|
AuthorizationGrant, BrowserSession, Client, CompatSsoLogin, CompatSsoLoginState,
|
||||||
UpstreamOAuthProvider, User, UserEmail, UserEmailVerification,
|
UpstreamOAuthLink, UpstreamOAuthProvider, User, UserEmail, UserEmailVerification,
|
||||||
};
|
};
|
||||||
use mas_router::{PostAuthAction, Route};
|
use mas_router::{PostAuthAction, Route};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
@ -395,25 +395,42 @@ impl RegisterContext {
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct ConsentContext {
|
pub struct ConsentContext {
|
||||||
grant: AuthorizationGrant,
|
grant: AuthorizationGrant,
|
||||||
|
client: Client,
|
||||||
action: PostAuthAction,
|
action: PostAuthAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateContext for ConsentContext {
|
impl TemplateContext for ConsentContext {
|
||||||
fn sample(_now: chrono::DateTime<Utc>, _rng: &mut impl Rng) -> Vec<Self>
|
fn sample(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
// TODO
|
Client::samples(now, rng)
|
||||||
vec![]
|
.into_iter()
|
||||||
|
.map(|client| {
|
||||||
|
let mut grant = AuthorizationGrant::sample(now, rng);
|
||||||
|
let action = PostAuthAction::continue_grant(grant.id);
|
||||||
|
// XXX
|
||||||
|
grant.client_id = client.id;
|
||||||
|
Self {
|
||||||
|
grant,
|
||||||
|
client,
|
||||||
|
action,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConsentContext {
|
impl ConsentContext {
|
||||||
/// Constructs a context for the client consent page
|
/// Constructs a context for the client consent page
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(grant: AuthorizationGrant) -> Self {
|
pub fn new(grant: AuthorizationGrant, client: Client) -> Self {
|
||||||
let action = PostAuthAction::continue_grant(grant.id);
|
let action = PostAuthAction::continue_grant(grant.id);
|
||||||
Self { grant, action }
|
Self {
|
||||||
|
grant,
|
||||||
|
client,
|
||||||
|
action,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,25 +438,42 @@ impl ConsentContext {
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct PolicyViolationContext {
|
pub struct PolicyViolationContext {
|
||||||
grant: AuthorizationGrant,
|
grant: AuthorizationGrant,
|
||||||
|
client: Client,
|
||||||
action: PostAuthAction,
|
action: PostAuthAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateContext for PolicyViolationContext {
|
impl TemplateContext for PolicyViolationContext {
|
||||||
fn sample(_now: chrono::DateTime<Utc>, _rng: &mut impl Rng) -> Vec<Self>
|
fn sample(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
// TODO
|
Client::samples(now, rng)
|
||||||
vec![]
|
.into_iter()
|
||||||
|
.map(|client| {
|
||||||
|
let mut grant = AuthorizationGrant::sample(now, rng);
|
||||||
|
let action = PostAuthAction::continue_grant(grant.id);
|
||||||
|
// XXX
|
||||||
|
grant.client_id = client.id;
|
||||||
|
Self {
|
||||||
|
grant,
|
||||||
|
client,
|
||||||
|
action,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PolicyViolationContext {
|
impl PolicyViolationContext {
|
||||||
/// Constructs a context for the policy violation page
|
/// Constructs a context for the policy violation page
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(grant: AuthorizationGrant) -> Self {
|
pub const fn new(grant: AuthorizationGrant, client: Client) -> Self {
|
||||||
let action = PostAuthAction::continue_grant(grant.id);
|
let action = PostAuthAction::continue_grant(grant.id);
|
||||||
Self { grant, action }
|
Self {
|
||||||
|
grant,
|
||||||
|
client,
|
||||||
|
action,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,17 +23,17 @@ limitations under the License.
|
|||||||
<div class="rounded-lg bg-grey-25 dark:bg-grey-450 p-2 flex flex-col">
|
<div class="rounded-lg bg-grey-25 dark:bg-grey-450 p-2 flex flex-col">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="bg-white rounded w-16 h-16 overflow-hidden mx-auto">
|
<div class="bg-white rounded w-16 h-16 overflow-hidden mx-auto">
|
||||||
{% if grant.client.logo_uri %}
|
{% if client.logo_uri %}
|
||||||
<img class="w-16 h-16" src="{{ grant.client.logo_uri }}" />
|
<img class="w-16 h-16" src="{{ client.logo_uri }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-lg text-center font-medium"><a target="_blank" href="{{ grant.client.client_uri }}" class="text-accent">{{ grant.client.client_name | default(value=grant.client.client_id) }}</a></h1>
|
<h1 class="text-lg text-center font-medium"><a target="_blank" href="{{ client.client_uri }}" class="text-accent">{{ client.client_name | default(value=client.client_id) }}</a></h1>
|
||||||
<h1>at {{ grant.redirect_uri }}</h1>
|
<h1>at {{ grant.redirect_uri }}</h1>
|
||||||
<h1>wants to access your Matrix account</h1>
|
<h1>wants to access your Matrix account</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center m-2">
|
<div class="flex items-center m-2">
|
||||||
<div class="px-4 flex-1">
|
<div class="px-4 flex-1">
|
||||||
<p>This will allow <a target="_blank" href="{{ grant.client.client_uri }}" class="text-accent">{{ grant.client.client_name | default(value=grant.client.client_id) }}</a> to:</p>
|
<p>This will allow <a target="_blank" href="{{ client.client_uri }}" class="text-accent">{{ client.client_name | default(value=client.client_id) }}</a> to:</p>
|
||||||
|
|
||||||
<p class="my-2">
|
<p class="my-2">
|
||||||
<ul class="list-disc">
|
<ul class="list-disc">
|
||||||
@ -49,19 +49,19 @@ limitations under the License.
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
<p class="font-bold my-2">Make sure that you trust {{ grant.client.client_name }}</p>
|
<p class="font-bold my-2">Make sure that you trust {{ client.client_name }}</p>
|
||||||
<p>
|
<p>
|
||||||
You may be sharing sensitive information with this site or app.
|
You may be sharing sensitive information with this site or app.
|
||||||
{% if grant.client.policy_uri or grant.client.tos_uri %}
|
{% if client.policy_uri or client.tos_uri %}
|
||||||
Find out how {{ grant.client.client_name }} will handle your data by reviewing it's
|
Find out how {{ client.client_name }} will handle your data by reviewing it's
|
||||||
{% if grant.client.policy_uri %}
|
{% if client.policy_uri %}
|
||||||
<a target="_blank" href="{{ grant.client.policy_uri }}" class="text-accent">privacy policy</a>{% if not grant.client.tos_uri %}.{% endif %}
|
<a target="_blank" href="{{ client.policy_uri }}" class="text-accent">privacy policy</a>{% if not client.tos_uri %}.{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if grant.client.policy_uri and grant.client.tos_uri%}
|
{% if client.policy_uri and client.tos_uri%}
|
||||||
and
|
and
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if grant.client.tos_uri %}
|
{% if client.tos_uri %}
|
||||||
<a target="_blank" href="{{ grant.client.tos_uri }}" class="text-accent">terms of service</a>.
|
<a target="_blank" href="{{ client.tos_uri }}" class="text-accent">terms of service</a>.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
@ -24,11 +24,11 @@ limitations under the License.
|
|||||||
<p>This might be because of the client which authored the request, the currently logged in user, or the request itself.</p>
|
<p>This might be because of the client which authored the request, the currently logged in user, or the request itself.</p>
|
||||||
<div class="rounded-lg bg-grey-25 dark:bg-grey-450 p-2 flex items-center">
|
<div class="rounded-lg bg-grey-25 dark:bg-grey-450 p-2 flex items-center">
|
||||||
<div class="bg-white rounded w-16 h-16 overflow-hidden mx-auto">
|
<div class="bg-white rounded w-16 h-16 overflow-hidden mx-auto">
|
||||||
{% if grant.client.logo_uri %}
|
{% if client.logo_uri %}
|
||||||
<img class="w-16 h-16" src="{{ grant.client.logo_uri }}" />
|
<img class="w-16 h-16" src="{{ client.logo_uri }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-lg text-center font-medium flex-1"><a target="_blank" href="{{ grant.client.client_uri }}" class="text-accent">{{ grant.client.client_name | default(value=grant.client.client_id) }}</a></h1>
|
<h1 class="text-lg text-center font-medium flex-1"><a target="_blank" href="{{ client.client_uri }}" class="text-accent">{{ client.client_name | default(value=client.client_id) }}</a></h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-lg bg-grey-25 dark:bg-grey-450 p-2 flex items-center">
|
<div class="rounded-lg bg-grey-25 dark:bg-grey-450 p-2 flex items-center">
|
||||||
|
Reference in New Issue
Block a user