function handle_distributedinfo() { try { global $signing_alg_values_supported, $encryption_alg_values_supported, $encryption_enc_values_supported; $token = $_REQUEST['access_token']; if (!$token) { $token = get_bearer_token(); if (!$token) { throw new BearerException('invalid_request', 'No Access Token'); } } // check code $token = db_find_access_token($token); if (!$token) { throw new BearerException('invalid_request', 'Cannot find Access Token'); } $db_client = db_get_client($token['client']); if (!$db_client) { throw new BearerException('invalid_request', 'Invalid Client ID'); } $tinfo = json_decode($token['info'], true); $userinfo = array(); $persona = db_get_user_persona($tinfo['u'], $tinfo['p'])->toArray(); $scopes = explode(' ', $tinfo['g']['scope']); if (in_array('openid', $scopes)) { $userinfo['sub'] = wrap_userid($db_client, $tinfo['u']); } log_debug("userid = %s unwrapped = %s", $userinfo['sub'], unwrap_userid($userinfo['sub'])); $requested_userinfo_claims = get_userinfo_claims($tinfo['r'], $tinfo['r']['scope']); $persona_custom_claims = db_get_user_persona_custom_claims($tinfo['u'], $tinfo['p']); foreach ($persona_custom_claims as $pcc) { $persona_claims[$pcc['claim']] = $pcc->PersonaCustomClaim[0]['value']; } log_debug("ALLOWED CLAIMS = %s", print_r($tinfo['l'], true)); log_debug("REQUESTED_USER_INFO = %s", print_r($requested_userinfo_claims, true)); $src = 0; foreach ($tinfo['l'] as $key) { if (array_key_exists($key, $requested_userinfo_claims)) { $prefix = substr($key, 0, 3); if ($prefix == 'ax.') { $key = substr($key, 3); $mapped_key = $key; $kana = strpos($key, '_ja_kana_jp'); $hani = strpos($key, '_ja_hani_jp'); if ($kana !== false) { $mapped_key = substr($key, 0, $kana) . '#ja-Kana-JP'; } if ($hani !== false) { $mapped_key = substr($key, 0, $hani) . '#ja-Hani-JP'; } switch ($mapped_key) { case 'address': $userinfo[$mapped_key] = array('formatted' => $persona[$key]); break; case 'email_verified': case 'phone_number_verified': if ($persona[$key]) { $userinfo[$mapped_key] = true; } else { $userinfo[$mapped_key] = false; } break; default: $userinfo[$mapped_key] = $persona[$key]; break; } } elseif ($prefix == 'cx.') { $key = substr($key, 3); $userinfo[$key] = $persona_claims[$key]; } } } $sig_param = array('alg' => 'none'); $sig_key = NULL; if ($db_client['userinfo_signed_response_alg']) { if (in_array($db_client['userinfo_signed_response_alg'], $signing_alg_values_supported)) { $sig_param['alg'] = $db_client['userinfo_signed_response_alg']; if (substr($db_client['userinfo_signed_response_alg'], 0, 2) == 'HS') { $sig_key = $db_client['client_secret']; } elseif (substr($db_client['userinfo_signed_response_alg'], 0, 2) == 'RS') { $sig_param['jku'] = OP_JWK_URL; $sig_param['kid'] = OP_SIG_KID; $sig_key = array('key_file' => OP_SIG_PKEY, 'password' => OP_SIG_PKEY_PASSPHRASE); } log_debug("DistributedInfo Using Sig Alg %s", $sig_param['alg']); $userinfo_jwt = jwt_sign($userinfo, $sig_param, $sig_key); if (!$userinfo_jwt) { log_error("Unable to sign response for DistributedInfo"); send_bearer_error('400', 'invalid_request', 'Unable to sign response for DistributedInfo'); } if ($db_client['userinfo_encrypted_response_alg'] && $db_client['userinfo_encrypted_response_enc']) { log_debug("UserInfo Encryption Algs %s %s", $db_client['userinfo_encrypted_response_alg'], $db_client['userinfo_encrypted_response_enc']); list($alg, $enc) = array($db_client['userinfo_encrypted_response_alg'], $db_client['userinfo_encrypted_response_enc']); if (in_array($alg, $encryption_alg_values_supported) && in_array($enc, $encryption_enc_values_supported)) { $jwk_uri = ''; $encryption_keys = NULL; if ($db_client['jwks_uri']) { $jwk = get_url($db_client['jwks_uri']); if ($jwk) { $jwk_uri = $db_client['jwks_uri']; $encryption_keys = jwk_get_keys($jwk, 'RSA', 'enc', NULL); if (!$encryption_keys || !count($encryption_keys)) { $jwk_uri = NULL; if (!empty($db_client['jwks'])) { $encryption_keys = jwk_get_keys($db_client['jwks'], 'RSA', 'enc', NULL); } if (!$encryption_keys || !count($encryption_keys)) { $encryption_keys = NULL; } } } } if (!$encryption_keys) { send_bearer_error('400', 'invalid_request', 'Unable to retrieve JWK key for encryption'); } if ($jwk_uri) { $header_params = array('jku' => $jwk_uri); } if (isset($encryption_keys[0]['kid'])) { $header_params['kid'] = $encryption_keys[0]['kid']; } $userinfo_jwt = jwt_encrypt2($userinfo_jwt, $encryption_keys[0], false, NULL, $header_params, NULL, $alg, $enc, false); if (!$userinfo_jwt) { log_error("Unable to encrypt response for DistributedInfo"); send_bearer_error('400', 'invalid_request', 'Unable to encrypt response for DistributedInfo'); } } else { log_error("UserInfo Encryption Algs %s and %s not supported", $alg, $enc); send_bearer_error('400', 'invalid_request', 'Client registered unsupported encryption algs for UserInfo'); } } header("Content-Type: application/jwt"); header("Cache-Control: no-store"); header("Pragma: no-cache"); log_debug('DistributedInfo response = %s', $userinfo_jwt); echo $userinfo_jwt; } else { log_error("UserInfo Sig Alg %s not supported", $db_client['userinfo_signed_response_alg']); send_bearer_error('400', 'invalid_request', "UserInfo Sig Alg {$db_client['userinfo_signed_response_alg']} not supported"); } } else { header("Cache-Control: no-store"); header("Pragma: no-cache"); header("Content-Type: application/json"); log_debug('DistributedInfo response = %s', json_encode($userinfo)); echo json_encode($userinfo); } } catch (BearerException $e) { send_bearer_error('401', $e->error_code, $e->desc); } catch (OidcException $e) { send_error('', $e->error_code, $e->desc); } }
function webrtc_handle_auth() { $state = isset($_REQUEST['state']) ? $_REQUEST['state'] : NULL; $error_page = OP_INDEX_PAGE; $response_mode = 'query'; try { if (!isset($_REQUEST['client_id'])) { throw new OidcException('invalid_request', 'no client'); } // check client id $client = db_get_client($_REQUEST['client_id']); if (!$client) { throw new OidcException('unauthorized_client', 'Client ID not found'); } /* if(isset($_REQUEST['redirect_uri'])) { if(!is_valid_registered_redirect_uri($client['redirect_uris'], $_REQUEST['redirect_uri'])) throw new OidcException('invalid_request', 'no matching redirect_uri'); } else throw new OidcException('invalid_request', 'no redirect_uri in request'); $error_page = $_REQUEST['redirect_uri']; */ $response_mode = get_response_mode($_REQUEST); if (!isset($_REQUEST['response_type'])) { throw new OidcException('invalid_request', 'no response_type'); } $response_types = explode(' ', $_REQUEST['response_type']); $known_response_types = array('code', 'token', 'id_token'); if (count(array_diff($response_types, $known_response_types))) { throw new OidcException('invalid_response_type', "Unknown response_type {$_REQUEST['response_type']}"); } if (ENABLE_PKCE) { if (in_array('code', $response_types)) { if (!isset($_REQUEST['code_challenge'])) { throw new OidcException('invalid_request', 'code challenge required'); } if (isset($_REQUEST['code_challenge_method'])) { if (!in_array($_REQUEST['code_challenge_method'], array('plain', 'S256'))) { throw new OidcException('invalid_request', "unsupported code challenge method {$_REQUEST['code_challenge_method']}"); } } } } if (!isset($_REQUEST['scope'])) { throw new OidcException('invalid_request', 'no scope'); } $scopes = explode(' ', $_REQUEST['scope']); if (!in_array('openid', $scopes)) { throw new OidcException('invalid_scope', 'no openid scope'); } if (in_array('token', $response_types) || in_array('id_token', $response_types)) { if (!isset($_REQUEST['nonce'])) { throw new OidcException('invalid_request', 'no nonce'); } } $_SESSION['get'] = $_GET; $request_uri = isset($_REQUEST['request_uri']) ? $_REQUEST['request_uri'] : NULL; $requested_userid = NULL; $requested_userid_display = NULL; $request_object = NULL; if ($request_uri) { $request_object = get_url($request_uri); if (!$request_object) { throw new OidcException('invalid_request', "Unable to fetch request file {$request_uri}"); } } elseif (isset($_REQUEST['request'])) { $request_object = $_REQUEST['request']; } if (isset($_GET['claims'])) { $_GET['claims'] = json_decode($_GET['claims'], true); $_REQUEST['claims'] = $_GET['claims']; } if (isset($request_object)) { $cryptoError = ''; $payload = decrypt_verify_jwt($request_object, $client, $cryptoError); if (!isset($payload)) { if ($cryptoError == 'error_decrypt') { throw new OidcException('invalid_request', 'Unable to decrypt request object'); } elseif ($cryptoError == 'error_sig') { throw new OidcException('invalid_request', 'Unable to verify request object signature'); } } else { if (isset($payload['claims']['id_token'])) { if (array_key_exists('sub', $payload['claims']['id_token']) && isset($payload['claims']['id_token']['sub']['value'])) { $requested_userid_display = $payload['claims']['id_token']['sub']['value']; $requested_userid = unwrap_userid($payload['claims']['id_token']['sub']['value']); if (!db_get_user($requested_userid)) { throw new OidcException('invalid_request', 'Unrecognized userid in request'); } } } $merged_req = array_merge($_GET, $payload); if (!array_key_exists('max_age', $merged_req) && $client['default_max_age']) { $merged_req['max_age'] = $client['default_max_age']; } if ($merged_req['max_age']) { $merged_req['claims']['id_token']['auth_time'] = array('essential' => true); } if ((!$merged_req['claims']['id_token'] || !array_key_exists('auth_time', $merged_req['claims']['id_token'])) && $client['require_auth_time']) { $merged_req['claims']['id_token']['auth_time'] = array('essential' => true); } if (!$merged_req['claims']['id_token'] || !array_key_exists('acr', $merged_req['claims']['id_token'])) { if ($merged_req['acr_values']) { $merged_req['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode(' ', $merged_req['acr_values'])); } elseif ($client['default_acr_values']) { $merged_req['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode('|', $client['default_acr_values'])); } } $_SESSION['rpfA'] = $merged_req; log_debug("rpfA = %s", print_r($_SESSION['rpfA'], true)); foreach (array('client_id', 'response_type', 'scope', 'nonce', 'redirect_uri') as $key) { if (!isset($payload[$key])) { log_error("missing %s in payload => %s", $key, print_r($payload, true)); } // throw new OidcException('invalid_request', 'Request Object missing required parameters'); } log_debug("payload => %s", print_r($payload, true)); foreach ($payload as $key => $value) { if (isset($_REQUEST[$key]) && strcmp($_REQUEST[$key], $value)) { log_debug("key : %s value:%s", $key, print_r($value, true)); throw new OidcException('invalid_request', "Request Object Param Values do not match request '{$key}' '{$_REQUEST[$key]}' != '{$value}'"); } } } } else { if (isset($_GET['id_token_hint'])) { $cryptoError = ''; $payload = decrypt_verify_jwt($_REQUEST['id_token_hint'], $client, $cryptoError); if (!isset($payload)) { if ($cryptoError == 'error_decrypt') { throw new OidcException('invalid_request', 'Unable to decrypt request object'); } elseif ($cryptoError == 'error_sig') { throw new OidcException('invalid_request', 'Unable to verify request object signature'); } } else { $requested_userid_display = $payload['sub']; $requested_userid = unwrap_userid($payload['sub']); if (!db_get_user($requested_userid)) { throw new OidcException('invalid_request', 'Unrecognized userid in ID Token'); } } } else { if (isset($_GET['claims']['id_token']['sub']['value'])) { $requested_userid_display = $_GET['claims']['id_token']['sub']['value']; $requested_userid = unwrap_userid($_GET['claims']['id_token']['sub']['value']); if (!db_get_user($requested_userid)) { throw new OidcException('invalid_request', "Unrecognized userid in ID Token"); } } else { if (isset($_GET['login_hint'])) { $principal = $_GET['login_hint']; $at = strpos($principal, '@'); if ($at !== false) { error_log("EMAIL\n"); if ($at != 0) { // XRI // process email address list($principal, $domain) = explode('@', $principal); error_log("==> principal = {$principal} domain = {$domain}"); $port_pos = strpos($domain, ':'); if ($port_pos !== false) { $domain = substr($domain, 0, $port_pos); } $domain_parts = explode('.', $domain); $server_parts = explode('.', OP_SERVER_NAME); // check to see domain matches $domain_start = count($domain_parts) - 1; $server_start = count($server_parts) - 1; $domain_match = true; for ($i = $domain_start, $j = $server_start; $i >= 0 && $j >= 0; $i--, $j--) { if (strcasecmp($domain_parts[$i], $server_parts[$j]) != 0) { $domain_match = false; } } if ($domain_match) { $requested_userid_display = $principal; $requested_userid = unwrap_userid($requested_userid_display); if (!db_get_user($requested_userid)) { $requested_userid_display = NULL; $requested_userid = NULL; } } else { throw new OidcException('invalid_request', 'Unrecognized email domain'); } } } else { // name only $requested_userid_display = $_GET['login_hint']; $requested_userid = unwrap_userid($requested_userid_display); if (!db_get_user($requested_userid)) { $requested_userid_display = NULL; $requested_userid = NULL; } } } } } if (!array_key_exists('max_age', $_REQUEST) && $client['default_max_age']) { $_REQUEST['max_age'] = $client['default_max_age']; } if ($_REQUEST['max_age']) { $_REQUEST['claims']['id_token']['auth_time'] = array('essential' => true); } if ((!$_REQUEST['claims']['id_token'] || !array_key_exists('auth_time', $_REQUEST['claims']['id_token'])) && $client['require_auth_time']) { $_REQUEST['claims']['id_token']['auth_time'] = array('essential' => true); } if (!$_REQUEST['claims']['id_token'] || !array_key_exists('acr', $_REQUEST['claims']['id_token'])) { if ($_REQUEST['acr_values']) { $_REQUEST['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode(' ', $_REQUEST['acr_values'])); } elseif ($client['default_acr_values']) { $_REQUEST['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode('|', $client['default_acr_values'])); } } $_SESSION['rpfA'] = $_REQUEST; } log_debug("prompt = %s", $_SESSION['rpfA']['prompt']); $prompt = $_SESSION['rpfA']['prompt'] ? explode(' ', $_SESSION['rpfA']['prompt']) : array(); $num_prompts = count($prompt); if ($num_prompts > 1 && in_array('none', $prompt)) { throw new OidcException('interaction_required', "conflicting prompt parameters {$_SESSION['rpfA']['prompt']}"); } if (in_array('none', $prompt)) { $showUI = false; } else { $showUI = true; } log_debug("num prompt = %d %s", $num_prompts, print_r($prompt, true)); if ($_SESSION['username']) { if (in_array('login', $prompt)) { echo loginform($requested_userid_display, $requested_userid, $client); exit; } if (isset($_SESSION['rpfA']['max_age'])) { if (time() - $_SESSION['auth_time'] > $_SESSION['rpfA']['max_age']) { if (!$showUI) { throw new OidcException('interaction_required', 'max_age exceeded and prompt set to none'); } echo loginform($requested_userid_display, $requested_userid, $client); exit; } } if ($requested_userid) { if ($_SESSION['username'] != $requested_userid) { if (!$showUI) { // throw new OidcException('interaction_required', 'requested account is different from logged in account, no UI requested'); } else { // echo loginform($requested_userid_display, $requested_userid, $client); exit; } } } // if(in_array('consent', $prompt)){ // echo confirm_userinfo(); // exit(); // } if (!db_get_user_trusted_client($_SESSION['username'], $_REQUEST['client_id'])) { if (!$showUI) { throw new OidcException('interaction_required', 'consent needed and prompt set to none'); } echo confirm_userinfo(); } else { send_response_noRedirect($_SESSION['username'], true); } } else { // SBE Redirect to auth_time send_auth_response($request_uri, array(), $response_mode); // header("Location: /auth?client_id=$client_id&response_type=$_REQUEST['response_type']&scope=$_REQUEST['scope']&nonce=$_REQUEST['nonce']"); // if(!$showUI) // throw new OidcException('interaction_required', 'unauthenticated and prompt set to none'); // echo custom_loginform($requested_userid_display, $requested_userid, $client); } } catch (OidcException $e) { log_debug("handle_auth exception : %s", $e->getTraceAsString()); send_error($error_page, $e->error_code, $e->desc, NULL, $state, $response_mode); } catch (Exception $e) { log_debug("handle_auth exception : %s", $e->getTraceAsString()); send_error($error_page, 'invalid_request', $e->getMessage(), NULL, $state, $response_mode); } }