Skip to content
Snippets Groups Projects
Commit e68c7e55 authored by Sigmund Augdal's avatar Sigmund Augdal
Browse files

Make openid-connect-configuration.php more robust

 * Handle keys without the option x5c field. If these are RSA keys they can be parsed if phpseclib is available, otherwise they are ignored.
 * log warnings and errors to stderr using error_log.
 * Improve user feedback on issues

This uses phpseclib/phpseclib and requires dev-master to work. This
isn't added as a dependency to composer.json because it isn't run
during normal operation, and finding a set of dependencies that
includes both simplesaml and phpseclib which allows both to be
installed at the same time proved to be quite tricky.
parent 0895d28f
No related branches found
No related tags found
No related merge requests found
<?php <?php
require_once('./vendor/autoload.php');
const CONFIGURATION_PATH = '.well-known/openid-configuration'; const CONFIGURATION_PATH = '.well-known/openid-configuration';
$configurationPathLength = strlen(CONFIGURATION_PATH); $configurationPathLength = strlen(CONFIGURATION_PATH);
...@@ -8,6 +10,38 @@ function usage() { ...@@ -8,6 +10,38 @@ function usage() {
exit; exit;
} }
function base64url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
function process_jwks($url) {
$jwksData = file_get_contents($url);
if (!$jwksData) {
error_log("Failed to get jwks data from $url");
return;
}
$jwks = json_decode($jwksData, true);
if (!$jwks) {
error_log("Failed to json decode jwks data: " . $jwksData);
return;
}
$keys = [];
foreach ($jwks['keys'] as $key) {
$kid = $key['kid'];
if (array_key_exists('x5c', $key)) {
$x5c = $key['x5c'];
$keys[$kid] = "-----BEGIN CERTIFICATE-----\n" . $x5c[0] . "\n-----END CERTIFICATE-----";
} else if (class_exists('\phpseclib\Math\BigInteger') && $key['kty'] === 'RSA') {
$e = new \phpseclib\Math\BigInteger(base64url_decode($key['e']), 256);
$n = new \phpseclib\Math\BigInteger(base64url_decode($key['n']), 256);
$keys[$kid] = \phpseclib\Crypt\RSA\Formats\Keys\PKCS8::savePublicKey($n, $e);
} else {
error_log("Failed to load key data for key id: " . $kid);
}
}
return $keys;
}
if (sizeof($argv) < 2) { if (sizeof($argv) < 2) {
usage(); usage();
} }
...@@ -26,12 +60,12 @@ if (substr($url, -$configurationPathLength) !== CONFIGURATION_PATH) { ...@@ -26,12 +60,12 @@ if (substr($url, -$configurationPathLength) !== CONFIGURATION_PATH) {
$data = file_get_contents($url); $data = file_get_contents($url);
if (!$data) { if (!$data) {
echo "Failed to get configuration data from $url\n"; error_log("Failed to get configuration data from $url");
exit; exit;
} }
$conf = json_decode($data); $conf = json_decode($data);
if (!$conf) { if (!$conf) {
echo "Failed to json decode configuration data: " . $data; error_log("Failed to json decode configuration data: " . $data);
exit; exit;
} }
...@@ -57,23 +91,12 @@ SNIP1; ...@@ -57,23 +91,12 @@ SNIP1;
if (isset($conf->end_session_endpoint)) { if (isset($conf->end_session_endpoint)) {
echo " 'urlEndSession' => '$conf->end_session_endpoint',\n"; echo " 'urlEndSession' => '$conf->end_session_endpoint',\n";
} }
$jwksData = file_get_contents($conf->jwks_uri); $keys = process_jwks($conf->jwks_uri);
if (!$jwksData) { if ($keys) {
echo "Failed to get jwks data from $conf->jwks_uri\n"; echo " 'keys' => " . var_export($keys, true);
exit; } else {
} error_log("Couldn't get or parse jwks data, generated config without id token verification");
$jwks = json_decode($jwksData, true);
if (!$jwks) {
echo "Failed to json decode jwks data: " . $jwksData;
exit;
}
$keys = [];
foreach ($jwks['keys'] as $key) {
$kid = $key['kid'];
$x5c = $key['x5c'];
$keys[$kid] = "-----BEGIN CERTIFICATE-----\n" . $x5c[0] . "\n-----END CERTIFICATE-----";
} }
echo " 'keys' => " . var_export($keys, true);
echo <<<SNIP2 echo <<<SNIP2
), ),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment