Compare commits

...
Sign in to create a new pull request.

1 commit
i18n ... master

2 changed files with 51 additions and 24 deletions

View file

@ -38,7 +38,7 @@ pub struct TokenRequest<'r> {
pub grant_type: GrantType,
pub code: Option<&'r str>,
pub redirect_uri: Option<&'r str>,
pub client_id: &'r str,
pub client_id: Option<&'r str>,
pub client_secret: Option<&'r str>,
pub scope: Option<&'r str>,
pub refresh_token: Option<&'r str>,

View file

@ -51,12 +51,14 @@ pub enum TokenError {
RefreshTokenExpired,
AuthorizationCodeUsed,
AuthorizationCodeExpired,
HttpAuthDifferentClientId,
AppError(apps::Error),
AppNotFound(String),
AppNotFoundFromAuthorizationCode(String),
AppNotFoundFromRefreshToken(String),
AppIdNotProvided,
AppSecretNotProvided,
Blocking(task::JoinError),
SecretCompare(hash::Error),
AppIdWrong,
AppSecretWrong,
UserError(users::Error),
UserNotFound,
@ -111,14 +113,19 @@ impl<'r> Responder<'r, 'static> for TokenError {
Status::BadRequest,
"Authorization code has expired".to_string(),
),
TokenError::HttpAuthDifferentClientId => (
Status::BadRequest,
"HTTP Auth differs from provided client_id".to_string(),
),
TokenError::AppError(e) => (Status::InternalServerError, e.to_string()),
TokenError::AppNotFound(e) => {
(Status::NotFound, format!("Could not find application {e}"))
}
TokenError::AppNotFoundFromAuthorizationCode(e) => (
Status::NotFound,
format!("Could not find application from authorization code {e}"),
),
TokenError::AppNotFoundFromRefreshToken(e) => (
Status::NotFound,
format!("Could not find application from refresh token {e}"),
),
TokenError::AppIdNotProvided => (
Status::BadRequest,
"Could not get client_id: not provided in any way".to_string(),
),
TokenError::AppSecretNotProvided => {
(Status::BadRequest, "Secret was not provided".to_string())
}
@ -127,6 +134,7 @@ impl<'r> Responder<'r, 'static> for TokenError {
Status::InternalServerError,
format!("Failed to check app secret: {e}"),
),
TokenError::AppIdWrong => (Status::Forbidden, "Invalid client_id provided".to_string()),
TokenError::AppSecretWrong => {
(Status::Forbidden, "Invalid secret provided".to_string())
}
@ -171,8 +179,8 @@ pub async fn request_token(
) -> std::result::Result<TokenResponse, TokenError> {
let mut transaction = db.begin().await.map_err(TokenError::TransactionStart)?;
// Get user depending on grant type
let user = match token_request.grant_type {
// Get user and app depending on grant type
let (user, app) = match token_request.grant_type {
GrantType::AuthorizationCode => {
let authorization_code = token_request
.code
@ -220,12 +228,20 @@ pub async fn request_token(
return Err(TokenError::UserArchived(user.id().to_string()));
}
// Get app from code
let app = App::get_one_from_authorization_code(&mut transaction, authorization_code)
.await
.map_err(TokenError::AppError)?
.ok_or(TokenError::AppNotFoundFromAuthorizationCode(
authorization_code.into(),
))?;
// Mark code as used
code.use_code(&mut transaction)
.await
.map_err(TokenError::AuthorizationError)?;
user
(user, app)
}
GrantType::RefreshToken => {
let refresh_token = token_request
@ -264,27 +280,38 @@ pub async fn request_token(
return Err(TokenError::RefreshTokenExpired);
}
// Get app
let app = App::get_one_by_id(&mut transaction, refresh_token.app().as_ref())
.await
.map_err(TokenError::AppError)?
.ok_or(TokenError::AppNotFoundFromRefreshToken(format!(
"Refresh token for user {}",
refresh_token.user()
)))?;
refresh_token
.use_token(&mut transaction)
.await
.map_err(TokenError::RefreshTokenError)?;
user
(user, app)
}
};
// If HTTP Basic Auth is provided, verify provided client id in form
if let Some(app_auth) = &app_auth {
if app_auth.id != token_request.client_id {
return Err(TokenError::HttpAuthDifferentClientId);
}
// Get client id
// https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3
let provided_client_id = match (&app_auth, token_request.client_id) {
(Some(http_auth), _) => http_auth.id.to_string(),
(None, Some(form)) => form.into(),
(None, None) => {
return Err(TokenError::AppIdNotProvided);
}
};
// Get app
let app = App::get_one_by_id(&mut transaction, token_request.client_id)
.await
.map_err(TokenError::AppError)?
.ok_or(TokenError::AppNotFound(token_request.client_id.into()))?;
// Verify client id
if app.id().as_ref() != provided_client_id {
return Err(TokenError::AppIdWrong);
}
if app.is_confidential() {
let provided_secret = match (app_auth, token_request.client_secret) {