Implements: blueprint openid-oauth2-authentication-integration-with-openid

[smarcet] -  #5037 - Authentication Integration with OpenID custom Idp

Change-Id: Ifb704254fa7274b169eb858a2596c9e5651ac76e
This commit is contained in:
smarcet 2014-01-14 19:00:06 -03:00
parent e602939754
commit 89bc75eb8c
97 changed files with 2451 additions and 1096 deletions

View File

@ -113,12 +113,12 @@ return array(
'Illuminate\View\ViewServiceProvider',
'Illuminate\Workbench\WorkbenchServiceProvider',
'Illuminate\Redis\RedisServiceProvider',
'openid\OpenIdServiceProvider',
'auth\AuthenticationServiceProvider',
'services\ServicesProvider',
'strategies\StrategyProvider',
'oauth2\OAuth2ServiceProvider',
'openid\OpenIdServiceProvider',
'Greggilbert\Recaptcha\RecaptchaServiceProvider',
'oauth2\OAuth2ServiceProvider'
),
/*

View File

@ -113,10 +113,11 @@ return array(
'Illuminate\View\ViewServiceProvider',
'Illuminate\Workbench\WorkbenchServiceProvider',
'Illuminate\Redis\RedisServiceProvider',
'openid\OpenIdServiceProvider',
'auth\AuthenticationServiceProvider',
'services\ServicesProvider',
'strategies\StrategyProvider',
'auth\AuthenticationServiceProvider',
'oauth2\OAuth2ServiceProvider',
'openid\OpenIdServiceProvider',
'Greggilbert\Recaptcha\RecaptchaServiceProvider',
),

View File

@ -26,7 +26,7 @@ return array(
|
*/
'url' => 'http://localhost',
'url' => 'https://dev.openstackid.com',
/*
|--------------------------------------------------------------------------
@ -113,10 +113,11 @@ return array(
'Illuminate\View\ViewServiceProvider',
'Illuminate\Workbench\WorkbenchServiceProvider',
'Illuminate\Redis\RedisServiceProvider',
'openid\OpenIdServiceProvider',
'auth\AuthenticationServiceProvider',
'services\ServicesProvider',
'strategies\StrategyProvider',
'oauth2\OAuth2ServiceProvider',
'openid\OpenIdServiceProvider',
'Greggilbert\Recaptcha\RecaptchaServiceProvider',
),

View File

@ -1,105 +0,0 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| PDO Fetch Style
|--------------------------------------------------------------------------
|
| By default, database results will be returned as instances of the PHP
| stdClass object; however, you may desire to retrieve records in an
| array format for simplicity. Here you can tweak the fetch style.
|
*/
'fetch' => PDO::FETCH_CLASS,
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for all database work. Of course
| you may use many connections at once using the Database library.
|
*/
'default' => 'mysql',
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Here are each of the database connections setup for your application.
| Of course, examples of configuring each database platform that is
| supported by Laravel is shown below to make development simple.
|
|
| All database work in Laravel is done through the PHP PDO facilities
| so make sure you have the driver for your particular database of
| choice installed on your machine before you begin development.
|
*/
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'openstackid',
'username' => 'root',
'password' => 'Koguryo@1981',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'mysql_external' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => '506635_oslive',
'username' => 'root',
'password' => 'Koguryo@1981',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
),
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk have not actually be run in the databases.
|
*/
'migrations' => 'migrations',
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer set of commands than a typical key-value systems
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/
'redis' => array(
'cluster' => true,
'default' => array(
'host' => '127.0.0.1',
'port' => 6379,
),
),
);

View File

@ -6,16 +6,35 @@ class ApiScopeSeeder extends Seeder {
{
DB::table('oauth2_api_scope')->delete();
$resource_server_api = Api::where('name','=','resource server api')->first();
$resource_server_api_create = Api::where('name','=','create resource server')->first();
$resource_server_api_get = Api::where('name','=','get resource server')->first();
$resource_server_api_get_page = Api::where('name','=','resource server get page')->first();
$resource_server_api_regenerate = Api::where('name','=','resource server regenerate secret')->first();
$resource_server_api_delete = Api::where('name','=','resource server delete')->first();
$resource_server_api_update = Api::where('name','=','resource server update')->first();
$resource_server_api_update_status = Api::where('name','=','resource server update status')->first();
$current_realm = Config::get('app.url');
// create api scopes
ApiScope::create(
array(
'name' => sprintf('%s/api/resource-server/read',$current_realm),
'short_description' => 'Resource Server Read Access',
'description' => 'Resource Server Read Access',
'api_id' => $resource_server_api->id,
'api_id' => $resource_server_api_get->id,
)
);
ApiScope::create(
array(
'name' => sprintf('%s/api/resource-server/read.page',$current_realm),
'short_description' => 'Resource Server Page Read Access',
'description' => 'Resource Server Page Read Access',
'api_id' => $resource_server_api_get_page->id,
)
);
@ -24,6 +43,43 @@ class ApiScopeSeeder extends Seeder {
'name' => sprintf('%s/api/resource-server/write',$current_realm),
'short_description' => 'Resource Server Write Access',
'description' => 'Resource Server Write Access',
'api_id' => $resource_server_api_create->id,
)
);
ApiScope::create(
array(
'name' => sprintf('%s/api/resource-server/delete',$current_realm),
'short_description' => 'Resource Server Delete Access',
'description' => 'Resource Server Delete Access',
'api_id' => $resource_server_api_delete->id,
)
);
ApiScope::create(
array(
'name' => sprintf('%s/api/resource-server/update',$current_realm),
'short_description' => 'Resource Server Update Access',
'description' => 'Resource Server Update Access',
'api_id' => $resource_server_api_update->id,
)
);
ApiScope::create(
array(
'name' => sprintf('%s/api/resource-server/update.status',$current_realm),
'short_description' => 'Resource Server Update Status',
'description' => 'Resource Server Update Status',
'api_id' => $resource_server_api_update_status->id,
)
);
ApiScope::create(
array(
'name' => sprintf('%s/api/resource-server/regenerate.secret',$current_realm),
'short_description' => 'Resource Server Regenerate Client Secret',
'description' => 'Resource Server Regenerate Client Secret',
'api_id' => $resource_server_api_regenerate->id,
)
);

View File

@ -6,15 +6,82 @@ class ApiSeeder extends Seeder {
DB::table('oauth2_api')->delete();
$resource_server = ResourceServer::first();
//create api endpoints
Api::create(
array(
'name' => 'get resource server api',
'logo' => null,
'active' => true,
'name' => 'create resource server',
'logo' => null,
'active' => true,
'resource_server_id' => $resource_server->id,
'route' => '/api/v1/resource-server/{id}',
'http_method' => 'GET'
'route' => '/api/v1/resource-server',
'http_method' => 'POST'
)
);
Api::create(
array(
'name' => 'get resource server',
'logo' => null,
'active' => true,
'resource_server_id' => $resource_server->id,
'route' => '/api/v1/resource-server/{id}',
'http_method' => 'GET'
)
);
Api::create(
array(
'name' => 'resource server regenerate secret',
'logo' => null,
'active' => true,
'resource_server_id' => $resource_server->id,
'route' => '/api/v1/resource-server/regenerate-client-secret/{id}',
'http_method' => 'GET'
)
);
Api::create(
array(
'name' => 'resource server get page',
'logo' => null,
'active' => true,
'resource_server_id' => $resource_server->id,
'route' => '/api/v1/resource-server/{page_nbr}/{page_size}',
'http_method' => 'GET'
)
);
Api::create(
array(
'name' => 'resource server delete',
'logo' => null,
'active' => true,
'resource_server_id' => $resource_server->id,
'route' => '/api/v1/resource-server/{id}',
'http_method' => 'DELETE'
)
);
Api::create(
array(
'name' => 'resource server update',
'logo' => null,
'active' => true,
'resource_server_id' => $resource_server->id,
'route' => '/api/v1/resource-server',
'http_method' => 'PUT'
)
);
Api::create(
array(
'name' => 'resource server update status',
'logo' => null,
'active' => true,
'resource_server_id' => $resource_server->id,
'route' => '/api/v1/resource-server/status/{id}/{active}',
'http_method' => 'GET'
)
);

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: smarcet
* Date: 10/25/13
* Time: 1:34 PM
*/
class OpenIdExtensionsSeeder extends Seeder {
@ -33,6 +27,18 @@ class OpenIdExtensionsSeeder extends Seeder {
'view_name' => 'extensions.sreg',
)
);
ServerExtension::create(
array(
'name' => 'OAUTH2',
'namespace' => 'http://specs.openid.net/extensions/oauth/2.0',
'active' => true,
'extension_class' => 'openid\extensions\implementations\OpenIdOAuth2Extension',
'description' => 'The OpenID OAuth2 Extension describes how to make the OpenID Authentication and OAuth2 Core specifications work well togethe',
'view_name' => 'extensions.oauth2',
)
);
}
}

View File

@ -1,8 +1,8 @@
<?php
use oauth2\models\IClient;
use auth\OpenIdUser;
use auth\User;
use utils\services\IAuthService;
/**
* Class OAuth2ApplicationSeeder
* This seeder is only for testing purposes
@ -14,16 +14,19 @@ class TestSeeder extends Seeder {
Eloquent::unguard();
DB::table('banned_ips')->delete();
DB::table('user_exceptions_trail')->delete();
DB::table('server_configuration')->delete();
DB::table('server_extensions')->delete();
DB::table('oauth2_client_api_scope')->delete();
DB::table('oauth2_api_scope')->delete();
DB::table('oauth2_api')->delete();
DB::table('oauth2_client_authorized_uri')->delete();
DB::table('oauth2_client_api_scope')->delete();
DB::table('oauth2_access_token')->delete();
DB::table('oauth2_refresh_token')->delete();
DB::table('oauth2_client')->delete();
DB::table('openid_trusted_sites')->delete();
DB::table('openid_associations')->delete();
DB::table('openid_users')->delete();
DB::table('oauth2_resource_server')->delete();
@ -236,6 +239,17 @@ class TestSeeder extends Seeder {
)
);
ServerExtension::create(
array(
'name' => 'OAUTH2',
'namespace' => 'http://specs.openid.net/extensions/oauth/2.0',
'active' => true,
'extension_class' => 'openid\extensions\implementations\OpenIdOAuth2Extension',
'description' => 'The OpenID OAuth2 Extension describes how to make the OpenID Authentication and OAuth2 Core specifications work well togethe',
'view_name' => 'extensions.oauth2',
)
);
ResourceServer::create(
array(
'friendly_name' => 'test resource server',
@ -404,7 +418,7 @@ class TestSeeder extends Seeder {
);
// create users and clients ...
OpenIdUser::create(
User::create(
array(
'identifier'=>'sebastian.marcet',
'external_id'=>'smarcet@gmail.com',
@ -412,7 +426,15 @@ class TestSeeder extends Seeder {
)
);
$user = OpenIdUser::where('external_id','=','smarcet@gmail.com')->first();
$user = User::where('external_id','=','smarcet@gmail.com')->first();
OpenIdTrustedSite::create(
array(
'user_id'=>$user->id,
'realm'=>'https://www.test.com/',
'policy'=>IAuthService::AuthorizationResponse_AllowForever
)
);
Client::create(
array(

View File

@ -48,12 +48,17 @@ class AuthService implements IAuthService
{
if (Session::has("openid.authorization.response")) {
$value = Session::get("openid.authorization.response");
Session::remove('openid.authorization.response');
return $value;
}
return IAuthService::AuthorizationResponse_None;
}
public function clearUserAuthorizationResponse(){
if (Session::has("openid.authorization.response")) {
Session::remove("openid.authorization.response");
}
}
public function setUserAuthorizationResponse($auth_response)
{
//todo : check valid response
@ -62,13 +67,13 @@ class AuthService implements IAuthService
public function getUserByOpenId($openid)
{
$user = OpenIdUser::where('identifier', '=', $openid)->first();
$user = User::where('identifier', '=', $openid)->first();
return $user;
}
public function getUserByUsername($username)
{
$user = OpenIdUser::where('external_id', '=', $username)->first();
$user = User::where('external_id', '=', $username)->first();
return $user;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace auth;
/**
* Class AuthenticationExtensionService
* @package auth
*/
class AuthenticationExtensionService implements IAuthenticationExtensionService {
private $extensions;
public function __construct(){
$this->extensions = array();
}
/**
* @return array
*/
public function getExtensions()
{
return $this->extensions;
}
/**
* @param IAuthenticationExtension $extension
* @return bool
*/
public function addExtension(IAuthenticationExtension $extension)
{
array_push($this->extensions, $extension);
}
}

View File

@ -14,6 +14,9 @@ class AuthenticationServiceProvider extends ServiceProvider
{
$this->app->singleton(UtilsServiceCatalog::AuthenticationService, 'auth\\AuthService');
Registry::getInstance()->set(UtilsServiceCatalog::AuthenticationService, $this->app->make(UtilsServiceCatalog::AuthenticationService));
$this->app->singleton('auth\\IAuthenticationExtensionService', 'auth\\AuthenticationExtensionService');
Registry::getInstance()->set('auth\\IAuthenticationExtensionService', $this->app->make('auth\\IAuthenticationExtensionService'));
}
public function register()

View File

