Fix on missing refresh token when consent params had more than 2 values

Fixed unit tests
Change-Id: I8800c3d768794bdd1d99c558225665e9e9ee13a0
This commit is contained in:
Sebastian Marcet 2016-03-22 19:09:38 -03:00
parent 0e93b131a0
commit 8f65e27cae
7 changed files with 197 additions and 17 deletions

View File

@ -179,7 +179,9 @@ PPK;
State varchar(64),
Postcode varchar(64),
Country varchar(2),
Gender varchar(32)
Gender varchar(32),
EmailVerified integer,
Active integer
);
SQL;
@ -202,6 +204,8 @@ SQL;
'Postcode' => '1824',
'Country' => 'AR',
'Locale' => 'ESP',
'Active' => 1,
'EmailVerified' => 1,
)
);
@ -222,6 +226,8 @@ SQL;
'Postcode' => '1824',
'Country' => 'AR',
'Locale' => 'ESP',
'Active' => 1,
'EmailVerified' => 1,
)
);
@ -242,6 +248,8 @@ SQL;
'Postcode' => '1824',
'Country' => 'AR',
'Locale' => 'ESP',
'Active' => 1,
'EmailVerified' => 1,
)
);
@ -262,6 +270,8 @@ SQL;
'Postcode' => '1824',
'Country' => 'AR',
'Locale' => 'ESP',
'Active' => 1,
'EmailVerified' => 1,
)
);
@ -282,6 +292,8 @@ SQL;
'Postcode' => '1824',
'Country' => 'AR',
'Locale' => 'ESP',
'Active' => 1,
'EmailVerified' => 1,
)
);
@ -302,6 +314,8 @@ SQL;
'Postcode' => '1824',
'Country' => 'AR',
'Locale' => 'ESP',
'Active' => 1,
'EmailVerified' => 1,
)
);
@ -322,6 +336,8 @@ SQL;
'Postcode' => '1824',
'Country' => 'AR',
'Locale' => 'ESP',
'Active' => 1,
'EmailVerified' => 1,
)
);

View File

