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