auth routes
This commit is contained in:
parent
7b50bfaffb
commit
6419fe55a0
@ -136,10 +136,6 @@ pub fn new_token(tx: &mut Transaction, id: Uuid) -> Result<String, Error> {
|
|||||||
let row = result.iter().next()
|
let row = result.iter().next()
|
||||||
.ok_or(format_err!("account not updated {:?}", id))?;
|
.ok_or(format_err!("account not updated {:?}", id))?;
|
||||||
|
|
||||||
let name: String = row.get(1);
|
|
||||||
|
|
||||||
info!("login account={:?}", name);
|
|
||||||
|
|
||||||
Ok(token)
|
Ok(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
|
|
||||||
use iron::status;
|
|
||||||
use iron::headers::{SetCookie};
|
|
||||||
use iron::prelude::*;
|
|
||||||
use persistent::Read;
|
|
||||||
use iron::typemap::Key;
|
|
||||||
use router::Router;
|
|
||||||
use iron::{AfterMiddleware};
|
|
||||||
use cookie::{Cookie, SameSite};
|
|
||||||
|
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
|
use cookie::{Cookie, SameSite};
|
||||||
use failure::Fail;
|
use failure::Fail;
|
||||||
|
use iron::headers::{Cookie as CookieHdr, SetCookie};
|
||||||
|
use iron::prelude::*;
|
||||||
|
use iron::status;
|
||||||
|
use iron::typemap::Key;
|
||||||
|
use iron::{typemap, BeforeMiddleware,AfterMiddleware};
|
||||||
|
use persistent::Read;
|
||||||
|
use router::Router;
|
||||||
|
|
||||||
// use warden::{warden};
|
// use warden::{warden};
|
||||||
// use pubsub::{pg_listen};
|
// use pubsub::{pg_listen};
|
||||||
@ -56,6 +53,38 @@ impl From<MnmlHttpError> for IronError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl typemap::Key for account::Account { type Value = account::Account; }
|
||||||
|
struct AuthMiddleware;
|
||||||
|
impl BeforeMiddleware for AuthMiddleware {
|
||||||
|
fn before(&self, req: &mut Request) -> IronResult<()> {
|
||||||
|
let state = req.get::<Read<State>>().unwrap();
|
||||||
|
let db = state.pool.get().or(Err(MnmlHttpError::DbError))?;
|
||||||
|
|
||||||
|
match req.headers.get::<CookieHdr>() {
|
||||||
|
Some(cookies) => {
|
||||||
|
for c in cookies.iter() {
|
||||||
|
let cookie = Cookie::parse(c)
|
||||||
|
.or(Err(MnmlHttpError::BadRequest))?;
|
||||||
|
|
||||||
|
// got auth token
|
||||||
|
if cookie.name() == TOKEN_HEADER {
|
||||||
|
match account::from_token(&db, cookie.value().to_string()) {
|
||||||
|
Ok(a) => req.extensions.insert::<account::Account>(a),
|
||||||
|
Err(_) => return Err(IronError::from(MnmlHttpError::Unauthorized)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const AUTH_CLEAR: &str =
|
||||||
|
"x-auth-token=; HttpOnly; SameSite=Strict; Max-Age=-1;";
|
||||||
|
|
||||||
struct ErrorHandler;
|
struct ErrorHandler;
|
||||||
impl AfterMiddleware for ErrorHandler {
|
impl AfterMiddleware for ErrorHandler {
|
||||||
fn catch(&self, _: &mut Request, mut err: IronError) -> IronResult<Response> {
|
fn catch(&self, _: &mut Request, mut err: IronError) -> IronResult<Response> {
|
||||||
@ -63,12 +92,7 @@ impl AfterMiddleware for ErrorHandler {
|
|||||||
// on unauthorized we clear the auth token
|
// on unauthorized we clear the auth token
|
||||||
match err.response.status {
|
match err.response.status {
|
||||||
Some(status::Unauthorized) => {
|
Some(status::Unauthorized) => {
|
||||||
let v = Cookie::build(TOKEN_HEADER, "")
|
err.response.headers.set(SetCookie(vec![AUTH_CLEAR.to_string()]));
|
||||||
.http_only(true)
|
|
||||||
.same_site(SameSite::Strict)
|
|
||||||
.max_age(Duration::seconds(-1)) // 1 week aligns with db set
|
|
||||||
.finish();
|
|
||||||
err.response.headers.set(SetCookie(vec![v.to_string()]));
|
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
@ -79,23 +103,18 @@ impl AfterMiddleware for ErrorHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn logout(r: HttpRequest, state: web::Data<State>) -> Result<HttpResponse, MnmlHttpError> {
|
fn token_res(token: String) -> Response {
|
||||||
// match r.cookie("x-auth-token") {
|
let v = Cookie::build(TOKEN_HEADER, token)
|
||||||
// Some(t) => {
|
.http_only(true)
|
||||||
// let db = state.pool.get().or(Err(MnmlHttpError::ServerError))?;
|
.same_site(SameSite::Strict)
|
||||||
// let mut tx = db.transaction().or(Err(MnmlHttpError::ServerError))?;
|
.max_age(Duration::weeks(1)) // 1 week aligns with db set
|
||||||
// match account::from_token(&mut tx, t.value().to_string()) {
|
.finish();
|
||||||
// Ok(a) => {
|
|
||||||
// account::new_token(&mut tx, a.id).or(Err(MnmlHttpError::Unauthorized))?;
|
let mut res = Response::with(status::Ok);
|
||||||
// tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
res.headers.set(SetCookie(vec![v.to_string()]));
|
||||||
// return Ok(logout_res());
|
|
||||||
// },
|
return res;
|
||||||
// Err(_) => Err(MnmlHttpError::Unauthorized),
|
}
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// None => Err(MnmlHttpError::Unauthorized),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug,Clone,Deserialize)]
|
#[derive(Debug,Clone,Deserialize)]
|
||||||
@ -118,7 +137,7 @@ fn register(req: &mut Request) -> IronResult<Response> {
|
|||||||
match account::create(¶ms.name, ¶ms.password, ¶ms.code, &mut tx) {
|
match account::create(¶ms.name, ¶ms.password, ¶ms.code, &mut tx) {
|
||||||
Ok(token) => {
|
Ok(token) => {
|
||||||
tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
||||||
Ok(login_res(token))
|
Ok(token_res(token))
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("{:?}", e);
|
warn!("{:?}", e);
|
||||||
@ -133,19 +152,6 @@ struct LoginBody {
|
|||||||
password: String,
|
password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn login_res(token: String) -> Response {
|
|
||||||
let v = Cookie::build(TOKEN_HEADER, token)
|
|
||||||
.http_only(true)
|
|
||||||
.same_site(SameSite::Strict)
|
|
||||||
.max_age(Duration::weeks(1)) // 1 week aligns with db set
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let mut res = Response::with(status::Ok);
|
|
||||||
res.headers.set(SetCookie(vec![v.to_string()]));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn login(req: &mut Request) -> IronResult<Response> {
|
fn login(req: &mut Request) -> IronResult<Response> {
|
||||||
let state = req.get::<Read<State>>().unwrap();
|
let state = req.get::<Read<State>>().unwrap();
|
||||||
let params = match req.get::<bodyparser::Struct<LoginBody>>() {
|
let params = match req.get::<bodyparser::Struct<LoginBody>>() {
|
||||||
@ -160,7 +166,7 @@ fn login(req: &mut Request) -> IronResult<Response> {
|
|||||||
Ok(a) => {
|
Ok(a) => {
|
||||||
let token = account::new_token(&mut tx, a.id).or(Err(MnmlHttpError::ServerError))?;
|
let token = account::new_token(&mut tx, a.id).or(Err(MnmlHttpError::ServerError))?;
|
||||||
tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
||||||
Ok(login_res(token))
|
Ok(token_res(token))
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("{:?}", e);
|
warn!("{:?}", e);
|
||||||
@ -169,6 +175,27 @@ fn login(req: &mut Request) -> IronResult<Response> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn logout(req: &mut Request) -> IronResult<Response> {
|
||||||
|
let state = req.get::<Read<State>>().unwrap();
|
||||||
|
match req.extensions.get::<account::Account>() {
|
||||||
|
Some(a) => {
|
||||||
|
let db = state.pool.get().or(Err(MnmlHttpError::DbError))?;
|
||||||
|
let mut tx = db.transaction().or(Err(MnmlHttpError::DbError))?;
|
||||||
|
|
||||||
|
account::new_token(&mut tx, a.id).or(Err(MnmlHttpError::Unauthorized))?;
|
||||||
|
|
||||||
|
tx.commit().or(Err(MnmlHttpError::ServerError))?;
|
||||||
|
|
||||||
|
let mut res = Response::with(status::Ok);
|
||||||
|
res.headers.set(SetCookie(vec![AUTH_CLEAR.to_string()]));
|
||||||
|
Ok(res)
|
||||||
|
|
||||||
|
},
|
||||||
|
None => Err(IronError::from(MnmlHttpError::Unauthorized)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const MAX_BODY_LENGTH: usize = 1024 * 1024 * 10;
|
const MAX_BODY_LENGTH: usize = 1024 * 1024 * 10;
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
@ -181,10 +208,13 @@ impl Key for State { type Value = State; }
|
|||||||
pub fn start(pool: PgPool) {
|
pub fn start(pool: PgPool) {
|
||||||
let mut router = Router::new();
|
let mut router = Router::new();
|
||||||
router.post("/api/login", login, "login");
|
router.post("/api/login", login, "login");
|
||||||
|
router.post("/api/logout", logout, "logout");
|
||||||
|
router.post("/api/register", register, "register");
|
||||||
|
|
||||||
let mut chain = Chain::new(router);
|
let mut chain = Chain::new(router);
|
||||||
chain.link(Read::<State>::both(State { pool }));
|
chain.link(Read::<State>::both(State { pool }));
|
||||||
chain.link_before(Read::<bodyparser::MaxBodyLength>::one(MAX_BODY_LENGTH));
|
chain.link_before(Read::<bodyparser::MaxBodyLength>::one(MAX_BODY_LENGTH));
|
||||||
|
chain.link_before(AuthMiddleware);
|
||||||
chain.link_after(ErrorHandler);
|
chain.link_after(ErrorHandler);
|
||||||
Iron::new(chain).http("127.0.0.1:40000").unwrap();
|
Iron::new(chain).http("127.0.0.1:40000").unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,7 @@ pub fn start(pool: PgPool) {
|
|||||||
|
|
||||||
let (acc_s, acc_r) = unbounded();
|
let (acc_s, acc_r) = unbounded();
|
||||||
|
|
||||||
|
// search through the ws request for the auth cookie
|
||||||
let cb = |req: &Request| {
|
let cb = |req: &Request| {
|
||||||
let err = || ErrorResponse {
|
let err = || ErrorResponse {
|
||||||
error_code: StatusCode::FORBIDDEN,
|
error_code: StatusCode::FORBIDDEN,
|
||||||
@ -50,7 +51,6 @@ pub fn start(pool: PgPool) {
|
|||||||
|
|
||||||
// got auth token
|
// got auth token
|
||||||
if cookie.name() == TOKEN_HEADER {
|
if cookie.name() == TOKEN_HEADER {
|
||||||
info!("{:?}", cookie.value().to_string());
|
|
||||||
acc_s.send(Some(cookie.value().to_string())).or(Err(err()))?;
|
acc_s.send(Some(cookie.value().to_string())).or(Err(err()))?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -61,6 +61,7 @@ pub fn start(pool: PgPool) {
|
|||||||
|
|
||||||
let mut websocket = accept_hdr(stream.unwrap(), cb).unwrap();
|
let mut websocket = accept_hdr(stream.unwrap(), cb).unwrap();
|
||||||
|
|
||||||
|
// get a copy of the account
|
||||||
let account = match acc_r.recv().unwrap() {
|
let account = match acc_r.recv().unwrap() {
|
||||||
Some(t) => {
|
Some(t) => {
|
||||||
let db = ws_pool.get()
|
let db = ws_pool.get()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user