Browse Source

Cleaning up the endpoint auth middleware

develop
Drew Short 6 years ago
parent
commit
00e11e760e
  1. 2
      src/config/mod.rs
  2. 10
      src/config/model.rs
  3. 4
      src/server/api.rs
  4. 79
      src/server/middleware/api_auth.rs

2
src/config/mod.rs

@ -1,5 +1,3 @@
use crate::config::model::Config;
pub mod default; pub mod default;
pub mod error; pub mod error;
pub mod load; pub mod load;

10
src/config/model.rs

@ -72,6 +72,16 @@ impl Config {
if users.len() > 0 { Some(users) } else { None } if users.len() > 0 { Some(users) } else { None }
} }
pub fn is_valid_username_and_token(&self, username: &str, token: &str) -> bool {
for user in &self.users {
if user.username == username && user.token == token {
return true;
}
}
return false;
}
} }
impl UserConfig { impl UserConfig {

4
src/server/api.rs

@ -9,7 +9,7 @@ use bytes::{Buf, Bytes, IntoBuf};
use futures::future::Future; use futures::future::Future;
use crate::server::error::APIError; use crate::server::error::APIError;
use crate::server::middleware::api_auth::APIAuthForRootAndZone;
use crate::server::middleware::api_auth::APIAuthRootAndZone;
use crate::server::router::AppState; use crate::server::router::AppState;
pub fn route(scope: Scope<AppState>) -> Scope<AppState> { pub fn route(scope: Scope<AppState>) -> Scope<AppState> {
@ -17,7 +17,7 @@ pub fn route(scope: Scope<AppState>) -> Scope<AppState> {
.resource("address", |r| r.method(Method::GET).f(get_address)) .resource("address", |r| r.method(Method::GET).f(get_address))
.nested("{root}/{zone}", |zone_scope| { .nested("{root}/{zone}", |zone_scope| {
zone_scope zone_scope
.middleware(APIAuthForRootAndZone)
.middleware(APIAuthRootAndZone)
.resource("", |r| r.method(Method::GET).f(get_address)) .resource("", |r| r.method(Method::GET).f(get_address))
.resource("update", |r| { .resource("update", |r| {
r.method(Method::GET).f(update_address_automatically); r.method(Method::GET).f(update_address_automatically);

79
src/server/middleware/api_auth.rs

@ -6,6 +6,41 @@ use crate::config::model::Config;
use crate::config::model::UserConfig; use crate::config::model::UserConfig;
use crate::server::router::AppState; use crate::server::router::AppState;
fn get_match_value<S>(req: &HttpRequest<S>, key: &str) -> Option<String> {
let match_info = req.resource().match_info();
match match_info.get(key) {
Some(value) => Some(String::from(value)),
None => None
}
}
fn get_header_value<S>(req: &HttpRequest<S>, key: &str) -> Option<String> {
match req.headers().get(key) {
Some(header) => match header.to_str() {
Ok(header_value) => Some(String::from(header_value)),
Err(_e) => None
},
None => None
}
}
fn get_user_from_request(req: &HttpRequest<AppState>) -> Option<&UserConfig> {
let config: &Config = &req.state().config;
let username = get_username_from_request(req);
match username {
Some(username) => config.get_user(&username),
None => None
}
}
fn get_username_from_request<S>(req: &HttpRequest<S>) -> Option<String> {
get_header_value(req, "X-AUTH-USERNAME")
}
fn get_token_from_request<S>(req: &HttpRequest<S>) -> Option<String> {
get_header_value(req, "X-AUTH-TOKEN")
}
fn valid_username_and_token_in_vec(username: &str, token: &str, users: Vec<&UserConfig>) -> bool { fn valid_username_and_token_in_vec(username: &str, token: &str, users: Vec<&UserConfig>) -> bool {
for user in users { for user in users {
if user.username == username && user.token == token { if user.username == username && user.token == token {
@ -15,31 +50,43 @@ fn valid_username_and_token_in_vec(username: &str, token: &str, users: Vec<&User
return false; return false;
} }
pub struct APIAuthForRootAndZone;
pub struct APIAuthUser;
pub struct APIAuthRootAndZone;
impl Middleware<AppState> for APIAuthUser {
fn start(&self, req: &HttpRequest<AppState>) -> Result<Started> {
let config: &Config = &req.state().config;
let username = get_username_from_request(req);
let token = get_token_from_request(req);
if username.is_none() || token.is_none() {
Ok(Started::Response(HttpResponse::Unauthorized().into()))
} else if config.is_valid_username_and_token(&username.unwrap(), &token.unwrap()) {
Ok(Started::Done)
} else {
Ok(Started::Response(HttpResponse::Unauthorized().into()))
}
}
}
impl Middleware<AppState> for APIAuthForRootAndZone {
impl Middleware<AppState> for APIAuthRootAndZone {
fn start(&self, req: &HttpRequest<AppState>) -> Result<Started> { fn start(&self, req: &HttpRequest<AppState>) -> Result<Started> {
let config: &Config = &req.state().config; let config: &Config = &req.state().config;
let match_info = req.resource().match_info();
let root = match_info.get("root");
let zone = match_info.get("zone");
let root = get_match_value(req, "root");
let zone = get_match_value(req, "zone");
if root.is_none() || zone.is_none() { if root.is_none() || zone.is_none() {
Ok(Started::Response(HttpResponse::BadRequest().into())) Ok(Started::Response(HttpResponse::BadRequest().into()))
} else { } else {
match config.get_users_for_root_and_zone(root.unwrap(), zone.unwrap()) {
match config.get_users_for_root_and_zone(&root.unwrap(), &zone.unwrap()) {
Some(users) => { Some(users) => {
let username_header = req.headers().get("X-AUTH-USERNAME");
let token_header = req.headers().get("X-AUTH-TOKEN");
if username_header.is_none() || token_header.is_none() {
let username = get_username_from_request(req);
let token = get_token_from_request(req);
if username.is_none() || token.is_none() {
Ok(Started::Response(HttpResponse::BadRequest().into())) Ok(Started::Response(HttpResponse::BadRequest().into()))
} else if valid_username_and_token_in_vec(&username.unwrap(), &token.unwrap(), users) {
Ok(Started::Done)
} else { } else {
let username = username_header.unwrap().to_str();
let token = token_header.unwrap().to_str();
if valid_username_and_token_in_vec(username.unwrap(), token.unwrap(), users) {
Ok(Started::Done)
} else {
Ok(Started::Response(HttpResponse::Unauthorized().into()))
}
Ok(Started::Response(HttpResponse::Unauthorized().into()))
} }
} }
None => Ok(Started::Response(HttpResponse::Unauthorized().into())) None => Ok(Started::Response(HttpResponse::Unauthorized().into()))

Loading…
Cancel
Save