@ -4,23 +4,29 @@
namespace auth;
use auth\exceptions\AuthenticationException;
use auth\exceptions\AuthenticationInvalidPasswordAttemptException;
use auth\exceptions\AuthenticationLockedUserLoginAttempt;
use Exception;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\UserProviderInterface;
use Log;
use Member;
use openid\helpers\OpenIdErrorMessages;
use openid\requests\OpenIdAuthenticationRequest;
use openid\services\OpenIdServiceCatalog;
use utils\services\Registry;
use utils\services\UtilsServiceCatalog;
use DB;
/**
* Class CustomAuthProvider
* Custom Authentication Provider against SS DB
* @package auth
*/
class CustomAuthProvider implements UserProviderInterface
{
private $auth_extension_service;
public function __construct(){
public function __construct(IAuthenticationExtensionService $auth_extension_service){
$this->auth_extension_service = $auth_extension_service;
}
/**
@ -33,7 +39,7 @@ class CustomAuthProvider implements UserProviderInterface
{
try {
//here we do the manuel join between 2 DB, (openid and SS db)
$user = OpenIdUser::where('external_id', '=', $identifier)->first();
$user = User::where('external_id', '=', $identifier)->first();
$member = Member::where('Email', '=', $identifier)->first();
if (!is_null($member) && !is_null($user)) {
$user->setMember($member);
@ -54,96 +60,85 @@ class CustomAuthProvider implements UserProviderInterface
*/
public function retrieveByCredentials(array $credentials)
{
$user = null;
try {
DB::transaction(function () use ($credentials, &$user) {
if (!isset($credentials['username']) || !isset($credentials['password']))
throw new AuthenticationException("invalid crendentials");
if (!isset($credentials['username']) || !isset($credentials['password']))
throw new AuthenticationException("invalid crendentials");
$identifier = $credentials['username'];
$password = $credentials['password'];
$user = OpenIdUser::where('external_id', '=', $identifier)->first();
$identifier = $credentials['username'];
$password = $credentials['password'];
$user = User::where('external_id', '=', $identifier)->first();
//check user status...
if (!is_null($user) && ($user->lock || !$user->active)){
Log::warning(sprintf("user %s is on lock state",$identifier));
return null;
}
//check user status...
if (!is_null($user) && ($user->lock || !$user->active)){
Log::warning(sprintf("user %s is on lock state",$identifier));
throw new AuthenticationLockedUserLoginAttempt($identifier,sprintf("user %s is on lock state",$identifier));
}
//get SS member
$member = Member::where('Email', '=', $identifier)->first();
if (is_null($member)) //member must exists
throw new AuthenticationException(sprintf("member %s does not exists!", $identifier));
//get SS member
$member = Member::where('Email', '=', $identifier)->first();
if (is_null($member)) //member must exists
throw new AuthenticationException(sprintf("member %s does not exists!", $identifier));
$valid_password = $member->checkPassword($password);
$valid_password = $member->checkPassword($password);
if(!$valid_password)
throw new AuthenticationInvalidPasswordAttemptException($identifier,sprintf("invalid login attempt for user %s ",$identifier));
if(!$valid_password)
throw new AuthenticationInvalidPasswordAttemptException($identifier,sprintf("invalid login attempt for user %s ",$identifier));
//if user does not exists, then create it
if (is_null($user)) {
//create user
$user = new OpenIdUser();
$user->external_id = $member->Email;
$user->identifier = $member->Email;
$user->last_login_date = gmdate("Y-m-d H:i:s", time());
//if user does not exists, then create it
if (is_null($user)) {
//create user
$user = new User();
$user->external_id = $member->Email;
$user->identifier = $member->Email;
$user->last_login_date = gmdate("Y-m-d H:i:s", time());
$user->Save();
$user = User::where('external_id', '=', $identifier)->first();
}
$user_service = Registry::getInstance()->get(OpenIdServiceCatalog::UserService);
$user_name = $member->FirstName . "." . $member->Surname;
//do association between user and member
$user_service->associateUser($user->id, strtolower($user_name));
$server_configuration = Registry::getInstance()->get(UtilsServiceCatalog::ServerConfigurationService);
//update user fields
$user->last_login_date = gmdate("Y-m-d H:i:s", time());
$user->login_failed_attempt = 0;
$user->active = true;
$user->lock = false;
$user->Save();
$user = OpenIdUser::where('external_id', '=', $identifier)->first();
}
$user_service = Registry::getInstance()->get(OpenIdServiceCatalog::UserService);
//reload user...
$user = User::where('external_id', '=', $identifier)->first();
$user->setMember($member);
$user_name = $member->FirstName . "." . $member->Surname;
//do association between user and member
$user_service->associateUser($user->id, strtolower($user_name));
$auth_extensions = $this->auth_extension_service->getExtensions();
$server_configuration = Registry::getInstance()->get(OpenIdServiceCatalog::ServerConfigurationService);
//update user fields
$user->last_login_date = gmdate("Y-m-d H:i:s", time());
$user->login_failed_attempt = 0;
$user->active = true;
$user->lock = false;
$user->Save();
//reload user...
$user = OpenIdUser::where('external_id', '=', $identifier)->first();
$user->setMember($member);
//check if we have a current openid message
$memento_service = Registry::getInstance()->get(OpenIdServiceCatalog::MementoService);
$msg = $memento_service->getCurrentRequest();
if (is_null($msg) || !$msg->isValid() || !OpenIdAuthenticationRequest::IsOpenIdAuthenticationRequest($msg))
return $user;
else {
//check if current user is has the same identity that the one claimed on openid message
$auth_request = new OpenIdAuthenticationRequest($msg);
if ($auth_request->isIdentitySelectByOP())
return $user;
$claimed_id = $auth_request->getClaimedId();
$identity = $auth_request->getIdentity();
$current_identity = $server_configuration->getUserIdentityEndpointURL($user->getIdentifier());
if ($claimed_id == $current_identity || $identity == $current_identity)
return $user;
Log::warning(sprintf(OpenIdErrorMessages::AlreadyExistSessionMessage, $current_identity, $identity));
//if not return fail ( we cant log in with a different user that the one stated on the authentication message!
return null;
}
} catch (Exception $ex) {
foreach($auth_extensions as $auth_extension){
$auth_extension->process($user);
}
});
} catch (Exception $ex) {
$checkpoint_service = Registry::getInstance()->get(UtilsServiceCatalog::CheckPointService);
$checkpoint_service->trackException($ex);
Log::error($ex);
return null;
$user = null;
}
return $user;
}
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Auth\UserInterface $user
* @param array $credentials
* @param UserInterface $user
* @param array $credentials
* @return bool
* @throws exceptions\AuthenticationException
*/
public function validateCredentials(UserInterface $user, array $credentials)
{
@ -152,8 +147,8 @@ class CustomAuthProvider implements UserProviderInterface
try {
$identifier = $credentials['username'];
$password = $credentials['password'];
$user = OpenIdUser::where('external_id', '=', $identifier)->first();
$password = $credentials['password'];
$user = User::where('external_id', '=', $identifier)->first();
if (is_null($user) || $user->lock || !$user->active)
return false;

View File

@ -0,0 +1,9 @@
<?php
namespace auth;
interface IAuthenticationExtension {
public function process(User $user);
}

View File

@ -0,0 +1,20 @@
<?php
namespace auth;
/**
* Interface IAuthenticationExtensionService
* @package auth
*/
interface IAuthenticationExtensionService {
/**
* @return array
*/
public function getExtensions();
/**
* @param IAuthenticationExtension $extension
* @return bool
*/
public function addExtension(IAuthenticationExtension $extension);
}

View File

@ -9,8 +9,9 @@ use openid\model\IOpenIdUser;
use openid\services\OpenIdServiceCatalog;
use utils\services\Registry;
use oauth2\models\IOAuth2User;
use Eloquent;
class OpenIdUser extends \Eloquent implements UserInterface, IOpenIdUser, IOAuth2User
class User extends Eloquent implements UserInterface, IOpenIdUser, IOAuth2User
{
protected $table = 'openid_users';

View File

@ -9,7 +9,7 @@ class AuthenticationException extends Exception
public function __construct($message = "")
{
$message = "AuthenticationException : " . $message;
$message = "Authentication Exception : " . $message;
parent::__construct($message, 0, null);
}

View File

@ -17,7 +17,7 @@ class AuthenticationInvalidPasswordAttemptException extends Exception
public function __construct($identifier,$message = "")
{
$message = "AuthenticationInvalidPasswordAttemptException : " . $message;
$message = "Invalid Password Attempt: " . $message;
$this->identifier = $identifier;
parent::__construct($message, 0, null);
}

View File

@ -0,0 +1,23 @@
<?php
namespace auth\exceptions;
use Exception;
class AuthenticationLockedUserLoginAttempt extends Exception
{
private $identifier;
public function __construct($identifier,$message = "")
{
$message = "Locked User Login Attempt : " . $message;
$this->identifier = $identifier;
parent::__construct($message, 0, null);
}
public function getIdentifier(){
return $this->identifier;
}
}

View File

@ -114,7 +114,7 @@ class OAuth2Protocol implements IOAuth2Protocol
* http://tools.ietf.org/html/rfc6749#appendix-A
* VSCHAR = %x20-7E
*/
const VsChar = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*-.:_|~';
const VsChar = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_~';
//services
private $log_service;

View File

@ -1,17 +1,16 @@
<?php
/**
* Created by PhpStorm.
* User: smarcet
* Date: 12/3/13
* Time: 10:25 AM
*/
namespace oauth2;
use Illuminate\Support\ServiceProvider;
use utils\services\Registry;
class OAuth2ServiceProvider extends ServiceProvider
{
public function boot()
{
Registry::getInstance()->set('oauth2\IOAuth2Protocol', $this->app->make('oauth2\IOAuth2Protocol'));
}
public function register()
{

View File

@ -33,7 +33,7 @@ use utils\services\ILogService;
/**
* Class AuthorizationCodeGrantType
* Authorization Code Grant Implementation
* The authorization code grant type is used to obtain both access
* The authorization code grant type is used to obtain both access
* tokens and refresh tokens and is optimized for confidential clients.
* Since this is a redirection-based flow, the client must be capable of
* interacting with the resource owner's user-agent (typically a web
@ -131,6 +131,7 @@ class AuthorizationCodeGrantType extends AbstractGrantType
} else if ($authorization_response === IAuthService::AuthorizationResponse_DenyOnce) {
throw new AccessDeniedException;
}
// build current audience ...
$audience = $this->scope_service->getStrAudienceByScopeNames(explode(' ',$scope));
@ -138,8 +139,10 @@ class AuthorizationCodeGrantType extends AbstractGrantType
if (is_null($auth_code))
throw new OAuth2GenericException("Invalid Auth Code");
return new OAuth2AuthorizationResponse($redirect_uri, $auth_code->getValue(), $state);
// clear save data ...
$this->auth_service->clearUserAuthorizationResponse();
$this->memento_service->clearCurrentRequest();
return new OAuth2AuthorizationResponse($redirect_uri, $auth_code->getValue() , $scope, $state);
}
throw new InvalidOAuth2Request;
}

View File

@ -148,7 +148,9 @@ class ImplicitGrantType extends AbstractGrantType
$audience = $this->scope_service->getStrAudienceByScopeNames(explode(' ',$scope));
//build access token
$access_token = $this->token_service->createAccessTokenFromParams($scope, $client_id, $audience);
//clear saved data ...
$this->memento_service->clearCurrentRequest();
$this->auth_service->clearUserAuthorizationResponse();
return new OAuth2AccessTokenFragmentResponse($redirect_uri, $access_token->getValue(), $access_token->getLifetime(), $scope, $state);
}
throw new InvalidOAuth2Request;

View File

@ -27,6 +27,7 @@ class AccessToken extends Token {
$instance->auth_code = $auth_code->getValue();
$instance->audience = $auth_code->getAudience();
$instance->lifetime = $lifetime;
$instance->is_hashed = false;
return $instance;
}
@ -39,6 +40,7 @@ class AccessToken extends Token {
$instance->audience = $audience;
$instance->refresh_token = null;
$instance->lifetime = $lifetime;
$instance->is_hashed = false;
return $instance;
}
@ -52,10 +54,11 @@ class AccessToken extends Token {
$instance->refresh_token = $refresh_token;
$instance->audience = $refresh_token->getAudience();
$instance->lifetime = $lifetime;
$instance->is_hashed = false;
return $instance;
}
public static function load($value, AuthorizationCode $auth_code, $issued = null, $lifetime = 3600){
public static function load($value, AuthorizationCode $auth_code, $issued = null, $lifetime = 3600, $is_hashed=false){
$instance = new self();
$instance->value = $value;
$instance->scope = $auth_code->getScope();
@ -65,6 +68,7 @@ class AccessToken extends Token {
$instance->from_ip = $auth_code->getFromIp();
$instance->issued = $issued;
$instance->lifetime = $lifetime;
$instance->is_hashed = $is_hashed;
return $instance;
}

View File

@ -2,6 +2,7 @@
namespace oauth2\models;
use services\IPHelper;
use Zend\Math\Rand;
use oauth2\OAuth2Protocol;
/**
@ -33,10 +34,12 @@ class AuthorizationCode extends Token {
$instance->client_id = $client_id;
$instance->lifetime = $lifetime;
$instance->audience = $audience;
$instance->is_hashed = false;
$instance->from_ip = IPHelper::getUserIp();
return $instance;
}
public static function load($value, $client_id, $scope,$audience='', $redirect_uri = null, $issued = null, $lifetime = 600, $from_ip = '127.0.0.1'){
public static function load($value, $client_id, $scope,$audience='', $redirect_uri = null, $issued = null, $lifetime = 600, $from_ip = '127.0.0.1',$is_hashed = false){
$instance = new self();
$instance->value = $value;
$instance->scope = $scope;
@ -46,6 +49,7 @@ class AuthorizationCode extends Token {
$instance->issued = $issued;
$instance->lifetime = $lifetime;
$instance->from_ip = $from_ip;
$instance->is_hashed = $is_hashed;
return $instance;
}

View File

@ -41,6 +41,7 @@ class RefreshToken extends Token {
$instance->audience = $access_token->getAudience();
$instance->from_ip = IPHelper::getUserIp();
$instance->lifetime = $lifetime;
$instance->is_hashed = false;
return $instance;
}
@ -52,6 +53,7 @@ class RefreshToken extends Token {
$instance->audience = $params['audience'];
$instance->from_ip = $params['from_ip'];
$instance->issued = $params['issued'];
$instance->is_hashed = isset($params['is_hashed'])?$params['is_hashed']:false;
$instance->lifetime = $lifetime;
return $instance;
}

View File

@ -22,11 +22,13 @@ abstract class Token
protected $scope;
protected $audience;
protected $from_ip;
protected $is_hashed;
public function __construct($len = self::DefaultByteLength)
{
$this->len = $len;
$this->issued = gmdate("Y-m-d H:i:s", time());
$this->len = $len;
$this->is_hashed = false;
$this->issued = gmdate("Y-m-d H:i:s", time());
}
public function getIssued()
@ -78,7 +80,12 @@ abstract class Token
return $seconds;
}
public function isHashed(){
return $this->is_hashed;
}
public abstract function toJSON();
public abstract function fromJSON($json);
}

View File

@ -10,14 +10,35 @@ use oauth2\OAuth2Protocol;
*/
class OAuth2AuthorizationResponse extends OAuth2IndirectResponse {
public function __construct($return_url, $code, $state=null)
/**
* @param $return_url
* @param $code
* @param null $scope
* @param null $state
*/
public function __construct($return_url, $code, $scope=null, $state=null)
{
parent::__construct();
$this[OAuth2Protocol::OAuth2Protocol_ResponseType_Code] = $code;
$this->setReturnTo($return_url);
if(!is_null($scope))
$this[OAuth2Protocol::OAuth2Protocol_Scope] = $scope;
if(!is_null($state))
$this[OAuth2Protocol::OAuth2Protocol_State] = $state;
}
public function getAuthCode(){
return isset($this[OAuth2Protocol::OAuth2Protocol_ResponseType_Code])?$this[OAuth2Protocol::OAuth2Protocol_ResponseType_Code] :null;
}
public function getState(){
return isset($this[OAuth2Protocol::OAuth2Protocol_State])?$this[OAuth2Protocol::OAuth2Protocol_State] :null;
}
public function getScope(){
return isset($this[OAuth2Protocol::OAuth2Protocol_Scope])?$this[OAuth2Protocol::OAuth2Protocol_Scope] :null;
}
}

View File

@ -9,7 +9,18 @@ use openid\services\OpenIdServiceCatalog;
use openid\XRDS\XRDSDocumentBuilder;
use openid\XRDS\XRDSService;
use utils\services\Registry;
use utils\services\UtilsServiceCatalog;
//services
use utils\services\ILogService;
use openid\services\IMementoOpenIdRequestService;
use openid\handlers\IOpenIdAuthenticationStrategy;
use openid\services\IServerExtensionsService;
use openid\services\IAssociationService;
use openid\services\ITrustedSitesService;
use openid\services\IServerConfigurationService;
use openid\services\INonceService;
use utils\services\IAuthService;
use utils\services\ICheckPointService;
/**
* Class OpenIdProtocol
@ -64,9 +75,11 @@ class OpenIdProtocol implements IOpenIdProtocol
const OpenIdProtocol_DHServerPublic = "dh_server_public";
const OpenIdProtocol_DHEncMacKey = "enc_mac_key";
const OpenIdProtocol_MacKey = "mac_key";
private static $OpenIDProtocol_SupportedAssocType = array(
self::SignatureAlgorithmHMAC_SHA1,
self::SignatureAlgorithmHMAC_SHA256
self::SignatureAlgorithmHMAC_SHA256,
self::AssociationSessionTypeNoEncryption,
);
private static $OpenIDProtocol_SupportedSessionType = array(
self::AssociationSessionTypeNoEncryption,
@ -111,25 +124,26 @@ class OpenIdProtocol implements IOpenIdProtocol
self::OpenIdProtocol_DHEncMacKey => self::OpenIdProtocol_DHEncMacKey,
self::OpenIdProtocol_MacKey => self::OpenIdProtocol_MacKey,
);
private $request_handlers;
public function __construct()
public function __construct(
IAuthService $auth_service,
IMementoOpenIdRequestService $memento_request_service,
IOpenIdAuthenticationStrategy $auth_strategy,
IServerExtensionsService $server_extension_service,
IAssociationService $association_service,
ITrustedSitesService $trusted_sites_service,
IServerConfigurationService $server_config_service,
INonceService $nonce_service,
ILogService $log_service,
ICheckPointService $checkpoint_service)
{
//create chain of responsibility
$auth_service = Registry::getInstance()->get(UtilsServiceCatalog::AuthenticationService);
$memento_request_service = Registry::getInstance()->get(OpenIdServiceCatalog::MementoService);
$auth_strategy = Registry::getInstance()->get(OpenIdServiceCatalog::AuthenticationStrategy);
$server_extension_service = Registry::getInstance()->get(OpenIdServiceCatalog::ServerExtensionsService);
$association_service = Registry::getInstance()->get(OpenIdServiceCatalog::AssociationService);
$trusted_sites_service = Registry::getInstance()->get(OpenIdServiceCatalog::TrustedSitesService);
$server_config_service = Registry::getInstance()->get(OpenIdServiceCatalog::ServerConfigurationService);
$nonce_service = Registry::getInstance()->get(OpenIdServiceCatalog::NonceService);
$log = Registry::getInstance()->get(UtilsServiceCatalog::LogService);
$check_auth = new OpenIdCheckAuthenticationRequestHandler($association_service, $nonce_service, $log, null);
$session_assoc = new OpenIdSessionAssociationRequestHandler($log, $check_auth);
$this->request_handlers = new OpenIdAuthenticationRequestHandler($auth_service, $memento_request_service, $auth_strategy, $server_extension_service, $association_service, $trusted_sites_service, $server_config_service, $nonce_service, $log, $session_assoc);
$check_auth = new OpenIdCheckAuthenticationRequestHandler($association_service, $nonce_service, $log_service,$checkpoint_service, null);
$session_assoc = new OpenIdSessionAssociationRequestHandler($log_service,$checkpoint_service, $check_auth);
$this->request_handlers = new OpenIdAuthenticationRequestHandler($auth_service, $memento_request_service, $auth_strategy, $server_extension_service, $association_service, $trusted_sites_service, $server_config_service, $nonce_service, $log_service,$checkpoint_service, $session_assoc);
}
public static function isAssocTypeSupported($assoc_type)
@ -154,7 +168,7 @@ class OpenIdProtocol implements IOpenIdProtocol
public static function param($param, $separator = '.')
{
return self::OpenIdPrefix . $separator . self::$protocol_definition[$param];
return self::OpenIdPrefix . $separator . $param ;
}
public function getXRDSDiscovery($mode, $canonical_id = null)
@ -179,4 +193,4 @@ class OpenIdProtocol implements IOpenIdProtocol
{
return $this->request_handlers->handleMessage($openIdMessage);
}
}
}

View File

@ -3,6 +3,9 @@
namespace openid;
use Illuminate\Support\ServiceProvider;
use openid\extensions\OpenIdAuthenticationExtension;
use openid\services\OpenIdServiceCatalog;
use utils\services\UtilsServiceCatalog;
/**
* Class OpenIdServiceProvider
@ -12,8 +15,26 @@ use Illuminate\Support\ServiceProvider;
class OpenIdServiceProvider extends ServiceProvider
{
public function register()
public function boot()
{
$this->app->bind('openid\IOpenIdProtocol', 'openid\OpenIdProtocol');
$auth_extension_service = $this->app->make('auth\\IAuthenticationExtensionService');
if(!is_null($auth_extension_service)){
$memento_service = $this->app->make(OpenIdServiceCatalog::MementoService);
$server_configuration_service = $this->app->make(UtilsServiceCatalog::ServerConfigurationService);
$auth_extension_service->addExtension(new OpenIdAuthenticationExtension($memento_service,$server_configuration_service));
}
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
// TODO: Implement register() method.
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace openid\exceptions;
use Exception;
class InvalidAssociation extends Exception
{
public function __construct($message = "")
{
$message = "Invalid Association: " . $message;
parent::__construct($message, 0, null);
}
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: smarcet
* Date: 10/28/13
* Time: 6:03 PM
*/
namespace openid\exceptions;

View File

@ -0,0 +1,52 @@
<?php
namespace openid\extensions;
use auth\exceptions\AuthenticationException;
use auth\IAuthenticationExtension;
use auth\User;
use openid\helpers\OpenIdErrorMessages;
use openid\requests\OpenIdAuthenticationRequest;
use openid\services\IServerConfigurationService;
use openid\services\IMementoOpenIdRequestService;
/**
* Class OpenIdAuthenticationExtension
* @package openid\extensions
*/
class OpenIdAuthenticationExtension implements IAuthenticationExtension
{
private $memento_service;
private $server_configuration;
/**
* @param IMementoOpenIdRequestService $memento_service
* @param IServerConfigurationService $server_configuration
*/
public function __construct(IMementoOpenIdRequestService $memento_service, IServerConfigurationService $server_configuration){
$this->server_configuration = $server_configuration;
$this->memento_service = $memento_service;
}
public function process(User $user)
{
//check if we have a current openid message
$msg = $this->memento_service->getCurrentRequest();
if (!is_null($msg) && $msg->isValid() && OpenIdAuthenticationRequest::IsOpenIdAuthenticationRequest($msg)) {
//check if current user is has the same identity that the one claimed on openid message
$auth_request = new OpenIdAuthenticationRequest($msg);
if (!$auth_request->isIdentitySelectByOP()) {
$claimed_id = $auth_request->getClaimedId();
$identity = $auth_request->getIdentity();
$current_identity = $this->server_configuration->getUserIdentityEndpointURL($user->getIdentifier());
//if not return fail ( we cant log in with a different user that the one stated on the authentication message!
if ($claimed_id !== $current_identity && $identity !== $current_identity) {
Log::warning(sprintf(OpenIdErrorMessages::AlreadyExistSessionMessage, $current_identity, $identity));
throw new AuthenticationException(sprintf(OpenIdErrorMessages::AlreadyExistSessionMessage, $current_identity, $identity));
}
}
}
}
}

View File

@ -30,7 +30,7 @@ abstract class OpenIdExtension
protected $name;
protected $description;
protected $view;
protected $log;
protected $log_service;
/**
* @param $name
@ -44,7 +44,7 @@ abstract class OpenIdExtension
$this->name = $name;
$this->view = $view;
$this->description = $description;
$this->log = Registry::getInstance()->get(UtilsServiceCatalog::LogService);
$this->log_service = Registry::getInstance()->get(UtilsServiceCatalog::LogService);
}
public function getNamespace()

View File

@ -2,6 +2,7 @@
namespace openid\extensions\implementations;
use Exception;
use openid\extensions\OpenIdExtension;
use openid\OpenIdProtocol;
use openid\requests\contexts\PartialView;
@ -9,11 +10,9 @@ use openid\requests\contexts\RequestContext;
use openid\requests\OpenIdRequest;
use openid\responses\contexts\ResponseContext;
use openid\responses\OpenIdResponse;
use openid\services\OpenIdServiceCatalog;
use utils\services\Registry;
use utils\services\UtilsServiceCatalog;
/**
* Class OpenIdAXExtension
* Implements
@ -59,8 +58,8 @@ class OpenIdAXExtension extends OpenIdExtension
}
$partial_view = new PartialView($this->view, array("attributes" => $data));
$context->addPartialView($partial_view);
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
}
@ -96,8 +95,8 @@ class OpenIdAXExtension extends OpenIdExtension
$response->addParam(self::param(self::Value) . "." . $attr, $user->getLanguage());
}
}
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
}
@ -122,8 +121,8 @@ class OpenIdAXExtension extends OpenIdExtension
array_push($data, $attr);
}
}
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
return $data;
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: smarcet
* Date: 11/4/13
* Time: 10:45 AM
*/
namespace openid\extensions\implementations;
@ -36,41 +30,38 @@ class OpenIdAXRequest extends OpenIdRequest
*/
public function isValid()
{
try {
//check identifier
if (isset($this->message[OpenIdAXExtension::paramNamespace('_')])
&& $this->message[OpenIdAXExtension::paramNamespace('_')] == OpenIdAXExtension::NamespaceUrl
) {
//check required fields
//check identifier
if (isset($this->message[OpenIdAXExtension::paramNamespace('_')])
&& $this->message[OpenIdAXExtension::paramNamespace('_')] == OpenIdAXExtension::NamespaceUrl
) {
if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::Mode, '_')])
|| $this->message[OpenIdAXExtension::param(OpenIdAXExtension::Mode, '_')] != OpenIdAXExtension::FetchRequest
)
throw new InvalidOpenIdMessageException(OpenIdErrorMessages::AXInvalidModeMessage);
//check required fields
if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::RequiredAttributes, '_')]))
throw new InvalidOpenIdMessageException(OpenIdErrorMessages::AXInvalidRequiredAttributesMessage);
if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::Mode, '_')])
|| $this->message[OpenIdAXExtension::param(OpenIdAXExtension::Mode, '_')] != OpenIdAXExtension::FetchRequest
)
throw new InvalidOpenIdMessageException(OpenIdErrorMessages::AXInvalidModeMessage);
//get attributes
$attributes = $this->message[OpenIdAXExtension::param(OpenIdAXExtension::RequiredAttributes, '_')];
$attributes = explode(",", $attributes);
if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::RequiredAttributes, '_')]))
throw new InvalidOpenIdMessageException(OpenIdErrorMessages::AXInvalidRequiredAttributesMessage);
foreach ($attributes as $attr) {
$attr = trim($attr);
if (!isset(OpenIdAXExtension::$available_properties[$attr]))
continue;
if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::Type, '_') . "_" . $attr]))
throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::AXInvalidNamespaceMessage, $attr));
$ns = $this->message[OpenIdAXExtension::param(OpenIdAXExtension::Type, "_") . "_" . $attr];
if ($ns != OpenIdAXExtension::$available_properties[$attr])
throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::AXInvalidNamespaceMessage, $attr));
array_push($this->attributes, $attr);
}
return true;
//get attributes
$attributes = $this->message[OpenIdAXExtension::param(OpenIdAXExtension::RequiredAttributes, '_')];
$attributes = explode(",", $attributes);
foreach ($attributes as $attr) {
$attr = trim($attr);
if (!isset(OpenIdAXExtension::$available_properties[$attr]))
continue;
if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::Type, '_') . "_" . $attr]))
throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::AXInvalidNamespaceMessage, $attr));
$ns = $this->message[OpenIdAXExtension::param(OpenIdAXExtension::Type, "_") . "_" . $attr];
if ($ns != OpenIdAXExtension::$available_properties[$attr])
throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::AXInvalidNamespaceMessage, $attr));
array_push($this->attributes, $attr);
}
} catch (\Exception $ex) {
$this->log->error($ex);
return true;
}
return false;
}

View File

@ -0,0 +1,181 @@
<?php
namespace openid\extensions\implementations;
use openid\requests\contexts\PartialView;
use oauth2\services\OAuth2ServiceCatalog;
use openid\extensions\OpenIdExtension;
use openid\OpenIdProtocol;
use openid\requests\contexts\RequestContext;
use openid\requests\OpenIdRequest;
use openid\responses\contexts\ResponseContext;
use openid\responses\OpenIdResponse;
use Exception;
use utils\services\Registry;
use utils\services\UtilsServiceCatalog;
use oauth2\requests\OAuth2AuthorizationRequest;
use oauth2\OAuth2Protocol;
use oauth2\OAuth2Message;
/**
* Class OpenIdOAuthExtension
* Implements
* http://step2.googlecode.com/svn/spec/openid_oauth_extension/latest/openid_oauth_extension.html
* OpenID+OAuth Hybrid protocol lets web developers combine an OpenID request with an
* OAuth authentication request. This extension is useful for web developers who use both OpenID
* and OAuth, particularly in that it simplifies the process for users by requesting
* their approval once instead of twice.
* In this way, the user can approve login and service access at the same time.
* @package openid\extensions\implementations
*/
class OpenIdOAuth2Extension extends OpenIdExtension
{
const Prefix = "oauth";
const NamespaceUrl = "http://specs.openid.net/extensions/oauth/2.0";
const NamespaceType = 'ns';
const RequestToken = 'request_token';
const Scope = OAuth2Protocol::OAuth2Protocol_Scope;
const ClientId = OAuth2Protocol::OAuth2Protocol_ClientId;
const State = OAuth2Protocol::OAuth2Protocol_State;
private $oauth2_protocol;
private $checkpoint_service;
private $client_service;
private $scope_service;
public function __construct($name, $namespace, $view, $description)
{
parent::__construct($name, $namespace, $view, $description);
$this->oauth2_protocol = Registry::getInstance()->get('oauth2\IOAuth2Protocol');
$this->checkpoint_service = Registry::getInstance()->get(UtilsServiceCatalog::CheckPointService);
$this->client_service = Registry::getInstance()->get(OAuth2ServiceCatalog::ClientService);
$this->scope_service = Registry::getInstance()->get(OAuth2ServiceCatalog::ScopeService);
}
public static function param($param, $separator = '.')
{
return OpenIdProtocol::OpenIdPrefix . $separator . self::Prefix . $separator . $param;
}
public static function paramNamespace($separator = '.')
{
return OpenIdProtocol::OpenIdPrefix . $separator . OpenIdProtocol::OpenIDProtocol_NS . $separator . self::Prefix;
}
public function parseRequest(OpenIdRequest $request, RequestContext $context)
{
try {
$oauth2_request = new OpenIdOAuth2Request($request->getMessage());
if (!$oauth2_request->isValid()) return;
$scopes = $oauth2_request->getScope();
$client_id = $oauth2_request->getClientId();
$client = $this->client_service->getClientById($client_id);
// do some validations to allow show the oauth2 sub view...
if(is_null($client)) return;
//check is redirect uri is allowed for client
$redirect_uri = $request->getParam(OpenIdProtocol::OpenIDProtocol_ReturnTo);
if (!$client->isUriAllowed($redirect_uri)) return;
//check if requested client is allowed to use this scopes
if(!$client->isScopeAllowed($scopes)) return;
$scopes = explode(' ', $scopes);
//get scopes entities
$requested_scopes = $this->scope_service->getScopesByName($scopes);
// set view data
$return_to = $request->getParam(OpenIdProtocol::OpenIDProtocol_ReturnTo);
$url_parts = @parse_url($return_to);
$return_to = $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'];
$partial_view = new PartialView ($this->view, array(
'requested_scopes' => $requested_scopes,
'app_name' => $client->getApplicationName(),
'app_logo' => $client->getApplicationLogo(),
'redirect_to' => $return_to,
'dev_info_email' => $client->getDeveloperEmail()
));
$context->addPartialView($partial_view);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
}
public function prepareResponse(OpenIdRequest $request, OpenIdResponse $response, ResponseContext $context)
{
try{
$oauth2_request = new OpenIdOAuth2Request($request->getMessage());
if (!$oauth2_request->isValid()) return;
//get auth code
$oauth2_msg = new OAuth2Message(
array(
OAuth2Protocol::OAuth2Protocol_ClientId => $oauth2_request->getClientId(),
OAuth2Protocol::OAuth2Protocol_Scope => $oauth2_request->getScope(),
OAuth2Protocol::OAuth2Protocol_RedirectUri => $request->getParam(OpenIdProtocol::OpenIDProtocol_ReturnTo),
OAuth2Protocol::OAuth2Protocol_State => $oauth2_request->getState(),
OAuth2Protocol::OAuth2Protocol_ResponseType => OAuth2Protocol::OAuth2Protocol_ResponseType_Code
)
);
// do oauth2 Authorization Code Grant 1st step (get auth code to exchange for an access token)
// http://tools.ietf.org/html/rfc6749#section-4.1
$oauth2_response = $this->oauth2_protocol->authorize(new OAuth2AuthorizationRequest($oauth2_msg));
if ( get_class($oauth2_response) =='oauth2\\responses\\OAuth2AuthorizationResponse') {
//add namespace
$response->addParam(self::paramNamespace(),self::NamespaceUrl );
$context->addSignParam(self::paramNamespace());
//add auth code
$response->addParam(self::param(self::RequestToken), $oauth2_response->getAuthCode());
$context->addSignParam(self::param(self::RequestToken));
//add requested scope
$response->addParam(self::param(self::Scope), $oauth2_response->getScope());
$context->addSignParam(self::param(self::Scope));
//add state
$response->addParam(self::param(self::State), $oauth2_request->getState());
$context->addSignParam(self::param(self::State));
}
}
catch (Exception $ex) {
$this->log_service->error($ex);
$this->checkpoint_service->trackException($ex);
//http://step2.googlecode.com/svn/spec/openid_oauth_extension/latest/openid_oauth_extension.html#AuthResp
/*
* To note that the OAuth Authorization was declined or not valid, the Combined Provider SHALL only
* respond with the parameter "openid.ns.oauth".
*/
//add namespace
$response->addParam(self::paramNamespace(),self::NamespaceUrl );
$context->addSignParam(self::paramNamespace());
}
}
public function getTrustedData(OpenIdRequest $request)
{
$data = array();
try {
$oauth2_request = new OpenIdOAuth2Request($request->getMessage());
if ($oauth2_request->isValid()) {
array_push($data,$oauth2_request->getScope());
array_push($data,$oauth2_request->getClientId());
}
} catch (Exception $ex) {
$this->log_service->error($ex);
}
return $data;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace openid\extensions\implementations;
use openid\exceptions\InvalidOpenIdMessageException;
use openid\helpers\OpenIdErrorMessages;
use openid\OpenIdMessage;
use openid\requests\OpenIdRequest;
use oauth2\OAuth2Protocol;
class OpenIdOAuth2Request extends OpenIdRequest {
public function __construct(OpenIdMessage $message)
{
parent::__construct($message);
}
public function isValid()
{
//check identifier
if (isset($this->message[OpenIdOAuth2Extension::paramNamespace('_')])
&& $this->message[OpenIdOAuth2Extension::paramNamespace('_')] == OpenIdOAuth2Extension::NamespaceUrl
) {
if(is_null($this->getClientId()))
throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::OAuth2MissingRequiredParam,'client_id'));
if(is_null($this->getScope()))
throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::OAuth2MissingRequiredParam,'scope'));
if(is_null($this->getState()))
throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::OAuth2MissingRequiredParam,'state'));
return true;
}
return false;
}
public function getClientId(){
return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_ClientId, '_')])?
$this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_ClientId, '_')]:null;
}
public function getScope(){
return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Scope, '_')])?
$this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Scope, '_')]:null;
}
public function getState(){
return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_State, '_')])?
$this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_State, '_')]:null;
}
}

View File

@ -1,59 +0,0 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: smarcet
* Date: 10/16/13
* Time: 2:43 PM
* To change this template use File | Settings | File Templates.
*/
namespace openid\extensions\implementations;
use openid\extensions\OpenIdExtension;
use openid\OpenIdProtocol;
use openid\requests\contexts\RequestContext;
use openid\requests\OpenIdRequest;
use openid\responses\contexts\ResponseContext;
use openid\responses\OpenIdResponse;
/**
* Class OpenIdOAuthExtension
* Implements
* http://step2.googlecode.com/svn/spec/openid_oauth_extension/latest/openid_oauth_extension.html
* @package openid\extensions\implementations
*/
class OpenIdOAuthExtension extends OpenIdExtension
{
const Prefix = "oauth";
public static function param($param, $separator = '.')
{
return OpenIdProtocol::OpenIdPrefix . $separator . self::Prefix . $separator . $param;
}
public static function paramNamespace($separator = '.')
{
return OpenIdProtocol::OpenIdPrefix . $separator . OpenIdProtocol::OpenIDProtocol_NS . $separator . self::Prefix;
}
public function parseRequest(OpenIdRequest $request, RequestContext $context)
{
// TODO: Implement parseRequest() method.
}
public function prepareResponse(OpenIdRequest $request, OpenIdResponse $response, ResponseContext $context)
{
// TODO: Implement prepareResponse() method.
}
public function getTrustedData(OpenIdRequest $request)
{
}
protected function populateProperties()
{
// TODO: Implement populateProperties() method.
}
}

View File

@ -1,11 +1,4 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: smarcet
* Date: 10/16/13
* Time: 2:42 PM
* To change this template use File | Settings | File Templates.
*/
namespace openid\extensions\implementations;
@ -19,6 +12,7 @@ use openid\responses\OpenIdResponse;
use openid\services\OpenIdServiceCatalog;
use utils\services\Registry;
use utils\services\UtilsServiceCatalog;
use Exception;
/**
* Class OpenIdSREGExtension
@ -81,8 +75,8 @@ class OpenIdSREGExtension extends OpenIdExtension
$partial_view = new PartialView($this->view, $view_data);
$context->addPartialView($partial_view);
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
}
@ -116,8 +110,8 @@ class OpenIdSREGExtension extends OpenIdExtension
$response->addParam(self::param($attr), $user->getLanguage());
}
}
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
}
@ -144,8 +138,8 @@ class OpenIdSREGExtension extends OpenIdExtension
array_push($data, $key);
}
}
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
return $data;
}

View File

@ -30,6 +30,7 @@ use openid\services\IServerExtensionsService;
use openid\services\ITrustedSitesService;
use utils\services\IAuthService;
use utils\services\ILogService;
use utils\services\ICheckPointService;
/**
* Class OpenIdAuthenticationRequestHandler
@ -61,9 +62,10 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
IServerConfigurationService $server_configuration_service,
INonceService $nonce_service,
ILogService $log,
ICheckPointService $checkpoint_service,
$successor)
{
parent::__construct($successor, $log);
parent::__construct($successor, $log,$checkpoint_service);
$this->auth_service = $authService;
$this->memento_service = $memento_service;
$this->auth_strategy = $auth_strategy;
@ -110,33 +112,33 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
}
} catch (InvalidAssociationTypeException $inv_assoc_type) {
$this->checkpoint_service->trackException($inv_assoc_type);
$this->log->warning($inv_assoc_type);
$this->log_service->warning($inv_assoc_type);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return new OpenIdIndirectGenericErrorResponse($inv_assoc_type->getMessage(), null, null, $this->current_request);
} catch (OpenIdInvalidRealmException $inv_realm_ex) {
$this->checkpoint_service->trackException($inv_realm_ex);
$this->log->error($inv_realm_ex);
$this->log_service->error($inv_realm_ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return new OpenIdIndirectGenericErrorResponse($inv_realm_ex->getMessage(), null, null, $this->current_request);
} catch (ReplayAttackException $replay_ex) {
$this->checkpoint_service->trackException($replay_ex);
$this->log->error($replay_ex);
$this->log_service->error($replay_ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return new OpenIdIndirectGenericErrorResponse($replay_ex->getMessage(), null, null, $this->current_request);
} catch (InvalidOpenIdMessageException $inv_msg_ex) {
$this->checkpoint_service->trackException($inv_msg_ex);
$this->log->error($inv_msg_ex);
$this->log_service->error($inv_msg_ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return new OpenIdIndirectGenericErrorResponse($inv_msg_ex->getMessage(), null, null, $this->current_request);
} catch (Exception $ex) {
$this->checkpoint_service->trackException($ex);
$this->log->error($ex);
$this->log_service->error($ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return new OpenIdIndirectGenericErrorResponse("Server Error", null, null, $this->current_request);
}
}
@ -147,66 +149,66 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
*/
private function doSetupMode()
{
if (!$this->auth_service->isUserLogged()) {
if (!$this->auth_service->isUserLogged())
return $this->doLogin();
} else {
//user already logged
$currentUser = $this->auth_service->getCurrentUser();
if (!$this->current_request->isIdentitySelectByOP()) {
$current_claimed_id = $this->current_request->getClaimedId();
$current_identity = $this->current_request->getIdentity();
// check is claimed identity match with current one
// if not logs out and do re login
$current_user = $this->auth_service->getCurrentUser();
//user already logged
$currentUser = $this->auth_service->getCurrentUser();
if (is_null($current_user))
throw new \Exception("User not set!");
if (!$this->current_request->isIdentitySelectByOP()) {
$current_owned_identity = $this->server_configuration_service->getUserIdentityEndpointURL($current_user->getIdentifier());
$current_claimed_id = $this->current_request->getClaimedId();
$current_identity = $this->current_request->getIdentity();
// check is claimed identity match with current one
// if not logs out and do re login
$current_user = $this->auth_service->getCurrentUser();
if (is_null($current_user))
throw new Exception("User not set!");
if ($current_claimed_id != $current_owned_identity && $current_identity != $current_owned_identity) {
$this->log->warning_msg(sprintf(OpenIdErrorMessages::AlreadyExistSessionMessage, $current_owned_identity, $current_identity));
$this->auth_service->logout();
return $this->doLogin();
}
$current_owned_identity = $this->server_configuration_service->getUserIdentityEndpointURL($current_user->getIdentifier());
if ($current_claimed_id != $current_owned_identity && $current_identity != $current_owned_identity) {
$this->log_service->warning_msg(sprintf(OpenIdErrorMessages::AlreadyExistSessionMessage, $current_owned_identity, $current_identity));
$this->auth_service->logout();
return $this->doLogin();
}
}
$authorization_response = $this->auth_service->getUserAuthorizationResponse();
$authorization_response = $this->auth_service->getUserAuthorizationResponse();
if ($authorization_response !== IAuthService::AuthorizationResponse_None)
return $this->checkAuthorizationResponse($authorization_response);
if ($authorization_response == IAuthService::AuthorizationResponse_None) {
$this->current_request_context->cleanTrustedData();
foreach ($this->extensions as $ext) {
$data = $ext->getTrustedData($this->current_request);
$this->current_request_context->setTrustedData($data);
// $authorization_response is none ...
$this->current_request_context->cleanTrustedData();
foreach ($this->extensions as $ext) {
$data = $ext->getTrustedData($this->current_request);
$this->current_request_context->setTrustedData($data);
}
$requested_data = $this->current_request_context->getTrustedData();
$sites = $this->trusted_sites_service->getTrustedSites($currentUser, $this->current_request->getRealm(), $requested_data);
//check trusted sites
if (is_null($sites) || count($sites) === 0)
return $this->doConsentProcess();
//there are trusted sites ... check the former authorization decision
$site = $sites[0];
$policy = $site->getAuthorizationPolicy();
switch ($policy) {
case IAuthService::AuthorizationResponse_AllowForever:
{
//save former user choice on session
$this->auth_service->setUserAuthorizationResponse($policy);
return $this->doAssertion();
}
$requested_data = $this->current_request_context->getTrustedData();
$sites = $this->trusted_sites_service->getTrustedSites($currentUser, $this->current_request->getRealm(), $requested_data);
if (!is_null($sites) && count($sites) > 0) {
$site = $sites[0];
$policy = $site->getAuthorizationPolicy();
switch ($policy) {
case IAuthService::AuthorizationResponse_AllowForever:
{
return $this->doAssertion();
}
break;
case IAuthService::AuthorizationResponse_DenyForever:
// black listed site
return new OpenIdIndirectGenericErrorResponse(sprintf(OpenIdErrorMessages::RealmNotAllowedByUserMessage, $site->getRealm()), null, null, $this->current_request);
break;
default:
throw new \Exception("Invalid Realm Policy");
break;
}
} else {
return $this->doConsentProcess();
}
} else {
return $this->checkAuthorizationResponse($authorization_response);
}
break;
case IAuthService::AuthorizationResponse_DenyForever:
// black listed site
return new OpenIdIndirectGenericErrorResponse(sprintf(OpenIdErrorMessages::RealmNotAllowedByUserMessage, $site->getRealm()), null, null, $this->current_request);
break;
default:
throw new Exception("Invalid Realm Policy");
break;
}
}
@ -246,33 +248,30 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
$context->addSignParam(OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity));
$op_endpoint = $this->server_configuration_service->getOPEndpointURL();
$identity = $this->server_configuration_service->getUserIdentityEndpointURL($currentUser->getIdentifier());
$nonce = $this->nonce_service->generateNonce();
$realm = $this->current_request->getRealm();
$response = new OpenIdPositiveAssertionResponse($op_endpoint, $identity, $identity, $this->current_request->getReturnTo(), $nonce->getRawFormat(), $realm);
$identity = $this->server_configuration_service->getUserIdentityEndpointURL($currentUser->getIdentifier());
$nonce = $this->nonce_service->generateNonce();
$realm = $this->current_request->getRealm();
$response = new OpenIdPositiveAssertionResponse($op_endpoint, $identity, $identity, $this->current_request->getReturnTo(), $nonce->getRawFormat(), $realm);
foreach ($this->extensions as $ext) {
$ext->prepareResponse($this->current_request, $response, $context);
}
//check former assoc handle...
$assoc_handle = $this->current_request->getAssocHandle();
$association = $this->association_service->getAssociation($assoc_handle);
if (empty($assoc_handle) || is_null($association)) {
if (is_null($assoc_handle = $this->current_request->getAssocHandle()) || is_null($association = $this->association_service->getAssociation($assoc_handle))) {
// if not present or if it already void then enter on dumb mode
$new_secret = OpenIdCryptoHelper::generateSecret(OpenIdProtocol::SignatureAlgorithmHMAC_SHA256);
$new_handle = AssocHandleGenerator::generate();
$lifetime = $this->server_configuration_service->getConfigValue("Private.Association.Lifetime");
$issued = gmdate("Y-m-d H:i:s", time());
//create private association ...
$this->association_service->addAssociation($new_handle, $new_secret, OpenIdProtocol::SignatureAlgorithmHMAC_SHA256, $lifetime, $issued, IAssociation::TypePrivate, $realm);
$association = $this->association_service->addAssociation($new_handle, $new_secret, OpenIdProtocol::SignatureAlgorithmHMAC_SHA256, $lifetime, $issued, IAssociation::TypePrivate, $realm);
$response->setAssocHandle($new_handle);
if (!empty($assoc_handle)) {
$response->setInvalidateHandle($assoc_handle);
}
$association = $this->association_service->getAssociation($new_handle);
} else {
if ($association->getType() != IAssociation::TypeSession)
throw new InvalidAssociationTypeException(OpenIdErrorMessages::InvalidAssociationTypeMessage);
@ -288,7 +287,9 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
* so associate $nonce with signature and realm
*/
$this->nonce_service->associateNonce($nonce, $response->getSig(), $realm);
//do cleaning ...
$this->memento_service->clearCurrentRequest();
$this->auth_service->clearUserAuthorizationResponse();
return $response;
}
@ -333,16 +334,22 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
break;
case IAuthService::AuthorizationResponse_DenyOnce:
{
$this->memento_service->clearCurrentRequest();
$this->auth_service->clearUserAuthorizationResponse();
return new OpenIdNonImmediateNegativeAssertion($this->current_request->getReturnTo());
}
break;
break;
case IAuthService::AuthorizationResponse_DenyForever:
{
$this->memento_service->clearCurrentRequest();
$this->auth_service->clearUserAuthorizationResponse();
$this->trusted_sites_service->addTrustedSite($currentUser, $this->current_request->getRealm(), IAuthService::AuthorizationResponse_DenyForever);
return new OpenIdNonImmediateNegativeAssertion($this->current_request->getReturnTo());
}
break;
default:
$this->memento_service->clearCurrentRequest();
$this->auth_service->clearUserAuthorizationResponse();
throw new \Exception("Invalid Authorization response!");
break;
}
@ -384,6 +391,8 @@ class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler
break;
case IAuthService::AuthorizationResponse_AllowForever:
{
//save former user choice on session
$this->auth_service->setUserAuthorizationResponse($policy);
return $this->doAssertion();
}
break;

View File

@ -18,22 +18,32 @@ use openid\responses\OpenIdDirectGenericErrorResponse;
use openid\services\IAssociationService;
use openid\services\INonceService;
use utils\services\ILogService;
use utils\services\ICheckPointService;
/**
* Class OpenIdCheckAuthenticationRequestHandler
* Implements http://openid.net/specs/openid-authentication-2_0.html#check_auth
* Verifying Directly with the OpenID Provider
* To have the signature verification performed by the OP, the Relying Party sends a direct request to the OP.
* To verify the signature, the OP uses a private association that was generated when it issued
* the positive assertion.
* @package openid\handlers
*/
class OpenIdCheckAuthenticationRequestHandler extends OpenIdMessageHandler
{
private $association_service;
private $nonce_service;
public function __construct(IAssociationService $association_service,
INonceService $nonce_service,
ILogService $log,
ILogService $log_service,
ICheckPointService $checkpoint_service,
$successor)
{
parent::__construct($successor, $log);
parent::__construct($successor, $log_service, $checkpoint_service);
$this->association_service = $association_service;
$this->nonce_service = $nonce_service;
$this->nonce_service = $nonce_service;
}
protected function internalHandle(OpenIdMessage $message)
@ -44,9 +54,7 @@ class OpenIdCheckAuthenticationRequestHandler extends OpenIdMessageHandler
if (!$this->current_request->isValid())
throw new InvalidOpenIdMessageException(OpenIdErrorMessages::InvalidOpenIdCheckAuthenticationRequestMessage);
$claimed_nonce = new OpenIdNonce($this->current_request->getNonce());
$this->nonce_service->lockNonce($claimed_nonce);
/**
* For verifying signatures an OP MUST only use private associations and MUST NOT
@ -60,14 +68,17 @@ class OpenIdCheckAuthenticationRequestHandler extends OpenIdMessageHandler
*/
$claimed_assoc = $this->current_request->getAssocHandle();
$stored_assoc = $this->association_service->getAssociation($claimed_assoc);
$claimed_realm = $this->current_request->getRealm();
$stored_assoc = $this->association_service->getAssociation($claimed_assoc, $claimed_realm);
if (is_null($stored_assoc) || $stored_assoc->getType() != IAssociation::TypePrivate)
throw new InvalidAssociationTypeException(OpenIdErrorMessages::InvalidAssociationTypeMessage);
$claimed_nonce = new OpenIdNonce($this->current_request->getNonce());
$claimed_realm = $this->current_request->getRealm();
$claimed_sig = $this->current_request->getSig();
$this->nonce_service->lockNonce($claimed_nonce);
$claimed_sig = $this->current_request->getSig();
$claimed_invalidate_handle = $this->current_request->getInvalidateHandle();
if (!is_null($claimed_invalidate_handle) && !empty($claimed_invalidate_handle)) {
@ -82,46 +93,42 @@ class OpenIdCheckAuthenticationRequestHandler extends OpenIdMessageHandler
$res = OpenIdSignatureBuilder::verify($this->current_request, $stored_assoc->getMacFunction(), $stored_assoc->getSecret(), $claimed_sig);
//delete association
$this->association_service->deleteAssociation($claimed_assoc);
$is_valid = 'false';
if ($res) {
//assertion is valid
$is_valid = 'true';
}
$is_valid = $res ? 'true':'false';
return new OpenIdCheckAuthenticationResponse($is_valid, $claimed_invalidate_handle);
} catch (InvalidAssociationTypeException $inv_assoc_ex) {
$this->checkpoint_service->trackException($inv_assoc_ex);
$this->log->warning($inv_assoc_ex);
$this->log_service->warning($inv_assoc_ex);
$response = new OpenIdDirectGenericErrorResponse($inv_assoc_ex->getMessage());
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return $response;
} catch (ReplayAttackException $replay_ex) {
$this->checkpoint_service->trackException($replay_ex);
$this->log->warning($replay_ex);
$this->log_service->warning($replay_ex);
$response = new OpenIdDirectGenericErrorResponse($replay_ex->getMessage());
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return $response;
} catch (InvalidNonce $inv_nonce_ex) {
$this->checkpoint_service->trackException($inv_nonce_ex);
$this->log->error($inv_nonce_ex);
$this->log_service->error($inv_nonce_ex);
$response = new OpenIdDirectGenericErrorResponse($inv_nonce_ex->getMessage());
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return $response;
} catch (InvalidOpenIdMessageException $inv_msg_ex) {
$this->checkpoint_service->trackException($inv_msg_ex);
$this->log->error($inv_msg_ex);
$this->log_service->error($inv_msg_ex);
$response = new OpenIdDirectGenericErrorResponse($inv_msg_ex->getMessage());
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return $response;
} catch (Exception $ex) {
$this->checkpoint_service->trackException($ex);
$this->log->error($ex);
$this->log_service->error($ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return new OpenIdDirectGenericErrorResponse("Server Error");
}
}
@ -131,6 +138,4 @@ class OpenIdCheckAuthenticationRequestHandler extends OpenIdMessageHandler
$res = OpenIdCheckAuthenticationRequest::IsOpenIdCheckAuthenticationRequest($message);
return $res;
}
}

View File

@ -1,21 +1,12 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: smarcet
* Date: 10/14/13
* Time: 5:41 PM
* To change this template use File | Settings | File Templates.
*/
namespace openid\handlers;
use openid\exceptions\InvalidOpenIdMessageException;
use openid\helpers\OpenIdErrorMessages;
use openid\OpenIdMessage;
use openid\services\OpenIdServiceCatalog;
use utils\services\ILogService;
use utils\services\Registry;
use utils\services\UtilsServiceCatalog;
use utils\services\ICheckPointService;
/**
* Class OpenIdMessageHandler
@ -28,14 +19,14 @@ abstract class OpenIdMessageHandler
protected $successor;
protected $current_request;
protected $log;
protected $log_service;
protected $checkpoint_service;
public function __construct($successor, ILogService $log)
public function __construct($successor, ILogService $log_service, ICheckPointService $checkpoint_service)
{
$this->successor = $successor;
$this->log = $log;
$this->checkpoint_service = Registry::getInstance()->get(UtilsServiceCatalog::CheckPointService);
$this->log_service = $log_service;
$this->checkpoint_service = $checkpoint_service;
}
/**
@ -53,8 +44,8 @@ abstract class OpenIdMessageHandler
} else if (isset($this->successor) && !is_null($this->successor)) {
return $this->successor->HandleMessage($message);
}
$this->log->warning_msg(sprintf(OpenIdErrorMessages::UnhandledMessage, $message->toString()));
$ex = new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::UnhandledMessage, $message->toString()));
$this->log_service->warning_msg(sprintf(OpenIdErrorMessages::UnhandledMessage, $message->toString()));
$ex = new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::UnhandledMessage, $message->toString()));
$this->checkpoint_service->trackException($ex);
throw $ex;
}

View File

@ -1,11 +1,4 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: smarcet
* Date: 10/14/13
* Time: 5:43 PM
* To change this template use File | Settings | File Templates.
*/
namespace openid\handlers;
@ -20,7 +13,7 @@ use openid\requests\OpenIdAssociationSessionRequest;
use openid\responses\OpenIdAssociationSessionUnsuccessfulResponse;
use openid\responses\OpenIdDirectGenericErrorResponse;
use utils\services\ILogService;
use utils\services\ICheckPointService;
/**
* Class OpenIdSessionAssociationRequestHandler
* Implements http://openid.net/specs/openid-authentication-2_0.html#associations
@ -29,9 +22,9 @@ use utils\services\ILogService;
class OpenIdSessionAssociationRequestHandler extends OpenIdMessageHandler
{
public function __construct(ILogService $log, $successor)
public function __construct(ILogService $log,ICheckPointService $checkpoint_service, $successor)
{
parent::__construct($successor, $log);
parent::__construct($successor, $log,$checkpoint_service);
}
protected function internalHandle(OpenIdMessage $message)
@ -49,30 +42,30 @@ class OpenIdSessionAssociationRequestHandler extends OpenIdMessageHandler
} catch (InvalidSessionTypeException $inv_session_ex) {
$this->checkpoint_service->trackException($inv_session_ex);
$response = new OpenIdAssociationSessionUnsuccessfulResponse($inv_session_ex->getMessage());
$this->log->error($inv_session_ex);
$this->log_service->error($inv_session_ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return $response;
} catch (InvalidAssociationTypeException $inv_assoc_ex) {
$this->checkpoint_service->trackException($inv_assoc_ex);
$response = new OpenIdAssociationSessionUnsuccessfulResponse($inv_assoc_ex->getMessage());
$this->log->error($inv_assoc_ex);
$this->log_service->error($inv_assoc_ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return $response;
} catch (InvalidOpenIdMessageException $inv_msg_ex) {
$response = new OpenIdDirectGenericErrorResponse($inv_msg_ex->getMessage());
$this->checkpoint_service->trackException($inv_msg_ex);
$this->log->error($inv_msg_ex);
$this->log_service->error($inv_msg_ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return $response;
} catch (Exception $ex) {
$this->checkpoint_service->trackException($ex);
$response = new OpenIdDirectGenericErrorResponse('Server Error');
$this->log->error($ex);
$this->log_service->error($ex);
if(!is_null($this->current_request))
$this->log->error_msg("current request: ".$this->current_request->toString());
$this->log_service->error_msg("current request: ".$this->current_request->toString());
return $response;
}
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: smarcet
* Date: 10/28/13
* Time: 6:17 PM
*/
namespace openid\handlers\factories;
@ -20,9 +14,9 @@ class SessionAssociationRequestFactory
public static function buildRequest(OpenIdMessage $message)
{
if (OpenIdDHAssociationSessionRequest::IsOpenIdAssociationSessionRequest($message))
if (OpenIdDHAssociationSessionRequest::IsOpenIdDHAssociationSessionRequest($message))
return new OpenIdDHAssociationSessionRequest($message);
return OpenIdAssociationSessionRequest($message);
return new OpenIdAssociationSessionRequest($message);
}
/**
@ -31,7 +25,7 @@ class SessionAssociationRequestFactory
*/
public static function buildSessionAssociationStrategy(OpenIdMessage $message)
{
if (OpenIdDHAssociationSessionRequest::IsOpenIdAssociationSessionRequest($message))
if (OpenIdDHAssociationSessionRequest::IsOpenIdDHAssociationSessionRequest($message))
return new SessionAssociationDHStrategy(new OpenIdDHAssociationSessionRequest($message));
if (OpenIdAssociationSessionRequest::IsOpenIdAssociationSessionRequest($message))
return new SessionAssociationUnencryptedStrategy(new OpenIdAssociationSessionRequest($message));

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: smarcet
* Date: 10/28/13
* Time: 6:23 PM
*/
namespace openid\handlers\strategies\implementations;
@ -78,7 +72,6 @@ class SessionAssociationDHStrategy implements ISessionAssociationStrategy
} catch (RuntimeException $exDH2) {
$response = new OpenIdDirectGenericErrorResponse($exDH2->getMessage());
$this->log->error($exDH2);
}
return $response;
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: smarcet
* Date: 10/28/13
* Time: 6:57 PM
*/
namespace openid\handlers\strategies\implementations;
@ -28,14 +22,14 @@ class SessionAssociationUnencryptedStrategy implements ISessionAssociationStrate
private $association_service;
private $server_configuration_service;
private $current_request;
private $log;
private $log_service;
public function __construct(OpenIdAssociationSessionRequest $request)
{
$this->current_request = $request;
$this->association_service = Registry::getInstance()->get(OpenIdServiceCatalog::AssociationService);
$this->server_configuration_service = Registry::getInstance()->get(OpenIdServiceCatalog:: ServerConfigurationService);
$this->log = Registry::getInstance()->get(UtilsServiceCatalog:: LogService);
$this->current_request = $request;
$this->association_service = Registry::getInstance()->get(OpenIdServiceCatalog::AssociationService);
$this->server_configuration_service = Registry::getInstance()->get(OpenIdServiceCatalog:: ServerConfigurationService);
$this->log_service = Registry::getInstance()->get(UtilsServiceCatalog:: LogService);
}
/**
@ -52,22 +46,22 @@ class SessionAssociationUnencryptedStrategy implements ISessionAssociationStrate
$assoc_handle = AssocHandleGenerator::generate();
$expires_in = $this->server_configuration_service->getSessionAssociationLifetime();
$expires_in = $this->server_configuration_service->getConfigValue("Session.Association.Lifetime");
$response = new OpenIdUnencryptedAssociationSessionResponse($assoc_handle, $session_type, $assoc_type, $expires_in, $HMAC_secret_handle);
$issued = gmdate("Y-m-d H:i:s", time());
$this->association_service->addAssociation($assoc_handle, $HMAC_secret_handle, $assoc_type, $expires_in, $issued, IAssociation::TypeSession, null);
} catch (InvalidDHParam $exDH) {
$response = new OpenIdDirectGenericErrorResponse($exDH->getMessage());
$this->log->error($exDH);
$this->log_service->error($exDH);
} catch (InvalidArgumentException $exDH1) {
$response = new OpenIdDirectGenericErrorResponse($exDH1->getMessage());
$this->log->error($exDH1);
$this->log_service->error($exDH1);
} catch (RuntimeException $exDH2) {
$response = new OpenIdDirectGenericErrorResponse($exDH2->getMessage());
$this->log->error($exDH2);
$this->log_service->error($exDH2);
}
return $response;
}

View File

@ -14,7 +14,7 @@ use Zend\Math\Rand;
class AssocHandleGenerator
{
const PrintableNonWhitespaceCharacters = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
const PrintableNonWhitespaceCharacters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_~';
/**
* @param int $len

View File

@ -59,7 +59,7 @@ class OpenIdCryptoHelper
} else if ($func == OpenIdProtocol::SignatureAlgorithmHMAC_SHA256) {
$macLen = 32; /* 256 bit */
} else {
return false;
$macLen = 20;/* 160 bit */
}
$bytes = self::randomBytes($macLen);
return $bytes;

