From 729e6438cc3c53765781d8457b10d65f499619b5 Mon Sep 17 00:00:00 2001 From: Daelon022 Date: Tue, 28 May 2024 02:05:32 +0300 Subject: [PATCH] Add getting user profile and finish AuthMiddleware --- src/consts.rs | 1 + src/errors.rs | 3 ++ src/middleware/auth.rs | 30 ++++++++++++------ src/user_flow/account_flow_methods.rs | 44 ++++++++++++++++++++++++--- src/user_flow/auth0.rs | 2 +- src/user_flow/consts.rs | 1 + src/user_flow/requests.rs | 41 +++++++++++++++++++++++-- src/utils.rs | 16 +++++----- 8 files changed, 115 insertions(+), 23 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index da43559..fc16991 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -2,4 +2,5 @@ pub static AUDIENCE: &str = "https://someexample.com"; pub static GRANT_TYPE_PASS: &str = "password"; pub static CONTENT_TYPE: &str = "Content-Type"; pub static APPLICATION_JSON: &str = "application/json"; +pub static AUTHORIZATION: &str = "Authorization"; pub static ACCESS_TOKEN: &str = "access_token"; diff --git a/src/errors.rs b/src/errors.rs index 16accf6..020a07d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -59,6 +59,9 @@ pub enum Error { #[error(transparent)] AlcoholicJwtValidationError(#[from] alcoholic_jwt::ValidationError), + + #[error("Error: {0}")] + StringError(String), } pub type Result = std::result::Result; diff --git a/src/middleware/auth.rs b/src/middleware/auth.rs index 6fc0046..201da4d 100644 --- a/src/middleware/auth.rs +++ b/src/middleware/auth.rs @@ -11,11 +11,17 @@ use std::sync::Arc; use std::task::{Context, Poll}; use tokio::sync::RwLock; +pub const AUDIENCE: &str = "https://someexample.com"; + #[derive(Debug, Deserialize)] #[allow(dead_code)] struct Claims { + aud: String, + azp: String, + exp: i64, + iat: i64, + iss: String, sub: String, - exp: usize, } pub struct AuthMiddleware; @@ -73,17 +79,22 @@ where if let Some(auth_header) = auth_header { if let Ok(auth_token) = auth_header.to_str() { if let Some(auth_str) = auth_token.strip_prefix("Bearer ") { - let token = &auth_str[7..]; + let token = auth_str; let decoding_key = decoding_key.read().await; - return match decode::( - token, - &decoding_key, - &Validation::new(Algorithm::HS256), - ) { + let audience = [AUDIENCE]; + + let validation = &mut Validation::new(Algorithm::RS256); + + validation.set_audience(&audience); + + return match decode::(token, &decoding_key, validation) { Ok(_) => service.call(req).await, - Err(_) => Ok(req.into_response(HttpResponse::Unauthorized().finish())), + Err(e) => { + log::error!("Unauthorized access: {}", e); + Ok(req.into_response(HttpResponse::Unauthorized().finish())) + } }; } } @@ -100,7 +111,8 @@ impl AuthMiddleware { let mut key_data = Vec::new(); file.read_to_end(&mut key_data)?; - let decoding_key = DecodingKey::from_secret(&key_data); + let decoding_key = + DecodingKey::from_rsa_pem(key_data.as_slice()).expect("Failed to load key"); Ok(decoding_key) } diff --git a/src/user_flow/account_flow_methods.rs b/src/user_flow/account_flow_methods.rs index e7aec88..806a974 100644 --- a/src/user_flow/account_flow_methods.rs +++ b/src/user_flow/account_flow_methods.rs @@ -1,7 +1,7 @@ -use crate::consts::{APPLICATION_JSON, CONTENT_TYPE}; -use crate::errors::Result; +use crate::consts::{APPLICATION_JSON, AUTHORIZATION, CONTENT_TYPE}; +use crate::errors::{Error, Result}; use crate::services::auth0::Auth0Service; -use crate::user_flow::consts::CHANGE_PASSWORD_URL; +use crate::user_flow::consts::{CHANGE_PASSWORD_URL, GET_PROFILE_URL}; use actix_web::web::Data; use http::Method; use reqwest::Client; @@ -14,7 +14,7 @@ pub async fn send_request_to_change_pass( ) -> Result<()> { let client = Client::new(); - let url = format!("{}{}", auth0_service.client_url, CHANGE_PASSWORD_URL); + let url = format!("{}/{}", auth0_service.client_url, CHANGE_PASSWORD_URL); let body = auth0_service .generate_body_for_change_password(user_id, email) @@ -29,3 +29,39 @@ pub async fn send_request_to_change_pass( Ok(()) } + +pub async fn send_request_to_get_profile( + access_token: &str, + auth0_service: Data, +) -> Result { + let client = Client::new(); + + let url = format!("{}/{}", auth0_service.client_url, GET_PROFILE_URL); + log::info!("Requesting profile from URL: {}", &url); + + let result = client + .get(&url) + .header(CONTENT_TYPE, "application/json") + .header(AUTHORIZATION, format!("Bearer {}", access_token)) + .send() + .await; + + match result { + Ok(response) => { + log::info!("Response status: {}", response.status()); + if response.status().is_success() { + let body = response.text().await?; + log::info!("Response body: {:?}", body); + Ok(body) + } else { + let error_body = response.text().await?; + log::error!("Error response body: {:?}", error_body); + Err(Error::StringError(error_body)) + } + } + Err(e) => { + log::error!("Request failed: {:?}", e); + Err(Error::StringError(e.to_string())) + } + } +} diff --git a/src/user_flow/auth0.rs b/src/user_flow/auth0.rs index b55b66a..44a8a32 100644 --- a/src/user_flow/auth0.rs +++ b/src/user_flow/auth0.rs @@ -16,7 +16,7 @@ pub async fn register_user( ) -> crate::errors::Result<()> { let client = Client::new(); - let url = format!("{}{}", auth0_service.client_url, REGISTRATION_URL); + let url = format!("{}/{}", auth0_service.client_url, REGISTRATION_URL); let body = auth0_service.generate_body_for_registration( user_id, diff --git a/src/user_flow/consts.rs b/src/user_flow/consts.rs index 0924c65..1112072 100644 --- a/src/user_flow/consts.rs +++ b/src/user_flow/consts.rs @@ -1,3 +1,4 @@ pub const REGISTRATION_URL: &str = "dbconnections/signup"; pub const LOGIN_URL: &str = "oauth/token"; pub const CHANGE_PASSWORD_URL: &str = "dbconnections/change_password"; +pub const GET_PROFILE_URL: &str = "userinfo"; diff --git a/src/user_flow/requests.rs b/src/user_flow/requests.rs index 98219c7..59c8ba4 100644 --- a/src/user_flow/requests.rs +++ b/src/user_flow/requests.rs @@ -2,11 +2,13 @@ use crate::actors::messages::{CheckIfRegisteredUser, CheckUser, CreateUser}; use crate::db::postgres_db::DbService; use crate::models::{RegisteredUserData, UpdatePasswordData, UserData}; use crate::services::auth0::Auth0Service; -use crate::user_flow::account_flow_methods::send_request_to_change_pass; +use crate::user_flow::account_flow_methods::{ + send_request_to_change_pass, send_request_to_get_profile, +}; use crate::user_flow::auth0::{get_jwt_user_token, register_user}; use actix::Addr; use actix_web::web::{Data, Json}; -use actix_web::HttpResponse; +use actix_web::{web, HttpRequest, HttpResponse}; use uuid::Uuid; #[utoipa::path( @@ -97,3 +99,38 @@ pub async fn change_password( Ok(HttpResponse::BadRequest().finish()) } } + +#[utoipa::path( + get, + path = "/profile/{user_id}", + responses( + (status = 200, description = "Successfully get user profile", body = String), + (status = BAD_REQUEST, description = "User not found") + ) +)] +pub async fn profile( + auth0_service: Data, + db_service: Data>, + req: HttpRequest, + user_id: web::Path, +) -> crate::errors::Result { + log::info!("Getting request for profile!"); + + let if_user = CheckUser { + id: user_id.into_inner(), + }; + + if !db_service.send(if_user).await?? { + return Ok(HttpResponse::BadRequest().finish()); + } + + let access_token = req + .headers() + .get("Authorization") + .expect("No Authorization header") + .to_str() + .expect("Invalid Authorization header"); + + let profile = send_request_to_get_profile(access_token, auth0_service).await?; + Ok(HttpResponse::Ok().body(profile)) +} diff --git a/src/utils.rs b/src/utils.rs index 711ed81..40f1be3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ use crate::db::postgres_db::DbService; use crate::middleware::auth::AuthMiddleware; use crate::services::auth0::Auth0Service; -use crate::user_flow::requests::{change_password, login, register}; +use crate::user_flow::requests::{change_password, login, profile, register}; use crate::ApiDoc; use actix::Addr; use actix_web::web; @@ -72,18 +72,20 @@ fn parse_thread_id(id: &ThreadId) -> String { parsed.unwrap_or(id_str) } -pub fn configure_routes(cfg: &mut web::ServiceConfig) { +pub fn configure_routes(cfg: &mut ServiceConfig) { let openapi = ApiDoc::openapi(); cfg.service( + web::scope("/user") + .wrap(AuthMiddleware) + .service(web::resource("/change_password").route(web::post().to(change_password))) + .service(web::resource("/profile/{user_id}").route(web::get().to(profile))), + ) + .service( web::scope("") .service(web::resource("/login").route(web::post().to(login))) .service(web::resource("/register").route(web::post().to(register))) - .service(SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-docs/openapi.json", openapi)), - ) - .service( - web::scope("/user") - .wrap(AuthMiddleware) + .service(SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-docs/openapi.json", openapi)) .service(web::resource("/change_password").route(web::post().to(change_password))), ); }