Skip to content

Commit

Permalink
clean-up
Browse files Browse the repository at this point in the history
  • Loading branch information
thebino committed Jul 9, 2023
1 parent d01b9c1 commit 51b061e
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 61 deletions.
19 changes: 17 additions & 2 deletions crates/authentication/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,37 @@ path = "src/lib.rs"
doctest = false

[dependencies]
core_common = { workspace = true }
# OIDC interfaces
openidconnect = { version = "3.2.0", features = ["accept-rfc3339-timestamps", "accept-string-booleans"] }

# OIDC Router
axum = { workspace = true }

# json payload
serde = { workspace = true, features = ["derive"] }

# time related data in models
chrono.workspace = true
uuid.workspace = true

# key signing and cryptographics
rsa = { version = "0.9.2" }

# error handling
thiserror = "1.0.40"
miette = "5.9.0"

# URL parsing
url = { version = "2.4.0", features = ["serde"] }

# Rendering login form
dioxus = "0.3.2"
dioxus-ssr = "0.3.0"

tower-http.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true


[dev-dependencies]
testdir = { version="0.7.3" }
rand = { version = "0.8.5" }
Expand Down
7 changes: 6 additions & 1 deletion crates/authentication/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,20 @@ sequenceDiagram;
U->>A: User clicks login
A->>AM: GET http://127.0.0.1/.well-known/openid-configuration
AM->>A: JSON meta-data document
Note right of A: { "authorization_endpoint":"http://localhost:7777/oidc/authorize", <br> "token_endpoint":"http://localhost:7777/oidc/token" ...
A->>A: Generate Code Verifier & Challenge
A->>AM: GET http://localhost:7777/oidc/authorize?[...]
Note right of A: GET /oidc/authorize parameters: <br> client_id=xxx (identifier) <br> redirect_uri=http://127.0.0.1/callback <br> state=xxxx (CRFS protection) <br> nonce=xyz (server-side replay protection) <br> scope=openid email profile library:read <br> code_challenge=elU6u5zyqQT2f92GRQUq6PautAeNDf4DQPayy <br> code_challenge_method=S256
Note right of A: GET /oidc/authorize parameters: <br> response_type=id_token%20token <br> client_id=mobile-app (identifier) <br> redirect_uri=photosapp://authenticate <br> state=xxxx (CRFS protection) <br> nonce=xyz (server-side replay protection) <br> scope=openid email profile library:read <br> code_challenge=elU6u5zyqQT2f92GRQUq6PautAeNDf4DQPayy <br> code_challenge_method=S256
AM->>U: show login prompt
U->>AM: perform login and grant consent
AM->>A: 302 Redirect to http://127.0.0.1/callback?[...] (redirect_uri)
Note right of A: GET /callback <br> state=xxx <br> code=xxx
A->>AM: GET http://localhost:7777/oidc/token
Note right of A: GET /oidc/token parameters: <br> client_id=xxx (identifier) <br> redirect_uri=http://127.0.0.1/callback <br> code_verifier=xxxx (generated verifier) <br> code=xyz (authorization_code) <br> grant_type=authorization_code
AM->>AM: Validate code verifier and challenge
Expand Down
4 changes: 1 addition & 3 deletions crates/authentication/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use miette::Diagnostic;

use thiserror::Error;

#[derive(Debug, Error, Diagnostic)]
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
OpenIDUrlParseError(#[from] openidconnect::url::ParseError),
Expand Down
4 changes: 2 additions & 2 deletions crates/authentication/src/handler/authorize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ pub(crate) async fn authorization_handler(
}
}
}

for client in state.read().unwrap().master_realm.clients.iter() {
if &client.id == &query.client_id {

Check failure on line 56 in crates/authentication/src/handler/authorize.rs

View workflow job for this annotation

GitHub Actions / Lints

needlessly taken reference of both operands
state.write().unwrap().master_realm.requests.push(req);
let realm_login_url = format!("/{}/login", &state.read().unwrap().master_realm.name);
return Ok(Redirect::to(&realm_login_url));
}
}

Err(StatusCode::UNAUTHORIZED)
}
2 changes: 2 additions & 0 deletions crates/authentication/src/handler/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub(crate) async fn post_realm_login(Form(login_form): Form<LoginFormData>) -> H
login_form.password
);

// TODO: validate credentials

Html(String::from("<div>Success</div>"))
}

Expand Down
24 changes: 12 additions & 12 deletions crates/authentication/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ impl OpenIdManager {
S: Send + Sync + 'static + Clone,
{
Router::new()
.route(
"/.well-known/openid-configuration",
get(openid_discover_handler),
)
.route("/jwk", get(openid_jwks_handler))
.route("/oidc/authorize", get(authorization_handler))
.route(
"/:realm/login",
get(get_realm_login_form).post(post_realm_login),
)
.layer(tower_http::trace::TraceLayer::new_for_http())
.with_state(Arc::new(RwLock::new(server.clone())))
.route(
"/.well-known/openid-configuration",
get(openid_discover_handler),
)
.route("/jwk", get(openid_jwks_handler))
.route("/oidc/authorize", get(authorization_handler))
.route(
"/:realm/login",
get(get_realm_login_form).post(post_realm_login),
)
.layer(tower_http::trace::TraceLayer::new_for_http())
.with_state(Arc::new(RwLock::new(server.clone())))

Check failure on line 62 in crates/authentication/src/lib.rs

View workflow job for this annotation

GitHub Actions / Lints

redundant clone
}
}
7 changes: 6 additions & 1 deletion crates/authentication/src/realm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ impl Realm {
.as_ref()
.join(name)
.with_extension("pem"),
).expect(&format!("key ({}) not found in directory ({})!", name, realm_keys_base_path.as_ref().display()));
)
.expect(&format!(

Check failure on line 60 in crates/authentication/src/realm.rs

View workflow job for this annotation

GitHub Actions / Lints

use of `expect` followed by a function call
"key ({}) not found in directory ({})!",
name,
realm_keys_base_path.as_ref().display()
));
let mut realm_key_str = String::new();
realm_key_file
.read_to_string(&mut realm_key_str)
Expand Down
4 changes: 2 additions & 2 deletions crates/authentication/tests/authorization_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/

