Files
Wallos/api/admin/set_oidc_settings.php
Miguel Ribeiro 11eaf402e8 feat!: complete ui overhaul (#1108)
feat: option for the week to start on sunday
feat: redesign login / registration pages
feat: more statistics
feat: declarative oidc settings
feat: grid view for subscriptions
feat: subscription details popup
feat: translate categories with ai
feat: google image search with serpapi
feat: selfh.st image search
feat: dashboard icons image search
fix: improve background removal feature for logos
feat: v2.0 api - write endpoints
fix: include todays subscriptions on amount due this month
fix: calendar occurrences to respect subscription start date
fix: honor configured outbound proxy for logo search without reopening httpoxy SSRF bypass
fix: remove hardcode string from the admin page
fix: ssrf via http proxy env var in payments logo search
fix: require cron auth guard on storetotalyearlycost.php
fix: validate per-user smtp host against ssrf
fix: escape iCal property values to prevent crlf injection
2026-07-11 23:54:52 +02:00

225 lines
8.8 KiB
PHP

<?php
/*
This API Endpoint accepts POST requests only.
It receives the following parameters:
- api_key: the API key of the user (must be user ID 1 / admin).
- oidc_enabled: (optional) '1' to enable OIDC logins, '0' to disable.
- name: (optional) provider name.
- client_id: (optional) OAuth client ID.
- client_secret: (optional) OAuth client secret.
- authorization_url: (optional) authorization endpoint.
- token_url: (optional) token endpoint.
- user_info_url: (optional) userinfo endpoint.
- redirect_url: (optional) callback/redirect URL.
- logout_url: (optional) logout/end-session URL.
- user_identifier_field: (optional) field identifier (e.g. sub).
- scopes: (optional) scope list.
- auth_style: (optional) authentication style (auto/header/params).
- auto_create_user: (optional) '1' to auto-register new OIDC users, '0' otherwise.
- password_login_disabled: (optional) '1' to disable password logins, '0' otherwise.
- require_email_verified: (optional) '1' to reject unverified emails, '0' otherwise.
It returns a JSON object with the following properties:
- success: whether the request was successful (boolean).
- title: the title of the response (string).
- message: detailed information or error message (string).
Example response:
{
"success": true,
"title": "OIDC settings saved",
"message": "OIDC configurations have been saved successfully."
}
*/
require_once '../../includes/connect_endpoint.php';
require_once '../../includes/ssrf_helper.php';
require_once '../../includes/oidc_settings.php';
header('Content-Type: application/json; charset=UTF-8');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode([
'success' => false,
'title' => 'Invalid request method',
'message' => 'Only POST requests are allowed.'
]);
exit;
}
$apiKey = $_POST['api_key'] ?? $_POST['apiKey'] ?? null;
// Authenticate user first
if (!$apiKey) {
echo json_encode([
'success' => false,
'title' => 'Missing API key',
'message' => 'API key is required.'
]);
exit;
}
$sql = "SELECT * FROM user WHERE api_key = :apiKey";
$stmt = $db->prepare($sql);
$stmt->bindValue(':apiKey', $apiKey, SQLITE3_TEXT);
$result = $stmt->execute();
$user = $result->fetchArray(SQLITE3_ASSOC);
if (!$user) {
echo json_encode([
'success' => false,
'title' => 'Unauthorized',
'message' => 'Invalid API key.'
]);
exit;
}
$userId = $user['id'];
// Must be Admin user (ID 1)
if ($userId !== 1) {
echo json_encode([
'success' => false,
'title' => 'Forbidden',
'message' => 'Only the admin user (user ID 1) can update OIDC configurations.'
]);
exit;
}
// 1. Handle OIDC Enabled Toggle
if (isset($_POST['oidc_enabled'])) {
if (wallos_has_oidc_env_value('OIDC_ENABLED')) {
echo json_encode([
'success' => false,
'title' => 'Environment override',
'message' => 'OIDC enablement is managed by the OIDC_ENABLED environment variable.'
]);
exit;
}
$oidcEnabled = ($_POST['oidc_enabled'] === '1' || $_POST['oidc_enabled'] === 1) ? 1 : 0;
$stmtEnabled = $db->prepare('UPDATE admin SET oidc_oauth_enabled = :oidcEnabled WHERE id = 1');
$stmtEnabled->bindParam(':oidcEnabled', $oidcEnabled, SQLITE3_INTEGER);
$stmtEnabled->execute();
}
// 2. Handle OIDC detailed configurations
$oidcConfiguration = wallos_get_effective_oidc_configuration($db);
$managedFields = $oidcConfiguration['managed_fields'];
$dbSettings = wallos_get_db_oidc_settings($db);
$incomingMapping = [
'name' => $_POST['name'] ?? null,
'client_id' => $_POST['client_id'] ?? null,
'client_secret' => $_POST['client_secret'] ?? null,
'authorization_url' => $_POST['authorization_url'] ?? null,
'token_url' => $_POST['token_url'] ?? null,
'user_info_url' => $_POST['user_info_url'] ?? null,
'redirect_url' => $_POST['redirect_url'] ?? null,
'logout_url' => $_POST['logout_url'] ?? null,
'user_identifier_field' => $_POST['user_identifier_field'] ?? null,
'scopes' => $_POST['scopes'] ?? null,
'auth_style' => $_POST['auth_style'] ?? null,
'auto_create_user' => isset($_POST['auto_create_user']) ? intval($_POST['auto_create_user']) : null,
'password_login_disabled' => isset($_POST['password_login_disabled']) ? intval($_POST['password_login_disabled']) : null,
'require_email_verified' => isset($_POST['require_email_verified']) ? intval($_POST['require_email_verified']) : null,
];
// Merge if not managed by environment
$hasConfigChange = false;
foreach ($incomingMapping as $field => $value) {
if ($value !== null) {
if (isset($managedFields[$field])) {
// Cannot modify field overridden by environment variables
continue;
}
$dbSettings[$field] = $value;
$hasConfigChange = true;
}
}
if ($hasConfigChange) {
// SSRF validations
if ($dbSettings['token_url'] && validate_oidc_endpoint_url($dbSettings['token_url'], $db) === false) {
echo json_encode([
"success" => false,
"title" => "Security Error",
"message" => "Security Error: Token URL must not target link-local or loopback addresses."
]);
exit;
}
if ($dbSettings['user_info_url'] && validate_oidc_endpoint_url($dbSettings['user_info_url'], $db) === false) {
echo json_encode([
"success" => false,
"title" => "Security Error",
"message" => "Security Error: User Info URL must not target link-local or loopback addresses."
]);
exit;
}
// Save to oauth_settings table
$checkStmt = $db->prepare('SELECT COUNT(*) as count FROM oauth_settings WHERE id = 1');
$resultCheck = $checkStmt->execute();
$rowCheck = $resultCheck->fetchArray(SQLITE3_ASSOC);
if ($rowCheck['count'] > 0) {
$stmtSave = $db->prepare('UPDATE oauth_settings SET
name = :oidcName,
client_id = :oidcClientId,
client_secret = :oidcClientSecret,
authorization_url = :oidcAuthUrl,
token_url = :oidcTokenUrl,
user_info_url = :oidcUserInfoUrl,
redirect_url = :oidcRedirectUrl,
logout_url = :oidcLogoutUrl,
user_identifier_field = :oidcUserIdentifierField,
scopes = :oidcScopes,
auth_style = :oidcAuthStyle,
auto_create_user = :oidcAutoCreateUser,
password_login_disabled = :oidcPasswordLoginDisabled,
require_email_verified = :oidcRequireEmailVerified
WHERE id = 1');
} else {
$stmtSave = $db->prepare('INSERT INTO oauth_settings (
id, name, client_id, client_secret, authorization_url, token_url, user_info_url, redirect_url, logout_url, user_identifier_field, scopes, auth_style, auto_create_user, password_login_disabled, require_email_verified
) VALUES (
1, :oidcName, :oidcClientId, :oidcClientSecret, :oidcAuthUrl, :oidcTokenUrl, :oidcUserInfoUrl, :oidcRedirectUrl, :oidcLogoutUrl, :oidcUserIdentifierField, :oidcScopes, :oidcAuthStyle, :oidcAutoCreateUser, :oidcPasswordLoginDisabled, :oidcRequireEmailVerified
)');
}
$stmtSave->bindValue(':oidcName', $dbSettings['name'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcClientId', $dbSettings['client_id'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcClientSecret', $dbSettings['client_secret'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcAuthUrl', $dbSettings['authorization_url'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcTokenUrl', $dbSettings['token_url'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcUserInfoUrl', $dbSettings['user_info_url'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcRedirectUrl', $dbSettings['redirect_url'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcLogoutUrl', $dbSettings['logout_url'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcUserIdentifierField', $dbSettings['user_identifier_field'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcScopes', $dbSettings['scopes'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcAuthStyle', $dbSettings['auth_style'], SQLITE3_TEXT);
$stmtSave->bindValue(':oidcAutoCreateUser', $dbSettings['auto_create_user'], SQLITE3_INTEGER);
$stmtSave->bindValue(':oidcPasswordLoginDisabled', $dbSettings['password_login_disabled'], SQLITE3_INTEGER);
$stmtSave->bindValue(':oidcRequireEmailVerified', $dbSettings['require_email_verified'], SQLITE3_INTEGER);
$resultSave = $stmtSave->execute();
if (!$resultSave) {
echo json_encode([
'success' => false,
'title' => 'Database error',
'message' => 'Failed to save OIDC configurations.'
]);
exit;
}
}
echo json_encode([
'success' => true,
'title' => 'OIDC settings saved',
'message' => 'OIDC configurations have been saved successfully.'
]);
$db->close();
?>