Cakephp authentication plugin how can I add difference session key? - cakephp

In present scenario after login in front end if I visit /admin prefix. It's accessing admin panel. Here I'm using difference model for login. For front end I'm using users table and for admin I'm using admin_users table. I have made this changes in application.php like
if($request->getParam('prefix') == 'Admin')
{
$identifierSettings += [
'resolver' => [
'className' => 'Authentication.Orm',
'userModel' => 'AdminUsers',
],
];
}
How could I add difference session key for admin and front-end ?

In Authentication.Session
Set your session key for admin 'sessionKey' => 'Auth.admin'
Note : Default sessionKey is Auth
Details : https://book.cakephp.org/authentication/2/en/authenticators.html#session

Related

Yii2 SaaS Authentication

I'm Developing SaaS application using Yii2 with separate DB architecture. I have a problem in login to system by using tenant database.
I need to get tenant database details from common db and establish tenant db connection after entering company id, username and password in login form.
This is my index.php file.
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require(__DIR__ . '/_protected/vendor/autoload.php');
require(__DIR__ . '/_protected/vendor/yiisoft/yii2/Yii.php');
$config = require(__DIR__ . '/_protected/config/web.php');
(new yii\web\Application($config));
if (Yii::$app->session->get('company')) :
$appConnection = \app\models\Userdbconnections::find()->where(['company_id' => Yii::$app->session->get('company')])->one();
\Yii::$app->dbDynamic->dsn = "mysql:host=localhost;dbname=$appConnection->dns";
\Yii::$app->dbDynamic->username = $appConnection->user;
\Yii::$app->dbDynamic->password = $appConnection->password;
\Yii::$app->dbDynamic->charset = 'utf8';
endif;
Yii::$app->run(); // this will run the application
?>
From login function after post logging data, auth controller is like this
if ( Yii::$app->request->post() ){
$connection = \app\models\Userdbconnections::find()->where(['company_id'=>Yii::$app->request->post('LoginForm')['company']])->one();
$_SESSION["dsn"] = $connection->dns;
$_SESSION["user"] = $connection->user;
$_SESSION["pass"] = $connection->password;
$_SESSION["company_id"] = $connection->company_id;
// Yii::$app->db()->close();
Yii::$app->set('db', [
'class' => '\yii\db\Connection',
'dsn' => "mysql:host=localhost;dbname={$connection->dns}",
'username' => $connection->user,
'password' => $connection->password,
]);
$model_db = new LoginForm();
$model_db->load(Yii::$app->request->post());
$model_db->login();
$_SESSION["login_user"] = $model_db->username;
}
User Management Module called in web.php under component part as following
'user' => [
'class' => 'webvimark\modules\UserManagement\components\UserConfig',
// Comment this if you don't want to record user logins
'on afterLogin' => function($event) {
\webvimark\modules\UserManagement\models\UserVisitLog::newVisitor($event->identity->id);
},
'enableSession' =>true,
],
Each model file consist with following code
public static function getDb()
{
return Yii::$app->get('dbDynamic');
}
So now i'm able to log from tenant db. But after checking i noticed User Management part, creation, role creation all these linked to common db when ever i logged in to tenant db. Is there anything I misses in here?
One way to do it is having two connections. One connection for common details coming from common database (user details, tenant db he belongs to, et al). This connection is static, so must be defined in the config (or just rename what comes with Yii Basic app to something like commonDb or use it with just db name.
Another one will be connected to the specific user tenant database. This will be dynamic and details must change. There are many ways to do it. One is to defined it before app runs. See this forum post for details. Another would be setting it up before request using Yii Container and call it inside your models et al. There might be other ways too.
So the process goes like this
User logs in. Connection used is the common connection (let it be defined as Yii::$app->db).
Using details from (1) create the dynamic connection.
Use the connections where needed (in models, Active data providers or Query builders)
Here is untested example
//common database with user login
----------------------------------
| id | name | tenant_database |
----------------------------------
| 1 | Stef | company_a |
----------------------------------
Note here that Yii::$app->user->identity will hold model class that wraps this table
//config/web.php
return [
'components' =>[
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=common_db',
'username' => 'username',
'password' => 'password',
'charset' => 'utf8',
]
'userDb' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=${database}',
'username' => 'username',
'password' => 'password',
'charset' => 'utf8',
]
]
//set it up before request
'on beforeRequest' => function ($event) {
if(Yii::$app->user->isGuest)
{
// redirect user to Login page
}
else
{
$currentDSN = Yii::$app->userDb->dsn;
$tenantDB = Yii::$app->user->identity->tenant_database;
Yii::$app->userDb->dsn = str_replace('${database}', $tenantDB, $currentDSN);
}
},
]
Then in model class override getDb as follows
class Data extends \yii\db\ActiveRecord
{
public static function getDb()
{
return Yii::$app->userDb;
}
}
Then user it as in:
$data = Data::find()->all();
$data = Yii::$app->userDb->createCommand('SELECT * FROM data')->queryAll();
UPDATE
Since OP wants the data to be in tenant db, the only way is having each tenant to have special Tenant Code, and on login page you will provide inputs for Tenant Code, Username and Password. Then
1. Query the common table for the database name associated with that code
2. Change Connection details as shown above
3. Login with TenantLogin class that uses tenant connection as shown above with Data class.
The new common table
----------------------------
| code | tenant_database |
----------------------------
| 12333 | company_a |
----------------------------

