19 declare(strict_types=1);
37 if (!class_exists(
'OAuthException')) {
47 if (!class_exists(
'OAuthConsumer')) {
54 public string $secret;
57 public ?
string $callback_url;
65 public function __construct(
string $key,
string $secret, ?
string $callback_url =
null)
68 $this->secret = $secret;
69 $this->callback_url = $callback_url;
76 public function __toString()
78 return "OAuthConsumer[key=$this->key,secret=$this->secret]";
82 if (!class_exists(
'OAuthToken')) {
90 public string $secret;
93 public $callback =
null;
99 public function __construct(
string $key,
string $secret)
102 $this->secret = $secret;
109 public function to_string():
string 112 $key = OAuthUtil::urlencode_rfc3986($this->key);
114 $secret = OAuthUtil::urlencode_rfc3986($this->secret);
115 return "oauth_token=" . $key .
116 "&oauth_token_secret=" . $secret .
117 "&oauth_callback_confirmed=true";
123 public function __toString()
125 return $this->to_string();
133 if (!class_exists(
'OAuthSignatureMethod')) {
139 abstract public function get_name(): string;
148 abstract public function build_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken
$token): string;
158 public function check_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken $token,
string $signature):
bool 160 $built = $this->build_signature($request, $consumer, $token);
163 if (strlen($built) == 0 || strlen($signature) == 0) {
167 if (strlen($built) != strlen($signature)) {
173 for ($i = 0; $i < strlen($signature); $i++) {
174 $result |= ord($built[$i]) ^ ord($signature[$i]);
200 public function build_signature(OAuthRequest $request, OAuthConsumer $consumer, ?OAuthToken
$token):
string 202 $base_string = $request->get_signature_base_string();
203 $request->base_string = $base_string;
207 (
$token) ? $token->secret :
"" 211 $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
212 $key = implode(
'&', $key_parts);
214 return base64_encode(hash_hmac(
'sha1', $base_string, $key,
true));
223 if (!class_exists(
'OAuthSignatureMethod_PLAINTEXT')) {
226 public function get_name():
string 243 public function build_signature(OAuthRequest $request, OAuthConsumer $consumer, ?OAuthToken
$token):
string 247 (
$token) ? $token->secret :
"" 251 $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
252 $key = implode(
'&', $key_parts);
253 $request->base_string = $key;
267 if (!class_exists(
'OAuthSignatureMethod_RSA_SHA1')) {
270 public function get_name():
string 286 abstract protected function fetch_public_cert(OAuthRequest &$request);
297 abstract protected function fetch_private_cert(OAuthRequest &$request);
300 public function build_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken
$token):
string 302 $base_string = $request->get_signature_base_string();
303 $request->base_string = $base_string;
306 $cert = $this->fetch_private_cert($request);
309 $privatekeyid = openssl_get_privatekey($cert);
312 openssl_sign($base_string, $signature, $privatekeyid);
314 if (PHP_MAJOR_VERSION < 8) {
316 openssl_free_key($privatekeyid);
318 return base64_encode($signature);
322 public function check_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken $token,
string $signature):
bool 324 $decoded_sig = base64_decode($signature);
326 $base_string = $request->get_signature_base_string();
329 $cert = $this->fetch_public_cert($request);
332 $publickeyid = openssl_get_publickey($cert);
335 $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
337 if (PHP_MAJOR_VERSION < 8) {
339 openssl_free_key($publickeyid);
346 if (!class_exists(
'OAuthRequest')) {
350 protected array $parameters;
353 protected string $http_method;
356 protected string $http_url;
360 public ?
string $base_string =
null;
363 public static string $version =
'1.0';
366 public static string $POST_INPUT =
'php://input';
375 public function __construct(
string $http_method,
string $http_url, ?array $parameters =
null)
377 $parameters = ($parameters) ? $parameters : [];
378 $parameters = array_merge(OAuthUtil::parse_parameters((
string) parse_url($http_url, PHP_URL_QUERY)), $parameters);
380 $this->http_method = $http_method;
381 $this->http_url = $http_url;
391 public static function from_request(?
string $http_method =
null, ?
string $http_url =
null, ?array $parameters =
null): OAuthRequest
399 if ($UseHttpHostInsteadOfServerName ==
true) {
402 strpos(
':',
$_SERVER[
'HTTP_HOST']) < 0) {
403 $port =
':' .
$_SERVER[
'SERVER_PORT'] ;
405 $http_url = ($http_url) ? $http_url : $scheme .
410 $http_url = ($http_url) ? $http_url : $scheme .
418 $http_method = ($http_method) ? $http_method :
$_SERVER[
'REQUEST_METHOD'];
426 $request_headers = OAuthUtil::get_headers();
429 $parameters = OAuthUtil::parse_parameters(
$_SERVER[
'QUERY_STRING']);
433 if ($http_method ==
"POST" 434 && isset($request_headers[
'Content-Type'])
435 && strstr($request_headers[
'Content-Type'],
'application/x-www-form-urlencoded')
437 $post_data = OAuthUtil::parse_parameters(
438 file_get_contents(self::$POST_INPUT)
440 $parameters = array_merge($parameters, $post_data);
445 if (isset($request_headers[
'Authorization'])
446 && substr($request_headers[
'Authorization'], 0, 6) ==
'OAuth ' 448 $header_parameters = OAuthUtil::split_header(
449 $request_headers[
'Authorization']
451 $parameters = array_merge($parameters, $header_parameters);
455 return new OAuthRequest($http_method, $http_url, $parameters);
467 public static function from_consumer_and_token(OAuthConsumer $consumer, ?OAuthToken
$token,
string $http_method,
string $http_url, ?array $parameters =
null): OAuthRequest
469 $parameters = ($parameters) ? $parameters : [];
471 "oauth_nonce" => OAuthRequest::generate_nonce(),
472 "oauth_timestamp" => OAuthRequest::generate_timestamp(),
473 "oauth_consumer_key" => $consumer->key];
475 $defaults[
'oauth_token'] = $token->key;
478 $parameters = array_merge($defaults, $parameters);
480 return new OAuthRequest($http_method, $http_url, $parameters);
484 public function set_parameter(
string $name,
string $value,
bool $allow_duplicates =
true):
void 486 if ($allow_duplicates && isset($this->
parameters[$name])) {
504 public function get_parameter(
string $name)
513 public function get_parameters(): array
515 return $this->parameters;
519 public function unset_parameter(
string $name):
void 528 public function get_signable_parameters():
string 535 if (isset(
$params[
'oauth_signature'])) {
536 unset(
$params[
'oauth_signature']);
539 return OAuthUtil::build_http_query(
$params);
550 public function get_signature_base_string():
string 553 $this->get_normalized_http_method(),
554 $this->get_normalized_http_url(),
555 $this->get_signable_parameters()
561 return implode(
'&',
$parts);
568 public function get_normalized_http_method():
string 570 return strtoupper($this->http_method);
578 public function get_normalized_http_url():
string 580 $parts = parse_url($this->http_url);
582 $scheme = (isset(
$parts[
'scheme'])) ?
$parts[
'scheme'] :
'http';
583 $port = (isset(
$parts[
'port'])) ?
$parts[
'port'] : (($scheme ==
'https') ?
'443' :
'80');
584 $host = (isset(
$parts[
'host'])) ? strtolower(
$parts[
'host']) :
'';
587 if (($scheme ==
'https' && $port !=
'443')
588 || ($scheme ==
'http' && $port !=
'80')) {
589 $host =
"$host:$port";
591 return "$scheme://$host$path";
598 public function to_url():
string 600 $post_data = $this->to_postdata();
601 $out = $this->get_normalized_http_url();
603 $out .=
'?' . $post_data;
612 public function to_postdata():
string 614 return OAuthUtil::build_http_query($this->
parameters);
623 public function to_header(?
string $realm =
null):
string 626 if (!is_null($realm)) {
628 $realm = OAuthUtil::urlencode_rfc3986($realm);
629 $out =
'Authorization: OAuth realm="' . $realm .
'"';
632 $out =
'Authorization: OAuth';
636 if (substr($k, 0, 5) !=
"oauth") {
640 throw new OAuthException(
'Arrays not supported in headers');
642 $out .= ($first) ?
' ' :
',';
644 $key = OAuthUtil::urlencode_rfc3986($k);
646 $value = OAuthUtil::urlencode_rfc3986($v);
647 $out .= $key .
'="' . $value .
'"';
657 public function __toString()
659 return $this->to_url();
663 public function sign_request(
OAuthSignatureMethod $signature_method, OAuthConsumer $consumer, ?OAuthToken $token):
void 665 $this->set_parameter(
666 "oauth_signature_method",
667 $signature_method->get_name(),
670 $signature = $this->build_signature($signature_method, $consumer, $token);
671 $this->set_parameter(
"oauth_signature", $signature,
false);
675 public function build_signature(
OAuthSignatureMethod $signature_method, OAuthConsumer $consumer, ?OAuthToken $token):
string 677 $signature = $signature_method->build_signature($this, $consumer, $token);
685 private static function generate_timestamp():
int 694 private static function generate_nonce():
string 699 return md5($mt . $rand);
703 if (!class_exists(
'OAuthServer')) {
707 protected int $timestamp_threshold = 300;
713 protected array $signature_methods = [];
724 $this->data_store = $data_store;
730 $this->signature_methods[$signature_method->get_name()] =
740 public function fetch_request_token(OAuthRequest &$request): OAuthToken
742 $this->getVersion($request);
744 $consumer = $this->getConsumer($request);
749 $this->checkSignature($request, $consumer,
$token);
752 $callback = $request->get_parameter(
'oauth_callback');
753 $new_token = $this->data_store->new_request_token($consumer, $callback);
763 public function fetch_access_token(OAuthRequest &$request): OAuthToken
765 $this->getVersion($request);
767 $consumer = $this->getConsumer($request);
770 $token = $this->getToken($request, $consumer,
"request");
772 $this->checkSignature($request, $consumer,
$token);
775 $verifier = $request->get_parameter(
'oauth_verifier');
776 $new_token = $this->data_store->new_access_token(
$token, $consumer, $verifier);
787 public function verify_request(OAuthRequest &$request): array
789 $this->getVersion($request);
790 $consumer = $this->getConsumer($request);
791 $token = $this->getToken($request, $consumer,
"access");
792 $this->checkSignature($request, $consumer,
$token);
793 return [$consumer,
$token];
801 private function getVersion(OAuthRequest &$request):
string 803 $version = $request->get_parameter(
"oauth_version");
809 if ($version !== $this->version) {
810 throw new OAuthException(
"OAuth version '$version' not supported");
821 private function getSignatureMethod(OAuthRequest $request):
object 823 $signature_method = $request->get_parameter(
"oauth_signature_method");
825 if (!$signature_method) {
828 if ($DefaultSignatureMethodPlaintext ==
true) {
829 $signature_method =
"PLAINTEXT";
833 throw new OAuthException(
'No signature method parameter. This parameter is required');
838 if (!in_array($signature_method, array_keys($this->signature_methods))) {
839 throw new OAuthException(
840 "Signature method '$signature_method' not supported " .
841 "try one of the following: " .
842 implode(
", ", array_keys($this->signature_methods))
845 return $this->signature_methods[$signature_method];
854 private function getConsumer(OAuthRequest $request): OAuthConsumer
856 $consumer_key = $request->get_parameter(
"oauth_consumer_key");
858 if (!$consumer_key) {
859 throw new OAuthException(
"Invalid consumer key");
862 $consumer = $this->data_store->lookup_consumer($consumer_key);
864 throw new OAuthException(
"Invalid consumer");
876 private function getToken(OAuthRequest $request, OAuthConsumer $consumer,
string $token_type =
"access"): OAuthToken
878 $token_field = $request->get_parameter(
'oauth_token');
880 if (!empty($token_field)) {
881 $token = $this->data_store->lookup_token($consumer, $token_type, $token_field);
883 throw new OAuthException(
'Invalid ' . $token_type .
' token: ' . $token_field);
886 $token =
new OAuthToken(
'',
'');
901 private function checkSignature(OAuthRequest $request, OAuthConsumer $consumer, ?OAuthToken
$token =
null):
void 904 $timestamp = (
int) $request->get_parameter(
'oauth_timestamp');
905 $nonce = $request->get_parameter(
'oauth_nonce');
911 $signature_method = $this->getSignatureMethod($request);
913 $method =
new $signature_method();
915 $signature = $request->get_parameter(
'oauth_signature');
917 $valid_sig = $method->check_signature(
925 throw new OAuthException(
"Invalid signature");
935 private function checkTimestamp(?
int $timestamp):
void 938 throw new OAuthException(
939 'Missing timestamp parameter. The parameter is required' 945 if (abs($now - $timestamp) > $this->timestamp_threshold) {
946 throw new OAuthException(
947 "Expired timestamp, yours $timestamp, ours $now" 958 private function checkNonce(OAuthConsumer $consumer, ?OAuthToken
$token,
string $nonce,
int $timestamp):
void 961 throw new OAuthException(
962 'Missing nonce parameter. The parameter is required' 967 $found = $this->data_store->lookup_nonce(
974 throw new OAuthException(
"Nonce already used: $nonce");
979 if (!class_exists(
'OAuthDataStore')) {
982 abstract public function lookup_consumer(
string $consumer_key);
985 abstract public function lookup_token(OAuthConsumer $consumer,
string $token_type,
string $token);
988 abstract public function lookup_nonce(OAuthConsumer $consumer, ?OAuthToken $token,
string $nonce,
int $timestamp);
994 abstract public function new_request_token(OAuthConsumer $consumer, ?
string $callback =
null);
1001 abstract public function new_access_token(OAuthToken $token, OAuthConsumer $consumer, ?
string $verifier =
null);
1004 if (!class_exists(
'OAuthUtil')) {
1011 public static function urlencode_rfc3986($input)
1013 if (is_array($input)) {
1014 return array_map([
'ILIAS\LTIOAuth\OAuthUtil',
'urlencode_rfc3986'], $input);
1015 } elseif (is_scalar($input)) {
1019 str_replace(
'%7E',
'~', rawurlencode(strval($input)))
1032 public static function urldecode_rfc3986(
string $string):
string 1034 return urldecode($string);
1047 public static function split_header(
string $header,
bool $only_allow_oauth_parameters =
true): array
1051 '/(' . ($only_allow_oauth_parameters ?
'oauth_' :
'') .
'[a-z_-]*)=(:?"([^"]*)"|([^,]*))/',
1055 foreach ($matches[1] as $i => $h) {
1056 $params[$h] = OAuthUtil::urldecode_rfc3986(empty($matches[3][$i]) ? $matches[4][$i] : $matches[3][$i]);
1058 if (isset(
$params[
'realm'])) {
1071 public static function get_headers(): array
1073 if (function_exists(
'apache_request_headers')) {
1076 $headers = getallheaders();
1083 foreach ($headers as $key => $value) {
1087 ucwords(strtolower(str_replace(
"-",
" ", $key)))
1089 $out[$key] = $value;
1095 if (isset(
$_SERVER[
'CONTENT_TYPE'])) {
1098 if (isset($_ENV[
'CONTENT_TYPE'])) {
1099 $out[
'Content-Type'] = $_ENV[
'CONTENT_TYPE'];
1102 foreach (
$_SERVER as $key => $value) {
1103 if (substr($key, 0, 5) ==
"HTTP_") {
1110 ucwords(strtolower(str_replace(
"_",
" ", substr($key, 5))))
1112 $out[$key] = $value;
1116 if (isset(
$out[
'Auth'])) {
1117 $out[
'Authorization'] =
$out[
'Auth'];
1131 public static function parse_parameters(?
string $input): array
1133 if (!isset($input) || $input ==
"") {
1137 $pairs = explode(
'&', $input);
1139 $parsed_parameters = [];
1140 foreach ($pairs as $pair) {
1141 $split = explode(
'=', $pair, 2);
1142 $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
1143 $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) :
'';
1145 if (isset($parsed_parameters[$parameter])) {
1149 if (is_scalar($parsed_parameters[$parameter])) {
1152 $parsed_parameters[$parameter] = [$parsed_parameters[$parameter]];
1155 $parsed_parameters[$parameter][] = $value;
1157 $parsed_parameters[$parameter] = $value;
1160 return $parsed_parameters;
1167 public static function build_http_query(array
$params):
string 1175 $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
1177 $values = OAuthUtil::urlencode_rfc3986(array_values($params));
1178 $params = array_combine($keys, $values);
1182 uksort($params,
'strcmp');
1185 foreach ($params as $parameter => $value) {
1186 if (is_array($value)) {
1190 sort($value, SORT_STRING);
1191 foreach ($value as $duplicate_value) {
1192 $pairs[] = $parameter .
'=' . $duplicate_value;
1195 $pairs[] = $parameter .
'=' . $value;
1200 return implode(
'&', $pairs);
parameters()
description: > This shows how different states are being used in the same Prompt according to parame...
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
OAuth PECL extension includes an OAuth Exception class, so we need to wrap the definition of this cla...
sort()
description: > Example for rendering a Sort Glyph.
$UseHttpHostInsteadOfServerName
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
__construct()
Constructor setup ILIAS global object public.
$DefaultSignatureMethodPlaintext
foreach($mandatory_scripts as $file) $timestamp