oauth: token route: client_id is not required if basic auth is present
This commit is contained in:
parent
3d79fc1817
commit
2e5a1b0c42
2 changed files with 51 additions and 24 deletions
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue