Add authentication #1

Merged
hannaeko merged 11 commits from feature/auth into master 2021-04-03 17:54:16 +02:00
6 changed files with 54 additions and 58 deletions
Showing only changes of commit b758c87521 - Show all commits

change architecture

Hannaeko 2021-04-02 16:09:51 -04:00

View file

@ -1,2 +0,0 @@
pub mod providers;
pub mod routes;

View file

@ -1,12 +0,0 @@
// enum Providers {
// Ldap(LdapProvider),
// Local(LocalProvider),
// }
// struct LdapProvider {
// user_filter: String,
// group_filter: String,
// // ...
// }
// struct LocalProvider;

View file

@ -4,62 +4,23 @@
#[macro_use] extern crate rocket_contrib;
#[macro_use] extern crate diesel;
use rocket::State;
use rocket::http::Status;
use rocket_contrib::json::Json;
use trust_dns_client::client::{Client, SyncClient};
use trust_dns_client::client::SyncClient;
use trust_dns_client::tcp::TcpClientConnection;
use trust_dns_client::op::{DnsResponse, ResponseCode};
use trust_dns_client::rr::{DNSClass, Name, RecordType};
mod models;
mod config;
mod auth;
mod schema;
mod routes;
use models::errors::ErrorResponse;
use models::users::UserInfo;
use auth::routes::*;
use routes::users::*;
use routes::zones::*;
#[database("db")]
pub struct DbConn(diesel::SqliteConnection);
type DnsClient = SyncClient<TcpClientConnection>;
#[get("/zones/<zone>/records")]
fn get_zone_records(
client: State<SyncClient<TcpClientConnection>>,
_user_info: UserInfo,
zone: String
) -> Result<Json<Vec<models::dns::Record>>, ErrorResponse<()>> {
// TODO: Implement FromParam for Name
let name = Name::from_utf8(&zone).unwrap();
let response: DnsResponse = client.query(&name, DNSClass::IN, RecordType::AXFR).unwrap();
if response.response_code() != ResponseCode::NoError {
return ErrorResponse::new(
Status::NotFound,
format!("zone {} could not be found", name.to_utf8())
).err()
}
let answers = response.answers();
let mut records: Vec<_> = answers.to_vec().into_iter()
.map(|record| models::dns::Record::from(record))
.filter(|record| match record.rdata {
models::dns::RData::NULL { .. } | models::dns::RData::DNSSEC(_) => false,
_ => true,
}).collect();
// AXFR response ends with SOA, we remove it so it is not doubled in the response.
records.pop();
Ok(Json(records))
}
#[launch]
fn rocket() -> rocket::Rocket {

2
src/routes/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod users;
pub mod zones;

39
src/routes/users.rs Normal file
View file

@ -0,0 +1,39 @@
use rocket_contrib::json::Json;
use rocket::{Response, State};
use rocket::http::Status;
use crate::config::Config;
use crate::DbConn;
use crate::models::errors::{ErrorResponse, make_500};
use crate::models::users::{LocalUser, CreateUserRequest, AuthClaims, AuthTokenRequest, AuthTokenResponse};
#[post("/users/me/token", data = "<auth_request>")]
pub async fn create_auth_token(
conn: DbConn,
config: State<'_, Config>,
auth_request: Json<AuthTokenRequest>
) -> Result<Json<AuthTokenResponse>, ErrorResponse<()>> {
let user_info = conn.run(move |c| {
LocalUser::get_user_by_creds(c, &auth_request.username, &auth_request.password)
}).await?;
let token = AuthClaims::new(&user_info, config.web_app.token_duration)
.encode(&config.web_app.secret)
.map_err(|e| make_500(e))?;
Ok(Json(AuthTokenResponse { token }))
}
#[post("/users", data = "<user_request>")]
pub async fn create_user<'r>(conn: DbConn, user_request: Json<CreateUserRequest>) -> Result<Response<'r>, ErrorResponse<()>>{
// TODO: Check current user if any to check if user has permission to create users (with or without role)
let _user_info = conn.run(|c| {
LocalUser::create_user(&c, user_request.into_inner())
}).await?;
Response::build()
.status(Status::Created)
.ok()
}

47
src/routes/zones.rs Normal file
View file

@ -0,0 +1,47 @@
use rocket::State;
use rocket::http::Status;
use rocket_contrib::json::Json;
use trust_dns_client::client::{Client};
use trust_dns_client::op::{DnsResponse, ResponseCode};
use trust_dns_client::rr::{DNSClass, Name, RecordType};
use crate::models::dns;
use crate::models::errors::ErrorResponse;
use crate::models::users::UserInfo;
use crate::DnsClient;
#[get("/zones/<zone>/records")]
pub fn get_zone_records(
client: State<DnsClient>,
_user_info: UserInfo,
zone: String
) -> Result<Json<Vec<dns::Record>>, ErrorResponse<()>> {
// TODO: Implement FromParam for Name
let name = Name::from_utf8(&zone).unwrap();
let response: DnsResponse = client.query(&name, DNSClass::IN, RecordType::AXFR).unwrap();
if response.response_code() != ResponseCode::NoError {
return ErrorResponse::new(
Status::NotFound,
format!("zone {} could not be found", name.to_utf8())
).err()
}
let answers = response.answers();
let mut records: Vec<_> = answers.to_vec().into_iter()
.map(|record| dns::Record::from(record))
.filter(|record| match record.rdata {
dns::RData::NULL { .. } | dns::RData::DNSSEC(_) => false,
_ => true,
}).collect();
// AXFR response ends with SOA, we remove it so it is not doubled in the response.
records.pop();
Ok(Json(records))
}