diff --git a/configuration.md b/configuration.md index c5911799..53b3d9ab 100644 --- a/configuration.md +++ b/configuration.md @@ -25,8 +25,8 @@ 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"]`. | -| `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. +| `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.| +| `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. | `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. | | `oidc_client_secret` | | The secret key for your SQLPage application. Keep this confidential as it allows your app to authenticate with the OIDC provider. | diff --git a/src/app_config.rs b/src/app_config.rs index 9e601ade..34acc10e 100644 --- a/src/app_config.rs +++ b/src/app_config.rs @@ -131,6 +131,23 @@ impl AppConfig { } } anyhow::ensure!(self.max_pending_rows > 0, "max_pending_rows cannot be null"); + + for path in &self.oidc_protected_paths { + if !path.starts_with('/') { + return Err(anyhow::anyhow!( + "All protected paths must start with '/', but found: '{path}'" + )); + } + } + + for path in &self.oidc_public_paths { + if !path.starts_with('/') { + return Err(anyhow::anyhow!( + "All public paths must start with '/', but found: '{path}'" + )); + } + } + Ok(()) } } diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index aa069959..ea429acc 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -92,8 +92,6 @@ impl TryFrom<&AppConfig> for OidcConfig { let client_secret = config.oidc_client_secret.as_ref().ok_or(Some( "The \"oidc_client_secret\" setting is required to authenticate with the OIDC provider", ))?; - let protected_paths: Vec = config.oidc_protected_paths.clone(); - let public_paths: Vec = config.oidc_public_paths.clone(); let app_host = get_app_host(config); @@ -101,6 +99,18 @@ impl TryFrom<&AppConfig> for OidcConfig { let redirect_uri = format!("{site_prefix_trimmed}{SQLPAGE_REDIRECT_URI}"); let logout_uri = format!("{site_prefix_trimmed}{SQLPAGE_LOGOUT_URI}"); + let protected_paths: Vec = config + .oidc_protected_paths + .iter() + .map(|path| format!("{site_prefix_trimmed}{path}")) + .collect(); + + let public_paths: Vec = config + .oidc_public_paths + .iter() + .map(|path| format!("{site_prefix_trimmed}{path}")) + .collect(); + Ok(Self { issuer_url: issuer_url.clone(), client_id: config.oidc_client_id.clone(),