first prototype for simple authorization middleware
This commit is contained in:
parent
c74aef3eb0
commit
577fd4078b
@ -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::http::StatusCode;
|
||||||
use axum::middleware::Next;
|
use axum::middleware::Next;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use axum_extra::headers::Authorization;
|
|
||||||
use axum_extra::headers::authorization::Bearer;
|
use axum_extra::headers::authorization::Bearer;
|
||||||
|
use axum_extra::headers::Authorization;
|
||||||
use axum_extra::TypedHeader;
|
use axum_extra::TypedHeader;
|
||||||
use axum_jwks::Jwks;
|
use axum_jwks::Jwks;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::AppState;
|
use tracing::debug;
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct Claims {}
|
struct Claims {
|
||||||
|
sub: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl FromRef<AppState> for Jwks {
|
impl FromRef<AppState> for Jwks {
|
||||||
fn from_ref(state: &AppState) -> Self {
|
fn from_ref(state: &AppState) -> Self {
|
||||||
@ -20,15 +23,35 @@ impl FromRef<AppState> for Jwks {
|
|||||||
|
|
||||||
pub async fn validate_token(
|
pub async fn validate_token(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>,
|
user: Option<Path<String>>,
|
||||||
|
auth_header: Option<TypedHeader<Authorization<Bearer>>>,
|
||||||
request: Request,
|
request: Request,
|
||||||
next: Next,
|
next: Next,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let jwks = Jwks::from_ref(&state);
|
let jwks = Jwks::from_ref(&state);
|
||||||
|
if request.uri().path().starts_with("/api/v1/user/") {
|
||||||
if jwks.validate_claims::<Claims>(bearer.token()).is_err() {
|
if auth_header.is_none() {
|
||||||
return StatusCode::UNAUTHORIZED.into_response();
|
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
|
next.run(request).await
|
||||||
}
|
}
|
||||||
|
|||||||
28
casket-bruno-collection/Auth.bru
Normal file
28
casket-bruno-collection/Auth.bru
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
meta {
|
||||||
|
name: Auth
|
||||||
|
type: http
|
||||||
|
seq: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: http://localhost:3000/api/v1/user/test123/files?path=&nesting=5
|
||||||
|
body: none
|
||||||
|
auth: oauth2
|
||||||
|
}
|
||||||
|
|
||||||
|
params:query {
|
||||||
|
path:
|
||||||
|
nesting: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@ -7,10 +7,22 @@ meta {
|
|||||||
get {
|
get {
|
||||||
url: http://localhost:3000/api/v1/user/test123/files?path=&nesting=5
|
url: http://localhost:3000/api/v1/user/test123/files?path=&nesting=5
|
||||||
body: none
|
body: none
|
||||||
auth: none
|
auth: oauth2
|
||||||
}
|
}
|
||||||
|
|
||||||
params:query {
|
params:query {
|
||||||
path:
|
path:
|
||||||
nesting: 5
|
nesting: 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|||||||
11
casket-bruno-collection/Invalid.bru
Normal file
11
casket-bruno-collection/Invalid.bru
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
meta {
|
||||||
|
name: Invalid
|
||||||
|
type: http
|
||||||
|
seq: 6
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: http://localhost:3000/api/v1/user/
|
||||||
|
body: none
|
||||||
|
auth: none
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user