Fix on missing refresh token when consent params had more than 2 values
Fixed unit tests Change-Id: I8800c3d768794bdd1d99c558225665e9e9ee13a0
This commit is contained in:
parent
0e93b131a0
commit
8f65e27cae
|
@ -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,
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -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
|
||||
(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -400,7 +400,7 @@ class OpenIdProtocolTest extends OpenStackIDBaseTest
|
|||
|
||||
$response = $this->action("POST", "OpenIdProviderController@endpoint", $params);
|
||||
|
||||
$this->assertResponseStatus(400);
|
||||
$this->assertResponseStatus(404);
|
||||
}
|
||||
|
||||
public function testAuthenticationCheckImmediateAuthenticationPrivateSession()
|
||||
|
|
|
@ -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> 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">
|
||||
|
|
|
@ -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> 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> 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
|
||||
|
|
Loading…
Reference in New Issue