revoke all refresh tokens and use all authorization codes for user
This commit is contained in:
parent
5100aa1b4e
commit
009b8664fd
11 changed files with 94 additions and 8 deletions
|
|
@ -50,4 +50,11 @@ impl AuthorizationCode {
|
||||||
pub async fn use_code(self, conn: impl SqliteExecutor<'_>) -> Result<Option<()>, Error> {
|
pub async fn use_code(self, conn: impl SqliteExecutor<'_>) -> Result<Option<()>, Error> {
|
||||||
Ok(DatabaseAuthorizationCodes::use_code(conn, &self.code).await?)
|
Ok(DatabaseAuthorizationCodes::use_code(conn, &self.code).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn use_all_for_user(
|
||||||
|
&self,
|
||||||
|
conn: impl SqliteExecutor<'_>,
|
||||||
|
) -> Result<Option<()>, Error> {
|
||||||
|
Ok(DatabaseAuthorizationCodes::use_all_for_user(conn, self.user.as_ref()).await?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,4 +26,7 @@ impl AuthorizationCode {
|
||||||
pub fn has_expired(&self) -> bool {
|
pub fn has_expired(&self) -> bool {
|
||||||
self.expires_at < Utc::now()
|
self.expires_at < Utc::now()
|
||||||
}
|
}
|
||||||
|
pub fn user(&self) -> &UserID {
|
||||||
|
&self.user
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
update authorization_codes
|
||||||
|
|
||||||
|
set used_at = CURRENT_TIMESTAMP
|
||||||
|
|
||||||
|
where user is ?
|
||||||
|
and used_at is null
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
update refresh_tokens
|
||||||
|
|
||||||
|
set revoked_at = CURRENT_TIMESTAMP
|
||||||
|
|
||||||
|
where user is ?
|
||||||
|
and revoked_at is null
|
||||||
|
|
@ -474,6 +474,16 @@
|
||||||
},
|
},
|
||||||
"query": "select id,\n created_at as \"created_at: DateTime<Utc>\",\n updated_at as \"updated_at: DateTime<Utc>\",\n is_admin as \"is_admin: bool\",\n username,\n name,\n email,\n password,\n password_recover,\n paper_key,\n is_archived as \"is_archived: bool\"\nfrom users\n\nwhere username is (?)\n"
|
"query": "select id,\n created_at as \"created_at: DateTime<Utc>\",\n updated_at as \"updated_at: DateTime<Utc>\",\n is_admin as \"is_admin: bool\",\n username,\n name,\n email,\n password,\n password_recover,\n paper_key,\n is_archived as \"is_archived: bool\"\nfrom users\n\nwhere username is (?)\n"
|
||||||
},
|
},
|
||||||
|
"c00e5fce25caebdeeb24db20880e6c2210f583cddb0d478075f78124258712dd": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "update refresh_tokens\n\nset revoked_at = CURRENT_TIMESTAMP\n\nwhere user is ?\n and revoked_at is null"
|
||||||
|
},
|
||||||
"c5a57c971d07532ec0cc897b5ac06e0814e506f9c24647d1eaf44174dc0a5954": {
|
"c5a57c971d07532ec0cc897b5ac06e0814e506f9c24647d1eaf44174dc0a5954": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
|
@ -832,6 +842,16 @@
|
||||||
},
|
},
|
||||||
"query": "select id,\n created_at as \"created_at: DateTime<Utc>\",\n updated_at as \"updated_at: DateTime<Utc>\",\n label,\n redirect_uri,\n secret,\n is_confidential as \"is_confidential: bool\",\n is_archived as \"is_archived: bool\"\nfrom apps\n\nwhere id is (?)\n and redirect_uri is (?)\n and is_archived is 0\n"
|
"query": "select id,\n created_at as \"created_at: DateTime<Utc>\",\n updated_at as \"updated_at: DateTime<Utc>\",\n label,\n redirect_uri,\n secret,\n is_confidential as \"is_confidential: bool\",\n is_archived as \"is_archived: bool\"\nfrom apps\n\nwhere id is (?)\n and redirect_uri is (?)\n and is_archived is 0\n"
|
||||||
},
|
},
|
||||||
|
"ebe28f418d28303b2efe1fe192a63538d29d75c57b67d5eac1ac4ceaa1472a5c": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "update authorization_codes\n\nset used_at = CURRENT_TIMESTAMP\n\nwhere user is ?\n and used_at is null"
|
||||||
|
},
|
||||||
"ed27954feb3e21b5c519ccd0312526e68fb3d88a1feb28bdafb414e990da55e8": {
|
"ed27954feb3e21b5c519ccd0312526e68fb3d88a1feb28bdafb414e990da55e8": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,17 @@ impl AuthorizationCodes {
|
||||||
|
|
||||||
Ok((query.rows_affected() == 1).then_some(()))
|
Ok((query.rows_affected() == 1).then_some(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn use_all_for_user(
|
||||||
|
conn: impl SqliteExecutor<'_>,
|
||||||
|
user: &str,
|
||||||
|
) -> Result<Option<()>, Error> {
|
||||||
|
let query: SqliteQueryResult =
|
||||||
|
sqlx::query_file!("queries/authorization_codes/use_all_for_user.sql", user)
|
||||||
|
.execute(conn)
|
||||||
|
.await
|
||||||
|
.map_err(handle_error)?;
|
||||||
|
|
||||||
|
Ok((query.rows_affected() >= 1).then_some(()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,4 +58,17 @@ impl RefreshTokens {
|
||||||
|
|
||||||
Ok((query.rows_affected() == 1).then_some(()))
|
Ok((query.rows_affected() == 1).then_some(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn revoke_all_for_user(
|
||||||
|
conn: impl SqliteExecutor<'_>,
|
||||||
|
user: &str,
|
||||||
|
) -> Result<Option<()>, Error> {
|
||||||
|
let query: SqliteQueryResult =
|
||||||
|
sqlx::query_file!("queries/refresh_tokens/revoke_all_for_user.sql", user)
|
||||||
|
.execute(conn)
|
||||||
|
.await
|
||||||
|
.map_err(handle_error)?;
|
||||||
|
|
||||||
|
Ok((query.rows_affected() >= 1).then_some(()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,12 @@ pub async fn redirect_page(
|
||||||
|
|
||||||
// Make sure code has not been used
|
// Make sure code has not been used
|
||||||
if code.has_been_used() {
|
if code.has_been_used() {
|
||||||
// TODO: revoke all codes and refresh tokens for user
|
// Revoke all codes and refresh tokens for user
|
||||||
|
code.use_all_for_user(&mut transaction).await?;
|
||||||
|
RefreshToken::revoke_all_for_user(&mut transaction, code.user()).await?;
|
||||||
|
|
||||||
|
transaction.commit().await?;
|
||||||
|
|
||||||
return Err(Error::bad_request(
|
return Err(Error::bad_request(
|
||||||
"Authorization code has already been used",
|
"Authorization code has already been used",
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -105,11 +105,17 @@ async fn logout(
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(|| Error::not_found("Unknown refresh token"))?;
|
.ok_or_else(|| Error::not_found("Unknown refresh token"))?;
|
||||||
|
|
||||||
|
// Delete cookies
|
||||||
|
cookie_jar.remove(Cookie::named("access_token"));
|
||||||
|
cookie_jar.remove(Cookie::named("refresh_token"));
|
||||||
|
|
||||||
// If refresh token has already been used
|
// If refresh token has already been used
|
||||||
if refresh_token.has_been_used() {
|
if refresh_token.has_been_used() {
|
||||||
// TODO: Revoke all tokens for user
|
// Revoke all refresh tokens for user
|
||||||
// user.revoke_all_refresh_tokens(&mut transaction).await?;
|
refresh_tokens::RefreshToken::revoke_all_for_user(&mut transaction, refresh_token.user())
|
||||||
// transaction.commit().await?;
|
.await?;
|
||||||
|
|
||||||
|
transaction.commit().await?;
|
||||||
|
|
||||||
return Err(Error::forbidden("This refresh token has already been used"));
|
return Err(Error::forbidden("This refresh token has already been used"));
|
||||||
}
|
}
|
||||||
|
|
@ -129,9 +135,5 @@ async fn logout(
|
||||||
|
|
||||||
transaction.commit().await?;
|
transaction.commit().await?;
|
||||||
|
|
||||||
// Delete cookies
|
|
||||||
cookie_jar.remove(Cookie::named("access_token"));
|
|
||||||
cookie_jar.remove(Cookie::named("refresh_token"));
|
|
||||||
|
|
||||||
Ok(Redirect::to(uri!(homepage)))
|
Ok(Redirect::to(uri!(homepage)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,11 @@ impl RefreshToken {
|
||||||
pub async fn revoke(self, conn: impl SqliteExecutor<'_>) -> Result<Option<()>, Error> {
|
pub async fn revoke(self, conn: impl SqliteExecutor<'_>) -> Result<Option<()>, Error> {
|
||||||
Ok(DatabaseRefreshTokens::revoke(conn, &self.token).await?)
|
Ok(DatabaseRefreshTokens::revoke(conn, &self.token).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn revoke_all_for_user(
|
||||||
|
conn: impl SqliteExecutor<'_>,
|
||||||
|
user: &UserID,
|
||||||
|
) -> Result<Option<()>, Error> {
|
||||||
|
Ok(DatabaseRefreshTokens::revoke_all_for_user(conn, user.as_ref()).await?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,4 +32,8 @@ impl RefreshToken {
|
||||||
pub fn is_revoked(&self) -> bool {
|
pub fn is_revoked(&self) -> bool {
|
||||||
self.revoked_at.is_some()
|
self.revoked_at.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn user(&self) -> &UserID {
|
||||||
|
&self.user
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue