Compare commits
32
Commits
f2810a7950
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b9a2dd109 | ||
|
|
fc96702600 | ||
|
|
efbfbe8441 | ||
|
|
9163437130 | ||
|
|
dd4b382d8c | ||
|
|
9dc05a72b5 | ||
|
|
9e4c6571cf | ||
|
|
2efd469f1e | ||
|
|
5ec16d4cbc | ||
|
|
49d2e818d0 | ||
|
|
ff8cf722f4 | ||
|
|
ca1e36b0b6 | ||
|
|
c5c1081589 | ||
|
|
0dd3e43893 | ||
|
|
07d3895eb5 | ||
|
|
4b7abac7ca | ||
|
|
e9bc19d5e2 | ||
|
|
124c5a1ff6 | ||
|
|
0cf83eb9d6 | ||
|
|
addf70b7bb | ||
|
|
221d435480 | ||
|
|
65a69b585d | ||
|
|
6f8dd7bbe3 | ||
|
|
933134e3b0 | ||
|
|
58de6d1073 | ||
|
|
ceb0ce1778 | ||
|
|
9ddcc36893 | ||
|
|
97a31db020 | ||
|
|
a759eb206f | ||
|
|
5cd6084c3c | ||
|
|
59e99b74a7 | ||
|
|
33644b69c3 |
No files matched your search
+12
-13
@@ -18,19 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
# Clean up
|
# Clean up
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# Install Composer (stand‑alone)
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
|
||||||
|
|
||||||
# Apache on 8069
|
|
||||||
COPY apache_ports.conf /etc/apache2/ports.conf
|
|
||||||
COPY apache_vhost.conf /etc/apache2/sites-available/000-default.conf
|
|
||||||
COPY web/ /var/www/html/
|
|
||||||
# Set up composer
|
|
||||||
WORKDIR /var/www/html/
|
|
||||||
RUN composer install --no-dev --optimize-autoloader --no-interaction
|
|
||||||
|
|
||||||
# API on 5000
|
# API on 5000
|
||||||
RUN mkdir -p /opt/Fitness
|
RUN mkdir -p /opt/Fitness
|
||||||
RUN python3 -m venv /opt/Fitness/venv
|
RUN python3 -m venv /opt/Fitness/venv
|
||||||
@@ -39,6 +26,18 @@ RUN /opt/Fitness/venv/bin/pip3 install --no-cache-dir -r /opt/Fitness/requiremen
|
|||||||
# Copy the actual app code after installing deps
|
# Copy the actual app code after installing deps
|
||||||
COPY api/ /opt/Fitness/
|
COPY api/ /opt/Fitness/
|
||||||
|
|
||||||
|
# Install Composer (stand‑alone)
|
||||||
|
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||||
|
|
||||||
|
# Apache on 8069
|
||||||
|
COPY apache_ports.conf /etc/apache2/ports.conf
|
||||||
|
COPY apache_vhost.conf /etc/apache2/sites-available/000-default.conf
|
||||||
|
COPY web/ /var/www/
|
||||||
|
# Set up composer
|
||||||
|
WORKDIR /var/www/
|
||||||
|
RUN composer require jumbojett/openid-connect-php
|
||||||
|
RUN composer install --no-dev --optimize-autoloader --no-interaction
|
||||||
|
|
||||||
# Add supervisord configuration
|
# Add supervisord configuration
|
||||||
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ This app is intended to use with tracking personal fitness providers and visits
|
|||||||
I will build this with LAPP stack - Linux, Apache, PHP & Python. I will build the front-end in PHP, and the back-end will be a Python API with a database.
|
I will build this with LAPP stack - Linux, Apache, PHP & Python. I will build the front-end in PHP, and the back-end will be a Python API with a database.
|
||||||
|
|
||||||
The database will be a SQLite file handled by the Python service. There will need to be a Users table, a Providers table, and a Visits table. The Users table will contain the information and settings for the site users. The settings can be a JSON structure inside a single text entry. The Providers table will track the Providers info and rates. The rates will also be a JSON structure in a single text field. Any user can add a provider, and set it private or not. If not private, other users can add visits for the same provider. The Visits table will contain enties for User Visits to Providers. This will have date, time, location, provider, cost. There should be a initialize_db function that checks for the file and creates it if needed, including all tables. Here is a complete list of data for each table.
|
The database will be a SQLite file handled by the Python service. There will need to be a Users table, a Providers table, and a Visits table. The Users table will contain the information and settings for the site users. The settings can be a JSON structure inside a single text entry. The Providers table will track the Providers info and rates. The rates will also be a JSON structure in a single text field. Any user can add a provider, and set it private or not. If not private, other users can add visits for the same provider. The Visits table will contain enties for User Visits to Providers. This will have date, time, location, provider, cost. There should be a initialize_db function that checks for the file and creates it if needed, including all tables. Here is a complete list of data for each table.
|
||||||
|
|
||||||
|
Found this for OIDC - don't wanna lose it
|
||||||
|
https://github.com/jumbojett/OpenID-Connect-PHP/blob/master/README.md
|
||||||
|
|
||||||
```
|
```
|
||||||
Users
|
Users
|
||||||
- Name
|
- Name
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
require_once __DIR__ . '/config.php';
|
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
|
||||||
|
|
||||||
use Fitness\OIDC\OIDC;
|
|
||||||
|
|
||||||
// Ensure a state was sent back.
|
|
||||||
if (!isset($_GET['state']) || !isset($_SESSION['oidc_state'])) {
|
|
||||||
http_response_code(400);
|
|
||||||
exit('Missing state parameter.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the state matches what we stored.
|
|
||||||
if ($_GET['state'] !== $_SESSION['oidc_state']) {
|
|
||||||
http_response_code(400);
|
|
||||||
exit('Invalid state.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up the session variables.
|
|
||||||
$state = $_SESSION['oidc_state'];
|
|
||||||
$nonce = $_SESSION['oidc_nonce'];
|
|
||||||
unset($_SESSION['oidc_state'], $_SESSION['oidc_nonce']);
|
|
||||||
|
|
||||||
if (!isset($_GET['code'])) {
|
|
||||||
http_response_code(400);
|
|
||||||
exit('Missing authorization code.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$code = $_GET['code'];
|
|
||||||
$oidc = new OIDC();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Exchange code for tokens.
|
|
||||||
$tokens = $oidc->exchangeCode($code);
|
|
||||||
|
|
||||||
// Validate ID token (minimal).
|
|
||||||
$idInfo = $oidc->validateIDToken($tokens['id_token'], $nonce);
|
|
||||||
|
|
||||||
// Get userinfo (includes groups because of scope).
|
|
||||||
$userInfo = $oidc->getUserInfo($tokens['access_token']);
|
|
||||||
|
|
||||||
// Store everything we need in the session.
|
|
||||||
$_SESSION['user'] = [
|
|
||||||
'id_token' => $tokens['id_token'],
|
|
||||||
'access_token'=> $tokens['access_token'],
|
|
||||||
'refresh_token'=> $tokens['refresh_token'] ?? null,
|
|
||||||
'expires_in' => $tokens['expires_in'] ?? null,
|
|
||||||
'id_info' => $idInfo,
|
|
||||||
'user_info' => $userInfo,
|
|
||||||
];
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
http_response_code(500);
|
|
||||||
exit('Error during OIDC exchange: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up the query string (code, state) by redirecting to the home page.
|
|
||||||
header('Location: /');
|
|
||||||
exit;
|
|
||||||
+3
-1
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"require": {
|
"require": {
|
||||||
|
"jumbojett/openid-connect-php": "^1.0",
|
||||||
|
"vlucas/phpdotenv": "^5.4",
|
||||||
"guzzlehttp/guzzle": "^7.0",
|
"guzzlehttp/guzzle": "^7.0",
|
||||||
"firebase/php-jwt": "^6.0"
|
"firebase/php-jwt": "^7.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+15
-19
@@ -1,23 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
// config.php
|
||||||
|
return [
|
||||||
|
// Base URL for the Authelia OpenID Provider
|
||||||
|
'provider_url' => 'https://auth.matt-cloud.com', // <-- change if you run locally
|
||||||
|
|
||||||
session_start();
|
// Client (your application) credentials
|
||||||
|
'client_id' => 'fitness-oidc',
|
||||||
|
'client_secret' => 'egebuqzZfVnjjBG9JDQ8tjW3TzV9gJurvT7qfB6c2SX2nPBNeaGycDfx4788QzJd',
|
||||||
|
|
||||||
/**
|
// The callback URL **must** match exactly what is in Authelia
|
||||||
* Load environment variables. If you don't use phpdotenv,
|
'redirect_uri' => 'https://fitness.matt-cloud.com/callback.php',
|
||||||
* copy the values from .env directly here.
|
|
||||||
*/
|
|
||||||
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
|
|
||||||
$dotenv->load();
|
|
||||||
|
|
||||||
/**
|
// Scopes we want – Authelia already provides “openid”, “profile”, “email”, “groups”
|
||||||
* Basic OIDC configuration – keep all secrets out of source‑control.
|
'scopes' => ['openid', 'profile', 'email', 'groups'],
|
||||||
*/
|
|
||||||
define('OIDC_CLIENT_ID', getenv('OIDC_CLIENT_ID'));
|
// Response type & grant type
|
||||||
define('OIDC_CLIENT_SECRET', getenv('OIDC_CLIENT_SECRET'));
|
'response_type' => 'code',
|
||||||
define('OIDC_REDIRECT_URI', getenv('OIDC_REDIRECT_URI'));
|
];
|
||||||
define('OIDC_AUTH_ENDPOINT', getenv('OIDC_AUTH_ENDPOINT'));
|
|
||||||
define('OIDC_TOKEN_ENDPOINT', getenv('OIDC_TOKEN_ENDPOINT'));
|
|
||||||
define('OIDC_USERINFO_ENDPOINT', getenv('OIDC_USERINFO_ENDPOINT'));
|
|
||||||
define('OIDC_LOGOUT_ENDPOINT', getenv('OIDC_LOGOUT_ENDPOINT'));
|
|
||||||
define('OIDC_POST_LOGOUT_REDIRECT_URI', getenv('OIDC_POST_LOGOUT_REDIRECT_URI'));
|
|
||||||
File renamed without changes.
@@ -5,7 +5,7 @@
|
|||||||
// When the form is submitted, it POSTs JSON to /providers.
|
// When the form is submitted, it POSTs JSON to /providers.
|
||||||
|
|
||||||
// file settings
|
// file settings
|
||||||
require_once __DIR__ . '/config.php';
|
require_once __DIR__ . '/../fitness-config.php';
|
||||||
|
|
||||||
// Helper to call the API -------------------------------------------
|
// Helper to call the API -------------------------------------------
|
||||||
function callApi(string $method, string $path, $body = null)
|
function callApi(string $method, string $path, $body = null)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
use Jumbojett\OpenIDConnectClient;
|
||||||
|
|
||||||
|
$config = require __DIR__ . '/../config.php';
|
||||||
|
|
||||||
|
$oidc = new OpenIDConnectClient(
|
||||||
|
$config['provider_url'],
|
||||||
|
$config['client_id'],
|
||||||
|
$config['client_secret']
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tell the library where to return after the user logs in
|
||||||
|
$oidc->setRedirectURL($config['redirect_uri']);
|
||||||
|
|
||||||
|
// Tell it which scopes we want
|
||||||
|
$oidc->addScope($config['scopes']);
|
||||||
|
|
||||||
|
// The OIDC flow we’ll use
|
||||||
|
$oidc->setResponseTypes([$config['response_type']]);
|
||||||
|
|
||||||
|
// Optional: for local development you can relax TLS validation
|
||||||
|
// $oidc->setVerifyHost(false);
|
||||||
|
// $oidc->setVerifyPeer(false);
|
||||||
|
|
||||||
|
$oidc->authenticate(); // This automatically redirects to Authelia
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
use Jumbojett\OpenIDConnectClient;
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
$config = require __DIR__ . '/../config.php';
|
||||||
|
|
||||||
|
$oidc = new OpenIDConnectClient(
|
||||||
|
$config['provider_url'],
|
||||||
|
$config['client_id'],
|
||||||
|
$config['client_secret']
|
||||||
|
);
|
||||||
|
$oidc->setRedirectURL($config['redirect_uri']);
|
||||||
|
$oidc->addScope($config['scopes']);
|
||||||
|
$oidc->setResponseTypes([$config['response_type']]);
|
||||||
|
|
||||||
|
// This will read the `code` query parameter, fetch the tokens
|
||||||
|
// and validate everything.
|
||||||
|
$oidc->authenticate();
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch the OpenID Connect userinfo claims
|
||||||
|
$claims = $oidc->requestUserInfo(); // → stdClass with the claims
|
||||||
|
|
||||||
|
// Store what we need in the PHP session
|
||||||
|
$_SESSION['authenticated'] = true;
|
||||||
|
$_SESSION['name'] = $claims->name ?? $claims->given_name ?? $claims->family_name ?? '';
|
||||||
|
$_SESSION['email'] = $claims->email ?? '';
|
||||||
|
$_SESSION['groups'] = $claims->groups ?? [];
|
||||||
|
|
||||||
|
// Redirect back to the home page
|
||||||
|
header('Location: ../');
|
||||||
|
exit;
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
// Edit an existing fitness provider.
|
// Edit an existing fitness provider.
|
||||||
// Handles rate options similar to add_provider.php.
|
// Handles rate options similar to add_provider.php.
|
||||||
|
|
||||||
require_once __DIR__ . '/config.php';
|
require_once __DIR__ . '/../fitness-config.php';
|
||||||
|
|
||||||
$provider_id = (int)($_GET['id'] ?? 0);
|
$provider_id = (int)($_GET['id'] ?? 0);
|
||||||
if ($provider_id <= 0) {
|
if ($provider_id <= 0) {
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
$config = require __DIR__ . '/../config.php';
|
||||||
|
$debug_output = false;
|
||||||
|
if (!isset($_SESSION['authenticated'])) {
|
||||||
|
// User not logged in – show a login button
|
||||||
|
// echo '<h1>Welcome to the demo</h1>';
|
||||||
|
// echo '<p><a href="auth.php">Login with Authelia SSO</a></p>';
|
||||||
|
header('Location: auth.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user is logged in – display the attributes
|
||||||
|
$name = $_SESSION['name'] ?? 'unknown';
|
||||||
|
$email = $_SESSION['email'] ?? 'unknown';
|
||||||
|
$groups = $_SESSION['groups'] ?? [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ($debug_output) {
|
||||||
|
echo '<h1>Logged in as ' . htmlspecialchars($name) . '</h1>';
|
||||||
|
echo '<ul>';
|
||||||
|
echo '<li><strong>Email:</strong> ' . htmlspecialchars($email) . '</li>';
|
||||||
|
echo '<li><strong>Groups:</strong> ' . htmlspecialchars(implode(', ', $groups)) . '</li>';
|
||||||
|
echo '</ul>';
|
||||||
|
}
|
||||||
|
// echo '<p><a href="logout.php">Logout</a></p>';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Fitness Tracker</title>
|
||||||
|
<link rel="stylesheet" href="https://cosmostat.matt-cloud.com/src/styles.css">
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 2rem; }
|
||||||
|
#search { margin-bottom: 1rem; padding: 0.5rem; width: 300px; }
|
||||||
|
table { width: 100%; border-collapse: collapse; }
|
||||||
|
img { max-width: 60px; height: auto; }
|
||||||
|
.header-container { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
include_once('list_providers.php');
|
||||||
|
?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
// The API endpoint for providers is /providers.
|
// The API endpoint for providers is /providers.
|
||||||
|
|
||||||
// file settings
|
// file settings
|
||||||
require_once __DIR__ . '/config.php';
|
require_once __DIR__ . '/../fitness-config.php';
|
||||||
// --- Helper to call the API -------------------------------------------
|
// --- Helper to call the API -------------------------------------------
|
||||||
function callApi(string $method, string $path, $body = null)
|
function callApi(string $method, string $path, $body = null)
|
||||||
{
|
{
|
||||||
@@ -77,6 +77,12 @@ unset($p);
|
|||||||
<h1>Providers</h1>
|
<h1>Providers</h1>
|
||||||
<a href="add_provider.php" class="btn">Add Provider</a>
|
<a href="add_provider.php" class="btn">Add Provider</a>
|
||||||
</div>
|
</div>
|
||||||
|
<?php
|
||||||
|
if (isset($_SESSION['authenticated'])){
|
||||||
|
echo "Welcome " . htmlspecialchars($_SESSION['name']);
|
||||||
|
echo "<p>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
<input type="text" id="search" placeholder="Search providers...">
|
<input type="text" id="search" placeholder="Search providers...">
|
||||||
<table id="providers-table">
|
<table id="providers-table">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
session_destroy();
|
||||||
|
header('Location: ../');
|
||||||
|
exit;
|
||||||
File renamed without changes.
File renamed without changes.
@@ -5,7 +5,7 @@
|
|||||||
// The design follows the pattern used in list_providers.php.
|
// The design follows the pattern used in list_providers.php.
|
||||||
|
|
||||||
// file settings
|
// file settings
|
||||||
require_once __DIR__ . '/config.php';
|
require_once __DIR__ . '/../fitness-config.php';
|
||||||
|
|
||||||
// --- Helper to call the Flask API -------------------------------------------
|
// --- Helper to call the Flask API -------------------------------------------
|
||||||
function callApi(string $method, string $path, $body = null)
|
function callApi(string $method, string $path, $body = null)
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
require_once __DIR__ . '/config.php';
|
|
||||||
?>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Fitness Site – OIDC Demo</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 2rem; }
|
|
||||||
.info { margin-top: 1rem; }
|
|
||||||
pre { background: #f4f4f4; padding: 1rem; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Fitness Site – OIDC Demo</h1>
|
|
||||||
|
|
||||||
<?php if (!isset($_SESSION['user'])): ?>
|
|
||||||
<p>You are not logged in.</p>
|
|
||||||
<p><a href="/login.php"><button>Login with Authelia</button></a></p>
|
|
||||||
<?php else: ?>
|
|
||||||
<p>Logged in as: <strong><?=htmlspecialchars($_SESSION['user']['user_info']['name'] ?? 'N/A')?></strong></p>
|
|
||||||
|
|
||||||
<div class="info">
|
|
||||||
<h2>User Information</h2>
|
|
||||||
<pre><?=htmlspecialchars(json_encode($_SESSION['user']['user_info'], JSON_PRETTY_PRINT))?></pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info">
|
|
||||||
<h2>ID Token Payload (claims)</h2>
|
|
||||||
<pre><?=htmlspecialchars(json_encode($_SESSION['user']['id_info'], JSON_PRETTY_PRINT))?></pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p><a href="/logout.php"><button>Logout</button></a></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
require_once __DIR__ . '/config.php';
|
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
|
||||||
|
|
||||||
use Fitness\OIDC\OIDC;
|
|
||||||
|
|
||||||
// Generate a cryptographically random state & nonce.
|
|
||||||
$state = bin2hex(random_bytes(16));
|
|
||||||
$nonce = bin2hex(random_bytes(16));
|
|
||||||
|
|
||||||
// Persist them in the session to validate later.
|
|
||||||
$_SESSION['oidc_state'] = $state;
|
|
||||||
$_SESSION['oidc_nonce'] = $nonce;
|
|
||||||
|
|
||||||
$oidc = new OIDC();
|
|
||||||
header('Location: ' . $oidc->buildAuthUrl($state, $nonce));
|
|
||||||
exit;
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
require_once __DIR__ . '/config.php';
|
|
||||||
|
|
||||||
// Destroy the PHP session.
|
|
||||||
session_start();
|
|
||||||
session_destroy();
|
|
||||||
|
|
||||||
// Redirect the user to Authelia’s logout endpoint.
|
|
||||||
// Authelia will clean its session and then redirect back.
|
|
||||||
$logoutUrl = OIDC_LOGOUT_ENDPOINT
|
|
||||||
. '?post_logout_redirect_uri=' . urlencode(OIDC_POST_LOGOUT_REDIRECT_URI);
|
|
||||||
|
|
||||||
header('Location: ' . $logoutUrl);
|
|
||||||
exit;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__.'/config.php';
|
require_once __DIR__ . '/../fitness-config.php';
|
||||||
|
|
||||||
function uploadPhotos($provider_id, $files) {
|
function uploadPhotos($provider_id, $files) {
|
||||||
$url = BASE_API_URL . "/api/providers/$provider_id/photos";
|
$url = BASE_API_URL . "/api/providers/$provider_id/photos";
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Fitness\OIDC;
|
|
||||||
|
|
||||||
use GuzzleHttp\Client;
|
|
||||||
use Firebase\JWT\JWT;
|
|
||||||
use Firebase\JWT\Key;
|
|
||||||
|
|
||||||
class OIDC
|
|
||||||
{
|
|
||||||
private Client $http;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->http = new Client(['http_errors' => false]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the Auth URL that redirects the user to Authelia.
|
|
||||||
*/
|
|
||||||
public function buildAuthUrl(string $state, string $nonce): string
|
|
||||||
{
|
|
||||||
$params = [
|
|
||||||
'response_type' => 'code',
|
|
||||||
'client_id' => OIDC_CLIENT_ID,
|
|
||||||
'redirect_uri' => OIDC_REDIRECT_URI,
|
|
||||||
'scope' => 'openid profile email groups',
|
|
||||||
'state' => $state,
|
|
||||||
'nonce' => $nonce,
|
|
||||||
];
|
|
||||||
|
|
||||||
return OIDC_AUTH_ENDPOINT . '?' . http_build_query($params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exchange the Authorization Code for tokens.
|
|
||||||
*/
|
|
||||||
public function exchangeCode(string $code): array
|
|
||||||
{
|
|
||||||
$response = $this->http->post(OIDC_TOKEN_ENDPOINT, [
|
|
||||||
'auth' => [OIDC_CLIENT_ID, OIDC_CLIENT_SECRET],
|
|
||||||
'form_params' => [
|
|
||||||
'grant_type' => 'authorization_code',
|
|
||||||
'code' => $code,
|
|
||||||
'redirect_uri' => OIDC_REDIRECT_URI,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() !== 200) {
|
|
||||||
throw new \RuntimeException('Token endpoint returned ' . $response->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
return json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call /userinfo with the access token.
|
|
||||||
*/
|
|
||||||
public function getUserInfo(string $accessToken): array
|
|
||||||
{
|
|
||||||
$response = $this->http->get(OIDC_USERINFO_ENDPOINT, [
|
|
||||||
'headers' => [
|
|
||||||
'Authorization' => 'Bearer ' . $accessToken,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() !== 200) {
|
|
||||||
throw new \RuntimeException('Userinfo endpoint returned ' . $response->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
return json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the ID Token (minimal validation for demo purposes).
|
|
||||||
*/
|
|
||||||
public function validateIDToken(string $idToken, string $nonce): array
|
|
||||||
{
|
|
||||||
// Authelia uses RS256 by default, but your config says "none".
|
|
||||||
// We'll decode without verification if alg is "none".
|
|
||||||
$decoded = JWT::decode($idToken, new Key('', ''), ['none', 'RS256']);
|
|
||||||
|
|
||||||
// Check nonce matches what we stored in session.
|
|
||||||
if ($decoded->nonce !== $nonce) {
|
|
||||||
throw new \RuntimeException('Invalid nonce');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (array)$decoded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user