View File

@ -35,4 +35,5 @@ class OpenIdErrorMessages
const InvalidMacFunctionMessage = "Invalid mac function %s";
const InvalidPrivateAssociationMessage = "Private Association %s was not emit for requested realm %s";
const AlreadyExistSessionMessage = "There is a current session with identity %s, but user wants to use a different identity %s";
const OAuth2MissingRequiredParam = 'OAuth2 OpenId Extension: missing required field %s';
}

View File

@ -29,6 +29,7 @@ class OpenIdSignatureBuilder
$res = false;
$signed = $request->getSigned();
$claimed_signed = explode(',', $signed);
ksort($claimed_signed);
$data = '';
foreach ($claimed_signed as $key) {
$key_php = str_ireplace('.', '_', $key);

View File

@ -34,4 +34,6 @@ interface IAssociation
public function IsExpired();
public function getRemainingLifetime();
}

View File

@ -34,21 +34,21 @@ class OpenIdAuthenticationRequest extends OpenIdRequest
public function isValid()
{
try{
$return_to = $this->getReturnTo();
$claimed_id = $this->getClaimedId();
$identity = $this->getIdentity();
$mode = $this->getMode();
$realm = $this->getRealm();
$valid_realm = OpenIdUriHelper::checkRealm($realm, $return_to);
$valid_id = $this->isValidIdentifier($claimed_id, $identity);
$return_to = $this->getReturnTo();
$claimed_id = $this->getClaimedId();
$identity = $this->getIdentity();
$mode = $this->getMode();
$realm = $this->getRealm();
$valid_realm = OpenIdUriHelper::checkRealm($realm, $return_to);
$valid_id = $this->isValidIdentifier($claimed_id, $identity);
return !empty($return_to)
&& !empty($realm)
&& $valid_realm
&& !empty($claimed_id)
&& !empty($identity)
&& $valid_id
&& !empty($mode) && ($mode == OpenIdProtocol::ImmediateMode || $mode == OpenIdProtocol::SetupMode);
return !empty($return_to)
&& !empty($realm)
&& $valid_realm
&& !empty($claimed_id)
&& !empty($identity)
&& $valid_id
&& !empty($mode) && ($mode == OpenIdProtocol::ImmediateMode || $mode == OpenIdProtocol::SetupMode);
}
catch(Exception $ex){
$log = Registry::getInstance()->get(UtilsServiceCatalog::LogService);

View File

@ -24,14 +24,16 @@ class OpenIdCheckAuthenticationRequest extends OpenIdAuthenticationRequest
public function isValid()
{
$mode = $this->getMode();
$claimed_assoc = $this->getAssocHandle();
$claimed_nonce = $this->getNonce();
$claimed_sig = $this->getSig();
$mode = $this->getMode();
$claimed_assoc = $this->getAssocHandle();
$claimed_nonce = $this->getNonce();
$claimed_sig = $this->getSig();
$claimed_op_endpoint = $this->getOPEndpoint();
$claimed_identity = $this->getClaimedId();
$claimed_realm = $this->getRealm();
$claimed_returnTo = $this->getReturnTo();
$claimed_identity = $this->getClaimedId();
$claimed_realm = $this->getRealm();
$claimed_returnTo = $this->getReturnTo();
$signed = $this->getSigned();
$server_configuration_service = Registry::getInstance()->get("openid\\services\\IServerConfigurationService");
if (
!is_null($mode) && !empty($mode) && $mode == OpenIdProtocol::CheckAuthenticationMode
@ -39,6 +41,7 @@ class OpenIdCheckAuthenticationRequest extends OpenIdAuthenticationRequest
&& !is_null($claimed_realm) && !empty($claimed_realm) && OpenIdUriHelper::checkRealm($claimed_realm, $claimed_returnTo)
&& !is_null($claimed_assoc) && !empty($claimed_assoc)
&& !is_null($claimed_sig) && !empty($claimed_sig)
&& !is_null($signed) && !empty($signed)
&& !is_null($claimed_nonce) && !empty($claimed_nonce)
&& !is_null($claimed_op_endpoint) && !empty($claimed_op_endpoint) && $server_configuration_service->getOPEndpointURL() == $claimed_op_endpoint
&& !is_null($claimed_identity) && !empty($claimed_identity) && OpenIdUriHelper::isValidUrl($claimed_identity)

View File

@ -36,7 +36,7 @@ class OpenIdDHAssociationSessionRequest extends OpenIdAssociationSessionRequest
public static function IsOpenIdDHAssociationSessionRequest(OpenIdMessage $message)
{
if (OpenIdAssociationSessionRequest::IsOpenIdAssociationSessionRequest($message)) {
$session_type = $message->getParam(OpenIdProtocol::OpenIDProtocol_AssocType);
$session_type = $message->getParam(OpenIdProtocol::OpenIDProtocol_SessionType);
if ($session_type == OpenIdProtocol::AssociationSessionTypeDHSHA1 || $session_type == OpenIdProtocol::AssociationSessionTypeDHSHA256)
return true;
}

View File

@ -23,6 +23,6 @@ class OpenIdUnencryptedAssociationSessionResponse extends OpenIdAssociationSessi
public function __construct($assoc_handle, $session_type, $assoc_type, $expires_in, $secret)
{
parent::__construct($assoc_handle, $session_type, $assoc_type, $expires_in);
$this[OpenIdProtocol::OpenIdProtocol_MacKey] = base64_decode($secret);
$this[OpenIdProtocol::OpenIdProtocol_MacKey] = base64_encode($secret);
}
}

View File

@ -4,9 +4,14 @@ namespace openid\services;
use openid\model\IAssociation;
/**
* Interface IAssociationService
* @package openid\services
*/
interface IAssociationService
{
/**
/** gets a given association by handle, and if association exists and its type is private, then lock it
* to prevent subsequent usage ( private association could be used once)
* @param $handle
* @param null $realm
* @return null|IAssociation
@ -22,8 +27,9 @@ interface IAssociationService
* @param $lifetime
* @param $issued
* @param $type
* @param $realm
* @return mixed
* @param null $realm
* @return IAssociation
* @throws \openid\exceptions\ReplayAttackException
*/
public function addAssociation($handle, $secret, $mac_function, $lifetime, $issued, $type, $realm);

View File

@ -31,6 +31,8 @@ interface IAuthService
public function setUserAuthorizationResponse($auth_response);
public function clearUserAuthorizationResponse();
public function logout();
public function getUserByOpenId($openid);

View File

@ -0,0 +1,89 @@
<?php
namespace utils\services;
/**
* Interface ICacheService
* @package utils\services
*/
interface ICacheService {
/**
* Determine if a key exists
* @param $key
* @return bool
*/
public function exists($key);
/**
* Delete a key
* @param $key
* @return mixed
*/
public function delete($key);
/**
* Delete a key
* @param array $keys
* @return mixed
*/
public function deleteArray(array $keys);
/**
* retrieves a hash
* @param $name
* @param array $values
* @return array
*/
public function getHash($name,array $values);
/**
* save a hash, with an optional time to live
* @param $name
* @param array $values
* @param int $ttl
* @return mixed
*/
public function storeHash($name,array $values, $ttl=0);
/**
* @param $counter_name
* @param int $ttl
* @return mixed
*/
public function incCounter($counter_name, $ttl=0);
/**
* @param $counter_name
* @return mixed
*/
public function incCounterIfExists($counter_name);
public function addMemberSet($set_name,$member);
public function deleteMemberSet($set_name,$member);
public function getSet($set_name);
public function getSingleValue($key);
public function setSingleValue($key, $value, $ttl=0);
/**
* adds a single value if given keys does not exists, with an optional
* time to live
* @param $key
* @param $value
* @param int $ttl
* @return mixed
*/
public function addSingleValue($key, $value, $ttl = 0);
/**
* Set time to live to a given key
* @param $key
* @param $ttl
* @return mixed
*/
public function setKeyExpiration($key, $ttl);
}

View File

@ -9,4 +9,5 @@ class UtilsServiceCatalog {
const AuthenticationService = 'utils\\services\\IAuthService';
const LockManagerService = 'utils\\services\\ILockManagerService';
const ServerConfigurationService = 'utils\\services\\IServerConfigurationService';
const CacheService = 'utils\\services\\ICacheService';
}

View File

@ -7,6 +7,6 @@ class UserAction extends Eloquent
public function user()
{
return $this->belongsTo("OpenIdUser");
return $this->belongsTo("User");
}
}

View File

@ -2,6 +2,8 @@
class AccessToken extends Eloquent {
protected $fillable = array('value', 'from_ip', 'associated_authorization_code','lifetime','scope','audience','created_at','updated_at','client_id','refresh_token_id');
protected $table = 'oauth2_access_token';
public function refresh_token()

View File

@ -29,7 +29,7 @@ class Client extends Eloquent implements IClient {
public function user()
{
return $this->belongsTo('auth\OpenIdUser');
return $this->belongsTo('auth\User');
}
public function resource_server()
@ -134,7 +134,10 @@ class Client extends Eloquent implements IClient {
public function getApplicationLogo()
{
return $this->app_logo;
$app_logo = $this->app_logo;
if(is_null($app_logo) || empty($app_logo))
$app_logo = asset('img/oauth2.default.logo.png');
return $app_logo;
}
public function getApplicationDescription()

View File

@ -4,6 +4,8 @@ class RefreshToken extends Eloquent {
protected $table = 'oauth2_refresh_token';
protected $fillable = array('value', 'from_ip', 'lifetime','scope','audience','void','created_at','updated_at','client_id');
public function access_tokens()
{
return $this->hasMany('AccessToken');

View File

@ -72,4 +72,16 @@ class OpenIdAssociation extends Eloquent implements IAssociation
{
// TODO: Implement setRealm() method.
}
public function getRemainingLifetime()
{
$created_at = new DateTime($this->issued);
$created_at->add(new DateInterval('PT' . $this->lifetime . 'S'));
$now = new DateTime(gmdate("Y-m-d H:i:s", time()));
//check validity...
if ($now > $created_at)
return -1;
$seconds = abs($created_at->getTimestamp() - $now->getTimestamp());;
return $seconds;
}
}

View File

@ -25,7 +25,7 @@ class OpenIdTrustedSite extends Eloquent implements ITrustedSite
public function getData()
{
$res = $this->data;
$res = is_null($this->data)?'[]':$this->data;
return json_decode($res);
}
@ -36,7 +36,7 @@ class OpenIdTrustedSite extends Eloquent implements ITrustedSite
public function user()
{
return $this->belongsTo('auth\OpenIdUser');
return $this->belongsTo('auth\User');
}
public function getAuthorizationPolicy()

View File

@ -1,27 +1,35 @@
<?php
namespace services;
use BannedIP;
use DB;
use Log;
use utils\services\ICacheService;
use utils\services\ILockManagerService;
use utils\services\ISecurityPolicy;
use utils\services\ISecurityPolicyCounterMeasure;
use utils\services\IServerConfigurationService;
use utils\services\ILockManagerService;
use Log;
use BannedIP;
use DB;
abstract class AbstractBlacklistSecurityPolicy implements ISecurityPolicy {
abstract class AbstractBlacklistSecurityPolicy implements ISecurityPolicy
{
protected $server_configuration_service;
protected $redis;
protected $counter_measure;
protected $lock_manager_service;
protected $cache_service;
public function __construct(IServerConfigurationService $server_configuration_service, ILockManagerService $lock_manager_service)
public function __construct(IServerConfigurationService $server_configuration_service, ILockManagerService $lock_manager_service, ICacheService $cache_service)
{
$this->redis = \RedisLV4::connection();
$this->server_configuration_service = $server_configuration_service;
$this->lock_manager_service = $lock_manager_service;
$this->lock_manager_service = $lock_manager_service;
$this->cache_service = $cache_service;
}
public function setCounterMeasure(ISecurityPolicyCounterMeasure $counter_measure)
{
$this->counter_measure = $counter_measure;
}
/**
@ -33,23 +41,20 @@ abstract class AbstractBlacklistSecurityPolicy implements ISecurityPolicy {
{
try {
$remote_address = IPHelper::getUserIp();
//try to create on redis
$success = $this->redis->setnx($remote_address, $initial_hits);
if ($success) { // if we created the set expiration on redis
$this->redis->expire($remote_address, intval($this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.BannedIpLifeTimeSeconds")));
}
//try to create on cache
$this->cache_service->addSingleValue($remote_address, $initial_hits, intval($this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.BannedIpLifeTimeSeconds")));
Log::warning(sprintf("AbstractBlacklistSecurityPolicy: Banning ip %s by Exception %s", $remote_address, $exception_type));
//try to create on db
DB::transaction(function () use($remote_address,$exception_type,$initial_hits) {
DB::transaction(function () use ($remote_address, $exception_type, $initial_hits) {
$banned_ip = BannedIP::where("ip", "=", $remote_address)->first();
if (!$banned_ip) {
$banned_ip = new BannedIP();
$banned_ip = new BannedIP();
$banned_ip->ip = $remote_address;
}
$banned_ip->exception_type = $exception_type;
$banned_ip->hits = $initial_hits;
$banned_ip->hits = $initial_hits;
$banned_ip->Save();
});
@ -58,9 +63,4 @@ abstract class AbstractBlacklistSecurityPolicy implements ISecurityPolicy {
}
}
public function setCounterMeasure(ISecurityPolicyCounterMeasure $counter_measure)
{
$this->counter_measure = $counter_measure;
}
}

View File

@ -9,6 +9,7 @@ use Exception;
use Log;
use UserExceptionTrail;
use utils\exceptions\UnacquiredLockException;
use utils\services\ICacheService;
use utils\services\ILockManagerService;
use utils\services\IServerConfigurationService;
@ -22,9 +23,9 @@ class BlacklistSecurityPolicy extends AbstractBlacklistSecurityPolicy
private $exception_dictionary = array();
public function __construct(IServerConfigurationService $server_configuration_service, ILockManagerService $lock_manager_service)
public function __construct(IServerConfigurationService $server_configuration_service, ILockManagerService $lock_manager_service, ICacheService $cache_service)
{
parent::__construct($server_configuration_service, $lock_manager_service);
parent::__construct($server_configuration_service, $lock_manager_service, $cache_service);
// here we configure on which exceptions are we interested and the max occurrence attempts and initial delay on tar pit for
// offending IP address
$this->exception_dictionary = array(
@ -34,6 +35,7 @@ class BlacklistSecurityPolicy extends AbstractBlacklistSecurityPolicy
'openid\exceptions\OpenIdInvalidRealmException' => array('BlacklistSecurityPolicy.MaxOpenIdInvalidRealmExceptionAttempts','BlacklistSecurityPolicy.OpenIdInvalidRealmExceptionInitialDelay'),
'openid\exceptions\InvalidOpenIdMessageMode' => array('BlacklistSecurityPolicy.MaxInvalidOpenIdMessageModeAttempts','BlacklistSecurityPolicy.InvalidOpenIdMessageModeInitialDelay'),
'openid\exceptions\InvalidOpenIdAuthenticationRequestMode' => array('BlacklistSecurityPolicy.MaxInvalidOpenIdAuthenticationRequestModeAttempts','BlacklistSecurityPolicy.InvalidOpenIdAuthenticationRequestModeInitialDelay'),
'openid\exceptions\InvalidAssociation' => array('BlacklistSecurityPolicy.MaxInvalidAssociationAttempts','BlacklistSecurityPolicy.InvalidAssociationInitialDelay'),
'auth\exceptions\AuthenticationException' => array('BlacklistSecurityPolicy.MaxAuthenticationExceptionAttempts','BlacklistSecurityPolicy.AuthenticationExceptionInitialDelay'),
'oauth2\exceptions\ReplayAttackException' => array(null,'BlacklistSecurityPolicy.OAuth2.AuthCodeReplayAttackInitialDelay'),
'oauth2\exceptions\InvalidAuthorizationCodeException' => array('BlacklistSecurityPolicy.OAuth2.MaxInvalidAuthorizationCodeAttempts','BlacklistSecurityPolicy.OAuth2.InvalidAuthorizationCodeInitialDelay'),
@ -49,58 +51,44 @@ class BlacklistSecurityPolicy extends AbstractBlacklistSecurityPolicy
{
$res = true;
$remote_address = IPHelper::getUserIp();
try {
//check if banned ip is on redis ...
if ($this->redis->exists($remote_address)) {
$this->redis->incr($remote_address);
$res = false;
} else {
//check on db
$banned_ip = BannedIP::where("ip", "=", $remote_address)->first();
//if exists ?
if ($banned_ip) {
//set lock
$this->lock_manager_service->acquireLock("lock.ip." . $remote_address);
try {
$issued = $banned_ip->created_at;
$utc_now = gmdate("Y-m-d H:i:s", time());
$utc_now = DateTime::createFromFormat("Y-m-d H:i:s", $utc_now);
//get time lived on seconds
$time_lived_seconds = abs($utc_now->getTimestamp() - $issued->getTimestamp());
if ($time_lived_seconds >= intval($this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.BannedIpLifeTimeSeconds"))) {
//void banned ip
$banned_ip->delete();
} else {
$banned_ip->hits = $banned_ip->hits + 1;
$banned_ip->Save();
//add ip back to redis
$success = $this->redis->setnx($banned_ip->ip, $banned_ip->hits);
if ($success) {
//set remaining time to live
$this->redis->expire($remote_address, intval($this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.BannedIpLifeTimeSeconds") - $time_lived_seconds));
}
$res = false;
//release lock
}
} catch (Exception $ex) {
//release lock
Log::error($ex);
$res = false;
//check if banned ip is on cache ...
if ($this->cache_service->incCounterIfExists($remote_address)){
$this->counter_measure->trigger();
return false;
}
//check on db
if (!is_null($banned_ip = BannedIP::where("ip", "=", $remote_address)->first())) {
// banned ip exists on DB, set lock
$this->lock_manager_service->acquireLock("lock.ip." . $remote_address);
try {
//check lifetime
$issued = $banned_ip->created_at;
$utc_now = gmdate("Y-m-d H:i:s", time());
$utc_now = DateTime::createFromFormat("Y-m-d H:i:s", $utc_now);
//get time lived on seconds
$time_lived_seconds = abs($utc_now->getTimestamp() - $issued->getTimestamp());
if ($time_lived_seconds >= intval($this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.BannedIpLifeTimeSeconds"))) {
//void banned ip
$banned_ip->delete();
return true;
}
$this->lock_manager_service->releaseLock("lock.ip." . $remote_address);
$banned_ip->hits = $banned_ip->hits + 1;
$banned_ip->Save();
//save ip on cache
$this->cache_service->addSingleValue($banned_ip->ip, $banned_ip->hits,intval($this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.BannedIpLifeTimeSeconds") - $time_lived_seconds));
}
}
if (!$res)
catch (Exception $ex) {
Log::error($ex);
}
//release lock
$this->lock_manager_service->releaseLock("lock.ip." . $remote_address);
$this->counter_measure->trigger();
} catch (UnacquiredLockException $ex1) {
return false;
}
}
catch (UnacquiredLockException $ex1) {
Log::error($ex1);
$res = false;
} catch (Exception $ex) {

View File

@ -4,22 +4,24 @@ namespace services;
use Exception;
use Log;
use utils\services\ICacheService;
use utils\services\ISecurityPolicyCounterMeasure;
class DelayCounterMeasure implements \utils\services\ISecurityPolicyCounterMeasure
class DelayCounterMeasure implements ISecurityPolicyCounterMeasure
{
private $redis;
private $cache_service;
public function __construct(){
$this->redis = \RedisLV4::connection();
public function __construct(ICacheService $cache_service){
$this->cache_service = $cache_service;
}
public function trigger(array $params = array())
{
try {
$remote_address = IPHelper::getUserIp();
if ($this->redis->exists($remote_address)) {
if ($this->cache_service->exists($remote_address)) {
Log::warning(sprintf("DelayCounterMeasure: attempt from banned ip %s",$remote_address));
$hits = $this->redis->get($remote_address);
$hits = intval($this->cache_service->getSingleValue($remote_address));
sleep(2 ^ $hits);
}
} catch (Exception $ex) {

View File

@ -2,20 +2,21 @@
namespace services;
use utils\services\ICacheService;
use utils\services\ILockManagerService;
use utils\exceptions\UnacquiredLockException;
class LockManagerService implements ILockManagerService {
private $redis;
private $cache_service;
public function __construct(){
$this->redis = \RedisLV4::connection();
public function __construct(ICacheService $cache_service){
$this->cache_service = $cache_service;
}
public function acquireLock($name,$lifetime=3600)
{
$success = $this->redis->setnx($name , time()+$lifetime+1);
$success = $this->cache_service->addSingleValue($name,time()+$lifetime+1,time()+$lifetime+1);
if (!$success) { // only one time we could use this handle
throw new UnacquiredLockException(sprintf("lock name %s",$name));
}
@ -23,6 +24,6 @@ class LockManagerService implements ILockManagerService {
public function releaseLock($name)
{
$this->redis->del($name);
$this->cache_service->delete($name);
}
}

View File

@ -2,7 +2,7 @@
namespace services;
use auth\OpenIdUser;
use auth\User;
use Exception;
use Log;
use openid\services\OpenIdServiceCatalog;
@ -21,7 +21,7 @@ class LockUserCounterMeasure implements ISecurityPolicyCounterMeasure
$server_configuration = Registry::getInstance()->get(OpenIdServiceCatalog::ServerConfigurationService);
$user_service = Registry::getInstance()->get(OpenIdServiceCatalog::UserService);
$user = OpenIdUser::where('external_id', '=', $user_identifier)->first();
$user = User::where('external_id', '=', $user_identifier)->first();
if(is_null($user))
return;
//apply lock policy

View File

@ -0,0 +1,127 @@
<?php
namespace services;
use utils\services\ICacheService;
/**
* Class RedisCacheService
* Cache Service Implementation Based on REDIS
* http://redis.io
* @package services
*/
class RedisCacheService implements ICacheService {
//services
private $redis;
public function __construct(){
$this->redis = \RedisLV4::connection();
}
/**
* @param $key
* @return mixed
*/
public function delete($key)
{
$res = 0;
if ($this->redis->exists($key)) {
$res = $this->redis->del($key);
}
return $res;
}
public function deleteArray(array $keys){
if(count($keys)>0)
$this->redis->del($keys);
}
/**
* @param $key
* @return bool
*/
public function exists($key){
$res = $this->redis->exists($key);
return $res>0;
}
/**
* @param $name
* @param array $values
* @return mixed
*/
public function getHash($name, array $values)
{
$res = array();
if($this->redis->exists($name)){
$cache_values = $this->redis->hmget($name,$values);
for($i=0;$i<count($cache_values);$i++)
$res[$values[$i]] = $cache_values[$i];
}
return $res;
}
public function storeHash($name,array $values, $ttl=0){
$res = false;
//stores in REDIS
if(!$this->redis->exists($name)){
$this->redis->hmset($name, $values);
$res = true;
//sets expiration time
if($ttl>0) $this->redis->expire($name, $ttl);
}
return $res;
}
public function incCounter($counter_name, $ttl = 0)
{
if($this->redis->setnx($counter_name,1))
$this->redis->expire($counter_name, $ttl);
else
$this->redis->incr($counter_name);
}
public function incCounterIfExists($counter_name){
$res = false;
if ($this->redis->exists($counter_name)) {
$this->redis->incr($counter_name);
$res = true;
}
return $res;
}
public function addMemberSet($set_name, $member){
return $this->redis->sadd($set_name, $member);
}
public function deleteMemberSet($set_name,$member){
return $this->redis->srem($set_name,$member);
}
public function getSet($set_name){
return $this->redis->smembers($set_name);
}
public function getSingleValue($key){
return $this->redis->get($key);
}
public function setSingleValue($key,$value,$ttl = 0){
if($ttl>0)
return $this->redis->setex($key , $ttl, $value);
else
return $this->redis->set($key ,$value);
}
public function addSingleValue($key, $value, $ttl = 0){
$res = $this->redis->setnx($key , $value);
if($res>0 && $ttl>0)
$this->redis->expire($key,$ttl);
return $res;
}
public function setKeyExpiration($key, $ttl){
$this->redis->expire($key, intval($ttl));
}
}

View File

@ -5,6 +5,7 @@ namespace services;
use Exception;
use openid\services\IServerConfigurationService as IOpenIdServerConfigurationService;
use ServerConfiguration;
use utils\services\ICacheService;
use utils\services\IServerConfigurationService;
class ServerConfigurationService implements IOpenIdServerConfigurationService,IServerConfigurationService
@ -16,28 +17,15 @@ class ServerConfigurationService implements IOpenIdServerConfigurationService,IS
const DefaultMaxFailedLoginAttempts = 10;
const DefaultMaxFailedLoginAttempts2ShowCaptcha = 3;
const DefaultNonceLifetime = 360;
private $private_association_lifetime;
private $session_association_lifetime;
private $max_failed_login_attempts;
private $max_failed_login_attempts_2_show_captcha;
private $nonce_lifetime;
private $assets_url;
private $redis;
private $default_config_params;
public function __construct()
private $cache_service;
public function __construct(ICacheService $cache_service)
{
//todo: remove all specific methods per key and use getConfigValue
$this->private_association_lifetime = null;
$this->session_association_lifetime = null;
$this->max_failed_login_attempts = null;
$this->max_failed_login_attempts_2_show_captcha = null;
$this->nonce_lifetime = null;
$this->assets_url = null;
$this->redis = \RedisLV4::connection();
$this->cache_service = $cache_service;
//default config values
$this->default_config_params = array();
$this->default_config_params["Private.Association.Lifetime"] = 240;
@ -62,6 +50,8 @@ class ServerConfigurationService implements IOpenIdServerConfigurationService,IS
$this->default_config_params["BlacklistSecurityPolicy.InvalidOpenIdAuthenticationRequestModeInitialDelay"] = 10;
$this->default_config_params["BlacklistSecurityPolicy.MaxAuthenticationExceptionAttempts"] = 10;
$this->default_config_params["BlacklistSecurityPolicy.AuthenticationExceptionInitialDelay"] = 20;
$this->default_config_params["BlacklistSecurityPolicy.MaxInvalidAssociationAttempts"] = 10;
$this->default_config_params["BlacklistSecurityPolicy.InvalidAssociationInitialDelay"] = 20;
$this->default_config_params["BlacklistSecurityPolicy.OAuth2.MaxAuthCodeReplayAttackAttempts"] = 3;
@ -93,8 +83,8 @@ class ServerConfigurationService implements IOpenIdServerConfigurationService,IS
return $url;
}
/**
* get config value from redis and if not in redis check for it on table server_configuration
/**
* get config value from cache and if not in cache check for it on table server_configuration
* @param $key
* @return mixed
*/
@ -103,25 +93,24 @@ class ServerConfigurationService implements IOpenIdServerConfigurationService,IS
$res = null;
try {
if (!$this->redis->exists($key)) {
$conf = ServerConfiguration::where('key', '=', $key)->first();
if ($conf)
$this->redis->setnx($key, $conf->value);
if (!$this->cache_service->exists($key)) {
if (!is_null($conf = ServerConfiguration::where('key', '=', $key)->first()))
$this->cache_service->addSingleValue($key, $conf->value);
else
if (isset($this->default_config_params[$key]))
$this->redis->setnx($key, $this->default_config_params[$key]);
$this->cache_service->addSingleValue($key, $this->default_config_params[$key]);
else
return null;
}
$res = $this->redis->get($key);
$res = $this->cache_service->getSingleValue($key);
} catch (Exception $ex) {
Log::error($ex);
if (isset($this->default_config_params[$key])) {
$res = $this->default_config_params[$key];
}
}
return $res;
}

View File

@ -13,6 +13,19 @@ class ServicesProvider extends ServiceProvider
public function boot()
{
$this->app->singleton(UtilsServiceCatalog::CacheService, 'services\\RedisCacheService');
$this->app['serverconfigurationservice'] = $this->app->share(function ($app) {
return new ServerConfigurationService($this->app->make(UtilsServiceCatalog::CacheService));
});
// Shortcut so developers don't need to add an Alias in app/config/app.php
$this->app->booting(function () {
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('ServerConfigurationService', 'services\\Facades\\ServerConfigurationService');
});
//register on boot bc we rely on Illuminate\Redis\ServiceProvider\RedisServiceProvider
$this->app->singleton(OpenIdServiceCatalog::MementoService, 'services\\MementoRequestService');
$this->app->singleton(OpenIdServiceCatalog::AuthenticationStrategy, 'services\\AuthenticationStrategy');
@ -26,6 +39,7 @@ class ServicesProvider extends ServiceProvider
$this->app->singleton(UtilsServiceCatalog::LockManagerService, 'services\\LockManagerService');
$this->app->singleton(UtilsServiceCatalog::ServerConfigurationService, 'services\\ServerConfigurationService');
$this->app->singleton("services\\DelayCounterMeasure", 'services\\DelayCounterMeasure');
$this->app->singleton("services\\LockUserCounterMeasure", 'services\\LockUserCounterMeasure');
$this->app->singleton("services\\oauth2\\RevokeAuthorizationCodeRelatedTokens", 'services\\oauth2\\RevokeAuthorizationCodeRelatedTokens');
@ -63,6 +77,7 @@ class ServicesProvider extends ServiceProvider
return $checkpoint_service;
});
Registry::getInstance()->set(UtilsServiceCatalog::CheckPointService, $this->app->make(UtilsServiceCatalog::CheckPointService));
Registry::getInstance()->set(OpenIdServiceCatalog::MementoService, $this->app->make(OpenIdServiceCatalog::MementoService));
Registry::getInstance()->set(OpenIdServiceCatalog::AuthenticationStrategy, $this->app->make(OpenIdServiceCatalog::AuthenticationStrategy));
Registry::getInstance()->set(OpenIdServiceCatalog::ServerExtensionsService, $this->app->make(OpenIdServiceCatalog::ServerExtensionsService));
@ -75,6 +90,7 @@ class ServicesProvider extends ServiceProvider
Registry::getInstance()->set(UtilsServiceCatalog::LogService, $this->app->make(UtilsServiceCatalog::LogService));
Registry::getInstance()->set(UtilsServiceCatalog::CheckPointService, $this->app->make(UtilsServiceCatalog::CheckPointService));
Registry::getInstance()->set(UtilsServiceCatalog::ServerConfigurationService, $this->app->make(UtilsServiceCatalog::ServerConfigurationService));
Registry::getInstance()->set(UtilsServiceCatalog::CacheService, $this->app->make(UtilsServiceCatalog::CacheService));
$this->app->singleton(OAuth2ServiceCatalog::MementoService, 'services\\oauth2\\MementoOAuth2AuthenticationRequestService');
$this->app->singleton(OAuth2ServiceCatalog::ClientService, 'services\\oauth2\\ClientService');
@ -94,15 +110,7 @@ class ServicesProvider extends ServiceProvider
public function register()
{
$this->app['serverconfigurationservice'] = $this->app->share(function ($app) {
return new ServerConfigurationService();
});
// Shortcut so developers don't need to add an Alias in app/config/app.php
$this->app->booting(function () {
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('ServerConfigurationService', 'services\\Facades\\ServerConfigurationService');
});
}

View File

@ -2,7 +2,7 @@
namespace services;
use auth\OpenIdUser;
use auth\User;
use Exception;
use openid\model\IOpenIdUser;
use UserAction;
@ -17,7 +17,7 @@ class UserActionService implements IUserActionService
$action->from_ip = $ip;
$action->user_action = $user_action;
$action->realm = $realm;
$user = OpenIdUser::find($user->getId());
$user = User::find($user->getId());
if ($user) {
$user->actions()->save($action);
return true;

View File

@ -2,10 +2,11 @@
namespace services;
use auth\OpenIdUser;
use auth\User;
use Log;
use openid\services\IUserService;
use Exception;
use DB;
class UserService implements IUserService
{
@ -13,9 +14,9 @@ class UserService implements IUserService
public function associateUser($id, $proposed_username)
{
try {
$user = OpenIdUser::where('id', '=', $id)->first();
$user = User::where('id', '=', $id)->first();
if (!is_null($user)) {
\DB::transaction(function () use ($id, $proposed_username) {
DB::transaction(function () use ($id, $proposed_username) {
$done = false;
$fragment_nbr = 1;
$aux_proposed_username = $proposed_username;
@ -45,10 +46,10 @@ class UserService implements IUserService
public function updateLastLoginDate($identifier)
{
try {
$user = OpenIdUser::where('id', '=', $identifier)->first();
$user = User::where('id', '=', $identifier)->first();
if (!is_null($user)) {
\DB::transaction(function () use ($identifier) {
\DB::table('openid_users')->where('id', '=', $identifier)->update(array('last_login_date' => gmdate("Y-m-d H:i:s", time())));
DB::transaction(function () use ($identifier) {
DB::table('openid_users')->where('id', '=', $identifier)->update(array('last_login_date' => gmdate("Y-m-d H:i:s", time())));
});
}
} catch (Exception $ex) {
@ -59,12 +60,12 @@ class UserService implements IUserService
public function updateFailedLoginAttempts($identifier)
{
try {
$user = OpenIdUser::where('id', '=', $identifier)->first();
$user = User::where('id', '=', $identifier)->first();
if (!is_null($user)) {
$attempts = $user->login_failed_attempt;
++$attempts;
\DB::transaction(function () use ($identifier, $attempts) {
\DB::table('openid_users')->where('id', '=', $identifier)->update(array('login_failed_attempt' => $attempts));
DB::transaction(function () use ($identifier, $attempts) {
DB::table('openid_users')->where('id', '=', $identifier)->update(array('login_failed_attempt' => $attempts));
});
}
} catch (Exception $ex) {
@ -75,10 +76,10 @@ class UserService implements IUserService
public function lockUser($identifier)
{
try {
$user = OpenIdUser::where('id', '=', $identifier)->first();
$user = User::where('id', '=', $identifier)->first();
if (!is_null($user)) {
\DB::transaction(function () use ($identifier) {
\DB::table('openid_users')->where('id', '=', $identifier)->update(array('lock' => 1));
DB::transaction(function () use ($identifier) {
DB::table('openid_users')->where('id', '=', $identifier)->update(array('lock' => 1));
});
Log::warning(sprintf("User %d locked ", $identifier));
}
@ -89,10 +90,10 @@ class UserService implements IUserService
public function unlockUser($identifier)
{
$user = OpenIdUser::where('id', '=', $identifier)->first();
$user = User::where('id', '=', $identifier)->first();
if (!is_null($user)) {
\DB::transaction(function () use ($identifier) {
\DB::table('openid_users')->where('id', '=', $identifier)->update(array('lock' => 0));
DB::transaction(function () use ($identifier) {
DB::table('openid_users')->where('id', '=', $identifier)->update(array('lock' => 0));
});
}
}
@ -100,10 +101,10 @@ class UserService implements IUserService
public function activateUser($identifier)
{
try {
$user = OpenIdUser::where('id', '=', $identifier)->first();
$user = User::where('id', '=', $identifier)->first();
if (!is_null($user)) {
\DB::transaction(function () use ($identifier) {
\DB::table('openid_users')->where('id', '=', $identifier)->update(array('active' => 1));
DB::transaction(function () use ($identifier) {
DB::table('openid_users')->where('id', '=', $identifier)->update(array('active' => 1));
});
}
} catch (Exception $ex) {
@ -114,10 +115,10 @@ class UserService implements IUserService
public function deActivateUser($identifier)
{
try {
$user = OpenIdUser::where('id', '=', $identifier)->first();
$user = User::where('id', '=', $identifier)->first();
if (!is_null($user)) {
\DB::transaction(function () use ($identifier) {
\DB::table('openid_users')->where('id', '=', $identifier)->update(array('active' => 0));
DB::transaction(function () use ($identifier) {
DB::table('openid_users')->where('id', '=', $identifier)->update(array('active' => 0));
});
}
} catch (Exception $ex) {
@ -128,7 +129,7 @@ class UserService implements IUserService
public function saveProfileInfo($identifier, $show_pic, $show_full_name, $show_email)
{
try {
$user = OpenIdUser::where('id', '=', $identifier)->first();
$user = User::where('id', '=', $identifier)->first();
if (!is_null($user)) {
$user->public_profile_show_photo = $show_pic;
$user->public_profile_show_fullname = $show_full_name;

View File

@ -5,15 +5,16 @@ namespace services\oauth2;
use Exception;
use DB;
use Log;
use utils\services\ICacheService;
use utils\services\IServerConfigurationService;
use services\AbstractBlacklistSecurityPolicy;
use utils\services\ILockManagerService;
class AuthorizationCodeRedeemPolicy extends AbstractBlacklistSecurityPolicy {
public function __construct(IServerConfigurationService $server_configuration_service, ILockManagerService $lock_manager_service)
public function __construct(IServerConfigurationService $server_configuration_service, ILockManagerService $lock_manager_service, ICacheService $cache_service)
{
parent::__construct($server_configuration_service,$lock_manager_service);
parent::__construct($server_configuration_service,$lock_manager_service,$cache_service);
}
/**

View File

@ -18,7 +18,7 @@ class MementoOAuth2AuthenticationRequestService implements IMementoOAuth2Authent
*/
public function saveCurrentAuthorizationRequest()
{
$input = Input::all();
$input = Input::all();
$oauth2_params = array();
foreach ($input as $key => $value) {
if (array_key_exists($key, OAuth2AuthorizationRequest::$params) === true) {
@ -72,7 +72,21 @@ class MementoOAuth2AuthenticationRequestService implements IMementoOAuth2Authent
public function clearCurrentRequest()
{
// TODO: Implement clearCurrentRequest() method.
$old_data = Input::old();
$oauth2_params = array();
foreach ($old_data as $key => $value) {
if (array_key_exists($key, OAuth2AuthorizationRequest::$params) === true){
array_push($oauth2_params, $key);
}
}
if (count($oauth2_params) > 0) {
foreach ($oauth2_params as $oauth2_param) {
Session::forget($oauth2_param);
Session::remove($oauth2_param);
}
}
}

View File

@ -29,13 +29,13 @@ use Zend\Crypt\Hash;
use DateInterval;
use DateTime;
use utils\services\ICacheService;
/**
* Class TokenService
* Provides all Tokens related operations (create, get and revoke)
* @package services\oauth2
*/
class TokenService implements ITokenService
{
const ClientAccessTokenPrefixList = '.atokens';
@ -50,19 +50,19 @@ class TokenService implements ITokenService
const ClientRefreshTokensQty = '.rtokens.qty';
const ClientRefreshTokensQtyLifetime = 86400;
//services
private $redis;
private $client_service;
private $lock_manager_service;
private $configuration_service;
private $cache_service;
public function __construct(IClientService $client_service, ILockManagerService $lock_manager_service, IServerConfigurationService $configuration_service)
public function __construct(IClientService $client_service, ILockManagerService $lock_manager_service, IServerConfigurationService $configuration_service, ICacheService $cache_service)
{
$this->redis = \RedisLV4::connection();
$this->client_service = $client_service;
$this->lock_manager_service = $lock_manager_service;
$this->configuration_service = $configuration_service;
$this->cache_service = $cache_service;
}
/**
@ -76,34 +76,25 @@ class TokenService implements ITokenService
public function createAuthorizationCode($client_id, $scope, $audience = '', $redirect_uri = null)
{
//create model
$code = AuthorizationCode::create($client_id, $scope, $audience, $redirect_uri, $this->configuration_service->getConfigValue('OAuth2.AuthorizationCode.Lifetime'));
$value = $code->getValue();
$code = AuthorizationCode::create($client_id, $scope, $audience, $redirect_uri, $this->configuration_service->getConfigValue('OAuth2.AuthorizationCode.Lifetime'));
$value = $code->getValue();
$hashed_value = Hash::compute('sha256', $value);
//stores in REDIS
$this->redis->hmset($hashed_value, array(
'value' => $hashed_value,
//stores on cache
$this->cache_service->storeHash($hashed_value,
array(
'client_id' => $code->getClientId(),
'scope' => $code->getScope(),
'audience' => $code->getAudience(),
'redirect_uri' => $code->getRedirectUri(),
'issued' => $code->getIssued(),
'lifetime' => $code->getLifetime(),
'audience' => $code->getAudience()
));
//sets expiration time
$this->redis->expire($hashed_value, $code->getLifetime());
'from_ip' => $code->getFromIp()
), $code->getLifetime());
//stores brand new auth code hash value on a set by client id...
$this->redis->sadd($client_id . self::ClientAuthCodePrefixList, $hashed_value);
if($this->redis->setnx($client_id . self::ClientAuthCodeQty,1)){
$this->redis->expire($client_id . self::ClientAuthCodeQty, self::ClientAuthCodeQtyLifetime);
}
else{
$this->redis->incr($client_id . self::ClientAuthCodeQty);
}
$this->cache_service->addMemberSet($client_id . self::ClientAuthCodePrefixList, $hashed_value);
$this->cache_service->incCounter($client_id . self::ClientAuthCodeQty,self::ClientAuthCodeQtyLifetime);
return $code;
}
@ -118,24 +109,23 @@ class TokenService implements ITokenService
$hashed_value = Hash::compute('sha256', $value);
if (!$this->redis->exists($hashed_value))
if (!$this->cache_service->exists($hashed_value))
throw new InvalidAuthorizationCodeException(sprintf("auth_code %s ", $value));
try {
$this->lock_manager_service->acquireLock('lock.get.authcode.' . $hashed_value);
$values = $this->redis->hmget($hashed_value, array(
'value',
'client_id',
'scope',
'redirect_uri',
'issued',
'lifetime',
'audience'
));
$cache_values = $this->cache_service->getHash($hashed_value, array('client_id','scope','audience','redirect_uri','issued','lifetime','from_ip'));
$code = AuthorizationCode::load($value,
$cache_values['client_id'],
$cache_values['scope'],
$cache_values['audience'],
$cache_values['redirect_uri'],
$cache_values['issued'],
$cache_values['lifetime'],
$cache_values['from_ip']);
$code = AuthorizationCode::load($values[0], $values[1], $values[2], $values[6], $values[3], $values[4], $values[5]);
return $code;
} catch (UnacquiredLockException $ex1) {
throw new ReplayAttackException($value, sprintf("auth_code %s ", $value));
@ -153,22 +143,23 @@ class TokenService implements ITokenService
$access_token = AccessToken::create($auth_code, $this->configuration_service->getConfigValue('OAuth2.AccessToken.Lifetime'));
DB::transaction(function () use ($auth_code, $redirect_uri, &$access_token) {
$value = $access_token->getValue();
$hashed_value = Hash::compute('sha256', $value);
$client_id = $access_token->getClientId();
$client = $this->client_service->getClientById($client_id);
$client_id = $access_token->getClientId();
$client = $this->client_service->getClientById($client_id);
$access_token_db = new DBAccessToken (
array(
'value' => $hashed_value,
'from_ip' => IPHelper::getUserIp(),
'associated_authorization_code' => Hash::compute('sha256', $access_token->getAuthCode()),
'associated_authorization_code' => Hash::compute('sha256', $auth_code->getValue()),
'lifetime' => $access_token->getLifetime(),
'scope' => $access_token->getScope(),
'audience' => $access_token->getAudience()
)
);
$access_token_db->client()->associate($client);
$access_token_db->save();
//check if use refresh tokens...
@ -176,20 +167,13 @@ class TokenService implements ITokenService
$this->createRefreshToken($access_token);
}
$this->storesAccessTokenOnRedis($access_token);
$this->storesAccessTokenOnCache($access_token);
//stores brand new access token hash value on a set by client id...
$this->redis->sadd($client_id . self::ClientAccessTokenPrefixList, $hashed_value);
if($this->redis->setnx($client_id . self::ClientAccessTokensQty,1)){
$this->redis->expire($client_id . self::ClientAccessTokensQty, self::ClientAccessTokensQtyLifetime);
}
else{
$this->redis->incr($client_id . self::ClientAccessTokensQty);
}
$this->cache_service->addMemberSet($client_id . self::ClientAccessTokenPrefixList, $hashed_value);
$this->cache_service->incCounter($client_id . self::ClientAccessTokensQty,self::ClientAccessTokensQtyLifetime);
});
return $access_token;
}
@ -199,7 +183,7 @@ class TokenService implements ITokenService
$value = $access_token->getValue();
$hashed_value = Hash::compute('sha256', $value);
$this->storesAccessTokenOnRedis($access_token);
$this->storesAccessTokenOnCache($access_token);
$client_id = $access_token->getClientId();
$client = $this->client_service->getClientById($client_id);
@ -218,17 +202,10 @@ class TokenService implements ITokenService
$access_token_db->client()->associate($client);
$access_token_db->Save();
//stores brand new access token hash value on a set by client id...
$this->redis->sadd($client_id . self::ClientAccessTokenPrefixList, $hashed_value);
$this->cache_service->addMemberSet($client_id . self::ClientAccessTokenPrefixList, $hashed_value);
if($this->redis->setnx($client_id . self::ClientAccessTokensQty,1)){
$this->redis->expire($client_id . self::ClientAccessTokensQty, self::ClientAccessTokensQtyLifetime);
}
else{
$this->redis->incr($client_id . self::ClientAccessTokensQty);
}
$this->cache_service->incCounter($client_id . self::ClientAccessTokensQty,self::ClientAccessTokensQtyLifetime);
return $access_token;
}
@ -270,7 +247,7 @@ class TokenService implements ITokenService
$value = $access_token->getValue();
$hashed_value = Hash::compute('sha256', $value);
$this->storesAccessTokenOnRedis($access_token);
$this->storesAccessTokenOnCache($access_token);
//get current client
$client_id = $access_token->getClientId();
@ -294,14 +271,9 @@ class TokenService implements ITokenService
$access_token_db->Save();
//stores brand new access token hash value on a set by client id...
$this->redis->sadd($client_id . self::ClientAccessTokenPrefixList, $hashed_value);
$this->cache_service->addMemberSet($client_id . self::ClientAccessTokenPrefixList, $hashed_value);
if($this->redis->setnx($client_id . self::ClientAccessTokensQty,1)){
$this->redis->expire($client_id . self::ClientAccessTokensQty, self::ClientAccessTokensQtyLifetime);
}
else{
$this->redis->incr($client_id . self::ClientAccessTokensQty);
}
$this->cache_service->incCounter($client_id . self::ClientAccessTokensQty,self::ClientAccessTokensQtyLifetime);
});
return $access_token;
}
@ -310,51 +282,49 @@ class TokenService implements ITokenService
* @param AccessToken $access_token
* @throws \oauth2\exceptions\InvalidAccessTokenException
*/
private function storesAccessTokenOnRedis(AccessToken $access_token)
private function storesAccessTokenOnCache(AccessToken $access_token)
{
//stores in REDIS
$value = $access_token->getValue();
$value = $access_token->getValue();
$hashed_value = Hash::compute('sha256', $value);
if ($this->redis->exists($hashed_value))
if ($this->cache_service->exists($hashed_value))
throw new InvalidAccessTokenException;
$auth_code = !is_null($access_token->getAuthCode()) ? Hash::compute('sha256', $access_token->getAuthCode()):'';
$refresh_token_value = !is_null($access_token->getRefreshToken()) ? Hash::compute('sha256', $access_token->getRefreshToken()->getValue()):'';
$this->redis->hmset($hashed_value, array(
'value' => $hashed_value,
$this->cache_service->storeHash($hashed_value, array(
'client_id' => $access_token->getClientId(),
'scope' => $access_token->getScope(),
'auth_code' => Hash::compute('sha256', $access_token->getAuthCode()),
'auth_code' => $auth_code,
'issued' => $access_token->getIssued(),
'lifetime' => $access_token->getLifetime(),
'audience' => $access_token->getAudience(),
'from_ip' => IPHelper::getUserIp(),
'refresh_token' => $refresh_token_value
'refresh_token' => $refresh_token_value,
$access_token->getLifetime()
));
$this->redis->expire($hashed_value, $access_token->getLifetime());
}
/**
* @param DBAccessToken $access_token
* @throws \oauth2\exceptions\InvalidAccessTokenException
*/
private function storesDBAccessTokenOnRedis(DBAccessToken $access_token)
private function storesDBAccessTokenOnCache(DBAccessToken $access_token)
{
//stores in REDIS
//stores in Cache
if ($this->redis->exists($access_token->value))
if ($this->cache_service->exists($access_token->value))
throw new InvalidAccessTokenException;
$refresh_token_value = '';
$refresh_token_db = $access_token->refresh_token()->first();
$refresh_token_db = $access_token->refresh_token()->first();
if(!is_null($refresh_token_db))
$refresh_token_value = $refresh_token_db->value;
$this->redis->hmset($access_token->value, array(
'value' => $access_token->value,
$this->cache_service->storeHash($access_token->value, array(
'client_id' => $access_token->client_id,
'scope' => $access_token->scope,
'auth_code' => $access_token->associated_authorization_code,
@ -363,9 +333,9 @@ class TokenService implements ITokenService
'from_ip' => $access_token->from_ip,
'audience' => $access_token->audience,
'refresh_token' => $refresh_token_value
));
)
,$access_token->lifetime);
$this->redis->expire($access_token->value, $access_token->lifetime);
}
/**
@ -380,7 +350,7 @@ class TokenService implements ITokenService
$hashed_value = Hash::compute('sha256', $value);
try {
if (!$this->redis->exists($hashed_value)) {
if (!$this->cache_service->exists($hashed_value)) {
//check on DB...
$access_token_db = DBAccessToken::where('value', '=', $hashed_value)->first();
if (is_null($access_token_db))
@ -399,14 +369,13 @@ class TokenService implements ITokenService
$access_token_db->delete();
throw new InvalidGrantTypeException(sprintf('Access token %s is expired!', $value));
}
//reload on redis
$this->storesDBAccessTokenOnRedis($access_token_db);
//reload on cache
$this->storesDBAccessTokenOnCache($access_token_db);
//release lock
$this->lock_manager_service->releaseLock($lock_name);
}
$values = $this->redis->hmget($hashed_value, array(
'value',
$cache_values = $this->cache_service->getHash($hashed_value, array(
'client_id',
'scope',
'auth_code',
@ -417,9 +386,21 @@ class TokenService implements ITokenService
'refresh_token'
));
$code = AuthorizationCode::load($values[3], $values[1], $values[2], $values[7]);
$access_token = AccessToken::load($values[0], $code, $values[4], $values[5], $values[6], $values[7]);
$refresh_token_value = $values[8];
// reload auth code ...
$auth_code = AuthorizationCode::load(
$cache_values['auth_code'],
$cache_values['client_id'],
$cache_values['scope'],
$cache_values['audience'],
null,
null,
$this->configuration_service->getConfigValue('OAuth2.AuthorizationCode.Lifetime'),
$cache_values['from_ip'],
true
);
// reload access token ...
$access_token = AccessToken::load($value, $auth_code, $cache_values['issued'],$cache_values['lifetime']);
$refresh_token_value = $cache_values['refresh_token'];
if(!empty($refresh_token_value)){
$refresh_token = $this->getRefreshToken($refresh_token_value,true);
@ -459,38 +440,35 @@ class TokenService implements ITokenService
public function createRefreshToken(AccessToken &$access_token)
{
$refresh_token = RefreshToken::create($access_token, $this->configuration_service->getConfigValue('OAuth2.RefreshToken.Lifetime'));
$value = $refresh_token->getValue();
//hash the given value, bc tokens values are stored hashed on DB
$hashed_value = Hash::compute('sha256', $value);
$client_id = $refresh_token->getClientId();
$client = $this->client_service->getClientById($client_id);
//stores in DB
$refresh_token_db = new DBRefreshToken (
array(
'value' => $hashed_value,
'lifetime' => $refresh_token->getLifetime(),
'scope' => $refresh_token->getScope(),
'from_ip' => IPHelper::getUserIp(),
'audience' => $access_token->getAudience(),
)
);
DB::transaction(function () use (&$refresh_token, &$access_token) {
$value = $refresh_token->getValue();
//hash the given value, bc tokens values are stored hashed on DB
$hashed_value = Hash::compute('sha256', $value);
$client_id = $refresh_token->getClientId();
$client = $this->client_service->getClientById($client_id);
//stores in DB
$refresh_token_db = new DBRefreshToken (
array(
'value' => $hashed_value,
'lifetime' => $refresh_token->getLifetime(),
'scope' => $refresh_token->getScope(),
'from_ip' => IPHelper::getUserIp(),
'audience' => $access_token->getAudience(),
)
);
$refresh_token_db->client()->associate($client);
$refresh_token_db->Save();
//associate current access token to refresh token on DB
$access_token_db = DBAccessToken::where('value','=',Hash::compute('sha256',$access_token->getValue()))->first();
$access_token_db->refresh_token()->associate($refresh_token_db);
$access_token_db->Save();
$refresh_token_db->client()->associate($client);
$refresh_token_db->Save();
//associate current access token to refresh token on DB
$access_token_db = DBAccessToken::where('value','=',Hash::compute('sha256',$access_token->getValue()))->first();
$access_token_db->refresh_token()->associate($refresh_token_db);
$access_token_db->Save();
$access_token->setRefreshToken($refresh_token);
$access_token->setRefreshToken($refresh_token);
if($this->redis->setnx($client_id . self::ClientRefreshTokensQty,1)){
$this->redis->expire($client_id . self::ClientRefreshTokensQty, self::ClientRefreshTokensQtyLifetime);
}
else{
$this->redis->incr($client_id . self::ClientRefreshTokensQty);
}
$this->cache_service->incCounter($client_id . self::ClientRefreshTokensQty,self::ClientRefreshTokensQtyLifetime);
});
return $refresh_token;
}
@ -535,7 +513,8 @@ class TokenService implements ITokenService
'client_id' => $client->client_id,
'audience' => $refresh_token_db->audience,
'from_ip' => $refresh_token_db->from_ip,
'issued' => $refresh_token_db->created_at
'issued' => $refresh_token_db->created_at,
'is_hashed' => $is_hashed
), $refresh_token_db->lifetime);
return $refresh_token;
@ -551,13 +530,23 @@ class TokenService implements ITokenService
$auth_code_hashed_value = Hash::compute('sha256', $auth_code);
DB::transaction(function () use ($auth_code_hashed_value) {
//get related access tokens
$db_access_tokens = DBAccessToken::where('associated_authorization_code', '=', $auth_code_hashed_value)->get();
foreach ($db_access_tokens as $db_access_token) {
$client = $db_access_tokens->client()->first();
$access_token_value = $db_access_token->value;
$refresh_token_db = $db_access_token->refresh_token()->first();
if(!is_null($refresh_token_db))
if(!is_null($refresh_token_db)){
$refresh_token_db->delete();
$this->redis->del($access_token_value);
}
//remove auth code from client list on cache
$this->cache_service->deleteMemberSet($client->client_id . self::ClientAuthCodePrefixList, $auth_code_hashed_value);
//remove access token from client list on cache
$this->cache_service->deleteMemberSet($client->client_id . self::ClientAccessTokenPrefixList,$access_token_value);
$this->cache_service->delete($access_token_value);
$db_access_token->delete();
}
});
@ -576,13 +565,14 @@ class TokenService implements ITokenService
DB::transaction(function () use ($value, $is_hashed, &$res) {
//hash the given value, bc tokens values are stored hashed on DB
$hashed_value = !$is_hashed?Hash::compute('sha256', $value):$value;
//delete from redis
if ($this->redis->exists($hashed_value)) {
$res = $this->redis->del($hashed_value);
}
//check on DB... and delete it
$res = DBAccessToken::where('value', '=', $hashed_value)->delete();
$access_token_db = DBAccessToken::where('value', '=', $hashed_value)->first();
$client = $access_token_db->client()->first();
//delete from cache
$res = $this->cache_service->delete($hashed_value);
$res = $this->cache_service->deleteMemberSet($client->client_id . self::ClientAccessTokenPrefixList, $access_token_db->value);
//check on DB... and delete it
$res = $access_token_db->delete();
});
return $res > 0;
}
@ -594,24 +584,21 @@ class TokenService implements ITokenService
public function revokeClientRelatedTokens($client_id)
{
//get client auth codes
$auth_codes = $this->redis->smembers($client_id . self::ClientAuthCodePrefixList);
$auth_codes = $this->cache_service->getSet($client_id . self::ClientAuthCodePrefixList);
//get client access tokens
$access_tokens = $this->redis->smembers($client_id . self::ClientAccessTokenPrefixList);
$access_tokens = $this->cache_service->getSet($client_id . self::ClientAccessTokenPrefixList);
DB::transaction(function () use ($client_id, $auth_codes, $access_tokens) {
if(count($auth_codes)>0)
$this->redis->del($auth_codes);
if(count($access_tokens)>0)
$this->redis->del($access_tokens);
$this->cache_service->deleteArray($auth_codes);
$this->cache_service->deleteArray($access_tokens);
DBAccessToken::where('client_id','=',$client_id)->delete();
DBRefreshToken::where('client_id','=',$client_id)->delete();
//delete client list (auth codes and access tokens)
$this->redis->del($client_id . self::ClientAuthCodePrefixList);
$this->redis->del($client_id . self::ClientAccessTokenPrefixList);
$this->cache_service->delete($client_id . self::ClientAuthCodePrefixList);
$this->cache_service->delete($client_id . self::ClientAccessTokenPrefixList);
});
}
@ -620,8 +607,7 @@ class TokenService implements ITokenService
* Mark a given refresh token as void
* @param $value
* @param bool $is_hashed
* @param bool $revoke_related_access_token
* @return mixed
* @return bool
*/
public function invalidateRefreshToken($value, $is_hashed = false)
{
@ -661,9 +647,9 @@ class TokenService implements ITokenService
if(!is_null($refresh_token_db)){
$access_tokens_db = DBAccessToken::where('refresh_token_id','=',$refresh_token_db->id)->get();
foreach($access_tokens_db as $access_token_db){
$res = $this->redis->del(array($access_token_db->value));
$res = $this->cache_service->delete($access_token_db->value);
$client = $access_token_db->client()->first();
$res = $this->redis->srem($client->client_id . self::ClientAccessTokenPrefixList, $access_token_db->value);
$res = $this->cache_service->deleteMemberSet($client->client_id . self::ClientAccessTokenPrefixList, $access_token_db->value);
$access_token_db->delete();
}
}

View File

@ -2,94 +2,102 @@
namespace services;
use DateInterval;
use DateTime;
use Log;
use openid\exceptions\OpenIdInvalidRealmException;
use openid\exceptions\ReplayAttackException;
use openid\exceptions\InvalidAssociation;
use openid\helpers\OpenIdErrorMessages;
use openid\model\IAssociation;
use openid\services\IAssociationService;
use OpenIdAssociation;
use utils\exceptions\UnacquiredLockException;
use utils\services\ILockManagerService;
use utils\services\ICacheService;
/**
* Class AssociationService
* @package services
*/
class AssociationService implements IAssociationService
{
private $redis;
private $lock_manager_service;
private $cache_service;
public function __construct(ILockManagerService $lock_manager_service)
public function __construct(ILockManagerService $lock_manager_service, ICacheService $cache_service)
{
$this->redis = \RedisLV4::connection();
$this->lock_manager_service = $lock_manager_service;
$this->cache_service = $cache_service;
}
/**
* gets a given association by handle, and if association exists and its type is private, then lock it
* to prevent subsequent usage ( private association could be used once)
* @param $handle
* @param null $realm
* @return null|IAssociation
* @return null|IAssociation|OpenIdAssociation
* @throws \openid\exceptions\ReplayAttackException
* @throws \openid\exceptions\InvalidAssociation
* @throws \openid\exceptions\OpenIdInvalidRealmException
*/
public function getAssociation($handle, $realm = null)
{
//todo: refactor this code !!!
$lock_name = 'lock.get.assoc.' . $handle;
try {
// check if association is on redis cache
if ($this->redis->exists($handle)) {
//get hash from redis
$values = $this->redis->hmget($handle, array(
"type",
"mac_function",
"issued",
"lifetime",
"secret",
"realm"));
if ($values[0] == IAssociation::TypePrivate) {
// only one time we could use this handle
$this->lock_manager_service->acquireLock($lock_name);
if (is_null($realm) || empty($realm) || $values[5] != $realm) {
throw new OpenIdInvalidRealmException(sprintf(OpenIdErrorMessages::InvalidPrivateAssociationMessage, $handle, $realm));
}
}
$assoc = new OpenIdAssociation();
$assoc->type = $values[0];
$assoc->mac_function = $values[1];
$assoc->issued = $values[2];
$assoc->lifetime = $values[3];
$assoc->secret = \hex2bin($values[4]);
$realm = $values[5];
if (!empty($realm))
$assoc->realm = $realm;
return $assoc;
}
// if not , check on db
$assoc = OpenIdAssociation::where('identifier', '=', $handle)->first();
if (!is_null($assoc)) {
$issued_date = new DateTime($assoc->issued);
if ($assoc->type == IAssociation::TypePrivate) {
// only one time we could use this handle
$this->lock_manager_service->acquireLock($lock_name);
if (is_null($realm) || empty($realm) || $assoc->realm != $realm) {
throw new OpenIdInvalidRealmException(sprintf(OpenIdErrorMessages::InvalidPrivateAssociationMessage, $handle, $realm));
}
}
$life_time = $assoc->lifetime;
$issued_date->add(new DateInterval('PT' . $life_time . 'S'));
$now = new DateTime(gmdate("Y-m-d H:i:s", time()));
if ($now > $issued_date) {
// check if association is on cache
if (!$this->cache_service->exists($handle)) {
// if not , check on db
$assoc = OpenIdAssociation::where('identifier', '=', $handle)->first();
if(is_null($assoc))
throw new InvalidAssociation(sprintf('openid association %s does not exists!',$handle));
//check association lifetime ...
$remaining_lifetime = $assoc->getRemainingLifetime();
if ($remaining_lifetime < 0) {
$this->deleteAssociation($handle);
$assoc = null;
return null;
}
//repopulate cache
$this->cache_service->storeHash($handle, array(
"type" => $assoc->type,
"mac_function" => $assoc->mac_function,
"issued" => $assoc->issued,
"lifetime" => $assoc->lifetime,
"secret" => \bin2hex($assoc->secret),
"realm" => $assoc->realm),
$remaining_lifetime);
}
//get hash from cache
$cache_values = $this->cache_service->getHash($handle, array(
"type",
"mac_function",
"issued",
"lifetime",
"secret",
"realm"));
if ($cache_values['type'] == IAssociation::TypePrivate) {
if (is_null($realm) || empty($realm) || $cache_values['realm'] != $realm) {
throw new OpenIdInvalidRealmException(sprintf(OpenIdErrorMessages::InvalidPrivateAssociationMessage, $handle, $realm));
}
// only one time we could use this handle
$this->lock_manager_service->acquireLock($lock_name);
}
$assoc = new OpenIdAssociation();
$assoc->type = $cache_values['type'];
$assoc->mac_function = $cache_values['mac_function'];
$assoc->issued = $cache_values['issued'];
$assoc->lifetime = $cache_values['lifetime'];
$assoc->secret = \hex2bin($cache_values['secret']);
$realm = $cache_values['realm'];
if (!empty($realm))
$assoc->realm = $realm;
return $assoc;
} catch (UnacquiredLockException $ex1) {
throw new ReplayAttackException(sprintf(OpenIdErrorMessages::ReplayAttackPrivateAssociationAlreadyUsed, $handle));
}
@ -101,7 +109,7 @@ class AssociationService implements IAssociationService
*/
public function deleteAssociation($handle)
{
$this->redis->del($handle);
$this->cache_service->delete($handle);
$assoc = OpenIdAssociation::where('identifier', '=', $handle)->first();
if (!is_null($assoc)) {
$assoc->delete();
@ -111,44 +119,53 @@ class AssociationService implements IAssociationService
}
/**
* @param IAssociation $association
* @return bool
* @param $handle
* @param $secret
* @param $mac_function
* @param $lifetime
* @param $issued
* @param $type
* @param null $realm
* @return IAssociation
* @throws \openid\exceptions\ReplayAttackException
*/
public function addAssociation($handle, $secret, $mac_function, $lifetime, $issued, $type, $realm = null)
{
$assoc = new OpenIdAssociation();
try {
$lock_name = 'lock.add.assoc.' . $handle;
$this->lock_manager_service->acquireLock($lock_name);
$assoc = new OpenIdAssociation();
$assoc->identifier = $handle;
$assoc->secret = $secret;
$assoc->type = $type;
$assoc->mac_function = $mac_function;
$assoc->lifetime = $lifetime;
$assoc->issued = $issued;
if (!is_null($realm))
$assoc->realm = $realm;
if ($type == IAssociation::TypeSession) {
$assoc->identifier = $handle;
$assoc->secret = $secret;
$assoc->type = $type;
$assoc->mac_function = $mac_function;
$assoc->lifetime = $lifetime;
$assoc->issued = $issued;
if (!is_null($realm))
$assoc->realm = $realm;
$assoc->Save();
}
if (is_null($realm))
$realm = '';
$this->redis->hmset($handle, array(
"type" => $type,
$this->cache_service->storeHash($handle, array(
"type" => $type,
"mac_function" => $mac_function,
"issued" => $issued,
"lifetime" => $lifetime,
"secret" => \bin2hex($secret),
"realm" => $realm));
"issued" => $issued,
"lifetime" => $lifetime,
"secret" => \bin2hex($secret),
"realm" => $realm),$lifetime);
$this->redis->expire($handle, $lifetime);
} catch (UnacquiredLockException $ex1) {
throw new ReplayAttackException(sprintf(OpenIdErrorMessages::ReplayAttackPrivateAssociationAlreadyUsed, $handle));
}
return $assoc;
}
/**

View File

@ -64,13 +64,15 @@ class MementoRequestService implements IMementoOpenIdRequestService
public function clearCurrentRequest()
{
$old_data = Input::old();
$old_data = Input::old();
$openid_params = array();
foreach ($old_data as $key => $value) {
if (stristr($key, "openid") !== false) {
array_push($openid_params, $key);
}
}
if (count($openid_params) > 0) {
foreach ($openid_params as $open_id_param) {
Session::forget($open_id_param);

View File

@ -10,17 +10,19 @@ use openid\model\OpenIdNonce;
use openid\services\INonceService;
use utils\exceptions\UnacquiredLockException;
use utils\services\ILockManagerService;
use utils\services\ICacheService;
class NonceService implements INonceService
{
private $redis;
public function __construct(ILockManagerService $lock_manager_service)
private $cache_service;
private $lock_manager_service;
public function __construct(ILockManagerService $lock_manager_service,ICacheService $cache_service)
{
$this->redis = \RedisLV4::connection();
$this->lock_manager_service = $lock_manager_service;
$this->cache_service = $cache_service;
}
/**
@ -67,15 +69,15 @@ class NonceService implements INonceService
$key = $raw_nonce . $signature;
try {
if ($this->redis->exists($key) == 0)
throw new ReplayAttackException(sprintf(OpenIdErrorMessages::ReplayAttackNonceAlreadyUsed, $nonce));
$old_realm = $this->redis->get($key);
if (!$this->cache_service->exists($key))
throw new ReplayAttackException(sprintf(OpenIdErrorMessages::ReplayAttackNonceAlreadyUsed, $nonce->getRawFormat()));
$old_realm = $this->cache_service->getSingleValue($key);
if ($realm != $old_realm) {
throw new ReplayAttackException(sprintf(OpenIdErrorMessages::ReplayAttackNonceAlreadyEmittedForAnotherRealm, $realm));
}
$this->redis->del($key);
$this->cache_service->delete($key);
} catch (ReplayAttackException $ex) {
$this->redis->del($key);
$this->cache_service->delete($key);
throw $ex;
}
}
@ -90,7 +92,7 @@ class NonceService implements INonceService
try {
$raw_nonce = $nonce->getRawFormat();
$lifetime = \ServerConfigurationService::getConfigValue("Nonce.Lifetime");
$this->redis->setex($raw_nonce . $signature, $lifetime, $realm);
$this->cache_service->setSingleValue($raw_nonce . $signature, $realm, $lifetime );
} catch (Exception $ex) {
Log::error($ex);
}

View File

@ -8,29 +8,30 @@ use openid\services\ITrustedSitesService;
use OpenIdTrustedSite;
use utils\services\IAuthService;
use utils\services\ILogService;
use Exception;
class TrustedSitesService implements ITrustedSitesService
{
private $log;
private $log_service;
public function __construct(ILogService $log)
public function __construct(ILogService $log_service)
{
$this->log = $log;
$this->log_service = $log_service;
}
public function addTrustedSite(IOpenIdUser $user, $realm, $policy, $data = array())
{
$res = false;
try {
$site = new OpenIdTrustedSite;
$site->realm = $realm;
$site->policy = $policy;
$site = new OpenIdTrustedSite;
$site->realm = $realm;
$site->policy = $policy;
$site->user_id = $user->getId();
$site->data = json_encode($data);
$site->data = json_encode($data);
$site->Save();
$res = true;
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
return $res;
}
@ -40,8 +41,8 @@ class TrustedSitesService implements ITrustedSitesService
try {
$site = OpenIdTrustedSite::where("id", "=", $id)->first();
if (!is_null($site)) $site->delete();
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
}
@ -72,8 +73,8 @@ class TrustedSitesService implements ITrustedSitesService
}
$sites = $query->get();
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
$res = array();
@ -136,8 +137,8 @@ class TrustedSitesService implements ITrustedSitesService
$sites = null;
try {
$sites = OpenIdTrustedSite::where("user_id", "=", $user->getId())->get();
} catch (\Exception $ex) {
$this->log->error($ex);
} catch (Exception $ex) {
$this->log_service->error($ex);
}
return $sites;
}

View File

@ -45,8 +45,7 @@ class OAuth2ConsentStrategy implements IConsentStrategy {
$data['redirect_to'] = $request->getRedirectUri();
$app_logo = $client->getApplicationLogo();
if(is_null($app_logo) || empty($app_logo))
$app_logo = asset('img/oauth2.default.logo.png');
$data['app_logo'] = $app_logo;
$data['app_description'] = $client->getApplicationDescription();
$data['dev_info_email'] = $client->getDeveloperEmail();

View File

@ -6,12 +6,12 @@ use openid\OpenIdProtocol;
use openid\requests\OpenIdDHAssociationSessionRequest;
use Zend\Crypt\PublicKey\DiffieHellman;
/**
* Class DiffieHellmanTest
*/
class DiffieHellmanTest extends TestCase
{
/**
*
*/
public function testDefaultDHParams()
{
$g = OpenIdDHAssociationSessionRequest::DH_G;
@ -33,44 +33,4 @@ class DiffieHellmanTest extends TestCase
$this->assertTrue(strlen($handler) == 32);
}
public function testAssociationMessage()
{
$g = pack('H*', OpenIdDHAssociationSessionRequest::DH_G);
$g = OpenIdCryptoHelper::convert($g, DiffieHellman::FORMAT_BINARY, DiffieHellman::FORMAT_NUMBER);
$p = pack('H*', OpenIdDHAssociationSessionRequest::DH_P);
$p = OpenIdCryptoHelper::convert($p, DiffieHellman::FORMAT_BINARY, DiffieHellman::FORMAT_NUMBER);
$dh = new DiffieHellman($p, $g);
$dh->generateKeys();
$rp_public_key = $dh->getPublicKey(DiffieHellman::FORMAT_BTWOC);
$dh->computeSecretKey($rp_public_key, DiffieHellman::FORMAT_BTWOC);
$rp_public_key = base64_encode($rp_public_key);
$shared_secret = $dh->getSharedSecretKey();
$params = array(
"openid.ns" => "http://specs.openid.net/auth/2.0",
"openid.assoc_type" => OpenIdProtocol::SignatureAlgorithmHMAC_SHA256,
"openid.dh_consumer_public" => $rp_public_key,
"openid.mode" => 'associate',
"openid.session_type" => OpenIdProtocol::AssociationSessionTypeDHSHA256,
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$body = $response->getContent();
$lines = explode("\n", $body);
$params = array();
foreach ($lines as $line) {
if (empty($line)) continue;
$param = explode(":", $line, 2);
$params[$param[0]] = $param[1];
}
$this->assertResponseStatus(200);
$this->assertTrue(isset($params[OpenIdProtocol::OpenIDProtocol_NS]) && $params[OpenIdProtocol::OpenIDProtocol_NS] == OpenIdProtocol::OpenID2MessageType);
$this->assertTrue(isset($params[OpenIdProtocol::OpenIDProtocol_AssocType]) && $params[OpenIdProtocol::OpenIDProtocol_AssocType] == OpenIdProtocol::SignatureAlgorithmHMAC_SHA256);
$this->assertTrue(isset($params[OpenIdProtocol::OpenIDProtocol_SessionType]) && $params[OpenIdProtocol::OpenIDProtocol_SessionType] == OpenIdProtocol::AssociationSessionTypeDHSHA256);
}
}

View File

@ -1,11 +1,12 @@
<?php
use auth\OpenIdUser;
use auth\User;
use oauth2\OAuth2Protocol;
use utils\services\IAuthService;
/**
* Class OAuth2ProtocolTest
* Test Suite for OAuth2 Protocol
*/
class OAuth2ProtocolTest extends TestCase
{
@ -34,7 +35,7 @@ class OAuth2ProtocolTest extends TestCase
'scope' => sprintf('%s/api/resource-server/read',$this->current_realm),
);
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -69,7 +70,7 @@ class OAuth2ProtocolTest extends TestCase
'scope' => sprintf('%s/api/resource-server/read',$this->current_realm),
);
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -135,7 +136,7 @@ class OAuth2ProtocolTest extends TestCase
$client_secret = 'ITc/6Y5N7kOtGKhg';
//do login and consent ...
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -232,7 +233,7 @@ class OAuth2ProtocolTest extends TestCase
$client_secret = 'ITc/6Y5N7kOtGKhg';
//do login and consent ...
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -333,7 +334,7 @@ class OAuth2ProtocolTest extends TestCase
$client_secret = 'ITc/6Y5N7kOtGKhg';
//do login and consent ...
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -438,7 +439,7 @@ class OAuth2ProtocolTest extends TestCase
$client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwKlfSyQ3x.openstack.client';
//do login and consent ...
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -480,7 +481,7 @@ class OAuth2ProtocolTest extends TestCase
$client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwKlfSyQ3x.openstack.client';
//do login and consent ...
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -537,7 +538,7 @@ class OAuth2ProtocolTest extends TestCase
$client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwKlfSyQ3x.openstack.client';
//do login and consent ...
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -595,7 +596,7 @@ class OAuth2ProtocolTest extends TestCase
$client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwKlfSyQ3x.openstack.client';
//do login and consent ...
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
@ -653,7 +654,7 @@ class OAuth2ProtocolTest extends TestCase
$client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwKlfSyQ3x.openstack.client';
//do login and consent ...
$user = OpenIdUser::where('external_id', '=', 'smarcet@gmail.com')->first();
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);

View File

@ -1,105 +1,731 @@
<?php
use openid\OpenIdProtocol;
use auth\User;
use utils\services\IAuthService;
use openid\extensions\implementations\OpenIdOAuth2Extension;
use openid\extensions\implementations\OpenIdSREGExtension;
use openid\helpers\OpenIdCryptoHelper;
use Zend\Crypt\PublicKey\DiffieHellman;
/**
* Class OpenIdProtocolTest
* Test Suite for OpenId Protocol
*/
class OpenIdProtocolTest extends TestCase
{
private $current_realm;
private $g;
private $private;
private $public;
private $mod;
private $oauth2_client_id;
private $oauth2_client_secret;
public function testCheckId_immediate_Invalid()
public function __construct(){
//DH openid values
$this->g = '2';
$this->private = '84009535308644335779530519631942543663544485189066558731295758689838227409144125540638118058012144795574289866857191302071807568041343083679600155026066530597177004145874642611724010339353151653679189142289183802715816551715563883085859667759854344959305451172754264893136955464706052993052626766687910313992';
$this->public = '93500922748114712465435925279613158240858799671601934136793652488458659380414896628304484614933937038790006320444306607890979422427297815641372302594684991758687126229761033142429422299990743006497200988301031430937819368909849994628108111270360657896230712920491471398605159969300956278883668998797148755353';
$this->mod = '155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443';
$this->oauth2_client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwTlfSyQ3x.openstack.client';
$this->oauth2_client_secret = 'ITc/6Y5N7kOtGKhg';
}
protected function prepareForTests()
{
parent::prepareForTests();
Route::enableFilters();
$this->current_realm = Config::get('app.url');
}
/**
* parse openid response from an url
* @param $url
* @return array
*/
private function parseOpenIdResponse($url){
$url_parts = @parse_url($url);
$openid_response = array();
$query_params = explode('&', $url_parts['query']);
foreach ($query_params as $param) {
$aux = explode('=', $param, 2);
$openid_response[$aux[0]] = @urldecode($aux[1]);
}
return $openid_response;
}
private function getOpenIdResponseLineBreak($content){
$params = explode("\n",$content);
$res = array();
foreach($params as $param){
if(empty($param)) continue;
$openid_param = explode(':',$param,2);
$res[$openid_param[0]] = $openid_param[1];
}
return $res;
}
/**
* Exact copies of all fields from the authentication response, except for "openid.mode".
* @param $openid_response
* @return array
*/
private function prepareCheckAuthenticationParams($openid_response){
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::ImmediateMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "*.uk", //invalid realm
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "http://dev.openstack.org/login",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "https://dev.openstackid.com/sebastian.marcet",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "https://dev.openstackid.com/sebastian.marcet",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::CheckAuthenticationMode,
);
$encode = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) =>OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo),
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) =>OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId),
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint) =>OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint),
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) =>OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm),
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) =>OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity),
);
foreach($openid_response as $key => $value){
if(!array_key_exists($key,$params))
$params[$key] = array_key_exists($key,$encode)? @urldecode($value):$value;
}
return $params;
}
// test for session associations
public function testAssociationSessionRequestDiffieHellmanSha1(){
$b64_public = base64_encode(OpenIdCryptoHelper::convert($this->public,DiffieHellman::FORMAT_NUMBER,DiffieHellman::FORMAT_BTWOC));
$this->assertTrue($b64_public === 'AIUmVPMheb/hEupD5m6veEEstnBVteyZPy+mlYX7ygxygLG/XuHFa8q4lZERJ9u1DNFOpXHRDq5RbjsaUYRDOtyrbkGbeKo5tPqjsynjXtoMAItxkxCU4jpQLvH85P+u7DeA0h3kKNHFa90ijZTIGSSDRF5wW9N+QPCUCt4G4xWZ');
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::AssociateMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_AssocType) => OpenIdProtocol::SignatureAlgorithmHMAC_SHA1,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_SessionType) => OpenIdProtocol::AssociationSessionTypeDHSHA1,
OpenIdProtocol::param(OpenIdProtocol::OpenIdProtocol_DHConsumerPublic) => $b64_public,
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$status = $response->getStatusCode();
$content = $response->getContent();
$target_url = $response->getTargetUrl();
$url = explode('?', $target_url, 2);
$openid_response = array();
$query_params = explode('&', $url[1]);
foreach ($query_params as $param) {
$aux = explode('=', $param, 2);
$openid_response[$aux[0]] = $aux[1];
}
$this->assertResponseStatus(200);
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertTrue(isset($openid_response['ns']));
$this->assertTrue($openid_response['ns'] === OpenIdProtocol::OpenID2MessageType);
$this->assertTrue(isset($openid_response['assoc_type']));
$this->assertTrue($openid_response['assoc_type'] === OpenIdProtocol::SignatureAlgorithmHMAC_SHA1);
$this->assertTrue(isset($openid_response['session_type']));
$this->assertTrue($openid_response['session_type'] === OpenIdProtocol::AssociationSessionTypeDHSHA1);
$this->assertTrue(isset($openid_response['assoc_handle']));
$this->assertTrue(isset($openid_response['dh_server_public']));
$this->assertTrue(isset($openid_response['enc_mac_key']));
$this->assertTrue(isset($openid_response['expires_in']));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Error)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue($status == 302);
}
public function testCheckId_immediate()
{
public function testAssociationSessionRequestDiffieHellmanSha256(){
$b64_public = base64_encode(OpenIdCryptoHelper::convert($this->public,DiffieHellman::FORMAT_NUMBER,DiffieHellman::FORMAT_BTWOC));
$this->assertTrue($b64_public === 'AIUmVPMheb/hEupD5m6veEEstnBVteyZPy+mlYX7ygxygLG/XuHFa8q4lZERJ9u1DNFOpXHRDq5RbjsaUYRDOtyrbkGbeKo5tPqjsynjXtoMAItxkxCU4jpQLvH85P+u7DeA0h3kKNHFa90ijZTIGSSDRF5wW9N+QPCUCt4G4xWZ');
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::ImmediateMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "http://dev.openstack.org",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "http://dev.openstack.org/login",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "https://dev.openstackid.com/sebastian.marcet",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "https://dev.openstackid.com/sebastian.marcet",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::AssociateMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_AssocType) => OpenIdProtocol::SignatureAlgorithmHMAC_SHA256,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_SessionType) => OpenIdProtocol::AssociationSessionTypeDHSHA256,
OpenIdProtocol::param(OpenIdProtocol::OpenIdProtocol_DHConsumerPublic) => $b64_public,
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$status = $response->getStatusCode();
$content = $response->getContent();
$target_url = $response->getTargetUrl();
$url = explode('?', $target_url, 2);
$openid_response = array();
$query_params = explode('&', $url[1]);
foreach ($query_params as $param) {
$aux = explode('=', $param, 2);
$openid_response[$aux[0]] = $aux[1];
}
$this->assertResponseStatus(200);
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertTrue(isset($openid_response['ns']));
$this->assertTrue($openid_response['ns'] === OpenIdProtocol::OpenID2MessageType);
$this->assertTrue(isset($openid_response['assoc_type']));
$this->assertTrue($openid_response['assoc_type'] === OpenIdProtocol::SignatureAlgorithmHMAC_SHA256);
$this->assertTrue(isset($openid_response['session_type']));
$this->assertTrue($openid_response['session_type'] === OpenIdProtocol::AssociationSessionTypeDHSHA256);
$this->assertTrue(isset($openid_response['assoc_handle']));
$this->assertTrue(isset($openid_response['dh_server_public']));
$this->assertTrue(isset($openid_response['enc_mac_key']));
$this->assertTrue(isset($openid_response['expires_in']));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$mode = $openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)];
$this->assertTrue($mode == OpenIdProtocol::SetupNeededMode);
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue($status == 302);
}
public function testCheckSetup()
{
public function testAssociationSessionRequestNoEncryption(){
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::SetupMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "http://drupal-openid.local/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "http://drupal-openid.local/openid/authenticate?destination=%3Cfront%3E",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::AssociateMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_AssocType) => OpenIdProtocol::AssociationSessionTypeNoEncryption,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_SessionType) => OpenIdProtocol::AssociationSessionTypeNoEncryption,
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(200);
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertTrue(isset($openid_response['ns']));
$this->assertTrue($openid_response['ns'] === OpenIdProtocol::OpenID2MessageType);
$this->assertTrue(isset($openid_response['assoc_type']));
$this->assertTrue($openid_response['assoc_type'] === OpenIdProtocol::AssociationSessionTypeNoEncryption);
$this->assertTrue(isset($openid_response['session_type']));
$this->assertTrue($openid_response['session_type'] === OpenIdProtocol::AssociationSessionTypeNoEncryption);
$this->assertTrue(isset($openid_response['assoc_handle']) && ! empty($openid_response['assoc_handle']));
$this->assertTrue(isset($openid_response['expires_in']));
$this->assertTrue(isset($openid_response['mac_key']) && !empty($openid_response['mac_key']));
}
// test for authentication
public function testAuthenticationSetupModePrivateAssociation(){
//set login info
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
Session::set("openid.authorization.response", IAuthService::AuthorizationResponse_AllowOnce);
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::SetupMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "https://www.test.com/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "https://www.test.com/oauth2",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "http://specs.openid.net/auth/2.0/identifier_select",
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$status = $response->getStatusCode();
$content = $response->getContent();
$target_url = $response->getTargetUrl();
$url = explode('?', $target_url, 2);
$openid_response = array();
$query_params = explode('&', $url[1]);
foreach ($query_params as $param) {
$aux = explode('=', $param, 2);
$openid_response[$aux[0]] = $aux[1];
}
$this->assertResponseStatus(302);
$openid_response = $this->parseOpenIdResponse($response->getTargetUrl());
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$mode = $openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)];
$this->assertTrue($mode == OpenIdProtocol::SetupNeededMode);
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue($status == 302);
//http://openid.net/specs/openid-authentication-2_0.html#check_auth
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $this->prepareCheckAuthenticationParams($openid_response));
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertResponseStatus(200);
$this->assertTrue($openid_response['is_valid'] === 'true');
}
public function testAuthenticationSetupModeSessionAssociationDHSha256(){
$b64_public = base64_encode(OpenIdCryptoHelper::convert($this->public,DiffieHellman::FORMAT_NUMBER,DiffieHellman::FORMAT_BTWOC));
$this->assertTrue($b64_public === 'AIUmVPMheb/hEupD5m6veEEstnBVteyZPy+mlYX7ygxygLG/XuHFa8q4lZERJ9u1DNFOpXHRDq5RbjsaUYRDOtyrbkGbeKo5tPqjsynjXtoMAItxkxCU4jpQLvH85P+u7DeA0h3kKNHFa90ijZTIGSSDRF5wW9N+QPCUCt4G4xWZ');
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::AssociateMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_AssocType) => OpenIdProtocol::SignatureAlgorithmHMAC_SHA256,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_SessionType) => OpenIdProtocol::AssociationSessionTypeDHSHA256,
OpenIdProtocol::param(OpenIdProtocol::OpenIdProtocol_DHConsumerPublic) => $b64_public,
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(200);
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertTrue(isset($openid_response['ns']));
$this->assertTrue($openid_response['ns'] === OpenIdProtocol::OpenID2MessageType);
$this->assertTrue(isset($openid_response['assoc_type']));
$this->assertTrue($openid_response['assoc_type'] === OpenIdProtocol::SignatureAlgorithmHMAC_SHA256);
$this->assertTrue(isset($openid_response['session_type']));
$this->assertTrue($openid_response['session_type'] === OpenIdProtocol::AssociationSessionTypeDHSHA256);
$this->assertTrue(isset($openid_response['assoc_handle']));
$this->assertTrue(isset($openid_response['dh_server_public']));
$this->assertTrue(isset($openid_response['enc_mac_key']));
$this->assertTrue(isset($openid_response['expires_in']));
//set login info
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
Session::set("openid.authorization.response", IAuthService::AuthorizationResponse_AllowOnce);
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::SetupMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "https://www.test.com/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "https://www.test.com/oauth2",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_AssocHandle) => $openid_response['assoc_handle'],
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(302);
$openid_response = $this->parseOpenIdResponse($response->getTargetUrl());
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
}
public function testAuthenticationCheckImmediateAuthenticationPrivateSession(){
//set login info
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
Session::set("openid.authorization.response", IAuthService::AuthorizationResponse_AllowOnce);
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::ImmediateMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "https://www.test.com/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "https://www.test.com/oauth2",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "http://specs.openid.net/auth/2.0/identifier_select",
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(302);
$openid_response = $this->parseOpenIdResponse($response->getTargetUrl());
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
}
//extension tests
public function testCheckSetupSREGExtension(){
//set login info
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
Session::set("openid.authorization.response", IAuthService::AuthorizationResponse_AllowForever);
$sreg_required_params = array('email','fullname');
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::SetupMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "https://www.test.com/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "https://www.test.com/oauth2",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "http://specs.openid.net/auth/2.0/identifier_select",
//sreg
OpenIdSREGExtension::paramNamespace() => OpenIdSREGExtension::NamespaceUrl,
OpenIdSREGExtension::param(OpenIdSREGExtension::Required) => implode(",",$sreg_required_params),
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(302);
$openid_response = $this->parseOpenIdResponse($response->getTargetUrl());
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
//sreg
$this->assertTrue(isset($openid_response[OpenIdSREGExtension::paramNamespace()]));
$this->assertTrue($openid_response[OpenIdSREGExtension::paramNamespace()] === OpenIdSREGExtension::NamespaceUrl);
$this->assertTrue(isset($openid_response[OpenIdSREGExtension::param(OpenIdSREGExtension::FullName)]));
$full_name = $openid_response[OpenIdSREGExtension::param(OpenIdSREGExtension::FullName)];
$this->assertTrue(!empty($full_name) && $full_name ==='Sebastian Marcet');
$this->assertTrue(isset($openid_response[OpenIdSREGExtension::param(OpenIdSREGExtension::Email)]));
$email = $openid_response[OpenIdSREGExtension::param(OpenIdSREGExtension::Email)];
$this->assertTrue(!empty($email) && $email ==='smarcet@gmail.com');
//http://openid.net/specs/openid-authentication-2_0.html#check_auth
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $this->prepareCheckAuthenticationParams($openid_response));
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertResponseStatus(200);
$this->assertTrue($openid_response['is_valid'] === 'true');
}
/**
* test openid oauth2 extension
* https://developers.google.com/accounts/docs/OpenID#oauth
*/
public function testCheckSetupOAuth2Extension(){
//set login info
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
Session::set("openid.authorization.response", IAuthService::AuthorizationResponse_AllowForever);
$scope = array(
sprintf('%s/api/resource-server/read',$this->current_realm),
sprintf('%s/api/resource-server/read.page',$this->current_realm),
sprintf('%s/api/resource-server/write',$this->current_realm),
sprintf('%s/api/resource-server/delete',$this->current_realm),
sprintf('%s/api/resource-server/update',$this->current_realm),
sprintf('%s/api/resource-server/update.status',$this->current_realm),
sprintf('%s/api/resource-server/regenerate.secret',$this->current_realm),
);
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::SetupMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "https://www.test.com/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "https://www.test.com/oauth2",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "http://specs.openid.net/auth/2.0/identifier_select",
//oauth2
OpenIdOAuth2Extension::paramNamespace() => OpenIdOAuth2Extension::NamespaceUrl,
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::ClientId) => $this->oauth2_client_id,
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::Scope) => implode(' ',$scope),
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::State) => uniqid(),
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(302);
$openid_response = $this->parseOpenIdResponse($response->getTargetUrl());
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
//oauth2
$this->assertTrue(isset($openid_response[OpenIdOAuth2Extension::paramNamespace()]));
$this->assertTrue($openid_response[OpenIdOAuth2Extension::paramNamespace()] === OpenIdOAuth2Extension::NamespaceUrl);
$this->assertTrue(isset($openid_response[OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::RequestToken)]));
$this->assertTrue(!empty($openid_response[OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::RequestToken)]));
$this->assertTrue(isset($openid_response[OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::Scope)]));
$this->assertTrue(!empty($openid_response[OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::Scope)]));
//http://openid.net/specs/openid-authentication-2_0.html#check_auth
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $this->prepareCheckAuthenticationParams($openid_response));
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertResponseStatus(200);
$this->assertTrue($openid_response['is_valid'] === 'true');
}
public function testCheckSetupOAuth2ExtensionWrongClientId(){
//set login info
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
Session::set("openid.authorization.response", IAuthService::AuthorizationResponse_AllowOnce);
$scope = array(
sprintf('%s/api/resource-server/read',$this->current_realm),
sprintf('%s/api/resource-server/read.page',$this->current_realm),
sprintf('%s/api/resource-server/write',$this->current_realm),
sprintf('%s/api/resource-server/delete',$this->current_realm),
sprintf('%s/api/resource-server/update',$this->current_realm),
sprintf('%s/api/resource-server/update.status',$this->current_realm),
sprintf('%s/api/resource-server/regenerate.secret',$this->current_realm),
);
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::SetupMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "https://www.test.com/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "https://www.test.com/oauth2",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "http://specs.openid.net/auth/2.0/identifier_select",
//oauth2
OpenIdOAuth2Extension::paramNamespace() => OpenIdOAuth2Extension::NamespaceUrl,
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::ClientId) => 'wrong_client_id',
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::Scope) => implode(' ',$scope),
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::State) => uniqid(),
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(302);
$openid_response = $this->parseOpenIdResponse($response->getTargetUrl());
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
//oauth 2
$this->assertTrue(isset($openid_response[OpenIdOAuth2Extension::paramNamespace()]));
$this->assertTrue($openid_response[OpenIdOAuth2Extension::paramNamespace()] === OpenIdOAuth2Extension::NamespaceUrl);
$this->assertTrue(!isset($openid_response[OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::Scope)]));
$this->assertTrue(!isset($openid_response[OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::RequestToken)]));
//http://openid.net/specs/openid-authentication-2_0.html#check_auth
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $this->prepareCheckAuthenticationParams($openid_response));
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertResponseStatus(200);
$this->assertTrue($openid_response['is_valid'] === 'true');
}
public function testCheckSetupOAuth2ExtensionBadRequest(){
//set login info
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
Session::set("openid.authorization.response", IAuthService::AuthorizationResponse_AllowOnce);
$scope = array(
sprintf('%s/api/resource-server/read',$this->current_realm),
sprintf('%s/api/resource-server/read.page',$this->current_realm),
sprintf('%s/api/resource-server/write',$this->current_realm),
sprintf('%s/api/resource-server/delete',$this->current_realm),
sprintf('%s/api/resource-server/update',$this->current_realm),
sprintf('%s/api/resource-server/update.status',$this->current_realm),
sprintf('%s/api/resource-server/regenerate.secret',$this->current_realm),
);
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::SetupMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "https://www.test.com/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "https://www.test.com/oauth2",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "http://specs.openid.net/auth/2.0/identifier_select",
//oauth2
OpenIdOAuth2Extension::paramNamespace() => OpenIdOAuth2Extension::NamespaceUrl,
//missing client id
//OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::ClientId) => 'wrong_client_id',
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::Scope) => implode(' ',$scope),
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::State) => uniqid(),
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(302);
$openid_response = $this->parseOpenIdResponse($response->getTargetUrl());
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Sig)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Signed)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity)]));
$this->assertTrue(isset($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
$this->assertTrue(!empty($openid_response[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId)]));
//oauth 2
$this->assertTrue(isset($openid_response[OpenIdOAuth2Extension::paramNamespace()]));
$this->assertTrue($openid_response[OpenIdOAuth2Extension::paramNamespace()] === OpenIdOAuth2Extension::NamespaceUrl);
$this->assertTrue(!isset($openid_response[OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::Scope)]));
$this->assertTrue(!isset($openid_response[OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::RequestToken)]));
//http://openid.net/specs/openid-authentication-2_0.html#check_auth
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $this->prepareCheckAuthenticationParams($openid_response));
$openid_response = $this->getOpenIdResponseLineBreak($response->getContent());
$this->assertResponseStatus(200);
$this->assertTrue($openid_response['is_valid'] === 'true');
}
public function testCheckSetupOAuth2ExtensionSubView(){
//set login info
$user = User::where('external_id', '=', 'smarcet@gmail.com')->first();
Auth::login($user);
$scope = array(
sprintf('%s/api/resource-server/read',$this->current_realm),
sprintf('%s/api/resource-server/read.page',$this->current_realm),
sprintf('%s/api/resource-server/write',$this->current_realm),
sprintf('%s/api/resource-server/delete',$this->current_realm),
sprintf('%s/api/resource-server/update',$this->current_realm),
sprintf('%s/api/resource-server/update.status',$this->current_realm),
sprintf('%s/api/resource-server/regenerate.secret',$this->current_realm),
);
$params = array(
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_NS) => OpenIdProtocol::OpenID2MessageType,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode) => OpenIdProtocol::SetupMode,
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm) => "https://www.test.com/",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo) => "https://www.test.com/oauth2",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity) => "http://specs.openid.net/auth/2.0/identifier_select",
OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId) => "http://specs.openid.net/auth/2.0/identifier_select",
//oauth2
OpenIdOAuth2Extension::paramNamespace() => OpenIdOAuth2Extension::NamespaceUrl,
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::ClientId) => $this->oauth2_client_id,
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::Scope) => implode(' ',$scope),
OpenIdOAuth2Extension::param(OpenIdOAuth2Extension::State) => uniqid(),
);
$response = $this->action("POST", "OpenIdProviderController@op_endpoint", $params);
$this->assertResponseStatus(302);
$content = $response->getContent();
}
}

