ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
Server.php
Go to the documentation of this file.
1<?php
2
95require_once "Auth/OpenID.php";
96require_once "Auth/OpenID/Association.php";
97require_once "Auth/OpenID/CryptUtil.php";
98require_once "Auth/OpenID/BigMath.php";
99require_once "Auth/OpenID/DiffieHellman.php";
100require_once "Auth/OpenID/KVForm.php";
101require_once "Auth/OpenID/TrustRoot.php";
102require_once "Auth/OpenID/ServerRequest.php";
103require_once "Auth/OpenID/Message.php";
104require_once "Auth/OpenID/Nonce.php";
105
106define('AUTH_OPENID_HTTP_OK', 200);
107define('AUTH_OPENID_HTTP_REDIRECT', 302);
108define('AUTH_OPENID_HTTP_ERROR', 400);
109
114$_Auth_OpenID_Request_Modes = array('checkid_setup',
115 'checkid_immediate');
116
120define('Auth_OpenID_ENCODE_KVFORM', 'kfvorm');
121
125define('Auth_OpenID_ENCODE_URL', 'URL/redirect');
126
130define('Auth_OpenID_ENCODE_HTML_FORM', 'HTML form');
131
135function Auth_OpenID_isError($obj, $cls = 'Auth_OpenID_ServerError')
136{
137 return is_a($obj, $cls);
138}
139
151 function Auth_OpenID_ServerError($message = null, $text = null,
152 $reference = null, $contact = null)
153 {
154 $this->message = $message;
155 $this->text = $text;
156 $this->contact = $contact;
157 $this->reference = $reference;
158 }
159
160 function getReturnTo()
161 {
162 if ($this->message &&
163 $this->message->hasKey(Auth_OpenID_OPENID_NS, 'return_to')) {
164 return $this->message->getArg(Auth_OpenID_OPENID_NS,
165 'return_to');
166 } else {
167 return null;
168 }
169 }
170
175 function hasReturnTo()
176 {
177 return $this->getReturnTo() !== null;
178 }
179
185 function encodeToURL()
186 {
187 if (!$this->message) {
188 return null;
189 }
190
191 $msg = $this->toMessage();
192 return $msg->toURL($this->getReturnTo());
193 }
194
201 function encodeToKVForm()
202 {
204 array('mode' => 'error',
205 'error' => $this->toString()));
206 }
207
208 function toFormMarkup($form_tag_attrs=null)
209 {
210 $msg = $this->toMessage();
211 return $msg->toFormMarkup($this->getReturnTo(), $form_tag_attrs);
212 }
213
214 function toHTML($form_tag_attrs=null)
215 {
217 $this->toFormMarkup($form_tag_attrs));
218 }
219
220 function toMessage()
221 {
222 // Generate a Message object for sending to the relying party,
223 // after encoding.
224 $namespace = $this->message->getOpenIDNamespace();
225 $reply = new Auth_OpenID_Message($namespace);
226 $reply->setArg(Auth_OpenID_OPENID_NS, 'mode', 'error');
227 $reply->setArg(Auth_OpenID_OPENID_NS, 'error', $this->toString());
228
229 if ($this->contact !== null) {
230 $reply->setArg(Auth_OpenID_OPENID_NS, 'contact', $this->contact);
231 }
232
233 if ($this->reference !== null) {
234 $reply->setArg(Auth_OpenID_OPENID_NS, 'reference',
235 $this->reference);
236 }
237
238 return $reply;
239 }
240
246 function whichEncoding()
247 {
249
250 if ($this->hasReturnTo()) {
251 if ($this->message->isOpenID2() &&
252 (strlen($this->encodeToURL()) >
255 } else {
257 }
258 }
259
260 if (!$this->message) {
261 return null;
262 }
263
264 $mode = $this->message->getArg(Auth_OpenID_OPENID_NS,
265 'mode');
266
267 if ($mode) {
268 if (!in_array($mode, $_Auth_OpenID_Request_Modes)) {
270 }
271 }
272 return null;
273 }
274
278 function toString()
279 {
280 if ($this->text) {
281 return $this->text;
282 } else {
283 return get_class($this) . " error";
284 }
285 }
286}
287
295 function Auth_OpenID_NoReturnToError($message = null,
296 $text = "No return_to URL available")
297 {
298 parent::Auth_OpenID_ServerError($message, $text);
299 }
300
301 function toString()
302 {
303 return "No return_to available";
304 }
305}
306
313 function Auth_OpenID_MalformedReturnURL($message, $return_to)
314 {
315 $this->return_to = $return_to;
316 parent::Auth_OpenID_ServerError($message, "malformed return_to URL");
317 }
318}
319
326 function Auth_OpenID_MalformedTrustRoot($message = null,
327 $text = "Malformed trust root")
328 {
329 parent::Auth_OpenID_ServerError($message, $text);
330 }
331
332 function toString()
333 {
334 return "Malformed trust root";
335 }
336}
337
344 var $mode = null;
345}
346
353 var $mode = "check_authentication";
355
356 function Auth_OpenID_CheckAuthRequest($assoc_handle, $signed,
357 $invalidate_handle = null)
358 {
359 $this->assoc_handle = $assoc_handle;
360 $this->signed = $signed;
361 if ($invalidate_handle !== null) {
362 $this->invalidate_handle = $invalidate_handle;
363 }
364 $this->namespace = Auth_OpenID_OPENID2_NS;
365 $this->message = null;
366 }
367
368 static function fromMessage($message, $server=null)
369 {
370 $required_keys = array('assoc_handle', 'sig', 'signed');
371
372 foreach ($required_keys as $k) {
373 if (!$message->getArg(Auth_OpenID_OPENID_NS, $k)) {
374 return new Auth_OpenID_ServerError($message,
375 sprintf("%s request missing required parameter %s from \
376 query", "check_authentication", $k));
377 }
378 }
379
380 $assoc_handle = $message->getArg(Auth_OpenID_OPENID_NS, 'assoc_handle');
381 $sig = $message->getArg(Auth_OpenID_OPENID_NS, 'sig');
382
383 $signed_list = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
384 $signed_list = explode(",", $signed_list);
385
386 $signed = $message;
387 if ($signed->hasKey(Auth_OpenID_OPENID_NS, 'mode')) {
388 $signed->setArg(Auth_OpenID_OPENID_NS, 'mode', 'id_res');
389 }
390
391 $result = new Auth_OpenID_CheckAuthRequest($assoc_handle, $signed);
392 $result->message = $message;
393 $result->sig = $sig;
394 $result->invalidate_handle = $message->getArg(Auth_OpenID_OPENID_NS,
395 'invalidate_handle');
396 return $result;
397 }
398
399 function answer($signatory)
400 {
401 $is_valid = $signatory->verify($this->assoc_handle, $this->signed);
402
403 // Now invalidate that assoc_handle so it this checkAuth
404 // message cannot be replayed.
405 $signatory->invalidate($this->assoc_handle, true);
406 $response = new Auth_OpenID_ServerResponse($this);
407
408 $response->fields->setArg(Auth_OpenID_OPENID_NS,
409 'is_valid',
410 ($is_valid ? "true" : "false"));
411
412 if ($this->invalidate_handle) {
413 $assoc = $signatory->getAssociation($this->invalidate_handle,
414 false);
415 if (!$assoc) {
416 $response->fields->setArg(Auth_OpenID_OPENID_NS,
417 'invalidate_handle',
418 $this->invalidate_handle);
419 }
420 }
421 return $response;
422 }
423}
424
435 var $session_type = 'no-encryption';
436 var $needs_math = false;
437 var $allowed_assoc_types = array('HMAC-SHA1', 'HMAC-SHA256');
438
439 static function fromMessage($unused_request)
440 {
442 }
443
444 function answer($secret)
445 {
446 return array('mac_key' => base64_encode($secret));
447 }
448}
449
461 var $session_type = 'DH-SHA1';
462 var $needs_math = true;
463 var $allowed_assoc_types = array('HMAC-SHA1');
464 var $hash_func = 'Auth_OpenID_SHA1';
465
466 function Auth_OpenID_DiffieHellmanSHA1ServerSession($dh, $consumer_pubkey)
467 {
468 $this->dh = $dh;
469 $this->consumer_pubkey = $consumer_pubkey;
470 }
471
472 static function getDH($message)
473 {
474 $dh_modulus = $message->getArg(Auth_OpenID_OPENID_NS, 'dh_modulus');
475 $dh_gen = $message->getArg(Auth_OpenID_OPENID_NS, 'dh_gen');
476
477 if ((($dh_modulus === null) && ($dh_gen !== null)) ||
478 (($dh_gen === null) && ($dh_modulus !== null))) {
479
480 if ($dh_modulus === null) {
481 $missing = 'modulus';
482 } else {
483 $missing = 'generator';
484 }
485
486 return new Auth_OpenID_ServerError($message,
487 'If non-default modulus or generator is '.
488 'supplied, both must be supplied. Missing '.
489 $missing);
490 }
491
492 $lib = Auth_OpenID_getMathLib();
493
494 if ($dh_modulus || $dh_gen) {
495 $dh_modulus = $lib->base64ToLong($dh_modulus);
496 $dh_gen = $lib->base64ToLong($dh_gen);
497 if ($lib->cmp($dh_modulus, 0) == 0 ||
498 $lib->cmp($dh_gen, 0) == 0) {
499 return new Auth_OpenID_ServerError(
500 $message, "Failed to parse dh_mod or dh_gen");
501 }
502 $dh = new Auth_OpenID_DiffieHellman($dh_modulus, $dh_gen);
503 } else {
504 $dh = new Auth_OpenID_DiffieHellman();
505 }
506
507 $consumer_pubkey = $message->getArg(Auth_OpenID_OPENID_NS,
508 'dh_consumer_public');
509 if ($consumer_pubkey === null) {
510 return new Auth_OpenID_ServerError($message,
511 'Public key for DH-SHA1 session '.
512 'not found in query');
513 }
514
515 $consumer_pubkey =
516 $lib->base64ToLong($consumer_pubkey);
517
518 if ($consumer_pubkey === false) {
519 return new Auth_OpenID_ServerError($message,
520 "dh_consumer_public is not base64");
521 }
522
523 return array($dh, $consumer_pubkey);
524 }
525
526 static function fromMessage($message)
527 {
529
530 if (is_a($result, 'Auth_OpenID_ServerError')) {
531 return $result;
532 } else {
533 list($dh, $consumer_pubkey) = $result;
535 $consumer_pubkey);
536 }
537 }
538
539 function answer($secret)
540 {
541 $lib = Auth_OpenID_getMathLib();
542 $mac_key = $this->dh->xorSecret($this->consumer_pubkey, $secret,
543 $this->hash_func);
544 return array(
545 'dh_server_public' =>
546 $lib->longToBase64($this->dh->public),
547 'enc_mac_key' => base64_encode($mac_key));
548 }
549}
550
558
559 var $session_type = 'DH-SHA256';
560 var $hash_func = 'Auth_OpenID_SHA256';
561 var $allowed_assoc_types = array('HMAC-SHA256');
562
563 static function fromMessage($message)
564 {
566
567 if (is_a($result, 'Auth_OpenID_ServerError')) {
568 return $result;
569 } else {
570 list($dh, $consumer_pubkey) = $result;
572 $consumer_pubkey);
573 }
574 }
575}
576
583 var $mode = "associate";
584
585 static function getSessionClasses()
586 {
587 return array(
588 'no-encryption' => 'Auth_OpenID_PlainTextServerSession',
589 'DH-SHA1' => 'Auth_OpenID_DiffieHellmanSHA1ServerSession',
590 'DH-SHA256' => 'Auth_OpenID_DiffieHellmanSHA256ServerSession');
591 }
592
593 function Auth_OpenID_AssociateRequest($session, $assoc_type)
594 {
595 $this->session = $session;
596 $this->namespace = Auth_OpenID_OPENID2_NS;
597 $this->assoc_type = $assoc_type;
598 }
599
600 static function fromMessage($message, $server=null)
601 {
602 if ($message->isOpenID1()) {
603 $session_type = $message->getArg(Auth_OpenID_OPENID_NS,
604 'session_type');
605
606 if ($session_type == 'no-encryption') {
607 // oidutil.log('Received OpenID 1 request with a no-encryption '
608 // 'assocaition session type. Continuing anyway.')
609 } else if (!$session_type) {
610 $session_type = 'no-encryption';
611 }
612 } else {
613 $session_type = $message->getArg(Auth_OpenID_OPENID_NS,
614 'session_type');
615 if ($session_type === null) {
616 return new Auth_OpenID_ServerError($message,
617 "session_type missing from request");
618 }
619 }
620
621 $session_class = Auth_OpenID::arrayGet(
623 $session_type);
624
625 if ($session_class === null) {
626 return new Auth_OpenID_ServerError($message,
627 "Unknown session type " .
628 $session_type);
629 }
630
631 $session = call_user_func(array($session_class, 'fromMessage'),
632 $message);
633 if (is_a($session, 'Auth_OpenID_ServerError')) {
634 return $session;
635 }
636
637 $assoc_type = $message->getArg(Auth_OpenID_OPENID_NS,
638 'assoc_type', 'HMAC-SHA1');
639
640 if (!in_array($assoc_type, $session->allowed_assoc_types)) {
641 $fmt = "Session type %s does not support association type %s";
642 return new Auth_OpenID_ServerError($message,
643 sprintf($fmt, $session_type, $assoc_type));
644 }
645
646 $obj = new Auth_OpenID_AssociateRequest($session, $assoc_type);
647 $obj->message = $message;
648 $obj->namespace = $message->getOpenIDNamespace();
649 return $obj;
650 }
651
652 function answer($assoc)
653 {
654 $response = new Auth_OpenID_ServerResponse($this);
655 $response->fields->updateArgs(Auth_OpenID_OPENID_NS,
656 array(
657 'expires_in' => sprintf('%d', $assoc->getExpiresIn()),
658 'assoc_type' => $this->assoc_type,
659 'assoc_handle' => $assoc->handle));
660
661 $response->fields->updateArgs(Auth_OpenID_OPENID_NS,
662 $this->session->answer($assoc->secret));
663
664 if (! ($this->session->session_type == 'no-encryption'
665 && $this->message->isOpenID1())) {
666 $response->fields->setArg(Auth_OpenID_OPENID_NS,
667 'session_type',
668 $this->session->session_type);
669 }
670
671 return $response;
672 }
673
674 function answerUnsupported($text_message,
675 $preferred_association_type=null,
676 $preferred_session_type=null)
677 {
678 if ($this->message->isOpenID1()) {
679 return new Auth_OpenID_ServerError($this->message);
680 }
681
682 $response = new Auth_OpenID_ServerResponse($this);
683 $response->fields->setArg(Auth_OpenID_OPENID_NS,
684 'error_code', 'unsupported-type');
685 $response->fields->setArg(Auth_OpenID_OPENID_NS,
686 'error', $text_message);
687
688 if ($preferred_association_type) {
689 $response->fields->setArg(Auth_OpenID_OPENID_NS,
690 'assoc_type',
691 $preferred_association_type);
692 }
693
694 if ($preferred_session_type) {
695 $response->fields->setArg(Auth_OpenID_OPENID_NS,
696 'session_type',
697 $preferred_session_type);
698 }
699 $response->code = AUTH_OPENID_HTTP_ERROR;
700 return $response;
701 }
702}
703
714 var $verifyReturnTo = 'Auth_OpenID_verifyReturnTo';
715
719 var $mode = "checkid_setup"; // or "checkid_immediate"
720
724 var $immediate = false;
725
729 var $trust_root = null;
730
736
737 static function make($message, $identity, $return_to, $trust_root = null,
738 $immediate = false, $assoc_handle = null, $server = null)
739 {
740 if ($server === null) {
741 return new Auth_OpenID_ServerError($message,
742 "server must not be null");
743 }
744
745 if ($return_to &&
746 !Auth_OpenID_TrustRoot::_parse($return_to)) {
747 return new Auth_OpenID_MalformedReturnURL($message, $return_to);
748 }
749
750 $r = new Auth_OpenID_CheckIDRequest($identity, $return_to,
752 $assoc_handle, $server);
753
754 $r->namespace = $message->getOpenIDNamespace();
755 $r->message = $message;
756
757 if (!$r->trustRootValid()) {
758 return new Auth_OpenID_UntrustedReturnURL($message,
759 $return_to,
761 } else {
762 return $r;
763 }
764 }
765
766 function Auth_OpenID_CheckIDRequest($identity, $return_to,
767 $trust_root = null, $immediate = false,
768 $assoc_handle = null, $server = null,
769 $claimed_id = null)
770 {
771 $this->namespace = Auth_OpenID_OPENID2_NS;
772 $this->assoc_handle = $assoc_handle;
773 $this->identity = $identity;
774 if ($claimed_id === null) {
775 $this->claimed_id = $identity;
776 } else {
777 $this->claimed_id = $claimed_id;
778 }
779 $this->return_to = $return_to;
780 $this->trust_root = $trust_root;
781 $this->server = $server;
782
783 if ($immediate) {
784 $this->immediate = true;
785 $this->mode = "checkid_immediate";
786 } else {
787 $this->immediate = false;
788 $this->mode = "checkid_setup";
789 }
790 }
791
792 function equals($other)
793 {
794 return (
795 (is_a($other, 'Auth_OpenID_CheckIDRequest')) &&
796 ($this->namespace == $other->namespace) &&
797 ($this->assoc_handle == $other->assoc_handle) &&
798 ($this->identity == $other->identity) &&
799 ($this->claimed_id == $other->claimed_id) &&
800 ($this->return_to == $other->return_to) &&
801 ($this->trust_root == $other->trust_root));
802 }
803
804 /*
805 * Does the relying party publish the return_to URL for this
806 * response under the realm? It is up to the provider to set a
807 * policy for what kinds of realms should be allowed. This
808 * return_to URL verification reduces vulnerability to data-theft
809 * attacks based on open proxies, corss-site-scripting, or open
810 * redirectors.
811 *
812 * This check should only be performed after making sure that the
813 * return_to URL matches the realm.
814 *
815 * @return true if the realm publishes a document with the
816 * return_to URL listed, false if not or if discovery fails
817 */
819 {
821 return call_user_func_array($this->verifyReturnTo,
822 array($this->trust_root, $this->return_to, $fetcher));
823 }
824
825 static function fromMessage($message, $server)
826 {
827 $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode');
828 $immediate = null;
829
830 if ($mode == "checkid_immediate") {
831 $immediate = true;
832 $mode = "checkid_immediate";
833 } else {
834 $immediate = false;
835 $mode = "checkid_setup";
836 }
837
838 $return_to = $message->getArg(Auth_OpenID_OPENID_NS,
839 'return_to');
840
841 if (($message->isOpenID1()) &&
842 (!$return_to)) {
843 $fmt = "Missing required field 'return_to' from checkid request";
844 return new Auth_OpenID_ServerError($message, $fmt);
845 }
846
847 $identity = $message->getArg(Auth_OpenID_OPENID_NS,
848 'identity');
849 $claimed_id = $message->getArg(Auth_OpenID_OPENID_NS, 'claimed_id');
850 if ($message->isOpenID1()) {
851 if ($identity === null) {
852 $s = "OpenID 1 message did not contain openid.identity";
853 return new Auth_OpenID_ServerError($message, $s);
854 }
855 } else {
856 if ($identity && !$claimed_id) {
857 $s = "OpenID 2.0 message contained openid.identity but not " .
858 "claimed_id";
859 return new Auth_OpenID_ServerError($message, $s);
860 } else if ($claimed_id && !$identity) {
861 $s = "OpenID 2.0 message contained openid.claimed_id " .
862 "but not identity";
863 return new Auth_OpenID_ServerError($message, $s);
864 }
865 }
866
867 // There's a case for making self.trust_root be a TrustRoot
868 // here. But if TrustRoot isn't currently part of the
869 // "public" API, I'm not sure it's worth doing.
870 if ($message->isOpenID1()) {
871 $trust_root_param = 'trust_root';
872 } else {
873 $trust_root_param = 'realm';
874 }
875 $trust_root = $message->getArg(Auth_OpenID_OPENID_NS,
876 $trust_root_param);
877 if (! $trust_root) {
878 $trust_root = $return_to;
879 }
880
881 if (! $message->isOpenID1() &&
882 ($return_to === null) &&
883 ($trust_root === null)) {
884 return new Auth_OpenID_ServerError($message,
885 "openid.realm required when openid.return_to absent");
886 }
887
888 $assoc_handle = $message->getArg(Auth_OpenID_OPENID_NS,
889 'assoc_handle');
890
891 $obj = Auth_OpenID_CheckIDRequest::make($message,
892 $identity,
893 $return_to,
896 $assoc_handle,
897 $server);
898
899 if (is_a($obj, 'Auth_OpenID_ServerError')) {
900 return $obj;
901 }
902
903 $obj->claimed_id = $claimed_id;
904
905 return $obj;
906 }
907
908 function idSelect()
909 {
910 // Is the identifier to be selected by the IDP?
911 // So IDPs don't have to import the constant
912 return $this->identity == Auth_OpenID_IDENTIFIER_SELECT;
913 }
914
915 function trustRootValid()
916 {
917 if (!$this->trust_root) {
918 return true;
919 }
920
921 $tr = Auth_OpenID_TrustRoot::_parse($this->trust_root);
922 if ($tr === false) {
923 return new Auth_OpenID_MalformedTrustRoot($this->message,
924 $this->trust_root);
925 }
926
927 if ($this->return_to !== null) {
928 return Auth_OpenID_TrustRoot::match($this->trust_root,
929 $this->return_to);
930 } else {
931 return true;
932 }
933 }
934
974 function answer($allow, $server_url = null, $identity = null,
975 $claimed_id = null)
976 {
977 if (!$this->return_to) {
978 return new Auth_OpenID_NoReturnToError();
979 }
980
981 if (!$server_url) {
982 if ((!$this->message->isOpenID1()) &&
983 (!$this->server->op_endpoint)) {
984 return new Auth_OpenID_ServerError(null,
985 "server should be constructed with op_endpoint to " .
986 "respond to OpenID 2.0 messages.");
987 }
988
989 $server_url = $this->server->op_endpoint;
990 }
991
992 if ($allow) {
993 $mode = 'id_res';
994 } else if ($this->message->isOpenID1()) {
995 if ($this->immediate) {
996 $mode = 'id_res';
997 } else {
998 $mode = 'cancel';
999 }
1000 } else {
1001 if ($this->immediate) {
1002 $mode = 'setup_needed';
1003 } else {
1004 $mode = 'cancel';
1005 }
1006 }
1007
1008 if (!$this->trustRootValid()) {
1009 return new Auth_OpenID_UntrustedReturnURL(null,
1010 $this->return_to,
1011 $this->trust_root);
1012 }
1013
1014 $response = new Auth_OpenID_ServerResponse($this);
1015
1016 if ($claimed_id &&
1017 ($this->message->isOpenID1())) {
1018 return new Auth_OpenID_ServerError(null,
1019 "claimed_id is new in OpenID 2.0 and not " .
1020 "available for ".$this->namespace);
1021 }
1022
1023 if ($identity && !$claimed_id) {
1024 $claimed_id = $identity;
1025 }
1026
1027 if ($allow) {
1028
1029 if ($this->identity == Auth_OpenID_IDENTIFIER_SELECT) {
1030 if (!$identity) {
1031 return new Auth_OpenID_ServerError(null,
1032 "This request uses IdP-driven identifier selection. " .
1033 "You must supply an identifier in the response.");
1034 }
1035
1036 $response_identity = $identity;
1037 $response_claimed_id = $claimed_id;
1038
1039 } else if ($this->identity) {
1040 if ($identity &&
1041 ($this->identity != $identity)) {
1042 $fmt = "Request was for %s, cannot reply with identity %s";
1043 return new Auth_OpenID_ServerError(null,
1044 sprintf($fmt, $this->identity, $identity));
1045 }
1046
1047 $response_identity = $this->identity;
1048 $response_claimed_id = $this->claimed_id;
1049 } else {
1050 if ($identity) {
1051 return new Auth_OpenID_ServerError(null,
1052 "This request specified no identity and " .
1053 "you supplied ".$identity);
1054 }
1055
1056 $response_identity = null;
1057 }
1058
1059 if (($this->message->isOpenID1()) &&
1060 ($response_identity === null)) {
1061 return new Auth_OpenID_ServerError(null,
1062 "Request was an OpenID 1 request, so response must " .
1063 "include an identifier.");
1064 }
1065
1066 $response->fields->updateArgs(Auth_OpenID_OPENID_NS,
1067 array('mode' => $mode,
1068 'return_to' => $this->return_to,
1069 'response_nonce' => Auth_OpenID_mkNonce()));
1070
1071 if (!$this->message->isOpenID1()) {
1072 $response->fields->setArg(Auth_OpenID_OPENID_NS,
1073 'op_endpoint', $server_url);
1074 }
1075
1076 if ($response_identity !== null) {
1077 $response->fields->setArg(
1079 'identity',
1080 $response_identity);
1081 if ($this->message->isOpenID2()) {
1082 $response->fields->setArg(
1084 'claimed_id',
1085 $response_claimed_id);
1086 }
1087 }
1088
1089 } else {
1090 $response->fields->setArg(Auth_OpenID_OPENID_NS,
1091 'mode', $mode);
1092
1093 if ($this->immediate) {
1094 if (($this->message->isOpenID1()) &&
1095 (!$server_url)) {
1096 return new Auth_OpenID_ServerError(null,
1097 'setup_url is required for $allow=false \
1098 in OpenID 1.x immediate mode.');
1099 }
1100
1101 $setup_request = new Auth_OpenID_CheckIDRequest(
1102 $this->identity,
1103 $this->return_to,
1104 $this->trust_root,
1105 false,
1106 $this->assoc_handle,
1107 $this->server,
1108 $this->claimed_id);
1109 $setup_request->message = $this->message;
1110
1111 $setup_url = $setup_request->encodeToURL($server_url);
1112
1113 if ($setup_url === null) {
1114 return new Auth_OpenID_NoReturnToError();
1115 }
1116
1117 $response->fields->setArg(Auth_OpenID_OPENID_NS,
1118 'user_setup_url',
1119 $setup_url);
1120 }
1121 }
1122
1123 return $response;
1124 }
1125
1126 function encodeToURL($server_url)
1127 {
1128 if (!$this->return_to) {
1129 return new Auth_OpenID_NoReturnToError();
1130 }
1131
1132 // Imported from the alternate reality where these classes are
1133 // used in both the client and server code, so Requests are
1134 // Encodable too. That's right, code imported from alternate
1135 // realities all for the love of you, id_res/user_setup_url.
1136
1137 $q = array('mode' => $this->mode,
1138 'identity' => $this->identity,
1139 'claimed_id' => $this->claimed_id,
1140 'return_to' => $this->return_to);
1141
1142 if ($this->trust_root) {
1143 if ($this->message->isOpenID1()) {
1144 $q['trust_root'] = $this->trust_root;
1145 } else {
1146 $q['realm'] = $this->trust_root;
1147 }
1148 }
1149
1150 if ($this->assoc_handle) {
1151 $q['assoc_handle'] = $this->assoc_handle;
1152 }
1153
1154 $response = new Auth_OpenID_Message(
1155 $this->message->getOpenIDNamespace());
1156 $response->updateArgs(Auth_OpenID_OPENID_NS, $q);
1157 return $response->toURL($server_url);
1158 }
1159
1160 function getCancelURL()
1161 {
1162 if (!$this->return_to) {
1163 return new Auth_OpenID_NoReturnToError();
1164 }
1165
1166 if ($this->immediate) {
1167 return new Auth_OpenID_ServerError(null,
1168 "Cancel is not an appropriate \
1169 response to immediate mode \
1170 requests.");
1171 }
1172
1173 $response = new Auth_OpenID_Message(
1174 $this->message->getOpenIDNamespace());
1175 $response->setArg(Auth_OpenID_OPENID_NS, 'mode', 'cancel');
1176 return $response->toURL($this->return_to);
1177 }
1178}
1179
1186
1188 {
1189 $this->request = $request;
1190 $this->fields = new Auth_OpenID_Message($this->request->namespace);
1191 }
1192
1193 function whichEncoding()
1194 {
1196
1197 if (in_array($this->request->mode, $_Auth_OpenID_Request_Modes)) {
1198 if ($this->fields->isOpenID2() &&
1199 (strlen($this->encodeToURL()) >
1202 } else {
1204 }
1205 } else {
1207 }
1208 }
1209
1210 /*
1211 * Returns the form markup for this response.
1212 *
1213 * @return str
1214 */
1215 function toFormMarkup($form_tag_attrs=null)
1216 {
1217 return $this->fields->toFormMarkup($this->request->return_to,
1218 $form_tag_attrs);
1219 }
1220
1221 /*
1222 * Returns an HTML document containing the form markup for this
1223 * response that autosubmits with javascript.
1224 */
1225 function toHTML()
1226 {
1228 }
1229
1230 /*
1231 * Returns True if this response's encoding is ENCODE_HTML_FORM.
1232 * Convenience method for server authors.
1233 *
1234 * @return bool
1235 */
1236 function renderAsForm()
1237 {
1239 }
1240
1241
1242 function encodeToURL()
1243 {
1244 return $this->fields->toURL($this->request->return_to);
1245 }
1246
1247 function addExtension($extension_response)
1248 {
1249 $extension_response->toMessage($this->fields);
1250 }
1251
1252 function needsSigning()
1253 {
1254 return $this->fields->getArg(Auth_OpenID_OPENID_NS,
1255 'mode') == 'id_res';
1256 }
1257
1259 {
1260 return $this->fields->toKVForm();
1261 }
1262}
1263
1272 var $body = "";
1273
1274 function Auth_OpenID_WebResponse($code = null, $headers = null,
1275 $body = null)
1276 {
1277 if ($code) {
1278 $this->code = $code;
1279 }
1280
1281 if ($headers !== null) {
1282 $this->headers = $headers;
1283 } else {
1284 $this->headers = array();
1285 }
1286
1287 if ($body !== null) {
1288 $this->body = $body;
1289 }
1290 }
1291}
1292
1300
1301 // = 14 * 24 * 60 * 60; # 14 days, in seconds
1302 var $SECRET_LIFETIME = 1209600;
1303
1304 // keys have a bogus server URL in them because the filestore
1305 // really does expect that key to be a URL. This seems a little
1306 // silly for the server store, since I expect there to be only one
1307 // server URL.
1308 var $normal_key = 'http://localhost/|normal';
1309 var $dumb_key = 'http://localhost/|dumb';
1310
1314 function Auth_OpenID_Signatory($store)
1315 {
1316 // assert store is not None
1317 $this->store = $store;
1318 }
1319
1324 function verify($assoc_handle, $message)
1325 {
1326 $assoc = $this->getAssociation($assoc_handle, true);
1327 if (!$assoc) {
1328 // oidutil.log("failed to get assoc with handle %r to verify sig %r"
1329 // % (assoc_handle, sig))
1330 return false;
1331 }
1332
1333 return $assoc->checkMessageSignature($message);
1334 }
1335
1340 function sign($response)
1341 {
1342 $signed_response = $response;
1343 $assoc_handle = $response->request->assoc_handle;
1344
1345 if ($assoc_handle) {
1346 // normal mode
1347 $assoc = $this->getAssociation($assoc_handle, false, false);
1348 if (!$assoc || ($assoc->getExpiresIn() <= 0)) {
1349 // fall back to dumb mode
1350 $signed_response->fields->setArg(Auth_OpenID_OPENID_NS,
1351 'invalidate_handle', $assoc_handle);
1352 $assoc_type = ($assoc ? $assoc->assoc_type : 'HMAC-SHA1');
1353
1354 if ($assoc && ($assoc->getExpiresIn() <= 0)) {
1355 $this->invalidate($assoc_handle, false);
1356 }
1357
1358 $assoc = $this->createAssociation(true, $assoc_type);
1359 }
1360 } else {
1361 // dumb mode.
1362 $assoc = $this->createAssociation(true);
1363 }
1364
1365 $signed_response->fields = $assoc->signMessage(
1366 $signed_response->fields);
1367 return $signed_response;
1368 }
1369
1373 function createAssociation($dumb = true, $assoc_type = 'HMAC-SHA1')
1374 {
1376 Auth_OpenID_getSecretSize($assoc_type));
1377
1378 $uniq = base64_encode(Auth_OpenID_CryptUtil::getBytes(4));
1379 $handle = sprintf('{%s}{%x}{%s}', $assoc_type, intval(time()), $uniq);
1380
1382 $this->SECRET_LIFETIME, $handle, $secret, $assoc_type);
1383
1384 if ($dumb) {
1385 $key = $this->dumb_key;
1386 } else {
1387 $key = $this->normal_key;
1388 }
1389
1390 $this->store->storeAssociation($key, $assoc);
1391 return $assoc;
1392 }
1393
1398 function getAssociation($assoc_handle, $dumb, $check_expiration=true)
1399 {
1400 if ($assoc_handle === null) {
1401 return new Auth_OpenID_ServerError(null,
1402 "assoc_handle must not be null");
1403 }
1404
1405 if ($dumb) {
1406 $key = $this->dumb_key;
1407 } else {
1408 $key = $this->normal_key;
1409 }
1410
1411 $assoc = $this->store->getAssociation($key, $assoc_handle);
1412
1413 if (($assoc !== null) && ($assoc->getExpiresIn() <= 0)) {
1414 if ($check_expiration) {
1415 $this->store->removeAssociation($key, $assoc_handle);
1416 $assoc = null;
1417 }
1418 }
1419
1420 return $assoc;
1421 }
1422
1426 function invalidate($assoc_handle, $dumb)
1427 {
1428 if ($dumb) {
1429 $key = $this->dumb_key;
1430 } else {
1431 $key = $this->normal_key;
1432 }
1433 $this->store->removeAssociation($key, $assoc_handle);
1434 }
1435}
1436
1444
1445 var $responseFactory = 'Auth_OpenID_WebResponse';
1446
1451 function encode($response)
1452 {
1454
1455 $encode_as = $response->whichEncoding();
1456 if ($encode_as == Auth_OpenID_ENCODE_KVFORM) {
1457 $wr = new $cls(null, null, $response->encodeToKVForm());
1458 if (is_a($response, 'Auth_OpenID_ServerError')) {
1459 $wr->code = AUTH_OPENID_HTTP_ERROR;
1460 }
1461 } else if ($encode_as == Auth_OpenID_ENCODE_URL) {
1462 $location = $response->encodeToURL();
1463 $wr = new $cls(AUTH_OPENID_HTTP_REDIRECT,
1464 array('location' => $location));
1465 } else if ($encode_as == Auth_OpenID_ENCODE_HTML_FORM) {
1466 $wr = new $cls(AUTH_OPENID_HTTP_OK, array(),
1467 $response->toHTML());
1468 } else {
1469 return new Auth_OpenID_EncodingError($response);
1470 }
1471 /* Allow the response to carry a custom error code (ex: for Association errors) */
1472 if(isset($response->code)) {
1473 $wr->code = $response->code;
1474 }
1475 return $wr;
1476 }
1477}
1478
1485
1486 function Auth_OpenID_SigningEncoder($signatory)
1487 {
1488 $this->signatory = $signatory;
1489 }
1490
1495 function encode($response)
1496 {
1497 // the isinstance is a bit of a kludge... it means there isn't
1498 // really an adapter to make the interfaces quite match.
1499 if (!is_a($response, 'Auth_OpenID_ServerError') &&
1500 $response->needsSigning()) {
1501
1502 if (!$this->signatory) {
1503 return new Auth_OpenID_ServerError(null,
1504 "Must have a store to sign request");
1505 }
1506
1507 if ($response->fields->hasKey(Auth_OpenID_OPENID_NS, 'sig')) {
1508 return new Auth_OpenID_AlreadySigned($response);
1509 }
1510 $response = $this->signatory->sign($response);
1511 }
1512
1513 return parent::encode($response);
1514 }
1515}
1516
1523
1525 {
1526 $this->server = $server;
1527
1528 $this->handlers = array(
1529 'checkid_setup' => 'Auth_OpenID_CheckIDRequest',
1530 'checkid_immediate' => 'Auth_OpenID_CheckIDRequest',
1531 'check_authentication' => 'Auth_OpenID_CheckAuthRequest',
1532 'associate' => 'Auth_OpenID_AssociateRequest'
1533 );
1534 }
1535
1540 function decode($query)
1541 {
1542 if (!$query) {
1543 return null;
1544 }
1545
1547
1548 if ($message === null) {
1549 /*
1550 * It's useful to have a Message attached to a
1551 * ProtocolError, so we override the bad ns value to build
1552 * a Message out of it. Kinda kludgy, since it's made of
1553 * lies, but the parts that aren't lies are more useful
1554 * than a 'None'.
1555 */
1556 $old_ns = $query['openid.ns'];
1557
1558 $query['openid.ns'] = Auth_OpenID_OPENID2_NS;
1560 return new Auth_OpenID_ServerError(
1561 $message,
1562 sprintf("Invalid OpenID namespace URI: %s", $old_ns));
1563 }
1564
1565 $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode');
1566 if (!$mode) {
1567 return new Auth_OpenID_ServerError($message,
1568 "No mode value in message");
1569 }
1570
1571 if (Auth_OpenID::isFailure($mode)) {
1572 return new Auth_OpenID_ServerError($message,
1573 $mode->message);
1574 }
1575
1576 $handlerCls = Auth_OpenID::arrayGet($this->handlers, $mode,
1577 $this->defaultDecoder($message));
1578
1579 if (!is_a($handlerCls, 'Auth_OpenID_ServerError')) {
1580 return call_user_func_array(array($handlerCls, 'fromMessage'),
1581 array($message, $this->server));
1582 } else {
1583 return $handlerCls;
1584 }
1585 }
1586
1587 function defaultDecoder($message)
1588 {
1589 $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode');
1590
1591 if (Auth_OpenID::isFailure($mode)) {
1592 return new Auth_OpenID_ServerError($message,
1593 $mode->message);
1594 }
1595
1596 return new Auth_OpenID_ServerError($message,
1597 sprintf("Unrecognized OpenID mode %s", $mode));
1598 }
1599}
1600
1607 function Auth_OpenID_EncodingError($response)
1608 {
1609 $this->response = $response;
1610 }
1611}
1612
1619 // This response is already signed.
1620}
1621
1629 function Auth_OpenID_UntrustedReturnURL($message, $return_to,
1630 $trust_root)
1631 {
1632 parent::Auth_OpenID_ServerError($message, "Untrusted return_to URL");
1633 $this->return_to = $return_to;
1634 $this->trust_root = $trust_root;
1635 }
1636
1637 function toString()
1638 {
1639 return sprintf("return_to %s not under trust_root %s",
1640 $this->return_to, $this->trust_root);
1641 }
1642}
1643
1682 function Auth_OpenID_Server($store, $op_endpoint=null)
1683 {
1684 $this->store = $store;
1685 $this->signatory = new Auth_OpenID_Signatory($this->store);
1686 $this->encoder = new Auth_OpenID_SigningEncoder($this->signatory);
1687 $this->decoder = new Auth_OpenID_Decoder($this);
1688 $this->op_endpoint = $op_endpoint;
1689 $this->negotiator = Auth_OpenID_getDefaultNegotiator();
1690 }
1691
1703 function handleRequest($request)
1704 {
1705 if (method_exists($this, "openid_" . $request->mode)) {
1706 $handler = array($this, "openid_" . $request->mode);
1707 return call_user_func($handler, &$request);
1708 }
1709 return null;
1710 }
1711
1716 {
1717 return $request->answer($this->signatory);
1718 }
1719
1723 function openid_associate($request)
1724 {
1725 $assoc_type = $request->assoc_type;
1726 $session_type = $request->session->session_type;
1727 if ($this->negotiator->isAllowed($assoc_type, $session_type)) {
1728 $assoc = $this->signatory->createAssociation(false,
1729 $assoc_type);
1730 return $request->answer($assoc);
1731 } else {
1732 $message = sprintf('Association type %s is not supported with '.
1733 'session type %s', $assoc_type, $session_type);
1734 list($preferred_assoc_type, $preferred_session_type) =
1735 $this->negotiator->getAllowedType();
1736 return $request->answerUnsupported($message,
1737 $preferred_assoc_type,
1738 $preferred_session_type);
1739 }
1740 }
1741
1746 function encodeResponse($response)
1747 {
1748 return $this->encoder->encode($response);
1749 }
1750
1755 function decodeRequest($query=null)
1756 {
1757 if ($query === null) {
1759 }
1760
1761 return $this->decoder->decode($query);
1762 }
1763}
1764
1765
Auth_OpenID_getSecretSize($assoc_type)
Auth_OpenID_getDefaultNegotiator()
Auth_OpenID_getMathLib()
Definition: BigMath.php:400
$result
const Auth_OpenID_IDENTIFIER_SELECT
Import tools needed to deal with messages.
Definition: Message.php:18
const Auth_OpenID_OPENID1_URL_LIMIT
Definition: Message.php:54
const Auth_OpenID_OPENID_NS
Definition: Message.php:42
const Auth_OpenID_OPENID2_NS
Definition: Message.php:35
Auth_OpenID_mkNonce($when=null)
Definition: Nonce.php:91
const Auth_OpenID_ENCODE_KVFORM
@access private
Definition: Server.php:120
const Auth_OpenID_ENCODE_URL
@access private
Definition: Server.php:125
const AUTH_OPENID_HTTP_REDIRECT
Definition: Server.php:107
const AUTH_OPENID_HTTP_OK
Required imports.
Definition: Server.php:106
const Auth_OpenID_ENCODE_HTML_FORM
@access private
Definition: Server.php:130
const AUTH_OPENID_HTTP_ERROR
Definition: Server.php:108
global $_Auth_OpenID_Request_Modes
@access private
Definition: Server.php:113
Auth_OpenID_isError($obj, $cls='Auth_OpenID_ServerError')
@access private
Definition: Server.php:135
$location
Definition: buildRTE.php:44
static fromMessage($message, $server=null)
Definition: Server.php:600
answerUnsupported($text_message, $preferred_association_type=null, $preferred_session_type=null)
Definition: Server.php:674
Auth_OpenID_AssociateRequest($session, $assoc_type)
Definition: Server.php:593
static fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
This is an alternate constructor (factory method) used by the OpenID consumer library to create assoc...
Definition: Association.php:97
static fromMessage($message, $server=null)
Definition: Server.php:368
Auth_OpenID_CheckAuthRequest($assoc_handle, $signed, $invalidate_handle=null)
Definition: Server.php:356
$namespace
The OpenID namespace for this request.
Definition: Server.php:735
$immediate
Whether this request is for immediate mode.
Definition: Server.php:724
$trust_root
The trust_root value for this request.
Definition: Server.php:729
$mode
The mode of this request.
Definition: Server.php:719
$verifyReturnTo
Return-to verification callback.
Definition: Server.php:714
answer($allow, $server_url=null, $identity=null, $claimed_id=null)
Respond to this request.
Definition: Server.php:974
Auth_OpenID_CheckIDRequest($identity, $return_to, $trust_root=null, $immediate=false, $assoc_handle=null, $server=null, $claimed_id=null)
Definition: Server.php:766
static fromMessage($message, $server)
Definition: Server.php:825
encodeToURL($server_url)
Definition: Server.php:1126
static make($message, $identity, $return_to, $trust_root=null, $immediate=false, $assoc_handle=null, $server=null)
Definition: Server.php:737
static getBytes($num_bytes)
Get the specified number of random bytes.
Definition: CryptUtil.php:40
defaultDecoder($message)
Definition: Server.php:1587
decode($query)
Given an HTTP query in an array (key-value pairs), decode it into an Auth_OpenID_Request object.
Definition: Server.php:1540
Auth_OpenID_Decoder($server)
Definition: Server.php:1524
$session_type
An object that knows how to handle association requests with the Diffie-Hellman session type.
Definition: Server.php:461
Auth_OpenID_DiffieHellmanSHA1ServerSession($dh, $consumer_pubkey)
Definition: Server.php:466
encode($response)
Encode an Auth_OpenID_ServerResponse and return an Auth_OpenID_WebResponse.
Definition: Server.php:1451
Auth_OpenID_EncodingError($response)
Definition: Server.php:1607
static fromArray($values)
Convert an array into an OpenID colon/newline separated string.
Definition: KVForm.php:81
Auth_OpenID_MalformedReturnURL($message, $return_to)
Definition: Server.php:313
toString()
Returns this error message.
Definition: Server.php:332
Auth_OpenID_MalformedTrustRoot($message=null, $text="Malformed trust root")
Definition: Server.php:326
static fromPostArgs($args)
Definition: Message.php:444
toString()
Returns this error message.
Definition: Server.php:301
Auth_OpenID_NoReturnToError($message=null, $text="No return_to URL available")
Definition: Server.php:295
$session_type
An object that knows how to handle association requests with no session type.
Definition: Server.php:435
static fromMessage($unused_request)
Definition: Server.php:439
encodeToURL()
Encodes this error's response as a URL suitable for redirection.
Definition: Server.php:185
toHTML($form_tag_attrs=null)
Definition: Server.php:214
hasReturnTo()
Returns the return_to URL for the request which caused this error.
Definition: Server.php:175
Auth_OpenID_ServerError($message=null, $text=null, $reference=null, $contact=null)
@access private
Definition: Server.php:151
toString()
Returns this error message.
Definition: Server.php:278
encodeToKVForm()
Encodes the response to key-value form.
Definition: Server.php:201
toFormMarkup($form_tag_attrs=null)
Definition: Server.php:208
whichEncoding()
Returns one of Auth_OpenID_ENCODE_URL, Auth_OpenID_ENCODE_KVFORM, or null, depending on the type of e...
Definition: Server.php:246
Auth_OpenID_ServerResponse($request)
Definition: Server.php:1187
toFormMarkup($form_tag_attrs=null)
Definition: Server.php:1215
addExtension($extension_response)
Definition: Server.php:1247
openid_associate($request)
The callback for 'associate' messages.
Definition: Server.php:1723
openid_check_authentication($request)
The callback for 'check_authentication' messages.
Definition: Server.php:1715
Auth_OpenID_Server($store, $op_endpoint=null)
Definition: Server.php:1682
decodeRequest($query=null)
Decodes a query args array into the appropriate Auth_OpenID_Request object.
Definition: Server.php:1755
handleRequest($request)
Handle a request.
Definition: Server.php:1703
encodeResponse($response)
Encodes as response in the appropriate format suitable for sending to the user agent.
Definition: Server.php:1746
getAssociation($assoc_handle, $dumb, $check_expiration=true)
Given an association handle, get the association from the store, or return a ServerError or null if s...
Definition: Server.php:1398
Auth_OpenID_Signatory($store)
Create a new signatory using a given store.
Definition: Server.php:1314
verify($assoc_handle, $message)
Verify, using a given association handle, a signature with signed key-value pairs from an HTTP reques...
Definition: Server.php:1324
invalidate($assoc_handle, $dumb)
Invalidate a given association handle.
Definition: Server.php:1426
createAssociation($dumb=true, $assoc_type='HMAC-SHA1')
Make a new association.
Definition: Server.php:1373
sign($response)
Given a response, sign the fields in the response's 'signed' list, and insert the signature into the ...
Definition: Server.php:1340
Auth_OpenID_SigningEncoder($signatory)
Definition: Server.php:1486
encode($response)
Sign an Auth_OpenID_ServerResponse and return an Auth_OpenID_WebResponse.
Definition: Server.php:1495
static match($trust_root, $url)
Does this URL match the given trust root?
Definition: TrustRoot.php:270
static _parse($trust_root)
Parse a URL into its trust_root parts.
Definition: TrustRoot.php:94
Auth_OpenID_UntrustedReturnURL($message, $return_to, $trust_root)
Definition: Server.php:1629
toString()
Returns this error message.
Definition: Server.php:1637
Auth_OpenID_WebResponse($code=null, $headers=null, $body=null)
Definition: Server.php:1274
static autoSubmitHTML($form, $title="OpenId transaction in progress")
Definition: OpenID.php:532
static arrayGet($arr, $key, $fallback=null)
Convenience function for getting array values.
Definition: OpenID.php:242
static isFailure($thing)
Return true if $thing is an Auth_OpenID_FailureResponse object; false if not.
Definition: OpenID.php:118
static getQuery($query_str=null)
Gets the query data from the server environment based on the request method used.
Definition: OpenID.php:142
static getHTTPFetcher($timeout=20)
Returns an HTTP fetcher object.
Definition: Yadis.php:253
if($err=$client->getError()) $namespace
$server
$text
$r
Definition: example_031.php:79
$errors fields
Definition: imgupload.php:48