Browse Source

Simple username+token authentication

develop
Drew Short 6 years ago
parent
commit
b68cdce121
  1. 2
      src/config/mod.rs
  2. 22
      src/config/model.rs
  3. 5
      src/server/api.rs
  4. 49
      src/server/middleware/api_auth.rs
  5. 1
      src/server/mod.rs
  6. 3
      src/server/router.rs

2
src/config/mod.rs

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

22
src/config/model.rs

@ -49,4 +49,26 @@ pub struct Config {
pub cloudflare: CloudflareConfig,
pub ddns: DDNSConfig,
pub users: Vec<UserConfig>,
}
impl Config {
pub fn get_users_for_root_and_zone(&self, search_root: &str, search_zone: &str) -> Option<Vec<&UserConfig>> {
let mut users: Vec<&UserConfig> = Vec::new();
for user in &self.users {
for root in &user.roots {
let zone_match = &search_zone.to_string();
if root.root == search_root && root.zones.contains(zone_match) {
users.push(user);
break;
}
}
}
if users.len() > 0 {
Some(users)
} else {
None
}
}
}

5
src/server/api.rs

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

49
src/server/middleware/api_auth.rs

@ -0,0 +1,49 @@
use actix_web::{HttpRequest, HttpResponse};
use actix_web::error::{ErrorBadRequest, ErrorUnauthorized, Result};
use actix_web::middleware::{Middleware, Started};
use crate::config::model::Config;
use crate::config::model::UserConfig;
use crate::server::router::AppState;
fn valid_username_and_token_in_vec(username: &str, token: &str, users: Vec<&UserConfig>) -> bool {
for user in users {
if user.username == username && user.token == token {
return true;
}
}
return false;
}
pub struct APIAuthForRootAndZone;
impl Middleware<AppState> for APIAuthForRootAndZone {
fn start(&self, req: &HttpRequest<AppState>) -> Result<Started> {
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");
if root.is_none() || zone.is_none() {
Ok(Started::Response(HttpResponse::BadRequest().into()))
} else {
match config.get_users_for_root_and_zone(root.unwrap(), zone.unwrap()) {
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() {
Ok(Started::Response(HttpResponse::BadRequest().into()))
} 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()))
}
}
}
None => Ok(Started::Response(HttpResponse::Unauthorized().into()))
}
}
}
}

1
src/server/mod.rs

@ -5,6 +5,7 @@ use crate::VERSION;
pub mod api;
pub mod error;
pub mod middleware;
pub mod router;
#[derive(Serialize)]

3
src/server/router.rs

@ -9,14 +9,13 @@ use crate::config::model::Config;
use crate::server;
pub struct AppState {
config: Arc<Config>
pub config: Arc<Config>
}
pub fn create(config: Arc<Config>) -> App<AppState> {
actix_web::App::with_state(AppState { config })
.middleware(Logger::default())
.scope("api/", server::api::route)
// .middleware()
.resource("/health", |r| {
r.method(http::Method::GET).with(server::healthcheck)
})

Loading…
Cancel
Save