Cakephp 3 HTTP Basic Authentication login issue

I am using basic authentication in my project to access Api. In ApiController, I added below code in beforeFilter:
$this->Auth->config('authenticate', [
'Basic' => [
'fields' => ['username' => 'username', 'password' => 'api_key'],
'userModel' => 'Users'
]
]);
So from chrome postman application, I am sending post request with basic auth credentials. for example like below:
So when I send a request, I get unauthorized error back.
you are sending a post request with a 'password' field
Your application is expecting a 'api_key' field that would contain the password.
I think you missed this one script in your model entity.
use Cake\Auth\DefaultPasswordHasher;
protected function _setPassword($password)
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
}
Put this one in Model/Entity/User.php

When user signs out from SAML Service provider, it does not logs out user from the Salesforce Identity provider

I am doing SSO between Salesforce and Drupal using Salesforce as Identity provider and Drupal as Service provider using SimpleSAMLPHP. When user signs out from the Drupal web site, it is not getting logged out from the Salesforce.
To solve the issue, I used 'SingleLogoutService' as https://salescloud--OptusFull.cs13.my.salesforce.com/secur/logout.jsp in Drupal Service provider. But the issue here is that the log out process now ends up with Salesforce login page and I did not find a way to redirect it to the Drupal site. Is there any way to redirect user back to Drupal site.
Please find the metadata information from metadata/saml20-idp-remote.php
$metadata['https://salescloud--OptusFull.cs13.my.salesforce.com'] = array (
'entityid' => 'https://salescloud--OptusFull.cs13.my.salesforce.com',
'contacts' =>
array (
),
'metadata-set' => 'saml20-idp-remote',
'expire' => 1739182548,
'SingleSignOnService' =>
array (
0 =>
array (
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
'Location' => 'https://salescloud--OptusFull.cs13.my.salesforce.com/idp/endpoint/HttpPost',
),
1 =>
array (
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
'Location' => 'https://salescloud--OptusFull.cs13.my.salesforce.com/idp/endpoint/HttpRedirect',
),
),
'SingleLogoutService' => 'https://salescloud--OptusFull.cs13.my.salesforce.com/secur/logout.jsp',
'ArtifactResolutionService' =>
array (
),
'keys' =>
array (
0 =>
array (
'encryption' => false,
'signing' => true,
'type' => 'X509Certificate',
'X509Certificate' => 'MIIErDCCA.....',
),
),
);
There's a setting in Salesforce that controls the page where the user lands after logout via the identity provider. The setting is under Security Controls > Single Sign-On Settings -> - Identity Provider Logout URL . This setting will only appear in your SF production org if you have My Domain turned on.
Salesforce does not support Single Logout Service
(Initiated or not in the IdP).
If you set as SingleLogoutService the Salesforce normal logout service, you will end at the Salesforce login page and not LogoutResponse will be sent to the SP(drupal). Also, if you directly Logout from Salesforce, no LogoutRequest will be sent to the SP(drupal).

cakephp auth component, use two models

My site has a public section for employees and back end for admin. It uses 2 different models, Employee and Admin.
I want to use Auth component for employee login and admin login. I know how to setup Auth component to use a Model other than default User model. But can i have auth component use 2 models, one for Employee authentication and other for Admin authentication? I am using admin_ prefix routing.
Is this possible? I searched but all i could found was tutorials on howto make Auth component use models other than User model.
Please advise!
EDIT
I use separate login forms for admin login and employee login. Both use the employee controller, but separate actions.
http://api.cakephp.org/class/auth-component
check the property authenticate, your answer is there!
and more :
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html.
Look at authentication handlers!
Here is an example directly from cake page
<?php
// Basic setup
$this->Auth->authenticate = array('Form');
// Pass settings in
$this->Auth->authenticate = array(
'Form' => array('userModel' => 'Member'),
'Basic' => array('userModel' => 'Member')
);
Just put something else instead of Form and Basic and associate the good Model
Considering you are using two radio buttons for Employee and Admin. Then you can use the following code into the login method.
function login()
{
if ($this->request->is('post'))
{
$logged_in = false;
$login_type = $this->request->data['User']['login_type']
if ($login_type == 'Admin')
{
$this->Auth->authenticate = array('Form' => array('userModel' => 'Admin' ));
}
else //if ($login_type == 'Employee')
{
$this->Auth->authenticate = array('Form' => array('userModel' => 'Employee' ));
}
$this->Auth->constructAuthenticate();
if ($this->Auth->login())
{
$logged_in = true;
/*.... Do what you want............*/
}
}
}

CakePHP + Facebook

I am trying to implement facebook Connect to my cakephp Application. i am using Nick's Facebook Plugin.
I wanna implement it this way
When a user Visits the Site he should be able to login via Registration on the site or Facebook Connect
Existing users should be able to connect their account to their FB account
People who first time login to the site using FB Connect and dont have an account on the site. should be redirected to a page where they have to enter details to complete the profile.
What i have done -
I have followed the instruction of Nick to implement it and when i click Login - it connects to my app. but i dont understand how to create a username and password associated with the Fb Connect Id. and user it against the FB token.
Apparently I'm doing the same thing a little before you... ;-)
Here's a method for Facebook login I'm using (slightly redacted and annotated):
public function facebook($authorize = null) {
App::import('Lib', 'Facebook.FB');
$Fb = new FB();
$session = $Fb->getSession();
// not logged into Facebook and not a callback either,
// sending user over to Facebook to log in
if (!$session && !$authorize) {
$params = array(
'req_perms' => /* the permissions you require */,
'next' => Router::url(array('action' => 'facebook', 'authorize'), true),
'cancel_url' => Router::url(array('action' => 'login'), true)
);
$this->redirect($Fb->getLoginUrl($params));
}
// user is coming back from Facebook login,
// assume we have a valid Facebook session
$userInfo = $Fb->api('/me');
if (!$userInfo) {
// nope, login failed or something went wrong, aborting
$this->Session->setFlash('Facebook login failed');
$this->redirect(array('action' => 'login'));
}
$user = array(
'User' => array(
'firstname' => $userInfo['first_name'],
'lastname' => $userInfo['last_name'],
'username' => trim(parse_url($userInfo['link'], PHP_URL_PATH), '/'),
'email' => $userInfo['email'],
'email_validated' => $userInfo['verified']
),
'Oauth' => array(
'provider' => 'facebook',
'provider_uid' => $userInfo['id']
)
);
$this->oauthLogin($user);
}
This gives me an array with all the user details I could grab from Facebook and invokes ::oauthLogin, which either logs the user in with the given information or asks the user to fill in missing details and/or creates a new user record in the database. The most important part you get from the Facebook API is the $userInfo['id'] and/or email address, either of which you can use to identify the user in your database. If you're using the AuthComponent, you can "manually" log in the user using $this->Auth->login($user_id), where $user_id is the id of the user in your own database.
private function oauthLogin($data) {
$this->User->create();
// do we already know about these credentials?
$oauth = $this->User->Oauth->find('first', array('conditions' => $data['Oauth']));
if ($oauth) {
// yes we do, let's try to log this user in
if (empty($oauth['User']['id']) || !$this->Auth->login($oauth['User']['id'])) {
$this->Session->setFlash('Login failed');
}
$this->redirect('/');
}
// no we don't, let's see if we know this email address already
if (!empty($data['User']['email'])) {
$user = $this->User->find('first', array('conditions' => array('email' => $data['User']['email'])));
if ($user) {
// yes we do! let's store all data in the session
// and ask the user to associate his accounts
$data['User'] = array_merge($data['User'], $user['User']);
$data['Oauth']['user_id'] = $user['User']['id'];
$this->Session->write('Oauth.associate_accounts', $data);
$this->redirect(array('action' => 'oauth_associate_accounts'));
}
}
// no, this is a new user, let's ask him to register
$this->Session->write('Oauth.register', $data);
$this->redirect(array('action' => 'oauth_register'));
}
Look no further. Here is an excellent article that'll guide you all the way through (minus any readymade plugins):
Integrating Facebook Connect with CakePHP's Auth component
Simply follow the approach described in there.
Cheers,
m^e

Resources