Initial commit

This commit is contained in:
Alex Wright 2019-08-03 20:15:52 +02:00
commit 9f8c47712a
4 changed files with 1568 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
**/*.rs.bk

1403
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

15
Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "auth"
version = "0.1.0"
authors = ["alex"]
edition = "2018"
[dependencies]
futures = "0.1.21"
hyper = "0.12.25"
hyper-router = "0.5"
ldap3 = "0.6"
tokio = "0.1.0"
base64 = "0.10.0"
#[dependencies.ldap3]
# version = "0.6"

148
src/main.rs Normal file
View File

@ -0,0 +1,148 @@
// #![deny(warnings)]
// extern crate futures;
extern crate base64;
extern crate hyper;
extern crate ldap3;
extern crate tokio;
use std::str::{
FromStr,
from_utf8,
};
use std::thread;
use hyper::rt::{Future};
use hyper::{Body, Request, Response, Server, StatusCode};
use hyper::header::{AUTHORIZATION};
use hyper_router::{Route, RouterBuilder, RouterService};
use base64::decode;
use ldap3::{ LdapConn, Scope, SearchEntry };
#[derive(Debug)]
struct BasicAuthentication {
pub username: String,
pub password: String,
}
#[derive(Debug)]
pub enum AuthError {
Parse,
Decode,
}
impl FromStr for BasicAuthentication {
type Err = AuthError;
fn from_str(s: &str) -> Result<BasicAuthentication, AuthError> {
match decode(s) {
Ok(bytes) => match from_utf8(&bytes) {
Ok(text) => {
let mut pair = text.splitn(2, ":");
Ok(BasicAuthentication {
username: pair.next().unwrap().to_string(),
password: pair.next().unwrap().to_string(),
})
},
Err(_) => Err(AuthError::Parse)
},
Err(_) => Err(AuthError::Decode)
}
}
}
#[derive(Debug)]
struct LdapUser {
pub dn: String,
pub services: Vec<String>,
}
fn auth_user(auth: &BasicAuthentication) -> Result<LdapUser, AuthError> {
let ldap = match LdapConn::new("ldap://192.168.122.61:389") {
Ok(conn) => conn,
Err(err) => panic!(err),
};
let base = format!("uid={},ou=people,dc=xeentech,dc=com", auth.username);
match ldap.simple_bind(&base, &auth.password).unwrap().success() {
Ok(ldap) => println!("Connected and authenticated"),
Err(err) => panic!("Failed to bind with dn+password"),
};
let filter = format!("(uid={})", auth.username);
let s = match ldap.search(&base, Scope::Subtree, &filter, vec!["mail", "enabledService"]) {
Ok(result) => {
let (rs, _) = result.success().unwrap();
rs
},
Err(err) => panic!("Search failed? {:?}", err),
};
// Grab the first, if any, result and discard the rest
let se = SearchEntry::construct(s.first().unwrap().to_owned());
let services = match se.attrs.get("enabledService") {
Some(services) => services.to_vec(),
None => [].to_vec(),
};
let mail = match se.attrs.get("mail") {
Some(mail) => mail.to_vec(),
None => [].to_ved(),
};
Ok(LdapUser {
dn: base,
services: services,
})
}
fn auth_handler(req: Request<Body>) -> Response<Body> {
let header = match req.headers().get(AUTHORIZATION) {
Some(auth_value) => auth_value.to_str().unwrap(),
None => return Response::builder()
.status(StatusCode::UNAUTHORIZED)
.body(Body::from("Authentication header missing"))
.unwrap(),
};
let (auth_type, credentials) = {
let mut split = header.split_ascii_whitespace();
let auth_type = split.next().unwrap();
let credentials = split.next().unwrap();
(auth_type, credentials)
};
if auth_type != "Basic" {
return Response::builder()
.status(StatusCode::UNAUTHORIZED)
.body(Body::from("Basic Authentication was expected"))
.unwrap();
}
let auth = BasicAuthentication::from_str(credentials).unwrap();
let worker = thread::spawn(move || {
let user = auth_user(&auth);
user
});
let user = worker.join().expect("ldap thread threw?");
Response::new(Body::from(format!("BasicAuthentication {:?}", user)))
}
fn hello(req: Request<Body>) -> Response<Body> {
Response::new(Body::from("Hi!"))
}
fn router_service() -> Result<RouterService, std::io::Error> {
let router = RouterBuilder::new()
.add(Route::get("/hello").using(hello))
.add(Route::post("/auth").using(auth_handler))
.build();
Ok(RouterService::new(router))
}
fn main() {
let addr = "0.0.0.0:3000".parse().expect("Bad Address");
let server = Server::bind(&addr)
.serve(router_service)
.map_err(|e| eprintln!("server error: {}", e));
println!("Listening on http://{}", addr);
tokio::run(server);
}