/**
  * 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;
 }
Exemple #2
0
 public function testDhSha1()
 {
     // generate consumer
     $request = $this->generateConsumerRequest();
     // generate server
     $dhGen = $request['gen'];
     $dhModulus = $request['modulus'];
     $dhConsumerPub = $request['consumer_public'];
     $dhFunc = 'SHA1';
     $secret = ProviderAbstract::randomBytes(20);
     $res = ProviderAbstract::generateDh($dhGen, $dhModulus, $dhConsumerPub, $dhFunc, $secret);
     $this->assertEquals(true, isset($res['pubKey']));
     $this->assertEquals(true, isset($res['macKey']));
     // calculate consumer
     $serverPub = base64_decode($res['pubKey']);
     $dhSec = OpenSsl::dhComputeKey($serverPub, $request['pkey']);
     $sec = OpenSsl::digest(ProviderAbstract::btwoc($dhSec), $dhFunc, true);
     $serverSecret = $sec ^ base64_decode($res['macKey']);
     // compare with server
     $this->assertEquals(true, $secret === $serverSecret);
 }
Exemple #3
0
    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);
    }
Exemple #4
0
    public function onCheckidSetup(SetupRequest $request)
    {
        // check whether authenticated
        if (!$this->isAuthenticated()) {
            $loginUrl = $this->config['psx_url'] . '/' . $this->config['psx_dispatch'] . 'login';
            $selfUrl = new Url($this->base->getSelf());
            $values = array_merge($_GET, $_POST);
            foreach ($values as $key => $value) {
                $selfUrl->addParam($key, $value);
            }
            //$selfUrl->addParam('openid.mode', 'checkid_setup');
            //$selfUrl->addParam('openid.ns', self::NS);
            header('Location: ' . $loginUrl . '?redirect=' . urlencode(strval($selfUrl)));
            exit;
        }
        // check association
        $sql = <<<SQL
SELECT
\t`assoc`.`id`,
\t`assoc`.`expires`,
\t`assoc`.`date`
FROM 
\t{$this->registry['table.openid_assoc']} `assoc`
WHERE 
\t`assoc`.`assocHandle` = ?
SQL;
        $row = $this->sql->getRow($sql, array($request->getAssocHandle()));
        if (!empty($row)) {
            // check expire
            $now = new DateTime('NOW', $this->registry['core.default_timezone']);
            $expire = (int) $row['expires'];
            if (time() > $now->getTimestamp() + $expire) {
                throw new Exception('Association is expired');
            }
        } else {
            if (!$request->isImmediate()) {
                // create association
                $date = new DateTime('NOW', $this->registry['core.default_timezone']);
                $assocHandle = ProviderAbstract::generateHandle();
                $secret = base64_encode(ProviderAbstract::randomBytes(20));
                $this->sql->insert($this->registry['table.openid_assoc'], array('assocHandle' => $assocHandle, 'assocType' => 'HMAC-SHA1', 'sessionType' => 'DH-SHA1', 'secret' => $secret, 'expires' => self::EXPIRE, 'date' => $date->format(DateTime::SQL)));
                // set assoc handle
                $request->setAssocHandle($assocHandle);
            } else {
                throw new Exception('Invalid association');
            }
        }
        // count connect requests
        /*
        $maxCount = 5;
        $con      = new PSX_Sql_Condition(array('userId', '=', $this->user->getId()), array('status', '=', AmunService_Oauth_Record::TEMPORARY));
        $count    = $this->sql->count($this->registry['table.oauth_request'], $con);
        
        if($count > $maxCount)
        {
        	$conDelete = new PSX_Sql_Condition();
        	$result    = $this->sql->select($this->registry['table.oauth_request'], array('id', 'expire', 'date'), $con, PSX_Sql::SELECT_ALL);
        
        	foreach($result as $row)
        	{
        		$now  = new DateTime('NOW', $this->registry['core.default_timezone']);
        		$date = new DateTime($row['date'], $this->registry['core.default_timezone']);
        		$date->add(new DateInterval($row['expire']));
        
        		if($now > $date)
        		{
        			$conDelete->add('id', '=', $row['id'], 'OR');
        		}
        	}
        
        	if($conDelete->hasCondition())
        	{
        		$this->sql->delete($this->registry['table.oauth_request'], $conDelete);
        	}
        
        	throw new Exception('You can have max ' . $maxCount . ' temporary account connect requests. Each request expires after 30 hour');
        }
        */
        // save request params
        $_SESSION['amun_openid_request'] = $request;
        // redirect
        header('Location: ' . $this->config['psx_url'] . '/' . $this->config['psx_dispatch'] . 'login/connect');
        exit;
    }