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
Disallow Ulid generation without explicit timestamp and rng
This commit is contained in:
@ -4,6 +4,8 @@ doc-valid-idents = ["OpenID", "OAuth", ".."]
|
|||||||
disallowed-methods = [
|
disallowed-methods = [
|
||||||
{ path = "rand::thread_rng", reason = "do not create rngs on the fly, pass them as parameters" },
|
{ path = "rand::thread_rng", reason = "do not create rngs on the fly, pass them as parameters" },
|
||||||
{ path = "chrono::Utc::now", reason = "source the current time from the clock instead" },
|
{ path = "chrono::Utc::now", reason = "source the current time from the clock instead" },
|
||||||
|
{ path = "ulid::Ulid::from_datetime", reason = "use Ulid::from_datetime_with_source instead" },
|
||||||
|
{ path = "ulid::Ulid::new", reason = "use Ulid::from_datetime_with_source instead" },
|
||||||
]
|
]
|
||||||
|
|
||||||
disallowed-types = [
|
disallowed-types = [
|
||||||
|
@ -54,6 +54,8 @@ impl Options {
|
|||||||
pub async fn run(&self, root: &super::Options) -> anyhow::Result<()> {
|
pub async fn run(&self, root: &super::Options) -> anyhow::Result<()> {
|
||||||
use Subcommand as SC;
|
use Subcommand as SC;
|
||||||
let clock = Clock::default();
|
let clock = Clock::default();
|
||||||
|
// XXX: we should disallow SeedableRng::from_entropy
|
||||||
|
let mut rng = rand_chacha::ChaChaRng::from_entropy();
|
||||||
|
|
||||||
match &self.subcommand {
|
match &self.subcommand {
|
||||||
SC::Register { username, password } => {
|
SC::Register { username, password } => {
|
||||||
@ -61,9 +63,9 @@ impl Options {
|
|||||||
let pool = config.connect().await?;
|
let pool = config.connect().await?;
|
||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
let hasher = Argon2::default();
|
let hasher = Argon2::default();
|
||||||
let rng = rand_chacha::ChaChaRng::from_entropy();
|
|
||||||
|
|
||||||
let user = register_user(&mut txn, rng, &clock, hasher, username, password).await?;
|
let user =
|
||||||
|
register_user(&mut txn, &mut rng, &clock, hasher, username, password).await?;
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
info!(?user, "User registered");
|
info!(?user, "User registered");
|
||||||
|
|
||||||
@ -126,6 +128,8 @@ impl Options {
|
|||||||
|
|
||||||
insert_client_from_config(
|
insert_client_from_config(
|
||||||
&mut txn,
|
&mut txn,
|
||||||
|
&mut rng,
|
||||||
|
&clock,
|
||||||
client_id,
|
client_id,
|
||||||
client_auth_method,
|
client_auth_method,
|
||||||
encrypted_client_secret.as_deref(),
|
encrypted_client_secret.as_deref(),
|
||||||
|
@ -109,6 +109,7 @@ pub(crate) async fn post(
|
|||||||
State(policy_factory): State<Arc<PolicyFactory>>,
|
State(policy_factory): State<Arc<PolicyFactory>>,
|
||||||
Json(body): Json<ClientMetadata>,
|
Json(body): Json<ClientMetadata>,
|
||||||
) -> Result<impl IntoResponse, RouteError> {
|
) -> Result<impl IntoResponse, RouteError> {
|
||||||
|
let (clock, mut rng) = crate::rng_and_clock()?;
|
||||||
info!(?body, "Client registration");
|
info!(?body, "Client registration");
|
||||||
|
|
||||||
// Validate the body
|
// Validate the body
|
||||||
@ -127,10 +128,12 @@ pub(crate) async fn post(
|
|||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
|
|
||||||
// Let's generate a random client ID
|
// Let's generate a random client ID
|
||||||
let client_id = Ulid::new();
|
let client_id = Ulid::from_datetime_with_source(clock.now().into(), &mut rng);
|
||||||
|
|
||||||
insert_client(
|
insert_client(
|
||||||
&mut txn,
|
&mut txn,
|
||||||
|
&mut rng,
|
||||||
|
&clock,
|
||||||
client_id,
|
client_id,
|
||||||
metadata.redirect_uris(),
|
metadata.redirect_uris(),
|
||||||
None,
|
None,
|
||||||
|
@ -21,13 +21,14 @@ use mas_iana::{
|
|||||||
};
|
};
|
||||||
use mas_jose::jwk::PublicJsonWebKeySet;
|
use mas_jose::jwk::PublicJsonWebKeySet;
|
||||||
use oauth2_types::requests::GrantType;
|
use oauth2_types::requests::GrantType;
|
||||||
|
use rand::Rng;
|
||||||
use sqlx::{PgConnection, PgExecutor};
|
use sqlx::{PgConnection, PgExecutor};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::PostgresqlBackend;
|
use crate::{Clock, PostgresqlBackend};
|
||||||
|
|
||||||
// XXX: response_types & contacts
|
// XXX: response_types & contacts
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -317,6 +318,8 @@ pub async fn lookup_client_by_client_id(
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn insert_client(
|
pub async fn insert_client(
|
||||||
conn: &mut PgConnection,
|
conn: &mut PgConnection,
|
||||||
|
mut rng: impl Rng + Send,
|
||||||
|
clock: &Clock,
|
||||||
client_id: Ulid,
|
client_id: Ulid,
|
||||||
redirect_uris: &[Url],
|
redirect_uris: &[Url],
|
||||||
encrypted_client_secret: Option<&str>,
|
encrypted_client_secret: Option<&str>,
|
||||||
@ -391,9 +394,15 @@ pub async fn insert_client(
|
|||||||
.execute(&mut *conn)
|
.execute(&mut *conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let now = clock.now();
|
||||||
let (ids, redirect_uris): (Vec<Uuid>, Vec<String>) = redirect_uris
|
let (ids, redirect_uris): (Vec<Uuid>, Vec<String>) = redirect_uris
|
||||||
.iter()
|
.iter()
|
||||||
.map(|uri| (Uuid::from(Ulid::new()), uri.as_str().to_owned()))
|
.map(|uri| {
|
||||||
|
(
|
||||||
|
Uuid::from(Ulid::from_datetime_with_source(now.into(), &mut rng)),
|
||||||
|
uri.as_str().to_owned(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.unzip();
|
.unzip();
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
@ -413,8 +422,11 @@ pub async fn insert_client(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn insert_client_from_config(
|
pub async fn insert_client_from_config(
|
||||||
conn: &mut PgConnection,
|
conn: &mut PgConnection,
|
||||||
|
mut rng: impl Rng + Send,
|
||||||
|
clock: &Clock,
|
||||||
client_id: Ulid,
|
client_id: Ulid,
|
||||||
client_auth_method: OAuthClientAuthenticationMethod,
|
client_auth_method: OAuthClientAuthenticationMethod,
|
||||||
encrypted_client_secret: Option<&str>,
|
encrypted_client_secret: Option<&str>,
|
||||||
@ -451,9 +463,15 @@ pub async fn insert_client_from_config(
|
|||||||
.execute(&mut *conn)
|
.execute(&mut *conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let now = clock.now();
|
||||||
let (ids, redirect_uris): (Vec<Uuid>, Vec<String>) = redirect_uris
|
let (ids, redirect_uris): (Vec<Uuid>, Vec<String>) = redirect_uris
|
||||||
.iter()
|
.iter()
|
||||||
.map(|uri| (Uuid::from(Ulid::new()), uri.as_str().to_owned()))
|
.map(|uri| {
|
||||||
|
(
|
||||||
|
Uuid::from(Ulid::from_datetime_with_source(now.into(), &mut rng)),
|
||||||
|
uri.as_str().to_owned(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.unzip();
|
.unzip();
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
|
@ -442,7 +442,7 @@ pub async fn set_password(
|
|||||||
password: &str,
|
password: &str,
|
||||||
) -> Result<(), anyhow::Error> {
|
) -> Result<(), anyhow::Error> {
|
||||||
let created_at = clock.now();
|
let created_at = clock.now();
|
||||||
let id = Ulid::from_datetime(created_at.into());
|
let id = Ulid::from_datetime_with_source(created_at.into(), &mut rng);
|
||||||
tracing::Span::current().record("user_password.id", tracing::field::display(id));
|
tracing::Span::current().record("user_password.id", tracing::field::display(id));
|
||||||
|
|
||||||
let salt = SaltString::generate(&mut rng);
|
let salt = SaltString::generate(&mut rng);
|
||||||
|
Reference in New Issue
Block a user