You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Pass time and RNG in CSRF verification methods
This commit is contained in:
@ -15,7 +15,7 @@
|
|||||||
use axum_extra::extract::cookie::{Cookie, PrivateCookieJar};
|
use axum_extra::extract::cookie::{Cookie, PrivateCookieJar};
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::{DateTime, Duration, Utc};
|
||||||
use data_encoding::{DecodeError, BASE64URL_NOPAD};
|
use data_encoding::{DecodeError, BASE64URL_NOPAD};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{Rng, RngCore};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::{serde_as, TimestampSeconds};
|
use serde_with::{serde_as, TimestampSeconds};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -108,23 +108,22 @@ pub struct ProtectedForm<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait CsrfExt {
|
pub trait CsrfExt {
|
||||||
fn csrf_token(self) -> (CsrfToken, Self);
|
fn csrf_token<R>(self, now: DateTime<Utc>, rng: R) -> (CsrfToken, Self)
|
||||||
fn verify_form<T>(&self, form: ProtectedForm<T>) -> Result<T, CsrfError>;
|
where
|
||||||
|
R: RngCore;
|
||||||
|
fn verify_form<T>(&self, now: DateTime<Utc>, form: ProtectedForm<T>) -> Result<T, CsrfError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> CsrfExt for PrivateCookieJar<K> {
|
impl<K> CsrfExt for PrivateCookieJar<K> {
|
||||||
fn csrf_token(self) -> (CsrfToken, Self) {
|
fn csrf_token<R>(self, now: DateTime<Utc>, rng: R) -> (CsrfToken, Self)
|
||||||
|
where
|
||||||
|
R: RngCore,
|
||||||
|
{
|
||||||
let jar = self;
|
let jar = self;
|
||||||
let mut cookie = jar.get("csrf").unwrap_or_else(|| Cookie::new("csrf", ""));
|
let mut cookie = jar.get("csrf").unwrap_or_else(|| Cookie::new("csrf", ""));
|
||||||
cookie.set_path("/");
|
cookie.set_path("/");
|
||||||
cookie.set_http_only(true);
|
cookie.set_http_only(true);
|
||||||
|
|
||||||
// XXX: the rng source and clock should come from somewhere else
|
|
||||||
#[allow(clippy::disallowed_methods)]
|
|
||||||
let now = Utc::now();
|
|
||||||
#[allow(clippy::disallowed_methods)]
|
|
||||||
let rng = thread_rng();
|
|
||||||
|
|
||||||
let new_token = cookie
|
let new_token = cookie
|
||||||
.decode()
|
.decode()
|
||||||
.ok()
|
.ok()
|
||||||
@ -137,11 +136,7 @@ impl<K> CsrfExt for PrivateCookieJar<K> {
|
|||||||
(new_token, jar)
|
(new_token, jar)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_form<T>(&self, form: ProtectedForm<T>) -> Result<T, CsrfError> {
|
fn verify_form<T>(&self, now: DateTime<Utc>, form: ProtectedForm<T>) -> Result<T, CsrfError> {
|
||||||
// XXX: the clock should come from somewhere else
|
|
||||||
#[allow(clippy::disallowed_methods)]
|
|
||||||
let now = Utc::now();
|
|
||||||
|
|
||||||
let cookie = self.get("csrf").ok_or(CsrfError::Missing)?;
|
let cookie = self.get("csrf").ok_or(CsrfError::Missing)?;
|
||||||
let token: CsrfToken = cookie.decode()?;
|
let token: CsrfToken = cookie.decode()?;
|
||||||
let token = token.verify_expiration(now)?;
|
let token = token.verify_expiration(now)?;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use mas_config::{ConfigurationSection, RootConfig};
|
use mas_config::{ConfigurationSection, RootConfig};
|
||||||
|
use rand::SeedableRng;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@ -51,7 +52,9 @@ impl Options {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
SC::Generate => {
|
SC::Generate => {
|
||||||
let config = RootConfig::load_and_generate().await?;
|
// XXX: we should disallow SeedableRng::from_entropy
|
||||||
|
let rng = rand_chacha::ChaChaRng::from_entropy();
|
||||||
|
let config = RootConfig::load_and_generate(rng).await?;
|
||||||
|
|
||||||
serde_yaml::to_writer(std::io::stdout(), &config)?;
|
serde_yaml::to_writer(std::io::stdout(), &config)?;
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ use std::ops::{Deref, DerefMut};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use mas_iana::oauth::OAuthClientAuthenticationMethod;
|
use mas_iana::oauth::OAuthClientAuthenticationMethod;
|
||||||
use mas_jose::jwk::PublicJsonWebKeySet;
|
use mas_jose::jwk::PublicJsonWebKeySet;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
@ -171,8 +172,10 @@ impl ConfigurationSection<'_> for ClientsConfig {
|
|||||||
"clients"
|
"clients"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::serde_as;
|
use serde_with::serde_as;
|
||||||
@ -47,7 +48,10 @@ impl ConfigurationSection<'_> for CsrfConfig {
|
|||||||
"csrf"
|
"csrf"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ use std::{num::NonZeroU32, path::PathBuf, time::Duration};
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::{serde_as, skip_serializing_none};
|
use serde_with::{serde_as, skip_serializing_none};
|
||||||
@ -224,7 +225,10 @@ impl ConfigurationSection<'_> for DatabaseConfig {
|
|||||||
"database"
|
"database"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ use anyhow::Context;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use lettre::{message::Mailbox, Address};
|
use lettre::{message::Mailbox, Address};
|
||||||
use mas_email::MailTransport;
|
use mas_email::MailTransport;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::{
|
use schemars::{
|
||||||
gen::SchemaGenerator,
|
gen::SchemaGenerator,
|
||||||
schema::{InstanceType, Schema, SchemaObject},
|
schema::{InstanceType, Schema, SchemaObject},
|
||||||
@ -160,7 +161,10 @@ impl ConfigurationSection<'_> for EmailConfig {
|
|||||||
"email"
|
"email"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ use std::{borrow::Cow, io::Cursor, ops::Deref, path::PathBuf};
|
|||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use mas_keystore::PrivateKey;
|
use mas_keystore::PrivateKey;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
@ -328,7 +329,10 @@ impl ConfigurationSection<'_> for HttpConfig {
|
|||||||
"http"
|
"http"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::serde_as;
|
use serde_with::serde_as;
|
||||||
@ -46,7 +47,10 @@ impl ConfigurationSection<'_> for MatrixConfig {
|
|||||||
"matrix"
|
"matrix"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -96,18 +97,21 @@ impl ConfigurationSection<'_> for RootConfig {
|
|||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(mut rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
clients: ClientsConfig::generate().await?,
|
clients: ClientsConfig::generate(&mut rng).await?,
|
||||||
http: HttpConfig::generate().await?,
|
http: HttpConfig::generate(&mut rng).await?,
|
||||||
database: DatabaseConfig::generate().await?,
|
database: DatabaseConfig::generate(&mut rng).await?,
|
||||||
telemetry: TelemetryConfig::generate().await?,
|
telemetry: TelemetryConfig::generate(&mut rng).await?,
|
||||||
templates: TemplatesConfig::generate().await?,
|
templates: TemplatesConfig::generate(&mut rng).await?,
|
||||||
csrf: CsrfConfig::generate().await?,
|
csrf: CsrfConfig::generate(&mut rng).await?,
|
||||||
email: EmailConfig::generate().await?,
|
email: EmailConfig::generate(&mut rng).await?,
|
||||||
secrets: SecretsConfig::generate().await?,
|
secrets: SecretsConfig::generate(&mut rng).await?,
|
||||||
matrix: MatrixConfig::generate().await?,
|
matrix: MatrixConfig::generate(&mut rng).await?,
|
||||||
policy: PolicyConfig::generate().await?,
|
policy: PolicyConfig::generate(&mut rng).await?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::serde_as;
|
use serde_with::serde_as;
|
||||||
@ -76,7 +77,10 @@ impl ConfigurationSection<'_> for PolicyConfig {
|
|||||||
"policy"
|
"policy"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ use mas_jose::jwk::{JsonWebKey, JsonWebKeySet};
|
|||||||
use mas_keystore::{Encrypter, Keystore, PrivateKey};
|
use mas_keystore::{Encrypter, Keystore, PrivateKey};
|
||||||
use rand::{
|
use rand::{
|
||||||
distributions::{Alphanumeric, DistString},
|
distributions::{Alphanumeric, DistString},
|
||||||
thread_rng, SeedableRng,
|
Rng, SeedableRng,
|
||||||
};
|
};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -137,12 +137,11 @@ impl ConfigurationSection<'_> for SecretsConfig {
|
|||||||
"secrets"
|
"secrets"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(mut rng: R) -> anyhow::Result<Self>
|
||||||
// XXX: that RNG should come from somewhere else
|
where
|
||||||
#[allow(clippy::disallowed_methods)]
|
R: Rng + Send,
|
||||||
let mut rng = rand_chacha::ChaChaRng::from_rng(thread_rng())?;
|
{
|
||||||
|
|
||||||
info!("Generating keys...");
|
info!("Generating keys...");
|
||||||
|
|
||||||
let span = tracing::info_span!("rsa");
|
let span = tracing::info_span!("rsa");
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
use std::num::NonZeroU16;
|
use std::num::NonZeroU16;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
@ -274,7 +275,10 @@ impl ConfigurationSection<'_> for TelemetryConfig {
|
|||||||
"telemetry"
|
"telemetry"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -49,7 +50,10 @@ impl ConfigurationSection<'_> for TemplatesConfig {
|
|||||||
"templates"
|
"templates"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn generate() -> anyhow::Result<Self> {
|
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ use figment::{
|
|||||||
providers::{Env, Format, Serialized, Yaml},
|
providers::{Env, Format, Serialized, Yaml},
|
||||||
Figment, Profile,
|
Figment, Profile,
|
||||||
};
|
};
|
||||||
|
use rand::Rng;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -31,7 +32,9 @@ pub trait ConfigurationSection<'a>: Sized + Deserialize<'a> + Serialize {
|
|||||||
fn path() -> &'static str;
|
fn path() -> &'static str;
|
||||||
|
|
||||||
/// Generate a sample configuration for this section.
|
/// Generate a sample configuration for this section.
|
||||||
async fn generate() -> anyhow::Result<Self>;
|
async fn generate<R>(rng: R) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
R: Rng + Send;
|
||||||
|
|
||||||
/// Generate a sample configuration and override it with environment
|
/// Generate a sample configuration and override it with environment
|
||||||
/// variables.
|
/// variables.
|
||||||
@ -44,8 +47,11 @@ pub trait ConfigurationSection<'a>: Sized + Deserialize<'a> + Serialize {
|
|||||||
/// export MAS_HTTP_ADDRESS=127.0.0.1:1234
|
/// export MAS_HTTP_ADDRESS=127.0.0.1:1234
|
||||||
/// matrix-authentication-service config generate
|
/// matrix-authentication-service config generate
|
||||||
/// ```
|
/// ```
|
||||||
async fn load_and_generate() -> anyhow::Result<Self> {
|
async fn load_and_generate<R>(rng: R) -> anyhow::Result<Self>
|
||||||
let base = Self::generate()
|
where
|
||||||
|
R: Rng + Send,
|
||||||
|
{
|
||||||
|
let base = Self::generate(rng)
|
||||||
.await
|
.await
|
||||||
.context("could not generate configuration")?;
|
.context("could not generate configuration")?;
|
||||||
|
|
||||||
|
@ -28,10 +28,7 @@ use mas_axum_utils::{
|
|||||||
use mas_data_model::Device;
|
use mas_data_model::Device;
|
||||||
use mas_keystore::Encrypter;
|
use mas_keystore::Encrypter;
|
||||||
use mas_router::{CompatLoginSsoAction, PostAuthAction, Route};
|
use mas_router::{CompatLoginSsoAction, PostAuthAction, Route};
|
||||||
use mas_storage::{
|
use mas_storage::compat::{fullfill_compat_sso_login, get_compat_sso_login_by_id};
|
||||||
compat::{fullfill_compat_sso_login, get_compat_sso_login_by_id},
|
|
||||||
Clock,
|
|
||||||
};
|
|
||||||
use mas_templates::{CompatSsoContext, ErrorContext, TemplateContext, Templates};
|
use mas_templates::{CompatSsoContext, ErrorContext, TemplateContext, Templates};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
@ -58,11 +55,11 @@ pub async fn get(
|
|||||||
Path(id): Path<Ulid>,
|
Path(id): Path<Ulid>,
|
||||||
Query(params): Query<Params>,
|
Query(params): Query<Params>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
let clock = Clock::default();
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
|
|
||||||
@ -128,7 +125,7 @@ pub async fn post(
|
|||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
|
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
cookie_jar.verify_form(form)?;
|
cookie_jar.verify_form(clock.now(), form)?;
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut txn).await?;
|
let maybe_session = session_info.load_session(&mut txn).await?;
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ pub(crate) async fn get(
|
|||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
Path(grant_id): Path<Ulid>,
|
Path(grant_id): Path<Ulid>,
|
||||||
) -> Result<Response, RouteError> {
|
) -> Result<Response, RouteError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool
|
let mut conn = pool
|
||||||
.acquire()
|
.acquire()
|
||||||
.await
|
.await
|
||||||
@ -76,7 +77,7 @@ pub(crate) async fn get(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(session) = maybe_session {
|
if let Some(session) = maybe_session {
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
|
|
||||||
let mut policy = policy_factory.instantiate().await?;
|
let mut policy = policy_factory.instantiate().await?;
|
||||||
let res = policy
|
let res = policy
|
||||||
@ -126,7 +127,7 @@ pub(crate) async fn post(
|
|||||||
.context("failed to begin db transaction")?;
|
.context("failed to begin db transaction")?;
|
||||||
|
|
||||||
cookie_jar
|
cookie_jar
|
||||||
.verify_form(form)
|
.verify_form(clock.now(), form)
|
||||||
.context("csrf verification failed")?;
|
.context("csrf verification failed")?;
|
||||||
|
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
@ -42,9 +42,10 @@ pub(crate) async fn get(
|
|||||||
State(pool): State<PgPool>,
|
State(pool): State<PgPool>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.begin().await?;
|
let mut conn = pool.begin().await?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
@ -75,7 +76,7 @@ pub(crate) async fn post(
|
|||||||
let (clock, mut rng) = crate::rng_and_clock()?;
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
|
|
||||||
let form = cookie_jar.verify_form(form)?;
|
let form = cookie_jar.verify_form(clock.now(), form)?;
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut txn).await?;
|
let maybe_session = session_info.load_session(&mut txn).await?;
|
||||||
|
@ -57,6 +57,8 @@ pub(crate) async fn get(
|
|||||||
State(pool): State<PgPool>,
|
State(pool): State<PgPool>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
|
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
@ -64,7 +66,7 @@ pub(crate) async fn get(
|
|||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
|
|
||||||
if let Some(session) = maybe_session {
|
if let Some(session) = maybe_session {
|
||||||
render(templates, session, cookie_jar, &mut conn).await
|
render(&mut rng, &clock, templates, session, cookie_jar, &mut conn).await
|
||||||
} else {
|
} else {
|
||||||
let login = mas_router::Login::default();
|
let login = mas_router::Login::default();
|
||||||
Ok((cookie_jar, login.go()).into_response())
|
Ok((cookie_jar, login.go()).into_response())
|
||||||
@ -72,12 +74,14 @@ pub(crate) async fn get(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn render(
|
async fn render(
|
||||||
|
rng: impl Rng,
|
||||||
|
clock: &Clock,
|
||||||
templates: Templates,
|
templates: Templates,
|
||||||
session: BrowserSession<PostgresqlBackend>,
|
session: BrowserSession<PostgresqlBackend>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
executor: impl PgExecutor<'_>,
|
executor: impl PgExecutor<'_>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), rng);
|
||||||
|
|
||||||
let emails = get_user_emails(executor, &session.user).await?;
|
let emails = get_user_emails(executor, &session.user).await?;
|
||||||
|
|
||||||
@ -149,7 +153,7 @@ pub(crate) async fn post(
|
|||||||
return Ok((cookie_jar, login.go()).into_response());
|
return Ok((cookie_jar, login.go()).into_response());
|
||||||
};
|
};
|
||||||
|
|
||||||
let form = cookie_jar.verify_form(form)?;
|
let form = cookie_jar.verify_form(clock.now(), form)?;
|
||||||
|
|
||||||
match form {
|
match form {
|
||||||
ManagementForm::Add { email } => {
|
ManagementForm::Add { email } => {
|
||||||
@ -199,7 +203,15 @@ pub(crate) async fn post(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let reply = render(templates.clone(), session, cookie_jar, &mut txn).await?;
|
let reply = render(
|
||||||
|
&mut rng,
|
||||||
|
&clock,
|
||||||
|
templates.clone(),
|
||||||
|
session,
|
||||||
|
cookie_jar,
|
||||||
|
&mut txn,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
|
|
||||||
|
@ -49,9 +49,10 @@ pub(crate) async fn get(
|
|||||||
Path(id): Path<Ulid>,
|
Path(id): Path<Ulid>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
@ -90,7 +91,7 @@ pub(crate) async fn post(
|
|||||||
let clock = Clock::default();
|
let clock = Clock::default();
|
||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
|
|
||||||
let form = cookie_jar.verify_form(form)?;
|
let form = cookie_jar.verify_form(clock.now(), form)?;
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut txn).await?;
|
let maybe_session = session_info.load_session(&mut txn).await?;
|
||||||
|
@ -32,9 +32,10 @@ pub(crate) async fn get(
|
|||||||
State(pool): State<PgPool>,
|
State(pool): State<PgPool>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
|
@ -27,9 +27,10 @@ use mas_keystore::Encrypter;
|
|||||||
use mas_router::Route;
|
use mas_router::Route;
|
||||||
use mas_storage::{
|
use mas_storage::{
|
||||||
user::{authenticate_session, set_password},
|
user::{authenticate_session, set_password},
|
||||||
PostgresqlBackend,
|
Clock, PostgresqlBackend,
|
||||||
};
|
};
|
||||||
use mas_templates::{EmptyContext, TemplateContext, Templates};
|
use mas_templates::{EmptyContext, TemplateContext, Templates};
|
||||||
|
use rand::Rng;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ pub(crate) async fn get(
|
|||||||
State(pool): State<PgPool>,
|
State(pool): State<PgPool>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
@ -52,7 +54,7 @@ pub(crate) async fn get(
|
|||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
|
|
||||||
if let Some(session) = maybe_session {
|
if let Some(session) = maybe_session {
|
||||||
render(templates, session, cookie_jar).await
|
render(&mut rng, &clock, templates, session, cookie_jar).await
|
||||||
} else {
|
} else {
|
||||||
let login = mas_router::Login::and_then(mas_router::PostAuthAction::ChangePassword);
|
let login = mas_router::Login::and_then(mas_router::PostAuthAction::ChangePassword);
|
||||||
Ok((cookie_jar, login.go()).into_response())
|
Ok((cookie_jar, login.go()).into_response())
|
||||||
@ -60,11 +62,13 @@ pub(crate) async fn get(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn render(
|
async fn render(
|
||||||
|
rng: impl Rng,
|
||||||
|
clock: &Clock,
|
||||||
templates: Templates,
|
templates: Templates,
|
||||||
session: BrowserSession<PostgresqlBackend>,
|
session: BrowserSession<PostgresqlBackend>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), rng);
|
||||||
|
|
||||||
let ctx = EmptyContext
|
let ctx = EmptyContext
|
||||||
.with_session(session)
|
.with_session(session)
|
||||||
@ -84,7 +88,7 @@ pub(crate) async fn post(
|
|||||||
let (clock, mut rng) = crate::rng_and_clock()?;
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
|
|
||||||
let form = cookie_jar.verify_form(form)?;
|
let form = cookie_jar.verify_form(clock.now(), form)?;
|
||||||
|
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
@ -122,7 +126,7 @@ pub(crate) async fn post(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let reply = render(templates.clone(), session, cookie_jar).await?;
|
let reply = render(&mut rng, &clock, templates.clone(), session, cookie_jar).await?;
|
||||||
|
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
|
|
||||||
|
@ -29,9 +29,10 @@ pub async fn get(
|
|||||||
State(pool): State<PgPool>,
|
State(pool): State<PgPool>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<impl IntoResponse, FancyError> {
|
) -> Result<impl IntoResponse, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
let session = session_info.load_session(&mut conn).await?;
|
let session = session_info.load_session(&mut conn).await?;
|
||||||
|
|
||||||
|
@ -42,16 +42,16 @@ impl ToFormState for LoginForm {
|
|||||||
type Field = LoginFormField;
|
type Field = LoginFormField;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(templates, pool, cookie_jar))]
|
|
||||||
pub(crate) async fn get(
|
pub(crate) async fn get(
|
||||||
State(templates): State<Templates>,
|
State(templates): State<Templates>,
|
||||||
State(pool): State<PgPool>,
|
State(pool): State<PgPool>,
|
||||||
Query(query): Query<OptionalPostAuthAction>,
|
Query(query): Query<OptionalPostAuthAction>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
@ -83,9 +83,9 @@ pub(crate) async fn post(
|
|||||||
let (clock, mut rng) = crate::rng_and_clock()?;
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let form = cookie_jar.verify_form(form)?;
|
let form = cookie_jar.verify_form(clock.now(), form)?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
|
|
||||||
// Validate the form
|
// Validate the form
|
||||||
let state = {
|
let state = {
|
||||||
|
@ -34,7 +34,7 @@ pub(crate) async fn post(
|
|||||||
let clock = Clock::default();
|
let clock = Clock::default();
|
||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
|
|
||||||
let form = cookie_jar.verify_form(form)?;
|
let form = cookie_jar.verify_form(clock.now(), form)?;
|
||||||
|
|
||||||
let (session_info, mut cookie_jar) = cookie_jar.session_info();
|
let (session_info, mut cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
|
@ -41,9 +41,10 @@ pub(crate) async fn get(
|
|||||||
Query(query): Query<OptionalPostAuthAction>,
|
Query(query): Query<OptionalPostAuthAction>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
@ -83,7 +84,7 @@ pub(crate) async fn post(
|
|||||||
let (clock, mut rng) = crate::rng_and_clock()?;
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
|
|
||||||
let form = cookie_jar.verify_form(form)?;
|
let form = cookie_jar.verify_form(clock.now(), form)?;
|
||||||
|
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
|
@ -63,9 +63,10 @@ pub(crate) async fn get(
|
|||||||
Query(query): Query<OptionalPostAuthAction>,
|
Query(query): Query<OptionalPostAuthAction>,
|
||||||
cookie_jar: PrivateCookieJar<Encrypter>,
|
cookie_jar: PrivateCookieJar<Encrypter>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut conn = pool.acquire().await?;
|
let mut conn = pool.acquire().await?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||||
|
|
||||||
let maybe_session = session_info.load_session(&mut conn).await?;
|
let maybe_session = session_info.load_session(&mut conn).await?;
|
||||||
@ -100,9 +101,9 @@ pub(crate) async fn post(
|
|||||||
let (clock, mut rng) = crate::rng_and_clock()?;
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
|
|
||||||
let form = cookie_jar.verify_form(form)?;
|
let form = cookie_jar.verify_form(clock.now(), form)?;
|
||||||
|
|
||||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
|
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
|
||||||
|
|
||||||
// Validate the form
|
// Validate the form
|
||||||
let state = {
|
let state = {
|
||||||
|
Reference in New Issue
Block a user