Compare commits

...

2 Commits

Author SHA1 Message Date
Nico Fricke
c6cc3b6418 add some more .bru updates 2025-01-20 15:31:11 +01:00
Nico Fricke
577fd4078b first prototype for simple authorization middleware 2025-01-20 15:30:35 +01:00
6 changed files with 92 additions and 15 deletions

View File

@ -1,16 +1,19 @@
use axum::extract::{FromRef, Request, State};
use crate::AppState;
use axum::extract::{FromRef, Path, Request, State};
use axum::http::StatusCode;
use axum::middleware::Next;
use axum::response::{IntoResponse, Response};
use axum_extra::headers::Authorization;
use axum_extra::headers::authorization::Bearer;
use axum_extra::headers::Authorization;
use axum_extra::TypedHeader;
use axum_jwks::Jwks;
use serde::{Deserialize, Serialize};
use crate::AppState;
use tracing::debug;
#[derive(Deserialize, Serialize)]
struct Claims {}
struct Claims {
sub: String,
}
impl FromRef<AppState> for Jwks {
fn from_ref(state: &AppState) -> Self {
@ -20,15 +23,35 @@ impl FromRef<AppState> for Jwks {
pub async fn validate_token(
State(state): State<AppState>,
TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>,
user: Option<Path<String>>,
auth_header: Option<TypedHeader<Authorization<Bearer>>>,
request: Request,
next: Next,
) -> Response {
let jwks = Jwks::from_ref(&state);
if jwks.validate_claims::<Claims>(bearer.token()).is_err() {
return StatusCode::UNAUTHORIZED.into_response();
if request.uri().path().starts_with("/api/v1/user/") {
if auth_header.is_none() {
debug!("No auth header passed.");
return StatusCode::UNAUTHORIZED.into_response();
}
match jwks.validate_claims::<Claims>(auth_header.unwrap().0 .0.token()) {
Err(err) => {
debug!("JWT validation failed: {:?}", err);
return StatusCode::UNAUTHORIZED.into_response();
}
Ok(jwk) => match user {
Some(user) => {
if !user.0.eq(&jwk.claims.sub) {
debug!("JWT sub {:?} does not match user {:?}", jwk.claims.sub, user.0);
return StatusCode::FORBIDDEN.into_response();
}
}
None => {
panic!("User was none")
}
},
}
}
next.run(request).await
}
}

View File

@ -0,0 +1,27 @@
meta {
name: Auth
type: http
seq: 5
}
get {
url:
body: none
auth: oauth2
}
auth:oauth2 {
grant_type: authorization_code
callback_url: https://localhost:1234
authorization_url: https://login.nifni.net/realms/public_selfhosted/protocol/openid-connect/auth
access_token_url: https://login.nifni.net/realms/public_selfhosted/protocol/openid-connect/token
client_id: casket
client_secret:
scope:
state:
pkce: false
}
script:post-response {
bru.setVar('access_token', res.body.access_token);
}

View File

@ -5,11 +5,15 @@ meta {
}
get {
url: http://localhost:3000/api/v1/user/test123/download?path=test/blub.txt
url: http://localhost:3000/api/v1/user/cdf48a88-f0ae-4c09-acc3-c9f056229d95/download?path=test/blub.txt
body: none
auth: none
auth: bearer
}
params:query {
path: test/blub.txt
}
auth:bearer {
token: {{access_token}}
}

View File

@ -5,12 +5,16 @@ meta {
}
get {
url: http://localhost:3000/api/v1/user/test123/files?path=&nesting=5
url: http://localhost:3000/api/v1/user/cdf48a88-f0ae-4c09-acc3-c9f056229d95/files?path=&nesting=5
body: none
auth: none
auth: bearer
}
params:query {
path:
nesting: 5
}
auth:bearer {
token: {{access_token}}
}

View File

@ -0,0 +1,15 @@
meta {
name: Invalid
type: http
seq: 6
}
get {
url: http://localhost:3000/api/v1/user//files
body: none
auth: bearer
}
auth:bearer {
token: {{access_token}}
}

View File

@ -5,9 +5,13 @@ meta {
}
post {
url: http://localhost:3000/api/v1/user/test123/files
url: http://localhost:3000/api/v1/user/cdf48a88-f0ae-4c09-acc3-c9f056229d95/files
body: multipartForm
auth: none
auth: bearer
}
auth:bearer {
token: {{access_token}}
}
body:multipart-form {