@ -17,13 +17,14 @@ namespace services\oauth2;
use AccessToken as DBAccessToken;
use DB;
use Event;
use Session;
use Crypt;
use Log;
use libs\oauth2\exceptions\ReplayAttackAuthCodeException;
use libs\oauth2\exceptions\ReplayAttackRefreshTokenException;
use oauth2\exceptions\RevokedAccessTokenException;
use oauth2\exceptions\RevokedAccessTokenExceptionxtends;
use oauth2\exceptions\RevokedRefreshTokenException;
use Session;
use Crypt;
use jwa\cryptographic_algorithms\HashFunctionAlgorithm;
use jwt\IBasicJWT;
use jwt\impl\JWTClaimSet;
@ -38,7 +39,6 @@ use oauth2\exceptions\InvalidClientCredentials;
use oauth2\exceptions\InvalidGrantTypeException;
use oauth2\exceptions\RecipientKeyNotFoundException;
use oauth2\exceptions\ReplayAttackException;
use oauth2\heuristics\ClientEncryptionKeyFinder;
use oauth2\heuristics\EncryptionClientPublicKeyFinder;
use oauth2\heuristics\SigningClientPublicKeyFinder;
use oauth2\models\AccessToken;
@ -449,6 +449,21 @@ final class TokenService implements ITokenService
$access_token_db->save();
//check if use refresh tokens...
Log::debug
(
sprintf
(
'use_refresh_token: %s - app_type: %s - scopes: %s - auth_code_access_type: %s - prompt: %s - approval_prompt: %s',
$client->use_refresh_token,
$client->getApplicationType(),
$auth_code->getScope(),
$auth_code->getAccessType(),
$auth_code->getPrompt(),
$auth_code->getApprovalPrompt()
)
);
if
(
$client->use_refresh_token &&
@ -468,11 +483,12 @@ final class TokenService implements ITokenService
(
!$auth_code->getHasPreviousUserConsent() ||
// google oauth2 protocol
$auth_code->getApprovalPrompt() == OAuth2Protocol::OAuth2Protocol_Approval_Prompt_Force ||
strpos($auth_code->getApprovalPrompt(),OAuth2Protocol::OAuth2Protocol_Approval_Prompt_Force) !== false ||
// http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
$auth_code->getPrompt() == OAuth2Protocol::OAuth2Protocol_Prompt_Consent
strpos($auth_code->getPrompt(), OAuth2Protocol::OAuth2Protocol_Prompt_Consent) !== false
)
{
Log::debug('creating refresh token ....');
$this_var->createRefreshToken($access_token);
}
}
@ -1401,14 +1417,13 @@ final class TokenService implements ITokenService
* @param string $nonce
* @param string $client_id
* @param AccessToken|null $access_token
* @param AuthorizationCode $auth_code
* @param AuthorizationCode|null $auth_code
* @return IBasicJWT
* @throws AbsentClientException
* @throws AbsentCurrentUserException
* @throws ConfigurationException
* @throws InvalidClientCredentials
* @throws RecipientKeyNotFoundException
* @throws \jwt\exceptions\ClaimAlreadyExistsException
* @throws \oauth2\exceptions\InvalidClientType
* @throws \oauth2\exceptions\ServerKeyNotFoundException
*/
public function createIdToken
(

View File

@ -224,7 +224,7 @@ class OAuth2ProtocolTest extends OpenStackIDBaseTest
}
public function testTokenNTimes($n = 10000){
public function testTokenNTimes($n = 100){
for($i=0; $i< $n ;$i++){
$this->testToken($i === 0);

View File

@ -642,7 +642,6 @@ class OIDCProtocolTest extends OpenStackIDBaseTest
'grant_type' => OAuth2Protocol::OAuth2Protocol_GrantType_AuthCode,
);
$response = $this->action("POST", "OAuth2ProviderController@token",
$params,
array(),
@ -696,7 +695,151 @@ class OIDCProtocolTest extends OpenStackIDBaseTest
return $access_token;
}
public function testGetResfreshTokenFromNativeAppNTimes($n=5)
public function testGetRefreshTokenWithPromptSetToConsentLogin(){
$client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwTlfSyQ3x.openstack.client';
$client_secret = 'ITc/6Y5N7kOtGKhgITc/6Y5N7kOtGKhgITc/6Y5N7kOtGKhgITc/6Y5N7kOtGKhg';
$use_enc = true;
$params = array(
'client_id' => $client_id,
'redirect_uri' => 'https://www.test.com/oauth2',
'response_type' => 'code',
'scope' => sprintf('%s profile email address %s', OAuth2Protocol::OpenIdConnect_Scope,
OAuth2Protocol::OfflineAccess_Scope),
OAuth2Protocol::OAuth2Protocol_LoginHint => 'sebastian@tipit.net',
OAuth2Protocol::OAuth2Protocol_Nonce => 'test_nonce',
OAuth2Protocol::OAuth2Protocol_Prompt => sprintf('%s %s',OAuth2Protocol::OAuth2Protocol_Prompt_Login, OAuth2Protocol::OAuth2Protocol_Prompt_Consent),
OAuth2Protocol::OAuth2Protocol_MaxAge => 3200
);
$response = $this->action("POST", "OAuth2ProviderController@authorize",
$params,
array(),
array(),
array());
$this->assertResponseStatus(302);
$url = $response->getTargetUrl();
$response = $this->call('GET', $url);
$this->assertResponseStatus(200);
// verify that login hint (email) is populated
$this->assertTrue(str_contains($response->getContent(), 'sebastian@tipit.net'));
// do login
$response = $this->call('POST', $url,
array
(
'username' => 'sebastian@tipit.net',
'password' => '1qaz2wsx',
'_token' => Session::token()
)
);
$this->assertResponseStatus(302);
$response = $this->action("GET", "OAuth2ProviderController@authorize",
array(),
array(),
array(),
array());
$this->assertResponseStatus(302);
$response = $this->action('GET', 'UserController@getConsent');
$this->assertResponseStatus(200);
$response = $this->action('POST', 'UserController@getConsent', array(
'trust' => 'AllowOnce',
'_token' => Session::token()
));
$this->assertResponseStatus(302);
// get auth code
$response = $this->action("GET", "OAuth2ProviderController@authorize",
array(),
array(),
array(),
array());
$this->assertResponseStatus(302);
$url = $response->getTargetUrl();
$comps = @parse_url($url);
$query = $comps['query'];
$output = array();
parse_str($query, $output);
$this->assertTrue(array_key_exists('code', $output));
$this->assertTrue(!empty($output['code']));
$params = array(
'code' => $output['code'],
'redirect_uri' => 'https://www.test.com/oauth2',
'grant_type' => OAuth2Protocol::OAuth2Protocol_GrantType_AuthCode,
);
$response = $this->action("POST", "OAuth2ProviderController@token",
$params,
array(),
array(),
// Symfony interally prefixes headers with "HTTP", so
array("HTTP_Authorization" => " Basic " . base64_encode($client_id . ':' . $client_secret)));
$this->assertResponseStatus(200);
$this->assertEquals('application/json;charset=UTF-8', $response->headers->get('Content-Type'));
$content = $response->getContent();
$response = json_decode($content);
$access_token = $response->access_token;
$refresh_token = $response->refresh_token;
$id_token = $response->id_token;
$this->assertTrue(!empty($access_token));
$this->assertTrue(!empty($refresh_token));
$this->assertTrue(!empty($id_token));
$jwt = BasicJWTFactory::build($id_token);
if ($use_enc) {
$this->assertTrue($jwt instanceof IJWE);
$recipient_key = RSAJWKFactory::build
(
new RSAJWKPEMPrivateKeySpecification
(
TestSeeder::$client_private_key_1,
RSAJWKPEMPrivateKeySpecification::WithoutPassword,
$jwt->getJOSEHeader()->getAlgorithm()->getString()
)
);
$recipient_key->setKeyUse(JSONWebKeyPublicKeyUseValues::Encryption)->setId('recipient_public_key');
$jwt->setRecipientKey($recipient_key);
$payload = $jwt->getPlainText();
$jwt = BasicJWTFactory::build($payload);
$this->assertTrue($jwt instanceof IJWS);
}
}
public function testGetRefreshTokenFromNativeAppNTimes($n=5)
{
$client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwKlfSyQ3x.android.openstack.client';
$client_secret = '11c/6Y5N7kOtGKhg11c/6Y5N7kOtGKhg11c/6Y5N7kOtGKhg11c/6Y5N7kOtGKhgfdfdfdf';

View File

@ -400,7 +400,7 @@ class OpenIdProtocolTest extends OpenStackIDBaseTest
$response = $this->action("POST", "OpenIdProviderController@endpoint", $params);
$this->assertResponseStatus(400);
$this->assertResponseStatus(404);
}
public function testAuthenticationCheckImmediateAuthenticationPrivateSession()

View File

@ -6,6 +6,7 @@
@include('menu',array('is_oauth2_admin' => $is_oauth2_admin, 'is_openstackid_admin' => $is_openstackid_admin))
<div class="row">
<div id="clients" class="col-md-12">
<div class="table-responsive">
<legend><span class="glyphicon glyphicon-info-sign accordion-toggle" aria-hidden="true"
title="Users can keep track of their registered applications and manage them"></span>&nbsp;Registered
Applications
@ -60,9 +61,9 @@
</tbody>
</table>
@endif
</div>
</div>
</div>
<div id="dialog-form-application" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">

View File

@ -45,8 +45,9 @@
</div>
@if (count($sites)>0)
<div class="row">
<div id="trusted_sites" class="col-md-12 col-xs-12">
<div id="trusted_sites" class="col-md-12">
<legend><span class="glyphicon glyphicon-info-sign pointable" aria-hidden="true" title="Users can keep track of their trusted sites and manage them"></span>&nbsp;Trusted Sites</legend>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<thead>
<tr>
@ -71,14 +72,17 @@
@endforeach
</tbody>
</table>
</div>
</div>
</div>
@endif
@if (count($actions)>0)
<div class="row">
<div id="actions" class="col-md-12 col-xs-12">
<div id="actions" class="col-md-12">
<legend><span class="glyphicon glyphicon-info-sign pointable" aria-hidden="true" title="Users actions"></span>&nbsp;User Actions</legend>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<thead>
<tr>
@ -103,6 +107,7 @@
@endforeach
</tbody>
</table>
</div>
</div>
</div>
@endif