//! Thest the OIDC authorization code flow with PKCE
//!
//!
//! 1st - [OpenID Connect Discovery](https://server.com/.well-known/openid-configuration)
//! 2nd - [Authorization](https://server.com/oidc/authorize?)
//! 3rd - [Token](https://server.com/oidc/token)
Expand All @@ -32,7 +32,7 @@ mod common;
mod tests {
use super::*;

// Test if OIDC discovery responds with 200 OK and contains mandatory fields
// Test if OIDC discovery responds with 200 OK and contains mandatory fields
// e.g. issuer, authorization_endpoint and token_endpoint
#[tokio::test]
async fn oidc_discovery_succesful() {
Expand Down
30 changes: 14 additions & 16 deletions crates/authentication/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,39 @@
*/

//! Create a private key file to use for OIDC.
//!
use testdir::testdir;
use std::path::PathBuf;
use std::fs::File;
use std::fs;
use std::io::Write;
use rsa::RsaPrivateKey;
//!
use authentication::{config::ServerConfig, state::ServerState, OpenIdManager};
use axum::Router;
use rand::rngs::OsRng;
use rsa::pkcs8::LineEnding;
use rsa::pkcs1::EncodeRsaPrivateKey;
use axum::Router;
use authentication::{OpenIdManager, config::ServerConfig, state::ServerState};
use rsa::pkcs8::LineEnding;
use rsa::RsaPrivateKey;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use testdir::testdir;

pub fn create_fake_pem(filename: &'static str) -> PathBuf {
let path: PathBuf = testdir!();
let keys_base_path = path.join("keys");
// create keys directory
fs::create_dir(&keys_base_path).unwrap();

// create a fake private key
let mut rng = OsRng;
let bits = 2048;
let key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate private key");
let pem = key.to_pkcs1_pem(LineEnding::LF).unwrap();

// write private key into file
let mut file: File = File::create(keys_base_path.join(filename)).expect("no file");
file.write_all(
pem.as_bytes()
).expect("write failed");
file.write_all(pem.as_bytes()).expect("write failed");

keys_base_path
}

pub fn create_router()-> Router {
pub fn create_router() -> Router {
let private_key: PathBuf = create_fake_pem("master.pem");

// create server config with fake key
Expand Down
40 changes: 18 additions & 22 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,20 @@ use std::net::SocketAddr;
use abi_stable::external_types::crossbeam_channel;
use abi_stable::std_types::RResult::{RErr, ROk};
use anyhow::Result;
use axum::routing::{get, head};
use axum::{Json, Router};
use authentication::OpenIdManager;
use authentication::config::ServerConfig;
use authentication::state::ServerState;
use authentication::client::Client;
use authentication::config::ConfigRealm;
use authentication::config::ServerConfig;
use authentication::state::ServerState;
use authentication::OpenIdManager;
use axum::routing::{get, head};
use axum::{Json, Router};
use photos_network_plugin::{PluginFactoryRef, PluginId};
use serde::{Deserialize, Serialize};
use std::path::Path;
use tower_http::services::ServeDir;
use tower_http::trace::TraceLayer;
use tracing::{debug, error, info};
use tracing_subscriber::{fmt, layer::SubscriberExt};
use std::path::Path;

use config::configuration::Configuration;
use plugin::plugin_manager::PluginManager;
Expand Down Expand Up @@ -79,29 +79,25 @@ pub async fn start_server() -> Result<()> {
// read config file
let config = Configuration::new(CONFIG_PATH).expect("Could not parse configuration!");
debug!("Configuration: {}", config);

// init application state
let mut app_state = ApplicationState::new(config.clone());

debug!("ServerConfig...");
let cfg = ServerConfig {
listen_addr: String::from("127.0.0.1:7777"),
domain: String::from("localhost:7777"),
use_ssl: false,
realm_keys_base_path: Path::new("keys").to_path_buf(),
realms: vec![
ConfigRealm {
name: String::from("master"),
domain: Some(String::from("localhost:7777")),
clients: vec![
Client {
id: String::from("mobile-app"),
secret: None,
redirect_uri: String::from("photosapp://authenticate"),
}
]
}
],
realms: vec![ConfigRealm {
name: String::from("master"),
domain: Some(String::from("localhost:7777")),
clients: vec![Client {
id: String::from("mobile-app"),
secret: None,
redirect_uri: String::from("photosapp://authenticate"),
}],
}],
};
debug!("ServerConfig:");
let server = ServerState::new(cfg)?;
Expand All @@ -113,7 +109,7 @@ pub async fn start_server() -> Result<()> {
// health check
.route("/", get(status))
.route("/", head(status))

// openid
.nest("/", OpenIdManager::routes(server))
// oauth 2
Expand Down

0 comments on commit 51b061e

Please sign in to comment.