From b15eb449dcebaaec6eae116da614df04be462753 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 13 Jun 2022 18:29:37 +0200 Subject: [PATCH] switch to role based auth --- src/api/auth.rs | 6 +++--- src/api/handles.rs | 2 -- src/api/routes.rs | 25 +++++++++++++++++++------ src/api/utils.rs | 17 +++++++++++++++++ src/bin/ffpapi.rs | 9 ++++++--- 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/api/auth.rs b/src/api/auth.rs index 9c2f902d..14c625a2 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -13,16 +13,16 @@ const JWT_EXPIRATION_MINUTES: i64 = 60; pub struct Claims { pub id: i64, pub username: String, - pub permissions: Vec, + pub role: String, exp: i64, } impl Claims { - pub fn new(id: i64, username: String, permissions: Vec) -> Self { + pub fn new(id: i64, username: String, role: String) -> Self { Self { id, username, - permissions, + role, exp: (Utc::now() + Duration::minutes(JWT_EXPIRATION_MINUTES)).timestamp(), } } diff --git a/src/api/handles.rs b/src/api/handles.rs index c4f6ce40..6882c5c7 100644 --- a/src/api/handles.rs +++ b/src/api/handles.rs @@ -128,8 +128,6 @@ pub async fn db_get_settings(id: &i64) -> Result { let result: Settings = sqlx::query_as(query).bind(id).fetch_one(&conn).await?; conn.close().await; - println!("{:#?}", result); - Ok(result) } diff --git a/src/api/routes.rs b/src/api/routes.rs index 889beccb..fcfc32a6 100644 --- a/src/api/routes.rs +++ b/src/api/routes.rs @@ -1,5 +1,5 @@ use actix_web::{get, http::StatusCode, patch, post, put, web, Responder}; -use actix_web_grants::proc_macro::has_permissions; +use actix_web_grants::proc_macro::has_any_role; use argon2::{ password_hash::{rand_core::OsRng, PasswordHash, SaltString}, Argon2, PasswordHasher, PasswordVerifier, @@ -14,6 +14,7 @@ use crate::api::{ db_add_user, db_get_settings, db_login, db_role, db_update_settings, db_update_user, }, models::{LoginUser, Settings, User}, + utils::Role, }; #[derive(Serialize)] @@ -25,7 +26,7 @@ struct ResponseObj { /// curl -X GET http://127.0.0.1:8080/api/settings/1 -H "Authorization: Bearer " #[get("/settings/{id}")] -#[has_permissions("admin", "user")] +#[has_any_role("Role::Admin", "Role::User", type = "Role")] async fn get_settings(id: web::Path) -> Result { if let Ok(settings) = db_get_settings(&id).await { return Ok(web::Json(ResponseObj { @@ -43,7 +44,7 @@ async fn get_settings(id: web::Path) -> Result" #[patch("/settings/{id}")] -#[has_permissions("admin")] +#[has_any_role("Role::Admin", type = "Role")] async fn patch_settings( id: web::Path, data: web::Json, @@ -55,10 +56,22 @@ async fn patch_settings( Err(ServiceError::InternalServerError) } +#[get("/playout/config/{id}")] +#[has_any_role("Role::Admin", "Role::User", type = "Role")] +async fn get_playout_config(id: web::Path) -> Result { + if let Ok(settings) = db_get_settings(&id).await { + println!("{:?}", settings.config_path); + + return Ok("settings"); + }; + + Err(ServiceError::InternalServerError) +} + /// curl -X PUT http://localhost:8080/api/user/1 --header 'Content-Type: application/json' \ /// --data '{"email": "", "password": ""}' --header 'Authorization: ' #[put("/user/{id}")] -#[has_permissions("admin", "user")] +#[has_any_role("Role::Admin", "Role::User", type = "Role")] async fn update_user( id: web::Path, user: web::ReqData, @@ -98,7 +111,7 @@ async fn update_user( /// -d '{"email": "", "username": "", "password": "", "role_id": 1}' \ /// --header 'Authorization: Bearer ' #[post("/user/")] -#[has_permissions("admin")] +#[has_any_role("Role::Admin", type = "Role")] async fn add_user(data: web::Json) -> Result { match db_add_user(data.into_inner()).await { Ok(_) => Ok("Add User Success"), @@ -127,7 +140,7 @@ pub async fn login(credentials: web::Json) -> impl Responder { let role = db_role(&user.role_id.unwrap_or_default()) .await .unwrap_or_else(|_| "guest".to_string()); - let claims = Claims::new(user.id, user.username.clone(), vec![role.clone()]); + let claims = Claims::new(user.id, user.username.clone(), role.clone()); if let Ok(token) = create_jwt(claims) { user.token = Some(token); diff --git a/src/api/utils.rs b/src/api/utils.rs index 58017868..71caa0aa 100644 --- a/src/api/utils.rs +++ b/src/api/utils.rs @@ -7,6 +7,23 @@ use crate::api::{ models::User, }; +#[derive(PartialEq, Clone)] +pub enum Role { + Admin, + User, + Guest, +} + +impl Role { + pub fn set_role(role: &str) -> Self { + match role { + "admin" => Role::Admin, + "user" => Role::User, + _ => Role::Guest, + } + } +} + #[derive(Debug, sqlx::FromRow)] pub struct GlobalSettings { pub secret: String, diff --git a/src/bin/ffpapi.rs b/src/bin/ffpapi.rs index eadbea87..220bef3c 100644 --- a/src/bin/ffpapi.rs +++ b/src/bin/ffpapi.rs @@ -13,8 +13,8 @@ use ffplayout_engine::{ args_parse::Args, auth, models::LoginUser, - routes::{add_user, get_settings, login, patch_settings, update_user}, - utils::{init_config, run_args}, + routes::{add_user, get_playout_config, get_settings, login, patch_settings, update_user}, + utils::{init_config, run_args, Role}, }, utils::{init_logging, GlobalConfig}, }; @@ -22,10 +22,12 @@ use ffplayout_engine::{ async fn validator(req: ServiceRequest, credentials: BearerAuth) -> Result { // We just get permissions from JWT let claims = auth::decode_jwt(credentials.token()).await?; - req.attach(claims.permissions); + req.attach(vec![Role::set_role(&claims.role)]); req.extensions_mut() .insert(LoginUser::new(claims.id, claims.username)); + + println!("{:#?}", req); Ok(req) } @@ -63,6 +65,7 @@ async fn main() -> std::io::Result<()> { web::scope("/api") .wrap(auth) .service(add_user) + .service(get_playout_config) .service(get_settings) .service(patch_settings) .service(update_user),