Skip to content

Commit

Permalink
Sogar registry inside devolutions-gateway (#166)
Browse files Browse the repository at this point in the history
* -added regsitry for hosting the files
-added logic for managing files

* -fixed cargo warnings

* -refactored code

* -refactored code

* -updated librecording api

* -refactored code
-fixed clippy warning

* -update code according to the sigar changes

Co-authored-by: Anastasiia Romaniuk <romaniuk.anastasiia@apriorit.com>
  • Loading branch information
AnastasiiaRomaniuk and Anastasiia Romaniuk authored Jun 17, 2021
1 parent 40da875 commit 1727a72
Show file tree
Hide file tree
Showing 18 changed files with 1,106 additions and 137 deletions.
369 changes: 357 additions & 12 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion devolutions-gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ indexmap = "1.0"
dlopen = "0.1.8"
dlopen_derive = "0.1.4"

sogar-core = { version = "0.1.0", git = "https://github.com/Devolutions/sogar.git", branch = "sogar_registry" }
tempfile = "3.0"
rust-argon2 = "0.8"

[dependencies.saphir]
version = "2.8"
default-features = false
Expand All @@ -70,7 +74,6 @@ winapi = { version = "0.3", features = ["winbase", "winuser", "winsvc", "libload
embed-resource = "1.3"

[dev-dependencies]
tempfile = "3.0"
reqwest = "0.9.20"
exitcode = "1.1"

127 changes: 100 additions & 27 deletions devolutions-gateway/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,39 @@ pub struct CertificateConfig {
pub private_key_data: Option<String>,
}

#[derive(Debug, Default, Clone)]
pub struct RecordingInfo {
pub sogar_path: Option<String>,
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct SogarPushRegistryInfo {
pub sogar_util_path: Option<PathBuf>,
pub registry_url: Option<String>,
pub username: Option<String>,
pub password: Option<String>,
pub image_name: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SogarPermission {
Push,
Pull,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct SogarUser {
pub password: Option<String>,
pub username: Option<String>,
pub permission: Option<SogarPermission>,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct SogarRegistryConfig {
pub serve_as_registry: Option<bool>,
pub local_registry_name: Option<String>,
pub local_registry_image: Option<String>,
pub keep_files: Option<bool>,
pub keep_time: Option<usize>,
pub push_files: Option<bool>,
pub sogar_push_registry_info: SogarPushRegistryInfo,
}

#[derive(Debug, Clone)]
pub struct Config {
pub service_mode: bool,
Expand All @@ -110,8 +134,9 @@ pub struct Config {
pub provisioner_public_key: Option<PublicKey>,
pub delegation_private_key: Option<PrivateKey>,
pub plugins: Option<Vec<String>>,
pub recording_path: Option<String>,
pub recording_info: RecordingInfo,
pub recording_path: Option<PathBuf>,
pub sogar_registry_config: SogarRegistryConfig,
pub sogar_user: Vec<SogarUser>,
}

impl Default for Config {
Expand Down Expand Up @@ -144,13 +169,22 @@ impl Default for Config {
delegation_private_key: None,
plugins: None,
recording_path: None,
recording_info: RecordingInfo {
sogar_path: None,
registry_url: None,
username: None,
password: None,
image_name: None,
sogar_registry_config: SogarRegistryConfig {
serve_as_registry: None,
local_registry_name: None,
local_registry_image: None,
keep_files: None,
keep_time: None,
push_files: None,
sogar_push_registry_info: SogarPushRegistryInfo {
sogar_util_path: None,
registry_url: None,
username: None,
password: None,
image_name: None,
},
},
sogar_user: Vec::new(),
}
}
}
Expand Down Expand Up @@ -226,7 +260,7 @@ pub struct ConfigFile {
#[serde(rename = "RecordingPath")]
pub recording_path: Option<String>,
#[serde(rename = "SogarPath")]
pub sogar_path: Option<String>,
pub sogar_util_path: Option<String>,
#[serde(rename = "SogarRegistryUrl")]
pub registry_url: Option<String>,
#[serde(rename = "SogarUsername")]
Expand All @@ -235,6 +269,20 @@ pub struct ConfigFile {
pub password: Option<String>,
#[serde(rename = "SogarImageName")]
pub image_name: Option<String>,
#[serde(rename = "SogarUsersList")]
pub sogar_users_list: Option<Vec<SogarUser>>,
#[serde(rename = "ServeAsRegistry")]
pub serve_as_registry: Option<bool>,
#[serde(rename = "RegistryName")]
pub registry_name: Option<String>,
#[serde(rename = "RegistryImage")]
pub registry_image: Option<String>,
#[serde(rename = "KeepFiles")]
pub keep_files: Option<bool>,
#[serde(rename = "KeepTime")]
pub keep_time: Option<usize>,
#[serde(rename = "PushFiles")]
pub push_files: Option<bool>,

// unstable options (subject to change)
#[serde(rename = "ApiKey")]
Expand Down Expand Up @@ -566,7 +614,14 @@ impl Config {
ARG_SOGAR_USERNAME,
ARG_SOGAR_PASSWORD,
ARG_SOGAR_IMAGE_NAME,
]),
])
.validator(|sogar_path| {
if PathBuf::from(sogar_path).is_file() {
Ok(())
} else {
Err(String::from("The value does not exist or is not a file."))
}
}),
)
.arg(
Arg::with_name(ARG_SOGAR_REGISTRY_URL)
Expand Down Expand Up @@ -737,23 +792,23 @@ impl Config {
}

if let Some(sogar_path) = matches.value_of(ARG_SOGAR_UTIL_PATH) {
config.recording_info.sogar_path = Some(sogar_path.to_owned());
config.sogar_registry_config.sogar_push_registry_info.sogar_util_path = Some(PathBuf::from(sogar_path));
}

if let Some(registry_url) = matches.value_of(ARG_SOGAR_REGISTRY_URL) {
config.recording_info.registry_url = Some(registry_url.to_owned());
config.sogar_registry_config.sogar_push_registry_info.registry_url = Some(registry_url.to_owned());
}

if let Some(username) = matches.value_of(ARG_SOGAR_USERNAME) {
config.recording_info.username = Some(username.to_owned());
config.sogar_registry_config.sogar_push_registry_info.username = Some(username.to_owned());
}

if let Some(password) = matches.value_of(ARG_SOGAR_PASSWORD) {
config.recording_info.password = Some(password.to_owned());
config.sogar_registry_config.sogar_push_registry_info.password = Some(password.to_owned());
}

if let Some(image_name) = matches.value_of(ARG_SOGAR_IMAGE_NAME) {
config.recording_info.image_name = Some(image_name.to_owned());
config.sogar_registry_config.sogar_push_registry_info.image_name = Some(image_name.to_owned());
}

// listeners parsing
Expand Down Expand Up @@ -828,7 +883,7 @@ impl Config {
}

if let Some(recording_path) = matches.value_of(ARG_RECORDING_PATH) {
config.recording_path = Some(recording_path.to_owned());
config.recording_path = Some(PathBuf::from(recording_path));
}

config
Expand Down Expand Up @@ -922,12 +977,21 @@ impl Config {
.map(|pem| PrivateKey::from_pem(pem).unwrap());

let plugins = config_file.plugins;
let recording_path = config_file.recording_path;
let sogar_path = config_file.sogar_path;
let recording_path = config_file.recording_path.map(PathBuf::from);

let sogar_util_path = config_file.sogar_util_path.map(PathBuf::from);

let registry_url = config_file.registry_url;
let username = config_file.username;
let password = config_file.password;
let image_name = config_file.image_name;
let serve_as_registry = config_file.serve_as_registry;
let registry_name = config_file.registry_name;
let registry_image = config_file.registry_image;
let keep_files = config_file.keep_files;
let keep_time = config_file.keep_time;
let push_files = config_file.push_files;
let sogar_user = config_file.sogar_users_list.unwrap_or_default();

// unstable options (subject to change)
let api_key = config_file.api_key;
Expand All @@ -952,13 +1016,22 @@ impl Config {
delegation_private_key,
plugins,
recording_path,
recording_info: RecordingInfo {
sogar_path,
registry_url,
username,
password,
image_name,
sogar_registry_config: SogarRegistryConfig {
serve_as_registry,
local_registry_name: registry_name,
local_registry_image: registry_image,
keep_files,
keep_time,
push_files,
sogar_push_registry_info: SogarPushRegistryInfo {
sogar_util_path,
registry_url,
username,
password,
image_name,
},
},
sogar_user,
..Default::default()
})
}
Expand Down
1 change: 1 addition & 0 deletions devolutions-gateway/src/http/controllers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod health;
pub mod jet;
pub mod sessions;
pub mod sogar_token;
92 changes: 92 additions & 0 deletions devolutions-gateway/src/http/controllers/sogar_token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use crate::config::{Config, SogarUser};
use picky::{
jose::{jws::JwsAlg, jwt::JwtSig},
key::PrivateKey,
};
use saphir::{
controller::Controller,
http::{Method, StatusCode},
macros::controller,
prelude::Request,
};
use serde::{Deserialize, Serialize};
use slog_scope::error;
use sogar_core::AccessToken;
use std::sync::Arc;

pub struct TokenController {
config: Arc<Config>,
}

impl TokenController {
pub fn new(config: Arc<Config>) -> Self {
Self { config }
}
}

#[controller(name = "registry")]
impl TokenController {
#[post("/oauth2/token")]
async fn get_token(&self, mut req: Request) -> (StatusCode, Option<String>) {
match req.form::<AccessToken>().await {
Ok(body) => {
let password_out = body.password;
let username_out = body.username;

for user in &self.config.sogar_user {
if let (Some(username), Some(hashed_password)) = (&user.username, &user.password) {
if username == &username_out {
let matched = argon2::verify_encoded(hashed_password.as_str(), password_out.as_bytes());
if matched.is_err() || !matched.unwrap() {
return (StatusCode::UNAUTHORIZED, None);
}

return create_token(&self.config.delegation_private_key, user);
}
}
}

(StatusCode::UNAUTHORIZED, None)
}
Err(e) => {
error!("Failed to read request body! Error is {}", e);
(StatusCode::BAD_REQUEST, None)
}
}
}
}

fn create_token(private_key: &Option<PrivateKey>, user: &SogarUser) -> (StatusCode, Option<String>) {
#[derive(Serialize, Deserialize, Debug)]
struct ResponseAccessToken {
access_token: String,
}

match private_key {
Some(private_key) => {
let signed_result = JwtSig::new(JwsAlg::RS256, user).encode(private_key);

match signed_result {
Ok(access_token) => {
let response = ResponseAccessToken { access_token };

match serde_json::to_string(&response) {
Ok(token) => (StatusCode::OK, Some(token)),
Err(e) => {
error!("Failed serialize token! Error is {}", e);
(StatusCode::BAD_REQUEST, None)
}
}
}
Err(e) => {
error!("Failed to create token! Error is {}", e);
(StatusCode::BAD_REQUEST, None)
}
}
}
None => {
error!("Private key is missing. Not able to create the jwt token.");
(StatusCode::BAD_REQUEST, None)
}
}
}
Loading

0 comments on commit 1727a72

Please sign in to comment.