Compare commits
2 Commits
c32477b307
...
62659a7746
Author | SHA1 | Date | |
---|---|---|---|
62659a7746 | |||
687d366f3d |
32
rust-backend/Cargo.lock
generated
32
rust-backend/Cargo.lock
generated
@ -423,6 +423,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -583,6 +584,15 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
@ -1082,6 +1092,17 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
@ -1101,9 +1122,14 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||
name = "skantravels"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-utils",
|
||||
"actix-web",
|
||||
"base64",
|
||||
"hmac",
|
||||
"refinery",
|
||||
"rusqlite",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1131,6 +1157,12 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.74"
|
||||
|
@ -4,7 +4,12 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.22.1"
|
||||
sha2 = "0.10.8"
|
||||
hmac = "0.12.1"
|
||||
serde_json = "1.0.124"
|
||||
actix-web = "4"
|
||||
actix-utils = "3.0.1"
|
||||
refinery = { version = "0.8.14", features = ["rusqlite"] }
|
||||
rusqlite = { version = "0.31", features = ["bundled"] }
|
||||
|
||||
|
66
rust-backend/src/auth.rs
Normal file
66
rust-backend/src/auth.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use actix_web::{Error, FromRequest, HttpRequest};
|
||||
use actix_web::dev::Payload;
|
||||
use actix_web::error::ErrorUnauthorized;
|
||||
use actix_utils::future::{Ready, ok, err};
|
||||
use std::string::String;
|
||||
use std::option::Option;
|
||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use sha2::Sha256;
|
||||
use hmac::{Hmac, Mac};
|
||||
use serde_json::Value;
|
||||
|
||||
pub struct AuthorizedUser {
|
||||
pub user_id: String,
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
impl FromRequest for AuthorizedUser {
|
||||
type Error = Error;
|
||||
type Future = Ready<Result<Self, Self::Error>>;
|
||||
|
||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||
let user = get_authorized_user(req);
|
||||
|
||||
if user.is_some() {
|
||||
ok(user.unwrap())
|
||||
} else {
|
||||
err(ErrorUnauthorized("Unauthorized"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_authorized_user(req: &HttpRequest) -> Option<AuthorizedUser> {
|
||||
let token = req.headers()
|
||||
.get("Authorization")
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.take_if(|value| value.starts_with("Bearer "))
|
||||
.and_then(|value| Some(value.replace("Bearer ", "")));
|
||||
|
||||
if token.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let token = token.unwrap();
|
||||
let jwt_parts: Vec<&str> = token.split('.').collect();
|
||||
|
||||
if jwt_parts.len() != 3 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let header: Value = serde_json::from_slice(&URL_SAFE_NO_PAD.decode(jwt_parts.get(0).unwrap()).ok()?).ok()?;
|
||||
let payload: Value = serde_json::from_slice(&URL_SAFE_NO_PAD.decode(jwt_parts.get(1).unwrap()).ok()?).ok()?;
|
||||
let signature = URL_SAFE_NO_PAD.decode(jwt_parts.get(2).unwrap()).ok()?;
|
||||
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice("DenHerMåAldrigVæreOffentligKunIDetteDemoProjekt".as_bytes()).ok()?;
|
||||
mac.update(format!("{}.{}", jwt_parts.get(0).unwrap(), jwt_parts.get(1).unwrap()).as_bytes());
|
||||
|
||||
if mac.verify_slice(&signature).is_err() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(AuthorizedUser {
|
||||
user_id: payload["sub"].as_str()?.to_string(),
|
||||
username: payload["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"].as_str()?.to_string(),
|
||||
})
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
mod auth;
|
||||
|
||||
use actix_web::{get, Responder, HttpResponse, HttpServer, App, web};
|
||||
use std::sync::{Mutex, Arc};
|
||||
use crate::auth::AuthorizedUser;
|
||||
|
||||
mod embedded {
|
||||
use refinery::embed_migrations;
|
||||
@ -21,6 +24,11 @@ async fn healthcheck(data: web::Data<AppData>) -> impl Responder {
|
||||
|
||||
}
|
||||
|
||||
#[get("/authorized")]
|
||||
async fn authorized(auth: AuthorizedUser) -> impl Responder {
|
||||
HttpResponse::Ok().body(format!("Authorized as {} ({})", auth.username, auth.user_id))
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let port = std::env::var("RUST_BACKEND_PORT")
|
||||
@ -50,8 +58,10 @@ async fn main() -> std::io::Result<()> {
|
||||
database: conn,
|
||||
}))
|
||||
.service(healthcheck)
|
||||
.service(authorized)
|
||||
})
|
||||
.bind(("0.0.0.0", port))?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user