PAPE.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. /**
  3. * An implementation of the OpenID Provider Authentication Policy
  4. * Extension 1.0
  5. *
  6. * See:
  7. * http://openid.net/developers/specs/
  8. */
  9. require_once "Auth/OpenID/Extension.php";
  10. define('Auth_OpenID_PAPE_NS_URI',
  11. "http://specs.openid.net/extensions/pape/1.0");
  12. define('PAPE_AUTH_MULTI_FACTOR_PHYSICAL',
  13. 'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical');
  14. define('PAPE_AUTH_MULTI_FACTOR',
  15. 'http://schemas.openid.net/pape/policies/2007/06/multi-factor');
  16. define('PAPE_AUTH_PHISHING_RESISTANT',
  17. 'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant');
  18. define('PAPE_TIME_VALIDATOR',
  19. '/^[0-9]{4,4}-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]Z$/');
  20. /**
  21. * A Provider Authentication Policy request, sent from a relying party
  22. * to a provider
  23. *
  24. * preferred_auth_policies: The authentication policies that
  25. * the relying party prefers
  26. *
  27. * max_auth_age: The maximum time, in seconds, that the relying party
  28. * wants to allow to have elapsed before the user must re-authenticate
  29. */
  30. class Auth_OpenID_PAPE_Request extends Auth_OpenID_Extension {
  31. var $ns_alias = 'pape';
  32. var $ns_uri = Auth_OpenID_PAPE_NS_URI;
  33. function Auth_OpenID_PAPE_Request($preferred_auth_policies=null,
  34. $max_auth_age=null)
  35. {
  36. if ($preferred_auth_policies === null) {
  37. $preferred_auth_policies = array();
  38. }
  39. $this->preferred_auth_policies = $preferred_auth_policies;
  40. $this->max_auth_age = $max_auth_age;
  41. }
  42. /**
  43. * Add an acceptable authentication policy URI to this request
  44. *
  45. * This method is intended to be used by the relying party to add
  46. * acceptable authentication types to the request.
  47. *
  48. * policy_uri: The identifier for the preferred type of
  49. * authentication.
  50. */
  51. function addPolicyURI($policy_uri)
  52. {
  53. if (!in_array($policy_uri, $this->preferred_auth_policies)) {
  54. $this->preferred_auth_policies[] = $policy_uri;
  55. }
  56. }
  57. function getExtensionArgs()
  58. {
  59. $ns_args = array(
  60. 'preferred_auth_policies' =>
  61. implode(' ', $this->preferred_auth_policies)
  62. );
  63. if ($this->max_auth_age !== null) {
  64. $ns_args['max_auth_age'] = strval($this->max_auth_age);
  65. }
  66. return $ns_args;
  67. }
  68. /**
  69. * Instantiate a Request object from the arguments in a checkid_*
  70. * OpenID message
  71. */
  72. static function fromOpenIDRequest($request)
  73. {
  74. $obj = new Auth_OpenID_PAPE_Request();
  75. $args = $request->message->getArgs(Auth_OpenID_PAPE_NS_URI);
  76. if ($args === null || $args === array()) {
  77. return null;
  78. }
  79. $obj->parseExtensionArgs($args);
  80. return $obj;
  81. }
  82. /**
  83. * Set the state of this request to be that expressed in these
  84. * PAPE arguments
  85. *
  86. * @param args: The PAPE arguments without a namespace
  87. */
  88. function parseExtensionArgs($args)
  89. {
  90. // preferred_auth_policies is a space-separated list of policy
  91. // URIs
  92. $this->preferred_auth_policies = array();
  93. $policies_str = Auth_OpenID::arrayGet($args, 'preferred_auth_policies');
  94. if ($policies_str) {
  95. foreach (explode(' ', $policies_str) as $uri) {
  96. if (!in_array($uri, $this->preferred_auth_policies)) {
  97. $this->preferred_auth_policies[] = $uri;
  98. }
  99. }
  100. }
  101. // max_auth_age is base-10 integer number of seconds
  102. $max_auth_age_str = Auth_OpenID::arrayGet($args, 'max_auth_age');
  103. if ($max_auth_age_str) {
  104. $this->max_auth_age = Auth_OpenID::intval($max_auth_age_str);
  105. } else {
  106. $this->max_auth_age = null;
  107. }
  108. }
  109. /**
  110. * Given a list of authentication policy URIs that a provider
  111. * supports, this method returns the subsequence of those types
  112. * that are preferred by the relying party.
  113. *
  114. * @param supported_types: A sequence of authentication policy
  115. * type URIs that are supported by a provider
  116. *
  117. * @return array The sub-sequence of the supported types that are
  118. * preferred by the relying party. This list will be ordered in
  119. * the order that the types appear in the supported_types
  120. * sequence, and may be empty if the provider does not prefer any
  121. * of the supported authentication types.
  122. */
  123. function preferredTypes($supported_types)
  124. {
  125. $result = array();
  126. foreach ($supported_types as $st) {
  127. if (in_array($st, $this->preferred_auth_policies)) {
  128. $result[] = $st;
  129. }
  130. }
  131. return $result;
  132. }
  133. }
  134. /**
  135. * A Provider Authentication Policy response, sent from a provider to
  136. * a relying party
  137. */
  138. class Auth_OpenID_PAPE_Response extends Auth_OpenID_Extension {
  139. var $ns_alias = 'pape';
  140. var $ns_uri = Auth_OpenID_PAPE_NS_URI;
  141. function Auth_OpenID_PAPE_Response($auth_policies=null, $auth_time=null,
  142. $nist_auth_level=null)
  143. {
  144. if ($auth_policies) {
  145. $this->auth_policies = $auth_policies;
  146. } else {
  147. $this->auth_policies = array();
  148. }
  149. $this->auth_time = $auth_time;
  150. $this->nist_auth_level = $nist_auth_level;
  151. }
  152. /**
  153. * Add a authentication policy to this response
  154. *
  155. * This method is intended to be used by the provider to add a
  156. * policy that the provider conformed to when authenticating the
  157. * user.
  158. *
  159. * @param policy_uri: The identifier for the preferred type of
  160. * authentication.
  161. */
  162. function addPolicyURI($policy_uri)
  163. {
  164. if (!in_array($policy_uri, $this->auth_policies)) {
  165. $this->auth_policies[] = $policy_uri;
  166. }
  167. }
  168. /**
  169. * Create an Auth_OpenID_PAPE_Response object from a successful
  170. * OpenID library response.
  171. *
  172. * @param success_response $success_response A SuccessResponse
  173. * from Auth_OpenID_Consumer::complete()
  174. *
  175. * @returns: A provider authentication policy response from the
  176. * data that was supplied with the id_res response.
  177. */
  178. static function fromSuccessResponse($success_response)
  179. {
  180. $obj = new Auth_OpenID_PAPE_Response();
  181. // PAPE requires that the args be signed.
  182. $args = $success_response->getSignedNS(Auth_OpenID_PAPE_NS_URI);
  183. if ($args === null || $args === array()) {
  184. return null;
  185. }
  186. $result = $obj->parseExtensionArgs($args);
  187. if ($result === false) {
  188. return null;
  189. } else {
  190. return $obj;
  191. }
  192. }
  193. /**
  194. * Parse the provider authentication policy arguments into the
  195. * internal state of this object
  196. *
  197. * @param args: unqualified provider authentication policy
  198. * arguments
  199. *
  200. * @param strict: Whether to return false when bad data is
  201. * encountered
  202. *
  203. * @return null The data is parsed into the internal fields of
  204. * this object.
  205. */
  206. function parseExtensionArgs($args, $strict=false)
  207. {
  208. $policies_str = Auth_OpenID::arrayGet($args, 'auth_policies');
  209. if ($policies_str && $policies_str != "none") {
  210. $this->auth_policies = explode(" ", $policies_str);
  211. }
  212. $nist_level_str = Auth_OpenID::arrayGet($args, 'nist_auth_level');
  213. if ($nist_level_str !== null) {
  214. $nist_level = Auth_OpenID::intval($nist_level_str);
  215. if ($nist_level === false) {
  216. if ($strict) {
  217. return false;
  218. } else {
  219. $nist_level = null;
  220. }
  221. }
  222. if (0 <= $nist_level && $nist_level < 5) {
  223. $this->nist_auth_level = $nist_level;
  224. } else if ($strict) {
  225. return false;
  226. }
  227. }
  228. $auth_time = Auth_OpenID::arrayGet($args, 'auth_time');
  229. if ($auth_time !== null) {
  230. if (preg_match(PAPE_TIME_VALIDATOR, $auth_time)) {
  231. $this->auth_time = $auth_time;
  232. } else if ($strict) {
  233. return false;
  234. }
  235. }
  236. }
  237. function getExtensionArgs()
  238. {
  239. $ns_args = array();
  240. if (count($this->auth_policies) > 0) {
  241. $ns_args['auth_policies'] = implode(' ', $this->auth_policies);
  242. } else {
  243. $ns_args['auth_policies'] = 'none';
  244. }
  245. if ($this->nist_auth_level !== null) {
  246. if (!in_array($this->nist_auth_level, range(0, 4), true)) {
  247. return false;
  248. }
  249. $ns_args['nist_auth_level'] = strval($this->nist_auth_level);
  250. }
  251. if ($this->auth_time !== null) {
  252. if (!preg_match(PAPE_TIME_VALIDATOR, $this->auth_time)) {
  253. return false;
  254. }
  255. $ns_args['auth_time'] = $this->auth_time;
  256. }
  257. return $ns_args;
  258. }
  259. }