Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# CHANGELOG.md

## v0.47.0 (unreleased)
- OIDC now checks both normalized request paths and their resolved SQL files against protected prefixes, closing authentication bypasses through path and clean-URL aliases. Nonce verification also rejects provider-returned Argon2 parameters outside SQLPage's fixed low-cost profile before hashing.
- `cargo install sqlpage`, and any build from the crates.io tarball, no longer needs internet access. The browser libraries now come from npm and ship inside the published crate. Building from a git checkout needs `npm ci` first. Pre-built binaries and the Docker image are unaffected.

## v0.46.3
Expand Down
2 changes: 1 addition & 1 deletion configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Here are the available configuration options and their default values:
| `configuration_directory` | `./sqlpage/` | The directory where the `sqlpage.json` file is located. This is used to find the path to [`templates/`](https://sql-page.com/custom_components.sql), [`migrations/`](https://sql-page.com/your-first-sql-website/migrations.sql), and `on_connect.sql`. Obviously, this configuration parameter can be set only through environment variables, not through the `sqlpage.json` file itself in order to find the `sqlpage.json` file. Be careful not to use a path that is accessible from the public WEB_ROOT |
| `allow_exec` | false | Allow usage of the `sqlpage.exec` function. Do this only if all users with write access to sqlpage query files and to the optional `sqlpage_files` table on the database are trusted. |
| `max_uploaded_file_size` | 5242880 | Maximum size of forms and uploaded files in bytes. Defaults to 5 MiB. |
| `oidc_protected_paths` | `["/"]` | A list of URL prefixes that should be protected by OIDC authentication. By default, all paths are protected (`["/"]`). If you want to make some pages public, you can restrict authentication to a sub-path, for instance `["/admin", "/users/settings"]`. All paths must start with a "/" and will be prepended by `site_prefix` if defined. When set through an environment variable, use a space-separated list, such as `/admin /users/settings`.|
| `oidc_protected_paths` | `["/"]` | A list of URL prefixes that should be protected by OIDC authentication. By default, all paths are protected (`["/"]`). If you want to make some pages public, you can restrict authentication to a sub-path, for instance `["/admin", "/users/settings"]`. Decoded dot and repeated-separator aliases are normalized before matching, and protected prefixes also match ASCII case aliases on case-insensitive storage. All paths must start with a "/" and will be prepended by `site_prefix` if defined. When set through an environment variable, use a space-separated list, such as `/admin /users/settings`.|
| `oidc_public_paths` | `[]` | A list of URL prefixes that should be publicly available. By default, no paths are publicly accessible (`[]`). If you want to make some pages public, you can bypass authentication for a sub-path, for instance `["/public/", "/assets/"]`. Keep in mind that without the closing backslashes, that any directory or file starting with `public` or `assets` will be publicly available. This will also overwrite any protected path restriction. If you have a private path `/private` and you define the public path `/private/public/` everything in `/private/public/` will be publicly accessible, while everything else in private will still need authentication. All paths must start with a "/" and will be prepended by `site_prefix` if defined. When set through an environment variable, use a space-separated list, such as `/public/ /assets/`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to update this one as well? if not LGTM!

| `oidc_issuer_url` | | The base URL of the [OpenID Connect provider](#openid-connect-oidc-authentication). Required for enabling Single Sign-On. |
| `oidc_client_id` | sqlpage | The ID that identifies your SQLPage application to the OIDC provider. You get this when registering your app with the provider. |
Expand Down
4 changes: 3 additions & 1 deletion examples/official-site/sso/single_sign_on.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ Sometimes, you don't want to protect your entire website with a login, but only
You can achieve this by adding the `oidc_protected_paths` option to your `sqlpage.json` file.

This option takes a list of URL prefixes. If a user requests a page whose address starts with one of these prefixes, they will be required to log in.
SQLPage decodes and normalizes path aliases such as `/admin/./dashboard.sql` before checking these prefixes, so another spelling of a protected URL still requires login. Public exceptions keep their configured spelling, and `/public/` remains distinct from `/public`.
For SQL files, the check also covers the file the URL resolves to. Protecting `/admin/dashboard.sql` therefore protects its shorter `/admin/dashboard` URL, and protecting `/admin/index.sql` protects `/admin/`.

**Example:** Protect only pages in the `/admin` folder.

Expand Down Expand Up @@ -158,4 +160,4 @@ When deploying to production:
- Verify your OIDC provider's logs for authentication attempts
- In production, confirm your domain name matches exactly in both the OIDC provider settings and `sqlpage.json`
- If [using a reverse proxy](/your-first-sql-website/nginx.sql), ensure it's properly configured to handle the OIDC callback path.
- If you have checked everything and you think the bug comes from SQLPage itself, [open an issue on our bug tracker](https://github.com/sqlpage/SQLPage/issues).
- If you have checked everything and you think the bug comes from SQLPage itself, [open an issue on our bug tracker](https://github.com/sqlpage/SQLPage/issues).
13 changes: 11 additions & 2 deletions src/webserver/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use actix_web::http::header::Accept;
use actix_web::http::header::{ContentType, Header, HttpDate, IfModifiedSince, LastModified};
use actix_web::http::{StatusCode, header};
use actix_web::web::PayloadConfig;
use actix_web::{App, Error, HttpResponse, HttpServer, dev::ServiceResponse, middleware, web};
use actix_web::{
App, Error, HttpMessage, HttpResponse, HttpServer, dev::ServiceResponse, middleware, web,
};
use opentelemetry_semantic_conventions::attribute as otel;
use tracing::{Instrument, Span};
use tracing_actix_web::{DefaultRootSpanBuilder, RootSpanBuilder, TracingLogger};
Expand Down Expand Up @@ -487,7 +489,14 @@ pub async fn main_handler(
.uri()
.path_and_query()
.ok_or_else(|| ErrorBadRequest("expected valid path with query from request"))?;
let routing_action = match calculate_route(path_and_query, &store, &app_state.config).await {
let authorized_route = service_request
.extensions_mut()
.remove::<super::routing::RoutingAction>();
let routing_action = match authorized_route {
Some(action) => Ok(action),
None => calculate_route(path_and_query, &store, &app_state.config).await,
};
let routing_action = match routing_action {
Ok(action) => action,
Err(e) => {
let e = e.context(format!(
Expand Down
Loading
Loading