Compare commits
3 Commits
f4ef3f501d
...
36f1c1e0f4
Author | SHA1 | Date |
---|---|---|
Aravinth Manivannan | 36f1c1e0f4 | |
Aravinth Manivannan | 702cdbdd99 | |
Aravinth Manivannan | 8d822e1b31 |
|
@ -255,6 +255,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.80"
|
||||
|
@ -686,6 +692,12 @@ version = "0.15.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "downcast"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.11.0"
|
||||
|
@ -816,6 +828,7 @@ dependencies = [
|
|||
"derive_more",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"mockall",
|
||||
"pretty_env_logger",
|
||||
"rand",
|
||||
"reqwest",
|
||||
|
@ -838,6 +851,12 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fragile"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
|
@ -1452,6 +1471,33 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockall"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"downcast",
|
||||
"fragile",
|
||||
"lazy_static",
|
||||
"mockall_derive",
|
||||
"predicates",
|
||||
"predicates-tree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockall_derive"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mutually_exclusive_features"
|
||||
version = "0.0.3"
|
||||
|
@ -1821,6 +1867,32 @@ version = "0.2.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"predicates-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pretty_env_logger"
|
||||
version = "0.5.0"
|
||||
|
@ -2683,6 +2755,12 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termtree"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.59"
|
||||
|
|
|
@ -28,7 +28,9 @@ tera = "1.19.1"
|
|||
tracing = { version = "0.1.40", features = ["log"] }
|
||||
tracing-actix-web = "0.7.10"
|
||||
url = { version = "2.5.0", features = ["serde"] }
|
||||
mockall = "0.12"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt= "2.9"
|
||||
mockall = { version = "0.12", features = ["nightly"] }
|
||||
|
|
|
@ -3,20 +3,19 @@ use std::sync::Arc;
|
|||
use actix_web::{http::header, HttpResponse};
|
||||
use url::Url;
|
||||
|
||||
use crate::auth::application::port::input::ui::{
|
||||
errors::*, login::RequestAuthorizationInterface,
|
||||
};
|
||||
use crate::auth::application::port::input::ui::{errors::*, login::RequestAuthorizationInterface};
|
||||
use crate::auth::application::port::out::db::save_oauth_state::SaveOAuthState;
|
||||
use crate::auth::application::port::out::forge::oauth_auth_req_uri::OAuthAuthReqUri;
|
||||
use crate::auth::application::services::request_authorization::{
|
||||
command::RequestAuthorizationCommand, service::RequestAuthorizationService,
|
||||
RequestAuthorizationUserCase,
|
||||
};
|
||||
//use crate::auth::application::services::request_authorization::command::RequestAuthorizationCommand;
|
||||
use crate::utils::random_string::GenerateRandomStringInterface;
|
||||
|
||||
pub struct RequestAuthorizationHandler {
|
||||
save_oauth_state_adapter: Arc<dyn SaveOAuthState>,
|
||||
oauth_auth_req_uri_adapter: Arc<dyn OAuthAuthReqUri>,
|
||||
generate_random_string: Arc<dyn GenerateRandomStringInterface>,
|
||||
process_authorization_response_redirect_uri: Url,
|
||||
}
|
||||
|
||||
|
@ -24,12 +23,14 @@ impl RequestAuthorizationHandler {
|
|||
pub fn new(
|
||||
save_oauth_state_adapter: Arc<dyn SaveOAuthState>,
|
||||
oauth_auth_req_uri_adapter: Arc<dyn OAuthAuthReqUri>,
|
||||
generate_random_string: Arc<dyn GenerateRandomStringInterface>,
|
||||
process_authorization_response_redirect_uri: Url,
|
||||
) -> Self {
|
||||
Self {
|
||||
save_oauth_state_adapter,
|
||||
oauth_auth_req_uri_adapter,
|
||||
process_authorization_response_redirect_uri,
|
||||
generate_random_string,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +43,7 @@ impl RequestAuthorizationInterface for RequestAuthorizationHandler {
|
|||
self.save_oauth_state_adapter.clone(),
|
||||
self.oauth_auth_req_uri_adapter.clone(),
|
||||
self.process_authorization_response_redirect_uri.clone(),
|
||||
self.generate_random_string.clone(),
|
||||
);
|
||||
|
||||
log::info!("service found");
|
||||
|
@ -53,3 +55,64 @@ impl RequestAuthorizationInterface for RequestAuthorizationHandler {
|
|||
.finish())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use actix_web::http::{header, StatusCode};
|
||||
|
||||
use super::*;
|
||||
use crate::auth::application::port::out::{
|
||||
db::save_oauth_state::MockSaveOAuthState, forge::oauth_auth_req_uri::MockOAuthAuthReqUri,
|
||||
};
|
||||
use crate::utils::random_string::*;
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_adapter() {
|
||||
let random_string = "foorand";
|
||||
|
||||
let url = Url::parse("http://test_ui_req_auth_interface_adapter").unwrap();
|
||||
let oauth_provider = "test_ui_req_auth_interface_adapter";
|
||||
let mut redirect_uri = url.clone();
|
||||
redirect_uri.set_query(Some(&format!("state={random_string}")));
|
||||
|
||||
let mut mock_random_generate_string = MockGenerateRandomStringInterface::new();
|
||||
mock_random_generate_string
|
||||
.expect_get_random()
|
||||
.times(1)
|
||||
.return_const(random_string.to_string());
|
||||
|
||||
let r = redirect_uri.clone();
|
||||
let mut mock_oauth_req_uri = MockOAuthAuthReqUri::new();
|
||||
mock_oauth_req_uri
|
||||
.expect_oauth_auth_req_uri()
|
||||
.times(1)
|
||||
.returning(move |_, _| Ok(r.clone()));
|
||||
|
||||
let mut mock_save_oauth_state = MockSaveOAuthState::new();
|
||||
mock_save_oauth_state
|
||||
.expect_save_oauth_state()
|
||||
.times(1)
|
||||
.returning(|_, _, _| Ok(()));
|
||||
|
||||
let adapter = RequestAuthorizationHandler::new(
|
||||
Arc::new(mock_save_oauth_state),
|
||||
Arc::new(mock_oauth_req_uri),
|
||||
Arc::new(mock_random_generate_string),
|
||||
url.clone(),
|
||||
);
|
||||
|
||||
let res = adapter
|
||||
.request_oauth_authorization(oauth_provider.into())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::FOUND);
|
||||
assert_eq!(
|
||||
res.headers()
|
||||
.get(header::LOCATION)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
redirect_uri.as_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{get, http::header, post, web, HttpResponse};
|
||||
use actix_web::http::header::ContentType;
|
||||
use actix_web::{get, post, web, HttpResponse};
|
||||
use url::Url;
|
||||
|
||||
use crate::auth::adapter::input::web::routes::RoutesRepository;
|
||||
use crate::auth::adapter::out::forge::SupportedForges;
|
||||
use crate::auth::application::port::input::ui::{
|
||||
errors::*, login::RequestAuthorizationInterface,
|
||||
};
|
||||
use crate::auth::application::port::input::ui::{errors::*, login::RequestAuthorizationInterface};
|
||||
use crate::auth::application::port::out::db::save_oauth_state::SaveOAuthState;
|
||||
use crate::utils::random_string::GenerateRandomStringInterface;
|
||||
use crate::ForgeRepository;
|
||||
|
||||
use super::template::{LoginCtxFactory, LoginPageInterface};
|
||||
use crate::ForgeRepository;
|
||||
|
||||
#[get("/login")]
|
||||
#[tracing::instrument(name = "login page handler", skip(forges, routes, template))]
|
||||
|
@ -23,16 +23,16 @@ async fn login_page(
|
|||
let template_ctx = LoginCtxFactory::get_ctx(forges.get_supported_forges(), &routes);
|
||||
let page = template.get_login_page(template_ctx).unwrap();
|
||||
Ok(HttpResponse::Ok()
|
||||
.append_header((header::CONTENT_TYPE, "text/html; charset=UTF-8"))
|
||||
.insert_header(ContentType::html())
|
||||
.body(page))
|
||||
}
|
||||
|
||||
#[post("/oauth/forgejo/login")]
|
||||
async fn request_oauth_authorization_forgejo(
|
||||
forge_name: web::Path<String>,
|
||||
forges: web::Data<Arc<ForgeRepository>>,
|
||||
save_oauth_state_adapter: web::Data<Arc<dyn SaveOAuthState>>,
|
||||
routes: web::Data<Arc<RoutesRepository>>,
|
||||
generate_random_string: web::Data<Arc<dyn GenerateRandomStringInterface>>,
|
||||
settings: web::Data<crate::settings::Settings>,
|
||||
) -> InUIResult<HttpResponse> {
|
||||
let oauth_auth_req_uri_adapter = &forges
|
||||
|
@ -51,11 +51,12 @@ async fn request_oauth_authorization_forgejo(
|
|||
let web_adapter = super::adapter::RequestAuthorizationHandler::new(
|
||||
save_oauth_state_adapter.as_ref().to_owned(),
|
||||
oauth_auth_req_uri_adapter.clone(),
|
||||
generate_random_string.as_ref().clone(),
|
||||
process_authorization_response_redirect_uri,
|
||||
);
|
||||
|
||||
web_adapter
|
||||
.request_oauth_authorization(forge_name.into_inner())
|
||||
.request_oauth_authorization(SupportedForges::Forgejo.to_string())
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -63,3 +64,42 @@ pub fn services(cfg: &mut web::ServiceConfig) {
|
|||
cfg.service(login_page);
|
||||
cfg.service(request_oauth_authorization_forgejo);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use actix_web::{http::header::ContentType, test, App};
|
||||
|
||||
use crate::auth::adapter::input::web::login::template::load_templates;
|
||||
use crate::auth::adapter::out::forge::forgejo::Forgejo;
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_get_login_page() {
|
||||
let settings = crate::settings::Settings::new().unwrap();
|
||||
|
||||
let forgejo = Forgejo::new(
|
||||
settings.forges.forgejo.url.clone(),
|
||||
settings.forges.forgejo.client_id.clone(),
|
||||
settings.forges.forgejo.client_secret.clone(),
|
||||
);
|
||||
let forges = ForgeRepository::new(forgejo);
|
||||
let routes = RoutesRepository::default();
|
||||
|
||||
let app = test::init_service(
|
||||
App::new()
|
||||
.app_data(web::Data::new(Arc::new(forges.clone())))
|
||||
.app_data(web::Data::new(Arc::new(routes.clone())))
|
||||
.configure(load_templates)
|
||||
.service(login_page),
|
||||
)
|
||||
.await;
|
||||
|
||||
let req = test::TestRequest::get()
|
||||
.uri("/login")
|
||||
.insert_header(ContentType::html())
|
||||
.to_request();
|
||||
let resp = test::call_service(&app, req).await;
|
||||
println!("{}", resp.status());
|
||||
assert!(resp.status().is_success());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ use std::sync::Arc;
|
|||
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::db::migrate::RunMigrations;
|
||||
use crate::auth::application::port::out::db::save_oauth_state::SaveOAuthState;
|
||||
use crate::db::migrate::RunMigrations;
|
||||
|
||||
pub mod postgres;
|
||||
|
||||
|
|
|
@ -2,46 +2,3 @@ pub mod delete_oauth_state;
|
|||
pub mod errors;
|
||||
pub mod oauth_state_exists;
|
||||
pub mod save_oauth_state;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use url::Url;
|
||||
|
||||
use super::*;
|
||||
|
||||
use errors::*;
|
||||
use save_oauth_state::SaveOAuthState;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct MockDB {
|
||||
pub calls: Arc<RwLock<Vec<Call>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Call {
|
||||
pub state: String,
|
||||
pub oauth_provider: String,
|
||||
pub redirect_uri: String,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl SaveOAuthState for MockDB {
|
||||
async fn save_oauth_state(
|
||||
&self,
|
||||
state: &str,
|
||||
oauth_provider: &str,
|
||||
redirect_uri: &Url,
|
||||
) -> OutDBPortResult<()> {
|
||||
let mut calls = self.calls.write().unwrap();
|
||||
calls.push(Call {
|
||||
state: state.to_string(),
|
||||
oauth_provider: oauth_provider.to_string(),
|
||||
redirect_uri: redirect_uri.to_string(),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use mockall::predicate::*;
|
||||
use mockall::*;
|
||||
use url::Url;
|
||||
|
||||
use super::errors::*;
|
||||
|
||||
#[automock]
|
||||
#[async_trait::async_trait]
|
||||
pub trait SaveOAuthState: Send + Sync {
|
||||
/// Save OAuth state code generated during authorization request, which will later be used to
|
||||
|
|
|
@ -2,29 +2,3 @@ pub mod errors;
|
|||
pub mod oauth_auth_req_uri;
|
||||
pub mod refresh_access_token;
|
||||
pub mod request_access_token;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use url::Url;
|
||||
|
||||
use super::*;
|
||||
|
||||
use errors::*;
|
||||
use oauth_auth_req_uri::OAuthAuthReqUri;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct MockForge; // {
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl OAuthAuthReqUri for MockForge {
|
||||
fn oauth_auth_req_uri(
|
||||
&self,
|
||||
state: &str,
|
||||
process_authorization_response_uri: &Url,
|
||||
) -> OutForgePortResult<Url> {
|
||||
let mut u = process_authorization_response_uri.clone();
|
||||
u.set_query(Some(&format!("state={state}")));
|
||||
Ok(u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use super::errors::*;
|
||||
use mockall::*;
|
||||
use url::Url;
|
||||
|
||||
use super::errors::*;
|
||||
|
||||
#[automock]
|
||||
pub trait OAuthAuthReqUri: Send + Sync {
|
||||
fn oauth_auth_req_uri(
|
||||
&self,
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
use super::errors::*;
|
||||
use crate::auth::domain::AuthCode;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait RefreshAccessToken {
|
||||
// returns ID of newly created user user
|
||||
async fn refresh_access_token(&self, auth_code: &AuthCode) -> OutForgePortResult<AuthCode>;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use super::errors::*;
|
||||
use crate::auth::domain::AuthCode;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait RequestAccessToken: Send + Sync {
|
||||
// returns ID of newly created user user
|
||||
async fn request_access_token(&self, code: &str) -> OutForgePortResult<AuthCode>;
|
||||
}
|
|
@ -2,10 +2,12 @@ use std::sync::Arc;
|
|||
|
||||
use url::Url;
|
||||
|
||||
use crate::auth::application::port::out::db::errors::OutDBPortError;
|
||||
use crate::auth::application::port::out::db::save_oauth_state::SaveOAuthState;
|
||||
use crate::auth::application::port::out::forge::oauth_auth_req_uri::OAuthAuthReqUri;
|
||||
use crate::utils;
|
||||
use crate::{
|
||||
auth::application::port::out::db::errors::OutDBPortError,
|
||||
utils::random_string::GenerateRandomStringInterface,
|
||||
};
|
||||
|
||||
use super::{errors::*, RequestAuthorizationUserCase};
|
||||
|
||||
|
@ -16,6 +18,7 @@ pub struct RequestAuthorizationService {
|
|||
save_oauth_state_adapter: Arc<dyn SaveOAuthState>,
|
||||
oauth_auth_req_uri_adapter: Arc<dyn OAuthAuthReqUri>,
|
||||
process_authorization_response_redirect_uri: Url,
|
||||
generate_random_string: Arc<dyn GenerateRandomStringInterface>,
|
||||
}
|
||||
|
||||
impl RequestAuthorizationService {
|
||||
|
@ -23,11 +26,13 @@ impl RequestAuthorizationService {
|
|||
save_oauth_state_adapter: Arc<dyn SaveOAuthState>,
|
||||
oauth_auth_req_uri_adapter: Arc<dyn OAuthAuthReqUri>,
|
||||
process_authorization_response_redirect_uri: Url,
|
||||
generate_random_string: Arc<dyn GenerateRandomStringInterface>,
|
||||
) -> Self {
|
||||
Self {
|
||||
save_oauth_state_adapter,
|
||||
oauth_auth_req_uri_adapter,
|
||||
process_authorization_response_redirect_uri,
|
||||
generate_random_string,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +43,7 @@ impl RequestAuthorizationUserCase for RequestAuthorizationService {
|
|||
&self,
|
||||
cmd: super::command::RequestAuthorizationCommand,
|
||||
) -> RequestAuthorizationServiceResult<Url> {
|
||||
let mut state = utils::get_random(STATE_LEN);
|
||||
let mut state = self.generate_random_string.get_random(STATE_LEN);
|
||||
loop {
|
||||
match self
|
||||
.save_oauth_state_adapter
|
||||
|
@ -50,7 +55,7 @@ impl RequestAuthorizationUserCase for RequestAuthorizationService {
|
|||
.await
|
||||
{
|
||||
Err(OutDBPortError::DuplicateState) => {
|
||||
state = utils::get_random(STATE_LEN);
|
||||
state = self.generate_random_string.get_random(STATE_LEN);
|
||||
continue;
|
||||
}
|
||||
Ok(_) => break,
|
||||
|
@ -69,36 +74,53 @@ mod tests {
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::auth::application::{
|
||||
port::out::{db::tests::MockDB, forge::tests::MockForge},
|
||||
port::out::{
|
||||
db::save_oauth_state::MockSaveOAuthState,
|
||||
forge::oauth_auth_req_uri::MockOAuthAuthReqUri,
|
||||
},
|
||||
services::request_authorization::command::RequestAuthorizationCommand,
|
||||
};
|
||||
use crate::utils::random_string::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_service() {
|
||||
let save_oauth_state = MockDB::default();
|
||||
let oauth_auth_req_uri = MockForge;
|
||||
let random_string = "foorand";
|
||||
|
||||
let url = Url::parse("http://test_service_request_auth").unwrap();
|
||||
let oauth_provider = "test_service_request_auth_oauth_provider";
|
||||
let mut redirect_uri = url.clone();
|
||||
redirect_uri.set_query(Some(&format!("state={random_string}")));
|
||||
|
||||
let mut mock_random_generate_string = MockGenerateRandomStringInterface::new();
|
||||
mock_random_generate_string
|
||||
.expect_get_random()
|
||||
.times(1)
|
||||
.return_const(random_string.to_string());
|
||||
|
||||
let r = redirect_uri.clone();
|
||||
let mut mock_oauth_req_uri = MockOAuthAuthReqUri::new();
|
||||
mock_oauth_req_uri
|
||||
.expect_oauth_auth_req_uri()
|
||||
.times(1)
|
||||
.returning(move |_, _| Ok(r.clone()));
|
||||
|
||||
let mut mock_save_oauth_state = MockSaveOAuthState::new();
|
||||
mock_save_oauth_state
|
||||
.expect_save_oauth_state()
|
||||
.times(1)
|
||||
.returning(|_, _, _| Ok(()));
|
||||
|
||||
let s = RequestAuthorizationService::new(
|
||||
Arc::new(save_oauth_state.clone()),
|
||||
Arc::new(oauth_auth_req_uri),
|
||||
Arc::new(mock_save_oauth_state),
|
||||
Arc::new(mock_oauth_req_uri),
|
||||
url.clone(),
|
||||
Arc::new(mock_random_generate_string),
|
||||
);
|
||||
let cmd = RequestAuthorizationCommand::new_command(oauth_provider.to_owned()).unwrap();
|
||||
|
||||
let res = s.request_authorization(cmd).await.unwrap().to_string();
|
||||
{
|
||||
let save_oauth_state_ctx = save_oauth_state.calls.read().unwrap();
|
||||
let call = save_oauth_state_ctx.first().unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
format!("http://test_service_request_auth/?state={}", &call.state)
|
||||
);
|
||||
assert_eq!(call.oauth_provider, oauth_provider);
|
||||
assert_eq!(call.redirect_uri, url.to_string());
|
||||
}
|
||||
let res = s.request_authorization(cmd).await.unwrap();
|
||||
assert_eq!(res, redirect_uri);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::env;
|
|||
use actix_web::{middleware, App, HttpServer};
|
||||
use db::migrate::RunMigrations;
|
||||
|
||||
mod db;
|
||||
mod auth;
|
||||
mod db;
|
||||
mod settings;
|
||||
mod utils;
|
||||
|
||||
|
@ -36,13 +36,11 @@ async fn main() {
|
|||
.wrap(tracing_actix_web::TracingLogger::default())
|
||||
.wrap(middleware::Compress::default())
|
||||
.app_data(actix_web::web::Data::new(settings.clone()))
|
||||
.app_data(utils::random_string::GenerateRandomString::inject())
|
||||
.wrap(
|
||||
middleware::DefaultHeaders::new().add(("Permissions-Policy", "interest-cohort=()")),
|
||||
)
|
||||
.configure(auth::adapter::load_adapters(
|
||||
db.pool.clone(),
|
||||
&settings,
|
||||
))
|
||||
.configure(auth::adapter::load_adapters(db.pool.clone(), &settings))
|
||||
})
|
||||
.bind(&socket_addr)
|
||||
.unwrap()
|
||||
|
|
|
@ -112,7 +112,7 @@ pub mod tests {
|
|||
use crate::db::delete_database::DeleteDatabase;
|
||||
use crate::db::migrate::RunMigrations;
|
||||
use crate::db::sqlx_postgres::Postgres;
|
||||
use crate::utils::get_random;
|
||||
use crate::utils::random_string::{GenerateRandomString, GenerateRandomStringInterface};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! env_helper {
|
||||
|
@ -136,7 +136,7 @@ pub mod tests {
|
|||
pub async fn get_settings() -> Settings {
|
||||
let mut settings = Settings::new().unwrap();
|
||||
let mut db_url = Url::parse(&settings.database.url).unwrap();
|
||||
db_url.set_path(&get_random(12));
|
||||
db_url.set_path(&GenerateRandomString.get_random(12));
|
||||
settings.database.url = db_url.to_string();
|
||||
|
||||
crate::db::sqlx_postgres::PostgresDatabase
|
||||
|
|
13
src/utils.rs
13
src/utils.rs
|
@ -1,13 +0,0 @@
|
|||
pub fn get_random(len: usize) -> String {
|
||||
use std::iter;
|
||||
|
||||
use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng};
|
||||
|
||||
let mut rng: ThreadRng = thread_rng();
|
||||
|
||||
iter::repeat(())
|
||||
.map(|()| rng.sample(Alphanumeric))
|
||||
.map(char::from)
|
||||
.take(len)
|
||||
.collect::<String>()
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod random_string;
|
|
@ -0,0 +1,38 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use actix_web::web;
|
||||
use mockall::predicate::*;
|
||||
use mockall::*;
|
||||
|
||||
#[automock]
|
||||
pub trait GenerateRandomStringInterface: Send + Sync {
|
||||
fn get_random(&self, len: usize) -> String;
|
||||
}
|
||||
|
||||
pub struct GenerateRandomString;
|
||||
impl GenerateRandomStringInterface for GenerateRandomString {
|
||||
fn get_random(&self, len: usize) -> String {
|
||||
use std::iter;
|
||||
|
||||
use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng};
|
||||
|
||||
let mut rng: ThreadRng = thread_rng();
|
||||
|
||||
iter::repeat(())
|
||||
.map(|()| rng.sample(Alphanumeric))
|
||||
.map(char::from)
|
||||
.take(len)
|
||||
.collect::<String>()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenerateRandomString {
|
||||
pub fn inject() -> impl FnOnce(&mut web::ServiceConfig) {
|
||||
let g: Arc<dyn GenerateRandomStringInterface> = Arc::new(GenerateRandomString);
|
||||
let f = move |cfg: &mut web::ServiceConfig| {
|
||||
cfg.app_data(web::Data::new(g));
|
||||
};
|
||||
|
||||
Box::new(f)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue