oidc.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. <?php
  2. /**
  3. * OIDC Authentication Routes
  4. */
  5. // Ensure PHP sessions are started for OIDC state management
  6. if (session_status() === PHP_SESSION_NONE) {
  7. // Configure session cookies for cross-site requests (OIDC redirect flow)
  8. session_set_cookie_params([
  9. 'lifetime' => 600, // 10 minutes for OIDC flow
  10. 'path' => '/',
  11. 'secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on',
  12. 'httponly' => true,
  13. 'samesite' => 'Lax' // Lax allows the session cookie to be sent on top-level navigations
  14. ]);
  15. session_start();
  16. }
  17. /**
  18. * Get enabled OIDC providers (public endpoint)
  19. */
  20. $app->get('/oidc/providers', function ($request, $response, $args) {
  21. $Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
  22. $providers = $Organizr->getEnabledOIDCProviders();
  23. $result = [];
  24. foreach ($providers as $provider => $config) {
  25. $result[$provider] = [
  26. 'name' => $Organizr->config[$config['configPrefix'] . 'Name'] ?? ucfirst($provider),
  27. 'enabled' => true,
  28. ];
  29. }
  30. $GLOBALS['api']['response']['data'] = $result;
  31. $response->getBody()->write(jsonE($GLOBALS['api']));
  32. return $response
  33. ->withHeader('Content-Type', 'application/json;charset=UTF-8')
  34. ->withStatus($GLOBALS['responseCode']);
  35. });
  36. /**
  37. * Initiate OIDC authorization flow
  38. */
  39. $app->get('/oidc/{provider}/authorize', function ($request, $response, $args) {
  40. $Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
  41. $provider = $args['provider'] ?? '';
  42. // This will redirect to the provider, exit happens in initiateOIDCFlow
  43. $Organizr->initiateOIDCFlow($provider);
  44. // If we get here, there was an error
  45. $response->getBody()->write(jsonE($GLOBALS['api']));
  46. return $response
  47. ->withHeader('Content-Type', 'application/json;charset=UTF-8')
  48. ->withStatus($GLOBALS['responseCode']);
  49. });
  50. /**
  51. * OIDC callback handler
  52. */
  53. $app->get('/oidc/{provider}/callback', function ($request, $response, $args) {
  54. $Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
  55. $provider = $args['provider'] ?? '';
  56. $params = $request->getQueryParams();
  57. $code = $params['code'] ?? null;
  58. $state = $params['state'] ?? null;
  59. $error = $params['error'] ?? null;
  60. $errorDescription = $params['error_description'] ?? 'Unknown error';
  61. // Handle error from provider
  62. if ($error) {
  63. $Organizr->outputOIDCCallbackError($errorDescription);
  64. return $response;
  65. }
  66. // Validate required parameters
  67. if (!$code || !$state) {
  68. $Organizr->outputOIDCCallbackError('Missing code or state parameter');
  69. return $response;
  70. }
  71. // Process callback
  72. $user = $Organizr->processOIDCCallback($provider, $code, $state);
  73. if ($user) {
  74. $Organizr->outputOIDCCallbackSuccess($user['username']);
  75. } else {
  76. $Organizr->outputOIDCCallbackError($GLOBALS['api']['response']['message'] ?? 'Authentication failed');
  77. }
  78. return $response;
  79. });
  80. /**
  81. * Test OIDC provider connection (admin only)
  82. */
  83. $app->get('/oidc/{provider}/test', function ($request, $response, $args) {
  84. $Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
  85. if ($Organizr->checkRoute($request)) {
  86. if ($Organizr->qualifyRequest(1, true)) {
  87. $provider = $args['provider'] ?? '';
  88. $Organizr->testOIDCConnection($provider);
  89. }
  90. }
  91. $response->getBody()->write(jsonE($GLOBALS['api']));
  92. return $response
  93. ->withHeader('Content-Type', 'application/json;charset=UTF-8')
  94. ->withStatus($GLOBALS['responseCode']);
  95. });