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> {
|
||||
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 {
|
||||
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"
|
||||
},
|
||||
"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": {
|
||||
"describe": {
|
||||
"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"
|
||||
},
|
||||
"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": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
|
|
|
|||
|
|
@ -54,4 +54,17 @@ impl AuthorizationCodes {
|
|||
|
||||
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(()))
|
||||
}
|
||||
|
||||
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
|
||||
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(
|
||||
"Authorization code has already been used",
|
||||
));
|
||||
|
|
|
|||
|
|
@ -105,11 +105,17 @@ async fn logout(
|
|||
.await?
|
||||
.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_been_used() {
|
||||
// TODO: Revoke all tokens for user
|
||||
// user.revoke_all_refresh_tokens(&mut transaction).await?;
|
||||
// transaction.commit().await?;
|
||||
// Revoke all refresh tokens for user
|
||||
refresh_tokens::RefreshToken::revoke_all_for_user(&mut transaction, refresh_token.user())
|
||||
.await?;
|
||||
|
||||
transaction.commit().await?;
|
||||
|
||||
return Err(Error::forbidden("This refresh token has already been used"));
|
||||
}
|
||||
|
|
@ -129,9 +135,5 @@ async fn logout(
|
|||
|
||||
transaction.commit().await?;
|
||||
|
||||
// Delete cookies
|
||||
cookie_jar.remove(Cookie::named("access_token"));
|
||||
cookie_jar.remove(Cookie::named("refresh_token"));
|
||||
|
||||
Ok(Redirect::to(uri!(homepage)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,4 +54,11 @@ impl RefreshToken {
|
|||
pub async fn revoke(self, conn: impl SqliteExecutor<'_>) -> Result<Option<()>, Error> {
|
||||
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 {
|
||||
self.revoked_at.is_some()
|
||||
}
|
||||
|
||||
pub fn user(&self) -> &UserID {
|
||||
&self.user
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue