Compare commits
No commits in common. "d70d622e041810c909d9a023e11ea110b403c925" and "fa31485e44680de0213553a2fc417eb57b290990" have entirely different histories.
d70d622e04
...
fa31485e44
6 changed files with 6 additions and 74 deletions
7
TODO.md
7
TODO.md
|
@ -28,13 +28,8 @@
|
||||||
|
|
||||||
- [ ] Support error responses by https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1
|
- [ ] Support error responses by https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1
|
||||||
|
|
||||||
- [ ] UserWebGUI: Redirect to login when JWT expire
|
- [ ] Redirect to login when JWT expire
|
||||||
- [ ] UserWebGUI: Show user authorizations.
|
|
||||||
- [ ] UserWebGUI: Show available apps
|
|
||||||
- [ ] UserWebGUI: Direct user grant flow, User can login to the target app/client, event if it did
|
|
||||||
not started here.
|
|
||||||
- [ ] Add admin panel via API
|
- [ ] Add admin panel via API
|
||||||
- [ ] AdminWebGUI: Ability to create invitation links
|
|
||||||
- [ ] Add admin CLI
|
- [ ] Add admin CLI
|
||||||
|
|
||||||
- [ ] add TOTP
|
- [ ] add TOTP
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
[instance]
|
|
||||||
base_uri = "http://localhost:8085"
|
|
||||||
name = "Example org"
|
|
||||||
logo_uri = "https://example.org/logo.png"
|
|
||||||
|
|
||||||
[[applications]]
|
|
||||||
slug = "demo_app"
|
|
||||||
name = "Demo app"
|
|
||||||
description = "A super application where you can do everything you want."
|
|
||||||
client_id = "a1785786-8be1-443c-9a6f-35feed703609"
|
|
||||||
client_secret = "49c6c16a-0a8a-4981-a60d-5cb96582cc1a"
|
|
||||||
allowed_redirect_uris = [
|
|
||||||
"http://localhost:9090/authorize",
|
|
||||||
"http://localhost:9876/callback"
|
|
||||||
]
|
|
||||||
authorize_flow = "implicit"
|
|
||||||
|
|
||||||
[[roles]]
|
|
||||||
slug = "basic"
|
|
||||||
name = "Basic"
|
|
||||||
description = "Basic user"
|
|
||||||
default = true
|
|
||||||
|
|
||||||
[[roles]]
|
|
||||||
slug = "admin"
|
|
||||||
name = "Administrator"
|
|
||||||
description = "Full power on organization instance"
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ allowed_redirect_uris = [
|
||||||
"http://localhost:9090/authorize",
|
"http://localhost:9090/authorize",
|
||||||
"http://localhost:9876/callback"
|
"http://localhost:9876/callback"
|
||||||
]
|
]
|
||||||
authorize_flow = "Implicit"
|
|
||||||
|
|
||||||
[[roles]]
|
[[roles]]
|
||||||
slug = "basic"
|
slug = "basic"
|
||||||
|
|
|
@ -8,7 +8,7 @@ use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{authorization::Authorization, config::AppAuthorizeFlow, token_claims::UserTokenClaims},
|
models::{authorization::Authorization, token_claims::UserTokenClaims},
|
||||||
renderer::TemplateRenderer, server::AppState,
|
renderer::TemplateRenderer, server::AppState,
|
||||||
services::oauth2::{parse_scope, verify_redirect_uri},
|
services::oauth2::{parse_scope, verify_redirect_uri},
|
||||||
utils::get_random_alphanumerical
|
utils::get_random_alphanumerical
|
||||||
|
@ -97,7 +97,6 @@ pub async fn authorize_form(
|
||||||
).into_response();
|
).into_response();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2. Check if the app is already authorized
|
// 2. Check if the app is already authorized
|
||||||
let authorizations_res = sqlx::query_as::<_, Authorization>(
|
let authorizations_res = sqlx::query_as::<_, Authorization>(
|
||||||
"SELECT * FROM authorizations WHERE user_id = $1 AND client_id = $2 AND scopes = $3"
|
"SELECT * FROM authorizations WHERE user_id = $1 AND client_id = $2 AND scopes = $3"
|
||||||
|
@ -140,19 +139,7 @@ pub async fn authorize_form(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Check for implicit/explicit flow
|
|
||||||
if app.authorize_flow == AppAuthorizeFlow::Implicit {
|
|
||||||
debug!("Performing Implicit authorization flow.");
|
|
||||||
// Authorization already given, just redirect to the app
|
|
||||||
return perform_authorize(
|
|
||||||
State(app_state),
|
|
||||||
Extension(token_claims),
|
|
||||||
Form(authorization_params)
|
|
||||||
).await.into_response()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Show form that POST to authorize
|
// 4. Show form that POST to authorize
|
||||||
debug!("Performing explicit authorization flow.");
|
|
||||||
renderer
|
renderer
|
||||||
.render(
|
.render(
|
||||||
"pages/authorize",
|
"pages/authorize",
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
use axum::{
|
|
||||||
extract::{OriginalUri, Request, State},
|
use axum::{extract::{OriginalUri, Request, State}, http::StatusCode, middleware::Next, response::{Html, IntoResponse, Redirect, Response}, Extension};
|
||||||
http::{HeaderMap, HeaderValue, StatusCode},
|
|
||||||
middleware::Next,
|
|
||||||
response::{Html, IntoResponse, Redirect, Response},
|
|
||||||
Extension
|
|
||||||
};
|
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -17,7 +12,6 @@ use crate::{
|
||||||
/// add optional auth to the extension data
|
/// add optional auth to the extension data
|
||||||
pub async fn auth_middleware(
|
pub async fn auth_middleware(
|
||||||
State(app_state): State<AppState>,
|
State(app_state): State<AppState>,
|
||||||
OriginalUri(original_uri): OriginalUri,
|
|
||||||
cookies: CookieJar,
|
cookies: CookieJar,
|
||||||
mut req: Request,
|
mut req: Request,
|
||||||
next: Next,
|
next: Next,
|
||||||
|
@ -32,13 +26,8 @@ pub async fn auth_middleware(
|
||||||
let token_claims: UserTokenClaims = match verify_token(&app_state.secrets, jwt) {
|
let token_claims: UserTokenClaims = match verify_token(&app_state.secrets, jwt) {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
// UserWebGUI: delete invalid JWT cookie
|
|
||||||
let mut headers = HeaderMap::new();
|
|
||||||
let jwt_cookie = "minauth_jwt=deleted; SameSite=Lax; Max-Age=0".to_string();
|
|
||||||
headers.insert("Set-Cookie", HeaderValue::from_str(&jwt_cookie).unwrap());
|
|
||||||
headers.insert("Location", HeaderValue::from_str(&original_uri.to_string()).unwrap());
|
|
||||||
return Err(
|
return Err(
|
||||||
(StatusCode::SEE_OTHER, headers, Html("Unauthorized: Invalid JWT cookie."))
|
(StatusCode::UNAUTHORIZED, Html("Unauthorized: The provided JWT is invalid."))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,15 +12,6 @@ struct InstanceConfig {
|
||||||
logo_uri: Option<String>
|
logo_uri: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
||||||
#[fully_pub]
|
|
||||||
enum AppAuthorizeFlow {
|
|
||||||
/// user must grant the app
|
|
||||||
Explicit,
|
|
||||||
/// authorized by default for all scopes
|
|
||||||
Implicit
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[fully_pub]
|
#[fully_pub]
|
||||||
struct Application {
|
struct Application {
|
||||||
|
@ -29,8 +20,7 @@ struct Application {
|
||||||
description: String,
|
description: String,
|
||||||
client_id: String,
|
client_id: String,
|
||||||
client_secret: String,
|
client_secret: String,
|
||||||
allowed_redirect_uris: Vec<String>,
|
allowed_redirect_uris: Vec<String>
|
||||||
authorize_flow: AppAuthorizeFlow
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
Loading…
Reference in a new issue