114 lines
4 KiB
PHP
Executable file
114 lines
4 KiB
PHP
Executable file
<?php
|
|
/**
|
|
* OAuth2 PKCE Authentication Handler
|
|
* Handles Microsoft Azure AD authentication flow with PKCE
|
|
*/
|
|
require_once 'auth_config.php';
|
|
|
|
use League\OAuth2\Client\Provider\GenericProvider;
|
|
|
|
// Start session
|
|
session_start();
|
|
|
|
// Azure AD OAuth2 Provider configuration
|
|
$provider = new GenericProvider([
|
|
'clientId' => AZURE_CLIENT_ID,
|
|
'redirectUri' => AZURE_REDIRECT_URI,
|
|
'urlAuthorize' => AZURE_AUTHORITY . '/oauth2/v2.0/authorize',
|
|
'urlAccessToken' => AZURE_AUTHORITY . '/oauth2/v2.0/token',
|
|
'urlResourceOwnerDetails' => 'https://graph.microsoft.com/v1.0/me',
|
|
'scopes' => 'openid profile email User.Read'
|
|
]);
|
|
|
|
// Step 1: No authorization code - initiate OAuth flow
|
|
if (!isset($_GET['code'])) {
|
|
|
|
// Generate PKCE code verifier and challenge
|
|
$codeVerifier = bin2hex(random_bytes(32)); // 64-character random string
|
|
$codeChallenge = rtrim(strtr(base64_encode(hash('sha256', $codeVerifier, true)), '+/', '-_'), '=');
|
|
|
|
// Store code verifier in session for later use
|
|
$_SESSION['oauth2_code_verifier'] = $codeVerifier;
|
|
|
|
// Generate authorization URL with PKCE parameters
|
|
$authorizationUrl = $provider->getAuthorizationUrl([
|
|
'scope' => 'openid profile email User.Read',
|
|
'code_challenge' => $codeChallenge,
|
|
'code_challenge_method' => 'S256',
|
|
'response_type' => 'code',
|
|
'response_mode' => 'query'
|
|
]);
|
|
|
|
// Store state for CSRF protection
|
|
$_SESSION['oauth2state'] = $provider->getState();
|
|
|
|
// Redirect to Azure AD
|
|
header('Location: ' . $authorizationUrl);
|
|
exit;
|
|
}
|
|
|
|
// Step 2: Authorization code received - exchange for access token
|
|
elseif (isset($_GET['code'])) {
|
|
|
|
// Verify state to prevent CSRF attacks
|
|
if (empty($_GET['state']) || (isset($_SESSION['oauth2state']) && $_GET['state'] !== $_SESSION['oauth2state'])) {
|
|
unset($_SESSION['oauth2state']);
|
|
unset($_SESSION['oauth2_code_verifier']);
|
|
die('Invalid state. Possible CSRF attack.');
|
|
}
|
|
|
|
try {
|
|
// Retrieve code verifier from session
|
|
if (!isset($_SESSION['oauth2_code_verifier'])) {
|
|
die('Code verifier not found in session.');
|
|
}
|
|
|
|
$codeVerifier = $_SESSION['oauth2_code_verifier'];
|
|
|
|
// Exchange authorization code for access token with PKCE
|
|
$accessToken = $provider->getAccessToken('authorization_code', [
|
|
'code' => $_GET['code'],
|
|
'code_verifier' => $codeVerifier
|
|
]);
|
|
|
|
// Get user information from Microsoft Graph API
|
|
$request = $provider->getAuthenticatedRequest(
|
|
'GET',
|
|
'https://graph.microsoft.com/v1.0/me',
|
|
$accessToken->getToken()
|
|
);
|
|
|
|
$client = new \GuzzleHttp\Client();
|
|
$response = $client->send($request);
|
|
$userData = json_decode($response->getBody(), true);
|
|
|
|
// Store user information in session
|
|
$_SESSION['authenticated'] = true;
|
|
$_SESSION['user_id'] = $userData['id'];
|
|
$_SESSION['user_name'] = $userData['displayName'] ?? $userData['userPrincipalName'];
|
|
$_SESSION['user_email'] = $userData['userPrincipalName'] ?? $userData['mail'];
|
|
$_SESSION['access_token'] = $accessToken->getToken();
|
|
$_SESSION['last_activity'] = time();
|
|
|
|
// Initialize user files array for tracking uploads
|
|
$_SESSION['user_files'] = [];
|
|
|
|
// Clean up temporary session variables
|
|
unset($_SESSION['oauth2state']);
|
|
unset($_SESSION['oauth2_code_verifier']);
|
|
|
|
// Regenerate session ID for security
|
|
session_regenerate_id(true);
|
|
|
|
// Redirect to main application
|
|
header('Location: index.php');
|
|
exit;
|
|
|
|
} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
|
|
// Handle authentication errors
|
|
die('Authentication failed: ' . htmlspecialchars($e->getMessage()));
|
|
} catch (\Exception $e) {
|
|
// Handle other errors
|
|
die('An error occurred: ' . htmlspecialchars($e->getMessage()));
|
|
}
|
|
}
|