/** * Tries to establish a association with the op if a store is available. The * method returns null or PSX\OpenId\Provider\Data\Association. Discovery * must be made before calling this method * * @return PSX\OpenId\Provider\Data\Association|null */ private function establishAssociaton($assocType = 'HMAC-SHA256', $sessionType = 'DH-SHA256') { // request association $g = pack('H*', ProviderAbstract::DH_G); $p = pack('H*', ProviderAbstract::DH_P); $pkey = new PKey(array('private_key_type' => OPENSSL_KEYTYPE_DH, 'dh' => array('p' => $p, 'g' => $g))); $details = $pkey->getDetails(); $params = array('openid.ns' => ProviderAbstract::NS, 'openid.mode' => 'associate', 'openid.assoc_type' => $assocType, 'openid.session_type' => $sessionType, 'openid.dh_modulus' => base64_encode(ProviderAbstract::btwoc($details['dh']['p'])), 'openid.dh_gen' => base64_encode(ProviderAbstract::btwoc($details['dh']['g'])), 'openid.dh_consumer_public' => base64_encode(ProviderAbstract::btwoc($details['dh']['pub_key']))); $request = new PostRequest($this->identity->getServer(), array('User-Agent' => __CLASS__ . ' ' . Base::VERSION), $params); $response = $this->http->request($request); if ($response->getStatusCode() == 200) { $data = self::keyValueDecode($response->getBody()); // check values $diff = array_diff(array('ns', 'assoc_handle', 'session_type', 'assoc_type', 'expires_in'), array_keys($data)); if (count($diff) > 0) { throw new Exception('Missing fields ' . implode(', ', $diff)); } if ($data['ns'] != ProviderAbstract::NS) { throw new Exception('Invalid namesspace'); } if (!in_array($data['session_type'], self::$supportedSessionTypes)) { throw new Exception('Invalid session type'); } if (!in_array($data['assoc_type'], self::$supportedAssocTypes)) { throw new Exception('Invalid assoc type'); } // decrypt shared secret if ($data['session_type'] != 'no-encryption') { if (!isset($data['dh_server_public'])) { throw new Exception('DH server public not set'); } if (!isset($data['enc_mac_key'])) { throw new Exception('Encoded mac key not set'); } $dhFunc = str_replace('DH-', '', $data['session_type']); $serverPub = base64_decode($data['dh_server_public']); $dhSec = OpenSsl::dhComputeKey($serverPub, $pkey); $sec = OpenSsl::digest(ProviderAbstract::btwoc($dhSec), $dhFunc, true); $serverSecret = base64_encode($sec ^ base64_decode($data['enc_mac_key'])); } else { if (!isset($data['mac_key'])) { throw new Exception('Mac key not set'); } $dhFunc = null; $serverSecret = $data['mac_key']; } // build association $assoc = new Association(); $assoc->setAssocHandle($data['assoc_handle']); $assoc->setAssocType($data['assoc_type']); $assoc->setSessionType($data['session_type']); $assoc->setSecret($serverSecret); $assoc->setExpire($data['expires_in']); return $assoc; } else { throw new Exception('Could not establish associaton received ' . $response->getStatusCode()); } }
private function generateConsumerRequest() { $g = pack('H*', ProviderAbstract::DH_G); $p = pack('H*', ProviderAbstract::DH_P); $pkey = new PKey(array('private_key_type' => OPENSSL_KEYTYPE_DH, 'dh' => array('p' => $p, 'g' => $g))); $details = $pkey->getDetails(); return array('modulus' => base64_encode(ProviderAbstract::btwoc($details['dh']['p'])), 'gen' => base64_encode(ProviderAbstract::btwoc($details['dh']['g'])), 'consumer_public' => base64_encode(ProviderAbstract::btwoc($details['dh']['pub_key'])), 'pkey' => $pkey); }
public function testInitialize() { $testCase = $this; $http = new Http(new Callback(function ($request) use($testCase) { // association endpoint if ($request->getUrl()->getPath() == '/server') { $data = array(); parse_str($request->getBody(), $data); $testCase->assertEquals('http://specs.openid.net/auth/2.0', $data['openid_ns']); $testCase->assertEquals('associate', $data['openid_mode']); $testCase->assertEquals('HMAC-SHA256', $data['openid_assoc_type']); $testCase->assertEquals('DH-SHA256', $data['openid_session_type']); $dhGen = $data['openid_dh_gen']; $dhModulus = $data['openid_dh_modulus']; $dhConsumerPub = $data['openid_dh_consumer_public']; $dhFunc = 'SHA1'; $secret = ProviderAbstract::randomBytes(20); $res = ProviderAbstract::generateDh($dhGen, $dhModulus, $dhConsumerPub, $dhFunc, $secret); $testCase->assertEquals(true, isset($res['pubKey'])); $testCase->assertEquals(true, isset($res['macKey'])); $body = OpenId::keyValueEncode(array('ns' => 'http://specs.openid.net/auth/2.0', 'assoc_handle' => 'foobar', 'session_type' => 'DH-SHA256', 'assoc_type' => 'HMAC-SHA256', 'expires_in' => 60 * 60, 'dh_server_public' => $res['pubKey'], 'enc_mac_key' => $res['macKey'])); $response = <<<TEXT HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Date: Sat, 04 Jan 2014 18:19:45 GMT {$body} TEXT; } else { if ($request->getUrl()->getPath() == '/identity') { $response = <<<TEXT HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Date: Sat, 04 Jan 2014 18:19:45 GMT <html> \t<head> \t\t<link rel="openid.server" href="http://openid.com/server" /> \t\t<link rel="openid.delegate" href="http://foo.com" /> \t</head> </html> TEXT; } } return Response::convert($response, ResponseParser::MODE_LOOSE)->toString(); })); $store = new Store\Memory(); $openid = new OpenId($http, 'http://localhost.com', $store); $openid->initialize('http://foo.com/identity', 'http://localhost.com/callback'); // check whether the store has the association $assoc = $store->loadByHandle('http://openid.com/server', 'foobar'); $this->assertEquals('foobar', $assoc->getAssocHandle()); $this->assertEquals('HMAC-SHA256', $assoc->getAssocType()); $this->assertEquals('DH-SHA256', $assoc->getSessionType()); $this->assertEquals(3600, $assoc->getExpire()); // check redirect url $url = $openid->getRedirectUrl(); $this->assertEquals('http://specs.openid.net/auth/2.0', $url->getParam('openid.ns')); $this->assertEquals('checkid_setup', $url->getParam('openid.mode')); $this->assertEquals('http://localhost.com/callback', $url->getParam('openid.return_to')); $this->assertEquals('http://localhost.com', $url->getParam('openid.realm')); $this->assertEquals('http://foo.com/identity', $url->getParam('openid.claimed_id')); $this->assertEquals('http://foo.com', $url->getParam('openid.identity')); $this->assertEquals('foobar', $url->getParam('openid.assoc_handle')); // the user gets redirected from the openid provider to our callback now // we verfiy the data $signed = array('ns', 'mode', 'op_endpoint', 'return_to', 'response_nonce', 'assoc_handle'); $data = array('openid_ns' => 'http://specs.openid.net/auth/2.0', 'openid_mode' => 'id_res', 'openid_op_endpoint' => 'http://openid.com/server', 'openid_return_to' => 'http://localhost.com/callback', 'openid_response_nonce' => uniqid(), 'openid_assoc_handle' => $assoc->getAssocHandle(), 'openid_signed' => implode(',', $signed)); // generate signature $sig = OpenId::buildSignature(OpenId::extractParams($data), $signed, $assoc->getSecret(), $assoc->getAssocType()); $data['openid_sig'] = $sig; // verify $result = $openid->verify($data); $this->assertTrue($result); }
protected function getAccountData(array $data) { $account = array(); // sreg extension $params = ProviderAbstract::getExtension($data, Extension\Sreg::NS); if (!empty($params)) { if (isset($params['fullname'])) { $account['name'] = $params['fullname']; } else { if (isset($params['nickname'])) { $account['name'] = $params['nickname']; } } if (isset($params['gender'])) { $params['gender'] = strtoupper($params['gender']); $account['gender'] = $params['gender'] == 'M' ? 'male' : ($params['gender'] == 'F' ? 'female' : 'undisclosed'); } else { $account['gender'] = 'undisclosed'; } if (isset($params['timezone']) && in_array($params['timezone'], DateTimeZone::listIdentifiers())) { $account['timezone'] = $params['timezone']; } else { $account['timezone'] = 'UTC'; } return $account; } // ax extension $params = ProviderAbstract::getExtension($data, Extension\Ax::NS); if (!empty($params)) { $keys = array(); $values = array('fullname' => 'http://axschema.org/namePerson', 'firstname' => 'http://axschema.org/namePerson/first', 'lastname' => 'http://axschema.org/namePerson/last', 'gender' => 'http://axschema.org/person/gender', 'timezone' => 'http://axschema.org/pref/timezone'); foreach ($params as $k => $v) { foreach ($values as $key => $ns) { if ($v == $ns) { $keys[$key] = str_replace('type', 'value', $k); } } } if (isset($keys['firstname']) && $keys['lastname'] && isset($params[$keys['firstname']]) && isset($params[$keys['lastname']])) { $account['name'] = $params[$keys['firstname']] . ' ' . $params[$keys['lastname']]; } elseif (isset($keys['fullname']) && isset($params[$keys['fullname']])) { $account['name'] = $params[$keys['fullname']]; } if (isset($keys['gender']) && isset($params[$keys['gender']])) { $params[$keys['gender']] = strtoupper($params[$keys['gender']]); $account['gender'] = $params[$keys['gender']] == 'M' ? 'male' : ($params[$keys['gender']] == 'F' ? 'female' : 'undisclosed'); } else { $account['gender'] = 'undisclosed'; } if (isset($keys['timezone']) && isset($params[$keys['timezone']]) && in_array($params[$keys['timezone']], DateTimeZone::listIdentifiers())) { $account['timezone'] = $params[$keys['timezone']]; } else { $account['timezone'] = 'UTC'; } return $account; } }
protected function handle() { try { parent::handle(); } catch (Exception $e) { echo $e->getMessage(); if ($this->config['psx_debug'] === true) { echo "\n\n" . $e->getTraceAsString(); } exit; } }
public function getExtension($ns) { return ProviderAbstract::getExtension($this->params, $ns); }
/** * Generates an association from an request * * @param PSX\OpenId\Provider\Data\AssociationRequest $request * @return PSX\OpenId\Provider\Association */ public function generate(AssociationRequest $request) { // generate secret switch ($request->getAssocType()) { case 'HMAC-SHA1': $secret = ProviderAbstract::randomBytes(20); $macFunc = 'SHA1'; break; case 'HMAC-SHA256': $secret = ProviderAbstract::randomBytes(32); $macFunc = 'SHA256'; break; default: throw new InvalidDataException('Invalid association type'); break; } // generate dh switch ($request->getSessionType()) { case 'no-encryption': // $secret = base64_encode($secret); // $this->macKey = $secret; throw new InvalidDataException('no-encryption not supported'); break; case 'DH-SHA1': $dh = ProviderAbstract::generateDh($request->getDhGen(), $request->getDhModulus(), $request->getDhConsumerPublic(), $macFunc, $secret); $this->dhServerPublic = $dh['pubKey']; $this->encMacKey = $dh['macKey']; break; case 'DH-SHA256': $dh = ProviderAbstract::generateDh($request->getDhGen(), $request->getDhModulus(), $request->getDhConsumerPublic(), $macFunc, $secret); $this->dhServerPublic = $dh['pubKey']; $this->encMacKey = $dh['macKey']; break; default: throw new InvalidDataException('Invalid association type'); break; } $this->assocHandle = ProviderAbstract::generateHandle(); $this->secret = base64_encode($secret); $this->macFunc = $macFunc; $assoc = new Association(); $assoc->setAssocHandle($this->assocHandle); $assoc->setAssocType($request->getAssocType()); $assoc->setSessionType($request->getSessionType()); $assoc->setSecret($this->secret); return $assoc; }
private function getOauthAccessToken($hostId, array $data) { $data = ProviderAbstract::getExtension($data, Extension\Oauth::NS); $token = isset($data['request_token']) ? $data['request_token'] : null; $verifier = isset($data['verifier']) ? $data['verifier'] : null; if ($hostId > 0 && !empty($token) && !empty($verifier)) { $row = $this->hm->getTable('AmunService\\Core\\Host')->select(array('consumerKey', 'consumerSecret', 'url'))->where('id', '=', $hostId)->where('status', '=', Host\Record::NORMAL)->getRow(); if (!empty($row)) { $url = $this->discoverOauthAcessUrl(new Url($row['url'])); $oauth = new Oauth($this->http); return $oauth->accessToken($url, $row['consumerKey'], $row['consumerSecret'], $token, '', $verifier); } else { throw new Exception('Invalid host id'); } } }