View File

@ -2,6 +2,10 @@
use oauth2\OAuth2Protocol;
/**
* Class ResourceServerApiTest
* Test Suite for OAuth2 Protected Resource Server Api
*/
class ResourceServerApiTest extends TestCase {
private $access_token;
@ -17,7 +21,6 @@ class ResourceServerApiTest extends TestCase {
$this->client_id = 'Jiz87D8/Vcvr6fvQbH4HyNgwTlfSyQ3x.openstack.client';
$this->client_secret = 'ITc/6Y5N7kOtGKhg';
$scope = array(
sprintf('%s/api/resource-server/read',$this->current_realm),
sprintf('%s/api/resource-server/read.page',$this->current_realm),
@ -34,6 +37,8 @@ class ResourceServerApiTest extends TestCase {
OAuth2Protocol::OAuth2Protocol_Scope => implode(' ',$scope)
);
//get access token for api ...
$response = $this->action("POST", "OAuth2ProviderController@token",
$params,
array(),

View File

@ -2,14 +2,22 @@
class TestCase extends Illuminate\Foundation\Testing\TestCase {
private $redis;
public function __construct(){
}
public function setUp()
{
parent::setUp(); // Don't forget this!
$this->redis = \RedisLV4::connection();
$this->redis->flushall();
$this->prepareForTests();
}
/**
/**
* Migrates the database and set the mailer to 'pretend'.
* This will cause the tests to run quickly.
*

View File

@ -1,10 +1,10 @@
@if(count($attributes)>0)
<label>
The site has also requested some personal information
<b>The site has also requested some personal information</b>
</label>
<ul class="unstyled list-inline">
@foreach ($attributes as $attr)
<li>{{$attr}}&nbsp;<i class="icon-info-sign"></i></li>
<li>{{$attr}}&nbsp;<i class="icon-info-sign info"></i></li>
@endforeach
</ul>
@endif

View File

@ -0,0 +1,55 @@
@if(count($requested_scopes)>0)
<label>
<b>The site has also requested some permissions for following OAuth2 application</b>
</label>
<div class="container">
<div class="row-fluid">
<div class="span6">
<div class="row-fluid">
<div class="span2">
<img src="{{$app_logo}}" border="0"/>
</div>
<div class="span10">
<h2>{{$app_name}}&nbsp;<i data-content="Developer Email: <a href='mailto:{{$dev_info_email}}'>{{$dev_info_email}}</a>.<br> Clicking 'Accept' will redirect you to: <a href='{{$redirect_to}}' target='_blank'>{{$redirect_to}}</a>" class="icon-info-sign info" title="Developer Info"></i></h2>
</div>
</div>
<legend>This app would like to:</legend>
<ul class="unstyled list-inline">
@foreach ($requested_scopes as $scope)
<li> {{$scope->short_description}}&nbsp;<i class="icon-info-sign info" data-content="{{$scope->description}}" title="Scope Info"></i></li>
@endforeach
</ul>
<p class="privacy-policy">
** <b>{{$app_name}}</b> Application and <b>Openstack</b> will use this information in accordance with their respective terms of service and privacy policies.
</p>
</div>
</div>
</div>
@endif
@section('subscripts')
<script type="application/javascript">
$(document).ready(function() {
var hideAllPopovers = function() {
$('.icon-info-sign').each(function() {
$(this).popover('hide');
});
};
$('.icon-info-sign').popover({html:true});
$(':not(#anything)').on('click', function (e) {
$('.icon-info-sign').each(function () {
//the 'is' for buttons that trigger popups
//the 'has' for icons and other elements within a button that triggers a popup
if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
$(this).popover('hide');
return;
}
});
});
});
</script>
@stop

View File

@ -1,10 +1,10 @@
@if(count($attributes)>0)
<label>
The site has also requested some personal information
<b>The site has also requested some personal information</b>
</label>
<ul class="unstyled list-inline">
@foreach ($attributes as $attr)
<li>{{$attr}}&nbsp;<i class="icon-info-sign"></i></li>
<li>{{$attr}}&nbsp;<i class="icon-info-sign info"></i></li>
@endforeach
</ul>
@endif

View File

@ -29,6 +29,7 @@
{{ HTML::script('js/jquery.validate.min.js')}}
{{ HTML::script('js/additional-methods.min.js')}}
@yield('scripts')
@yield('subscripts')
</body>
</html>

View File

@ -22,7 +22,7 @@
<img src="{{$app_logo}}" border="0"/>
</div>
<div class="span10">
<h2>{{$app_name}}&nbsp;<i data-content="Developer Email: <a href='#'>{{$dev_info_email}}</a>.<br> Clicking 'Accept' will redirect you to: <a href='#'>{{$redirect_to}}</a>" class="icon-info-sign info" title="Developer Info"></i></h2>
<h2>{{$app_name}}&nbsp;<i data-content="Developer Email: <a href='mailto:{{$dev_info_email}}'>{{$dev_info_email}}</a>.<br> Clicking 'Accept' will redirect you to: <a href='{{$redirect_to}}' target="_blank">{{$redirect_to}}</a>" class="icon-info-sign info" title="Developer Info"></i></h2>
</div>
</div>
<legend>This app would like to:</legend>
@ -50,6 +50,17 @@
$('.icon-info-sign').popover({html:true});
$(':not(#anything)').on('click', function (e) {
$('.icon-info-sign').each(function () {
//the 'is' for buttons that trigger popups
//the 'has' for icons and other elements within a button that triggers a popup
if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
$(this).popover('hide');
return;
}
});
});
$("body").on('click',"#cancel-authorization",function(event){
$form = $('#authorization_form');
$('#trust').attr('value','DenyOnce');

View File

@ -18,7 +18,10 @@ Welcome, <a href="{{ URL::action("UserController@getProfile") }}">{{Auth::user()
Sign in to <b>{{ $realm }}</b> using your openstackid
</legend>
<p>A site identifying itself as <b>{{ $realm }}</b></p>
<p>has asked us for confirmation that <a href="{{ str_replace("%23","#",$openid_url) }}">{{ str_replace("%23","#",$openid_url) }}</a> is your identity URL</p>
<p>has asked us for confirmation that <a href="{{ str_replace("%23","#",$openid_url) }}" target='_blank'>{{ str_replace("%23","#",$openid_url) }}</a> is your identity URL</p>
@foreach ($views as $view)
{{ $view}}
@endforeach
<div>
<label class="radio">
{{ Form::radio('trust[]', 'AllowOnce','true',array('id'=>'allow_once','class'=>'input-block-level')) }}
@ -41,9 +44,7 @@ Welcome, <a href="{{ URL::action("UserController@getProfile") }}">{{Auth::user()
{{ Form::button('Cancel',array('id'=>'cancel_authorization','class'=>'btn cancel_authorization')) }}
</fieldset>
{{ Form::close() }}
@foreach ($views as $view)
{{ $view}}
@endforeach
</div>
@stop
@ -59,4 +60,6 @@ Welcome, <a href="{{ URL::action("UserController@getProfile") }}">{{Auth::user()
});
});
</script>
@stop
@stop

View File

@ -69,7 +69,7 @@ use auth\CustomAuthProvider;
Auth::extend('custom', function($app) {
return new Guard(
new CustomAuthProvider(),
new CustomAuthProvider($app->app->make('auth\\IAuthenticationExtensionService')),
App::make('session.store')
);
});

View File

@ -69,3 +69,16 @@ select, input[type="text"]{
#redirect_uri{
width: 500px;
}
.popover-content{
font-size: 12px;
}
.popover {
width: auto;
max-width: 800px;
}
.info{
cursor: pointer;
}