BOINC /
boinc
| 1 | <?php |
||||
| 2 | /** |
||||
| 3 | * This class provides a simple interface for OpenID (1.1 and 2.0) authentication. |
||||
| 4 | * Supports Yadis discovery. |
||||
| 5 | * The authentication process is stateless/dumb. |
||||
| 6 | * |
||||
| 7 | * Usage: |
||||
| 8 | * Sign-on with OpenID is a two step process: |
||||
| 9 | * Step one is authentication with the provider: |
||||
| 10 | * <code> |
||||
| 11 | * $openid = new LightOpenID; |
||||
| 12 | * $openid->identity = 'ID supplied by user'; |
||||
| 13 | * header('Location: ' . $openid->authUrl()); |
||||
| 14 | * </code> |
||||
| 15 | * The provider then sends various parameters via GET, one of them is openid_mode. |
||||
| 16 | * Step two is verification: |
||||
| 17 | * <code> |
||||
| 18 | * if ($this->data['openid_mode']) { |
||||
| 19 | * $openid = new LightOpenID; |
||||
| 20 | * echo $openid->validate() ? 'Logged in.' : 'Failed'; |
||||
| 21 | * } |
||||
| 22 | * </code> |
||||
| 23 | * |
||||
| 24 | * Optionally, you can set $returnUrl and $realm (or $trustRoot, which is an alias). |
||||
| 25 | * The default values for those are: |
||||
| 26 | * $openid->realm = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; |
||||
| 27 | * $openid->returnUrl = $openid->realm . $_SERVER['REQUEST_URI']; |
||||
| 28 | * If you don't know their meaning, refer to any openid tutorial, or specification. Or just guess. |
||||
| 29 | * |
||||
| 30 | * AX and SREG extensions are supported. |
||||
| 31 | * To use them, specify $openid->required and/or $openid->optional before calling $openid->authUrl(). |
||||
| 32 | * These are arrays, with values being AX schema paths (the 'path' part of the URL). |
||||
| 33 | * For example: |
||||
| 34 | * $openid->required = array('namePerson/friendly', 'contact/email'); |
||||
| 35 | * $openid->optional = array('namePerson/first'); |
||||
| 36 | * If the server supports only SREG or OpenID 1.1, these are automaticaly |
||||
| 37 | * mapped to SREG names, so that user doesn't have to know anything about the server. |
||||
| 38 | * |
||||
| 39 | * To get the values, use $openid->getAttributes(). |
||||
| 40 | * |
||||
| 41 | * |
||||
| 42 | * The library requires PHP >= 5.1.2 with curl or http/https stream wrappers enabled. |
||||
| 43 | * @author Mewp |
||||
| 44 | * @copyright Copyright (c) 2010, Mewp |
||||
| 45 | * @license http://www.opensource.org/licenses/mit-license.php MIT |
||||
| 46 | */ |
||||
| 47 | class LightOpenID |
||||
| 48 | { |
||||
| 49 | public $returnUrl |
||||
| 50 | , $required = array() |
||||
| 51 | , $optional = array() |
||||
| 52 | , $verify_peer = null |
||||
| 53 | , $capath = null |
||||
| 54 | , $cainfo = null; |
||||
| 55 | private $identity, $claimed_id; |
||||
| 56 | protected $server, $version, $trustRoot, $aliases, $identifier_select = false |
||||
| 57 | , $ax = false, $sreg = false, $data, $setup_url = null; |
||||
| 58 | static protected $ax_to_sreg = array( |
||||
| 59 | 'namePerson/friendly' => 'nickname', |
||||
| 60 | 'contact/email' => 'email', |
||||
| 61 | 'namePerson' => 'fullname', |
||||
| 62 | 'birthDate' => 'dob', |
||||
| 63 | 'person/gender' => 'gender', |
||||
| 64 | 'contact/postalCode/home' => 'postcode', |
||||
| 65 | 'contact/country/home' => 'country', |
||||
| 66 | 'pref/language' => 'language', |
||||
| 67 | 'pref/timezone' => 'timezone', |
||||
| 68 | ); |
||||
| 69 | |||||
| 70 | function __construct() |
||||
| 71 | { |
||||
| 72 | $this->trustRoot = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; |
||||
| 73 | $uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?'); |
||||
| 74 | $this->returnUrl = $this->trustRoot . $uri; |
||||
| 75 | |||||
| 76 | $this->data = $_POST + $_GET; # OPs may send data as POST or GET. |
||||
|
0 ignored issues
–
show
Coding Style
introduced
by
Loading history...
|
|||||
| 77 | |||||
| 78 | if(!function_exists('curl_init') && !in_array('https', stream_get_wrappers())) { |
||||
| 79 | throw new ErrorException('You must have either https wrappers or curl enabled.'); |
||||
| 80 | } |
||||
| 81 | } |
||||
| 82 | |||||
| 83 | function __set($name, $value) |
||||
| 84 | { |
||||
| 85 | switch ($name) { |
||||
| 86 | case 'identity': |
||||
| 87 | if (strlen($value = trim((String) $value))) { |
||||
| 88 | if (preg_match('#^xri:/*#i', $value, $m)) { |
||||
| 89 | $value = substr($value, strlen($m[0])); |
||||
| 90 | } elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) { |
||||
| 91 | $value = "http://$value"; |
||||
| 92 | } |
||||
| 93 | if (preg_match('#^https?://[^/]+$#i', $value, $m)) { |
||||
| 94 | $value .= '/'; |
||||
| 95 | } |
||||
| 96 | } |
||||
| 97 | $this->$name = $this->claimed_id = $value; |
||||
| 98 | break; |
||||
| 99 | case 'trustRoot': |
||||
| 100 | case 'realm': |
||||
| 101 | $this->trustRoot = trim($value); |
||||
| 102 | } |
||||
| 103 | } |
||||
| 104 | |||||
| 105 | function __get($name) |
||||
| 106 | { |
||||
| 107 | switch ($name) { |
||||
| 108 | case 'identity': |
||||
| 109 | # We return claimed_id instead of identity, |
||||
|
0 ignored issues
–
show
|
|||||
| 110 | # because the developer should see the claimed identifier, |
||||
|
0 ignored issues
–
show
|
|||||
| 111 | # i.e. what he set as identity, not the op-local identifier (which is what we verify) |
||||
|
0 ignored issues
–
show
|
|||||
| 112 | return $this->claimed_id; |
||||
| 113 | case 'trustRoot': |
||||
| 114 | case 'realm': |
||||
| 115 | return $this->trustRoot; |
||||
| 116 | case 'mode': |
||||
| 117 | return empty($this->data['openid_mode']) ? null : $this->data['openid_mode']; |
||||
| 118 | } |
||||
| 119 | } |
||||
| 120 | |||||
| 121 | /** |
||||
| 122 | * Checks if the server specified in the url exists. |
||||
| 123 | * |
||||
| 124 | * @param $url url to check |
||||
|
0 ignored issues
–
show
The type
url was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 125 | * @return true, if the server exists; false otherwise |
||||
| 126 | */ |
||||
| 127 | function hostExists($url) |
||||
| 128 | { |
||||
| 129 | if (strpos($url, '/') === false) { |
||||
| 130 | $server = $url; |
||||
| 131 | } else { |
||||
| 132 | $server = @parse_url($url, PHP_URL_HOST); |
||||
| 133 | } |
||||
| 134 | |||||
| 135 | if (!$server) { |
||||
| 136 | return false; |
||||
| 137 | } |
||||
| 138 | |||||
| 139 | return !!gethostbynamel($server); |
||||
| 140 | } |
||||
| 141 | |||||
| 142 | protected function request_curl($url, $method='GET', $params=array()) |
||||
| 143 | { |
||||
| 144 | $params = http_build_query($params, '', '&'); |
||||
| 145 | $curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : '')); |
||||
| 146 | curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); |
||||
| 147 | curl_setopt($curl, CURLOPT_HEADER, false); |
||||
| 148 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); |
||||
| 149 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); |
||||
| 150 | curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*')); |
||||
| 151 | |||||
| 152 | if($this->verify_peer !== null) { |
||||
| 153 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); |
||||
| 154 | if($this->capath) { |
||||
| 155 | curl_setopt($curl, CURLOPT_CAPATH, $this->capath); |
||||
| 156 | } |
||||
| 157 | |||||
| 158 | if($this->cainfo) { |
||||
| 159 | curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo); |
||||
| 160 | } |
||||
| 161 | } |
||||
| 162 | |||||
| 163 | if ($method == 'POST') { |
||||
| 164 | curl_setopt($curl, CURLOPT_POST, true); |
||||
| 165 | curl_setopt($curl, CURLOPT_POSTFIELDS, $params); |
||||
| 166 | } elseif ($method == 'HEAD') { |
||||
| 167 | curl_setopt($curl, CURLOPT_HEADER, true); |
||||
| 168 | curl_setopt($curl, CURLOPT_NOBODY, true); |
||||
| 169 | } else { |
||||
| 170 | curl_setopt($curl, CURLOPT_HTTPGET, true); |
||||
| 171 | } |
||||
| 172 | $response = curl_exec($curl); |
||||
| 173 | |||||
| 174 | if($method == 'HEAD') { |
||||
| 175 | $headers = array(); |
||||
| 176 | foreach(explode("\n", $response) as $header) { |
||||
|
0 ignored issues
–
show
It seems like
$response can also be of type true; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 177 | $pos = strpos($header,':'); |
||||
| 178 | $name = strtolower(trim(substr($header, 0, $pos))); |
||||
| 179 | $headers[$name] = trim(substr($header, $pos+1)); |
||||
| 180 | } |
||||
| 181 | |||||
| 182 | # Updating claimed_id in case of redirections. |
||||
|
0 ignored issues
–
show
|
|||||
| 183 | $effective_url = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL); |
||||
| 184 | if($effective_url != $url) { |
||||
| 185 | $this->identity = $this->claimed_id = $effective_url; |
||||
| 186 | } |
||||
| 187 | |||||
| 188 | return $headers; |
||||
| 189 | } |
||||
| 190 | |||||
| 191 | if (curl_errno($curl)) { |
||||
| 192 | throw new ErrorException(curl_error($curl), curl_errno($curl)); |
||||
| 193 | } |
||||
| 194 | |||||
| 195 | return $response; |
||||
| 196 | } |
||||
| 197 | |||||
| 198 | protected function request_streams($url, $method='GET', $params=array()) |
||||
| 199 | { |
||||
| 200 | if(!$this->hostExists($url)) { |
||||
| 201 | throw new ErrorException('Invalid request.'); |
||||
| 202 | } |
||||
| 203 | |||||
| 204 | $params = http_build_query($params, '', '&'); |
||||
| 205 | switch($method) { |
||||
| 206 | case 'GET': |
||||
| 207 | $opts = array( |
||||
| 208 | 'http' => array( |
||||
| 209 | 'method' => 'GET', |
||||
| 210 | 'header' => 'Accept: application/xrds+xml, */*', |
||||
| 211 | 'ignore_errors' => true, |
||||
| 212 | ) |
||||
| 213 | ); |
||||
| 214 | $url = $url . ($params ? '?' . $params : ''); |
||||
| 215 | break; |
||||
| 216 | case 'POST': |
||||
| 217 | $opts = array( |
||||
| 218 | 'http' => array( |
||||
| 219 | 'method' => 'POST', |
||||
| 220 | 'header' => 'Content-type: application/x-www-form-urlencoded', |
||||
| 221 | 'content' => $params, |
||||
| 222 | 'ignore_errors' => true, |
||||
| 223 | ) |
||||
| 224 | ); |
||||
| 225 | break; |
||||
| 226 | case 'HEAD': |
||||
| 227 | # We want to send a HEAD request, |
||||
|
0 ignored issues
–
show
|
|||||
| 228 | # but since get_headers doesn't accept $context parameter, |
||||
|
0 ignored issues
–
show
|
|||||
| 229 | # we have to change the defaults. |
||||
|
0 ignored issues
–
show
|
|||||
| 230 | $default = stream_context_get_options(stream_context_get_default()); |
||||
| 231 | stream_context_get_default( |
||||
| 232 | array('http' => array( |
||||
|
0 ignored issues
–
show
|
|||||
| 233 | 'method' => 'HEAD', |
||||
| 234 | 'header' => 'Accept: application/xrds+xml, */*', |
||||
| 235 | 'ignore_errors' => true, |
||||
| 236 | )) |
||||
|
0 ignored issues
–
show
|
|||||
| 237 | ); |
||||
| 238 | |||||
| 239 | $url = $url . ($params ? '?' . $params : ''); |
||||
| 240 | $headers_tmp = get_headers ($url); |
||||
| 241 | if(!$headers_tmp) { |
||||
|
0 ignored issues
–
show
The expression
$headers_tmp of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 242 | return array(); |
||||
| 243 | } |
||||
| 244 | |||||
| 245 | # Parsing headers. |
||||
|
0 ignored issues
–
show
|
|||||
| 246 | $headers = array(); |
||||
| 247 | foreach($headers_tmp as $header) { |
||||
| 248 | $pos = strpos($header,':'); |
||||
| 249 | $name = strtolower(trim(substr($header, 0, $pos))); |
||||
| 250 | $headers[$name] = trim(substr($header, $pos+1)); |
||||
| 251 | |||||
| 252 | # Following possible redirections. The point is just to have |
||||
|
0 ignored issues
–
show
|
|||||
| 253 | # claimed_id change with them, because get_headers() will |
||||
|
0 ignored issues
–
show
|
|||||
| 254 | # follow redirections automatically. |
||||
|
0 ignored issues
–
show
|
|||||
| 255 | # We ignore redirections with relative paths. |
||||
|
0 ignored issues
–
show
|
|||||
| 256 | # If any known provider uses them, file a bug report. |
||||
|
0 ignored issues
–
show
|
|||||
| 257 | if($name == 'location') { |
||||
| 258 | if(strpos($headers[$name], 'http') === 0) { |
||||
| 259 | $this->identity = $this->claimed_id = $headers[$name]; |
||||
| 260 | } elseif($headers[$name][0] == '/') { |
||||
| 261 | $parsed_url = parse_url($this->claimed_id); |
||||
| 262 | $this->identity = |
||||
|
0 ignored issues
–
show
|
|||||
| 263 | $this->claimed_id = $parsed_url['scheme'] . '://' |
||||
| 264 | . $parsed_url['host'] |
||||
| 265 | . $headers[$name]; |
||||
| 266 | } |
||||
| 267 | } |
||||
| 268 | } |
||||
| 269 | |||||
| 270 | # And restore them. |
||||
|
0 ignored issues
–
show
|
|||||
| 271 | stream_context_get_default($default); |
||||
| 272 | return $headers; |
||||
| 273 | } |
||||
| 274 | |||||
| 275 | if($this->verify_peer) { |
||||
| 276 | $opts += array('ssl' => array( |
||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
| 277 | 'verify_peer' => true, |
||||
| 278 | 'capath' => $this->capath, |
||||
| 279 | 'cafile' => $this->cainfo, |
||||
| 280 | )); |
||||
|
0 ignored issues
–
show
|
|||||
| 281 | } |
||||
| 282 | |||||
| 283 | $context = stream_context_create ($opts); |
||||
| 284 | |||||
| 285 | return file_get_contents($url, false, $context); |
||||
| 286 | } |
||||
| 287 | |||||
| 288 | protected function request($url, $method='GET', $params=array()) |
||||
| 289 | { |
||||
| 290 | if(function_exists('curl_init') && !ini_get('safe_mode') && !ini_get('open_basedir')) { |
||||
| 291 | return $this->request_curl($url, $method, $params); |
||||
| 292 | } |
||||
| 293 | return $this->request_streams($url, $method, $params); |
||||
| 294 | } |
||||
| 295 | |||||
| 296 | protected function build_url($url, $parts) |
||||
| 297 | { |
||||
| 298 | if (isset($url['query'], $parts['query'])) { |
||||
| 299 | $parts['query'] = $url['query'] . '&' . $parts['query']; |
||||
| 300 | } |
||||
| 301 | |||||
| 302 | $url = $parts + $url; |
||||
| 303 | $url = $url['scheme'] . '://' |
||||
| 304 | . (empty($url['username'])?'' |
||||
| 305 | :(empty($url['password'])? "{$url['username']}@" |
||||
|
0 ignored issues
–
show
|
|||||
| 306 | :"{$url['username']}:{$url['password']}@")) |
||||
|
0 ignored issues
–
show
|
|||||
| 307 | . $url['host'] |
||||
| 308 | . (empty($url['port'])?'':":{$url['port']}") |
||||
| 309 | . (empty($url['path'])?'':$url['path']) |
||||
| 310 | . (empty($url['query'])?'':"?{$url['query']}") |
||||
| 311 | . (empty($url['fragment'])?'':"#{$url['fragment']}"); |
||||
| 312 | return $url; |
||||
| 313 | } |
||||
| 314 | |||||
| 315 | /** |
||||
| 316 | * Helper function used to scan for <meta>/<link> tags and extract information |
||||
| 317 | * from them |
||||
| 318 | */ |
||||
| 319 | protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName) |
||||
| 320 | { |
||||
| 321 | preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1); |
||||
| 322 | preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2); |
||||
| 323 | |||||
| 324 | $result = array_merge($matches1[1], $matches2[1]); |
||||
| 325 | return empty($result)?false:$result[0]; |
||||
| 326 | } |
||||
| 327 | |||||
| 328 | /** |
||||
| 329 | * Performs Yadis and HTML discovery. Normally not used. |
||||
| 330 | * @param $url Identity URL. |
||||
|
0 ignored issues
–
show
The type
Identity was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||
| 331 | * @return String OP Endpoint (i.e. OpenID provider address). |
||||
| 332 | * @throws ErrorException |
||||
| 333 | */ |
||||
| 334 | function discover($url) |
||||
| 335 | { |
||||
| 336 | if (!$url) throw new ErrorException('No identity supplied.'); |
||||
| 337 | # Use xri.net proxy to resolve i-name identities |
||||
|
0 ignored issues
–
show
|
|||||
| 338 | if (!preg_match('#^https?:#', $url)) { |
||||
| 339 | $url = "https://xri.net/$url"; |
||||
| 340 | } |
||||
| 341 | |||||
| 342 | # We save the original url in case of Yadis discovery failure. |
||||
|
0 ignored issues
–
show
|
|||||
| 343 | # It can happen when we'll be lead to an XRDS document |
||||
|
0 ignored issues
–
show
|
|||||
| 344 | # which does not have any OpenID2 services. |
||||
|
0 ignored issues
–
show
|
|||||
| 345 | $originalUrl = $url; |
||||
| 346 | |||||
| 347 | # A flag to disable yadis discovery in case of failure in headers. |
||||
|
0 ignored issues
–
show
|
|||||
| 348 | $yadis = true; |
||||
| 349 | |||||
| 350 | # We'll jump a maximum of 5 times, to avoid endless redirections. |
||||
|
0 ignored issues
–
show
|
|||||
| 351 | for ($i = 0; $i < 5; $i ++) { |
||||
| 352 | if ($yadis) { |
||||
| 353 | $headers = $this->request($url, 'HEAD'); |
||||
| 354 | |||||
| 355 | $next = false; |
||||
| 356 | if (isset($headers['x-xrds-location'])) { |
||||
| 357 | $url = $this->build_url(parse_url($url), parse_url(trim($headers['x-xrds-location']))); |
||||
| 358 | $next = true; |
||||
| 359 | } |
||||
| 360 | |||||
| 361 | if (isset($headers['content-type']) |
||||
| 362 | && (strpos($headers['content-type'], 'application/xrds+xml') !== false |
||||
| 363 | || strpos($headers['content-type'], 'text/xml') !== false) |
||||
| 364 | ) { |
||||
| 365 | # Apparently, some providers return XRDS documents as text/html. |
||||
|
0 ignored issues
–
show
|
|||||
| 366 | # While it is against the spec, allowing this here shouldn't break |
||||
|
0 ignored issues
–
show
|
|||||
| 367 | # compatibility with anything. |
||||
|
0 ignored issues
–
show
|
|||||
| 368 | # --- |
||||
|
0 ignored issues
–
show
|
|||||
| 369 | # Found an XRDS document, now let's find the server, and optionally delegate. |
||||
|
0 ignored issues
–
show
|
|||||
| 370 | $content = $this->request($url, 'GET'); |
||||
| 371 | |||||
| 372 | preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m); |
||||
| 373 | foreach($m[1] as $content) { |
||||
| 374 | $content = ' ' . $content; # The space is added, so that strpos doesn't return 0. |
||||
|
0 ignored issues
–
show
|
|||||
| 375 | |||||
| 376 | # OpenID 2 |
||||
|
0 ignored issues
–
show
|
|||||
| 377 | $ns = preg_quote('http://specs.openid.net/auth/2.0/'); |
||||
| 378 | if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) { |
||||
| 379 | if ($type[1] == 'server') $this->identifier_select = true; |
||||
| 380 | |||||
| 381 | preg_match('#<URI.*?>(.*)</URI>#', $content, $server); |
||||
| 382 | preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate); |
||||
| 383 | if (empty($server)) { |
||||
| 384 | return false; |
||||
| 385 | } |
||||
| 386 | # Does the server advertise support for either AX or SREG? |
||||
|
0 ignored issues
–
show
|
|||||
| 387 | $this->ax = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>'); |
||||
| 388 | $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') |
||||
| 389 | || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); |
||||
| 390 | |||||
| 391 | $server = $server[1]; |
||||
| 392 | if (isset($delegate[2])) $this->identity = trim($delegate[2]); |
||||
| 393 | $this->version = 2; |
||||
| 394 | |||||
| 395 | $this->server = $server; |
||||
| 396 | return $server; |
||||
| 397 | } |
||||
| 398 | |||||
| 399 | # OpenID 1.1 |
||||
|
0 ignored issues
–
show
|
|||||
| 400 | $ns = preg_quote('http://openid.net/signon/1.1'); |
||||
| 401 | if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) { |
||||
| 402 | |||||
| 403 | preg_match('#<URI.*?>(.*)</URI>#', $content, $server); |
||||
| 404 | preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate); |
||||
| 405 | if (empty($server)) { |
||||
| 406 | return false; |
||||
| 407 | } |
||||
| 408 | # AX can be used only with OpenID 2.0, so checking only SREG |
||||
|
0 ignored issues
–
show
|
|||||
| 409 | $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') |
||||
| 410 | || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); |
||||
| 411 | |||||
| 412 | $server = $server[1]; |
||||
| 413 | if (isset($delegate[1])) $this->identity = $delegate[1]; |
||||
| 414 | $this->version = 1; |
||||
| 415 | |||||
| 416 | $this->server = $server; |
||||
| 417 | return $server; |
||||
| 418 | } |
||||
| 419 | } |
||||
| 420 | |||||
| 421 | $next = true; |
||||
| 422 | $yadis = false; |
||||
| 423 | $url = $originalUrl; |
||||
| 424 | $content = null; |
||||
| 425 | break; |
||||
| 426 | } |
||||
| 427 | if ($next) continue; |
||||
| 428 | |||||
| 429 | # There are no relevant information in headers, so we search the body. |
||||
|
0 ignored issues
–
show
|
|||||
| 430 | $content = $this->request($url, 'GET'); |
||||
| 431 | $location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content'); |
||||
| 432 | if ($location) { |
||||
| 433 | $url = $this->build_url(parse_url($url), parse_url($location)); |
||||
| 434 | continue; |
||||
| 435 | } |
||||
| 436 | } |
||||
| 437 | |||||
| 438 | if (!$content) $content = $this->request($url, 'GET'); |
||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
| 439 | |||||
| 440 | # At this point, the YADIS Discovery has failed, so we'll switch |
||||
|
0 ignored issues
–
show
|
|||||
| 441 | # to openid2 HTML discovery, then fallback to openid 1.1 discovery. |
||||
|
0 ignored issues
–
show
|
|||||
| 442 | $server = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href'); |
||||
| 443 | $delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href'); |
||||
| 444 | $this->version = 2; |
||||
| 445 | |||||
| 446 | if (!$server) { |
||||
| 447 | # The same with openid 1.1 |
||||
|
0 ignored issues
–
show
|
|||||
| 448 | $server = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href'); |
||||
| 449 | $delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href'); |
||||
| 450 | $this->version = 1; |
||||
| 451 | } |
||||
| 452 | |||||
| 453 | if ($server) { |
||||
| 454 | # We found an OpenID2 OP Endpoint |
||||
|
0 ignored issues
–
show
|
|||||
| 455 | if ($delegate) { |
||||
| 456 | # We have also found an OP-Local ID. |
||||
|
0 ignored issues
–
show
|
|||||
| 457 | $this->identity = $delegate; |
||||
| 458 | } |
||||
| 459 | $this->server = $server; |
||||
| 460 | return $server; |
||||
| 461 | } |
||||
| 462 | |||||
| 463 | throw new ErrorException('No servers found!'); |
||||
| 464 | } |
||||
| 465 | throw new ErrorException('Endless redirection!'); |
||||
| 466 | } |
||||
| 467 | |||||
| 468 | protected function sregParams() |
||||
| 469 | { |
||||
| 470 | $params = array(); |
||||
| 471 | # We always use SREG 1.1, even if the server is advertising only support for 1.0. |
||||
|
0 ignored issues
–
show
|
|||||
| 472 | # That's because it's fully backwards compatibile with 1.0, and some providers |
||||
|
0 ignored issues
–
show
|
|||||
| 473 | # advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com |
||||
|
0 ignored issues
–
show
|
|||||
| 474 | $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1'; |
||||
| 475 | if ($this->required) { |
||||
|
0 ignored issues
–
show
The expression
$this->required of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 476 | $params['openid.sreg.required'] = array(); |
||||
| 477 | foreach ($this->required as $required) { |
||||
| 478 | if (!isset(self::$ax_to_sreg[$required])) continue; |
||||
| 479 | $params['openid.sreg.required'][] = self::$ax_to_sreg[$required]; |
||||
| 480 | } |
||||
| 481 | $params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']); |
||||
| 482 | } |
||||
| 483 | |||||
| 484 | if ($this->optional) { |
||||
|
0 ignored issues
–
show
The expression
$this->optional of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 485 | $params['openid.sreg.optional'] = array(); |
||||
| 486 | foreach ($this->optional as $optional) { |
||||
| 487 | if (!isset(self::$ax_to_sreg[$optional])) continue; |
||||
| 488 | $params['openid.sreg.optional'][] = self::$ax_to_sreg[$optional]; |
||||
| 489 | } |
||||
| 490 | $params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']); |
||||
| 491 | } |
||||
| 492 | return $params; |
||||
| 493 | } |
||||
| 494 | |||||
| 495 | protected function axParams() |
||||
| 496 | { |
||||
| 497 | $params = array(); |
||||
| 498 | if ($this->required || $this->optional) { |
||||
|
0 ignored issues
–
show
The expression
$this->required of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
The expression
$this->optional of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 499 | $params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0'; |
||||
| 500 | $params['openid.ax.mode'] = 'fetch_request'; |
||||
| 501 | $this->aliases = array(); |
||||
| 502 | $counts = array(); |
||||
| 503 | $required = array(); |
||||
| 504 | $optional = array(); |
||||
| 505 | foreach (array('required','optional') as $type) { |
||||
| 506 | foreach ($this->$type as $alias => $field) { |
||||
| 507 | if (is_int($alias)) $alias = strtr($field, '/', '_'); |
||||
| 508 | $this->aliases[$alias] = 'http://axschema.org/' . $field; |
||||
| 509 | if (empty($counts[$alias])) $counts[$alias] = 0; |
||||
| 510 | $counts[$alias] += 1; |
||||
| 511 | ${$type}[] = $alias; |
||||
| 512 | } |
||||
| 513 | } |
||||
| 514 | foreach ($this->aliases as $alias => $ns) { |
||||
| 515 | $params['openid.ax.type.' . $alias] = $ns; |
||||
| 516 | } |
||||
| 517 | foreach ($counts as $alias => $count) { |
||||
| 518 | if ($count == 1) continue; |
||||
| 519 | $params['openid.ax.count.' . $alias] = $count; |
||||
| 520 | } |
||||
| 521 | |||||
| 522 | # Don't send empty ax.requied and ax.if_available. |
||||
|
0 ignored issues
–
show
|
|||||
| 523 | # Google and possibly other providers refuse to support ax when one of these is empty. |
||||
|
0 ignored issues
–
show
|
|||||
| 524 | if($required) { |
||||
|
0 ignored issues
–
show
The expression
$required of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 525 | $params['openid.ax.required'] = implode(',', $required); |
||||
| 526 | } |
||||
| 527 | if($optional) { |
||||
|
0 ignored issues
–
show
The expression
$optional of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 528 | $params['openid.ax.if_available'] = implode(',', $optional); |
||||
| 529 | } |
||||
| 530 | } |
||||
| 531 | return $params; |
||||
| 532 | } |
||||
| 533 | |||||
| 534 | protected function authUrl_v1($immediate) |
||||
| 535 | { |
||||
| 536 | $returnUrl = $this->returnUrl; |
||||
| 537 | # If we have an openid.delegate that is different from our claimed id, |
||||
|
0 ignored issues
–
show
|
|||||
| 538 | # we need to somehow preserve the claimed id between requests. |
||||
|
0 ignored issues
–
show
|
|||||
| 539 | # The simplest way is to just send it along with the return_to url. |
||||
|
0 ignored issues
–
show
|
|||||
| 540 | if($this->identity != $this->claimed_id) { |
||||
| 541 | $returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id; |
||||
| 542 | } |
||||
| 543 | |||||
| 544 | $params = array( |
||||
| 545 | 'openid.return_to' => $returnUrl, |
||||
| 546 | 'openid.mode' => $immediate ? 'checkid_immediate' : 'checkid_setup', |
||||
| 547 | 'openid.identity' => $this->identity, |
||||
| 548 | 'openid.trust_root' => $this->trustRoot, |
||||
| 549 | ) + $this->sregParams(); |
||||
| 550 | |||||
| 551 | return $this->build_url(parse_url($this->server) |
||||
| 552 | , array('query' => http_build_query($params, '', '&'))); |
||||
| 553 | } |
||||
| 554 | |||||
| 555 | protected function authUrl_v2($immediate) |
||||
| 556 | { |
||||
| 557 | $params = array( |
||||
| 558 | 'openid.ns' => 'http://specs.openid.net/auth/2.0', |
||||
| 559 | 'openid.mode' => $immediate ? 'checkid_immediate' : 'checkid_setup', |
||||
| 560 | 'openid.return_to' => $this->returnUrl, |
||||
| 561 | 'openid.realm' => $this->trustRoot, |
||||
| 562 | ); |
||||
| 563 | if ($this->ax) { |
||||
| 564 | $params += $this->axParams(); |
||||
| 565 | } |
||||
| 566 | if ($this->sreg) { |
||||
| 567 | $params += $this->sregParams(); |
||||
| 568 | } |
||||
| 569 | if (!$this->ax && !$this->sreg) { |
||||
| 570 | # If OP doesn't advertise either SREG, nor AX, let's send them both |
||||
|
0 ignored issues
–
show
|
|||||
| 571 | # in worst case we don't get anything in return. |
||||
|
0 ignored issues
–
show
|
|||||
| 572 | $params += $this->axParams() + $this->sregParams(); |
||||
| 573 | } |
||||
| 574 | |||||
| 575 | if ($this->identifier_select) { |
||||
| 576 | $params['openid.identity'] = $params['openid.claimed_id'] |
||||
| 577 | = 'http://specs.openid.net/auth/2.0/identifier_select'; |
||||
| 578 | } else { |
||||
| 579 | $params['openid.identity'] = $this->identity; |
||||
| 580 | $params['openid.claimed_id'] = $this->claimed_id; |
||||
| 581 | } |
||||
| 582 | |||||
| 583 | return $this->build_url(parse_url($this->server) |
||||
| 584 | , array('query' => http_build_query($params, '', '&'))); |
||||
| 585 | } |
||||
| 586 | |||||
| 587 | /** |
||||
| 588 | * Returns authentication url. Usually, you want to redirect your user to it. |
||||
| 589 | * @return String The authentication url. |
||||
| 590 | * @param String $select_identifier Whether to request OP to select identity for an user in OpenID 2. Does not affect OpenID 1. |
||||
| 591 | * @throws ErrorException |
||||
| 592 | */ |
||||
| 593 | function authUrl($immediate = false) |
||||
| 594 | { |
||||
| 595 | if ($this->setup_url && !$immediate) return $this->setup_url; |
||||
| 596 | if (!$this->server) $this->discover($this->identity); |
||||
| 597 | |||||
| 598 | if ($this->version == 2) { |
||||
| 599 | return $this->authUrl_v2($immediate); |
||||
| 600 | } |
||||
| 601 | return $this->authUrl_v1($immediate); |
||||
| 602 | } |
||||
| 603 | |||||
| 604 | /** |
||||
| 605 | * Performs OpenID verification with the OP. |
||||
| 606 | * @return Bool Whether the verification was successful. |
||||
| 607 | * @throws ErrorException |
||||
| 608 | */ |
||||
| 609 | function validate() |
||||
| 610 | { |
||||
| 611 | # If the request was using immediate mode, a failure may be reported |
||||
|
0 ignored issues
–
show
|
|||||
| 612 | # by presenting user_setup_url (for 1.1) or reporting |
||||
|
0 ignored issues
–
show
|
|||||
| 613 | # mode 'setup_needed' (for 2.0). Also catching all modes other than |
||||
|
0 ignored issues
–
show
|
|||||
| 614 | # id_res, in order to avoid throwing errors. |
||||
|
0 ignored issues
–
show
|
|||||
| 615 | if(isset($this->data['openid_user_setup_url'])) { |
||||
| 616 | $this->setup_url = $this->data['openid_user_setup_url']; |
||||
| 617 | return false; |
||||
| 618 | } |
||||
| 619 | if($this->mode != 'id_res') { |
||||
|
0 ignored issues
–
show
The property
mode does not exist on LightOpenID. Since you implemented __get, consider adding a @property annotation.
Loading history...
|
|||||
| 620 | return false; |
||||
| 621 | } |
||||
| 622 | |||||
| 623 | $this->claimed_id = isset($this->data['openid_claimed_id'])?$this->data['openid_claimed_id']:$this->data['openid_identity']; |
||||
| 624 | $params = array( |
||||
| 625 | 'openid.assoc_handle' => $this->data['openid_assoc_handle'], |
||||
| 626 | 'openid.signed' => $this->data['openid_signed'], |
||||
| 627 | 'openid.sig' => $this->data['openid_sig'], |
||||
| 628 | ); |
||||
| 629 | |||||
| 630 | if (isset($this->data['openid_ns'])) { |
||||
| 631 | # We're dealing with an OpenID 2.0 server, so let's set an ns |
||||
|
0 ignored issues
–
show
|
|||||
| 632 | # Even though we should know location of the endpoint, |
||||
|
0 ignored issues
–
show
|
|||||
| 633 | # we still need to verify it by discovery, so $server is not set here |
||||
|
0 ignored issues
–
show
|
|||||
| 634 | $params['openid.ns'] = 'http://specs.openid.net/auth/2.0'; |
||||
| 635 | } elseif (isset($this->data['openid_claimed_id']) |
||||
| 636 | && $this->data['openid_claimed_id'] != $this->data['openid_identity'] |
||||
| 637 | ) { |
||||
| 638 | # If it's an OpenID 1 provider, and we've got claimed_id, |
||||
|
0 ignored issues
–
show
|
|||||
| 639 | # we have to append it to the returnUrl, like authUrl_v1 does. |
||||
|
0 ignored issues
–
show
|
|||||
| 640 | $this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?') |
||||
| 641 | . 'openid.claimed_id=' . $this->claimed_id; |
||||
| 642 | } |
||||
| 643 | |||||
| 644 | if ($this->data['openid_return_to'] != $this->returnUrl) { |
||||
| 645 | # The return_to url must match the url of current request. |
||||
|
0 ignored issues
–
show
|
|||||
| 646 | # I'm assuing that noone will set the returnUrl to something that doesn't make sense. |
||||
|
0 ignored issues
–
show
|
|||||
| 647 | return false; |
||||
| 648 | } |
||||
| 649 | |||||
| 650 | $server = $this->discover($this->claimed_id); |
||||
| 651 | |||||
| 652 | foreach (explode(',', $this->data['openid_signed']) as $item) { |
||||
| 653 | # Checking whether magic_quotes_gpc is turned on, because |
||||
|
0 ignored issues
–
show
|
|||||
| 654 | # the function may fail if it is. For example, when fetching |
||||
|
0 ignored issues
–
show
|
|||||
| 655 | # AX namePerson, it might containg an apostrophe, which will be escaped. |
||||
|
0 ignored issues
–
show
|
|||||
| 656 | # In such case, validation would fail, since we'd send different data than OP |
||||
|
0 ignored issues
–
show
|
|||||
| 657 | # wants to verify. stripslashes() should solve that problem, but we can't |
||||
|
0 ignored issues
–
show
|
|||||
| 658 | # use it when magic_quotes is off. |
||||
|
0 ignored issues
–
show
|
|||||
| 659 | $value = $this->data['openid_' . str_replace('.','_',$item)]; |
||||
| 660 | $params['openid.' . $item] = (version_compare(PHP_VERSION, '5.4.0') < 0 && get_magic_quotes_gpc()) ? stripslashes($value) : $value; |
||||
| 661 | |||||
| 662 | } |
||||
| 663 | |||||
| 664 | $params['openid.mode'] = 'check_authentication'; |
||||
| 665 | |||||
| 666 | $response = $this->request($server, 'POST', $params); |
||||
| 667 | |||||
| 668 | return preg_match('/is_valid\s*:\s*true/i', $response); |
||||
|
0 ignored issues
–
show
It seems like
$response can also be of type true; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 669 | } |
||||
| 670 | |||||
| 671 | protected function getAxAttributes() |
||||
| 672 | { |
||||
| 673 | $alias = null; |
||||
| 674 | if (isset($this->data['openid_ns_ax']) |
||||
| 675 | && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0' |
||||
| 676 | ) { # It's the most likely case, so we'll check it before |
||||
|
0 ignored issues
–
show
|
|||||
| 677 | $alias = 'ax'; |
||||
| 678 | } else { |
||||
| 679 | # 'ax' prefix is either undefined, or points to another extension, |
||||
|
0 ignored issues
–
show
|
|||||
| 680 | # so we search for another prefix |
||||
|
0 ignored issues
–
show
|
|||||
| 681 | foreach ($this->data as $key => $val) { |
||||
| 682 | if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_' |
||||
| 683 | && $val == 'http://openid.net/srv/ax/1.0' |
||||
| 684 | ) { |
||||
| 685 | $alias = substr($key, strlen('openid_ns_')); |
||||
| 686 | break; |
||||
| 687 | } |
||||
| 688 | } |
||||
| 689 | } |
||||
| 690 | if (!$alias) { |
||||
| 691 | # An alias for AX schema has not been found, |
||||
|
0 ignored issues
–
show
|
|||||
| 692 | # so there is no AX data in the OP's response |
||||
|
0 ignored issues
–
show
|
|||||
| 693 | return array(); |
||||
| 694 | } |
||||
| 695 | |||||
| 696 | $attributes = array(); |
||||
| 697 | foreach ($this->data as $key => $value) { |
||||
| 698 | $keyMatch = 'openid_' . $alias . '_value_'; |
||||
| 699 | if (substr($key, 0, strlen($keyMatch)) != $keyMatch) { |
||||
| 700 | continue; |
||||
| 701 | } |
||||
| 702 | $key = substr($key, strlen($keyMatch)); |
||||
| 703 | if (!isset($this->data['openid_' . $alias . '_type_' . $key])) { |
||||
| 704 | # OP is breaking the spec by returning a field without |
||||
|
0 ignored issues
–
show
|
|||||
| 705 | # associated ns. This shouldn't happen, but it's better |
||||
|
0 ignored issues
–
show
|
|||||
| 706 | # to check, than cause an E_NOTICE. |
||||
|
0 ignored issues
–
show
|
|||||
| 707 | continue; |
||||
| 708 | } |
||||
| 709 | $key = substr($this->data['openid_' . $alias . '_type_' . $key], |
||||
| 710 | strlen('http://axschema.org/')); |
||||
| 711 | $attributes[$key] = $value; |
||||
| 712 | } |
||||
| 713 | return $attributes; |
||||
| 714 | } |
||||
| 715 | |||||
| 716 | protected function getSregAttributes() |
||||
| 717 | { |
||||
| 718 | $attributes = array(); |
||||
| 719 | $sreg_to_ax = array_flip(self::$ax_to_sreg); |
||||
| 720 | foreach ($this->data as $key => $value) { |
||||
| 721 | $keyMatch = 'openid_sreg_'; |
||||
| 722 | if (substr($key, 0, strlen($keyMatch)) != $keyMatch) { |
||||
| 723 | continue; |
||||
| 724 | } |
||||
| 725 | $key = substr($key, strlen($keyMatch)); |
||||
| 726 | if (!isset($sreg_to_ax[$key])) { |
||||
| 727 | # The field name isn't part of the SREG spec, so we ignore it. |
||||
|
0 ignored issues
–
show
|
|||||
| 728 | continue; |
||||
| 729 | } |
||||
| 730 | $attributes[$sreg_to_ax[$key]] = $value; |
||||
| 731 | } |
||||
| 732 | return $attributes; |
||||
| 733 | } |
||||
| 734 | |||||
| 735 | /** |
||||
| 736 | * Gets AX/SREG attributes provided by OP. should be used only after successful validaton. |
||||
| 737 | * Note that it does not guarantee that any of the required/optional parameters will be present, |
||||
| 738 | * or that there will be no other attributes besides those specified. |
||||
| 739 | * In other words. OP may provide whatever information it wants to. |
||||
| 740 | * * SREG names will be mapped to AX names. |
||||
| 741 | * * @return Array Array of attributes with keys being the AX schema names, e.g. 'contact/email' |
||||
| 742 | * @see http://www.axschema.org/types/ |
||||
| 743 | */ |
||||
| 744 | function getAttributes() |
||||
| 745 | { |
||||
| 746 | if (isset($this->data['openid_ns']) |
||||
| 747 | && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0' |
||||
| 748 | ) { # OpenID 2.0 |
||||
|
0 ignored issues
–
show
|
|||||
| 749 | # We search for both AX and SREG attributes, with AX taking precedence. |
||||
|
0 ignored issues
–
show
|
|||||
| 750 | return $this->getAxAttributes() + $this->getSregAttributes(); |
||||
| 751 | } |
||||
| 752 | return $this->getSregAttributes(); |
||||
| 753 | } |
||||
| 754 | } |
||||
| 755 |