Single sign on using SimpleSamlPhp wrapper on Laravel - php

Implementing single sign on in my laravel application. I have decided to use this plugin https://github.com/aacotroneo/laravel-saml2 which is basically a wrapper on famous SimpleSamlPhp.
I downloaded the code via composer and as per given information Remember that you don't need to implement those routes, but you'll need to add them to your IDP configuration. For example, if you use simplesamlphp, add the following to /metadata/sp-remote.php
$metadata['http://laravel_url/saml/metadata'] = array(
'AssertionConsumerService' => 'http://laravel_url/saml/acs',
'SingleLogoutService' => 'http://laravel_url/saml/sls',
//the following two affect what the $Saml2user->getUserId() will return
'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
'simplesaml.nameidattribute' => 'uid'
);
I can't find metadata/sp-remote.php, any idea? and as far as http://laravel_url/saml/acs is concerned, do I need to deploy saml on the server? because at the moment the plugin code is in vendors in laravel core architecture code hierarchy.

First some background:
There are two parts to any SAML interaction - the Identity Provider ("IDP") and the Service Provider ("SP"). The IDP is the master authenticator if you like, to which various applications (SPs) connect.
The idea is that the user visits your app, which in turn communicates as a Service Provider to the Identity Provider to get your credentials. And because multiple apps / SPs connect to the same IDP, you get the benefits of a single sign-on.
During the set-up phase, metadata configurations are swapped between the SPs and IDP to establish trust between them. This isn't user-level data -- it's application-level data that allows them to talk.
OK. So now on to your question:
The package you are using allows your Laravel app to talk to an IDP, but before it can do so you need to swap some metadata. The metadata for your app is the snippet above. This needs to go in the IDP configurations, which is where you will find this metadata/sp-remote (or more precisely metadata/saml20-sp-remote, which is where you paste this in.
If you haven't done so already, I'd recommend using [https://simplesamlphp.org/docs/stable/][1] as the IDP here as the Laravel package works with it pretty much out of the box.
One final tip: if you are using SAML2, then I found that you need to change the metadata key to refer to saml2 instead of saml above. ie $metadata['http://laravel_url/saml2/metadata'] and not $metadata['http://laravel_url/saml/metadata']

I hope this will help others. I added saml2_settings.php in the config folder.
Updated the routes:
'logoutRoute' => '/logout',
'loginRoute' => '/homepage',
'errorRoute' => '/error',
updated x509cert (publickey.cer) and privateKey
Updated 'entityId', added the url of metadata xml.
Updated singleLogoutService and rest of the required details in the saml2_settings.php file.
Added two listeners
1) for login event
2) for logout event
Updated the routes file like this:
\Illuminate\Support\Facades\Event::listen('Aacotroneo\Saml2\Events\Saml2LogoutEvent', function ($event) {
\Illuminate\Support\Facades\Auth::logout();
\Illuminate\Support\Facades\Session::save();
return redirect("login");
});
\Illuminate\Support\Facades\Event::listen('Aacotroneo\Saml2\Events\Saml2LoginEvent', function (\Aacotroneo\Saml2\Events\Saml2LoginEvent $event) {
$user = $event->getSaml2User();
$userData = [
'id' => $user->getUserId(),
'attributes' => $user->getAttributes(),
'assertion' => $user->getRawSamlAssertion()
];
// add the login for auto login based on your settings
/// REDIRECT the user to homepage
}
});

Related

How to set env in controller for dacastro4 laravel-gmail package?

I am trying to implement Gmail API for CRM based on laravel, where users can store multiple Google credentials, and using those credentials users can log in with their Google account.
I used dacastro4 laravel-gmail package, but for dacastro4/laravel-gmail package by default design, those Google credentials are stored in .env file of the laravel project.
.env
GOOGLE_PROJECT_ID=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT_URI=
`
I tried setting the .env variable in the controller constructor function, but not working.
for example,
env('GOOGLE_PROJECT_ID',$project_id);
//OR
putenv("GOOGLE_PROJECT_ID=".$project_id);
//OR
config(['GOOGLE_PROJECT_ID' => $project_id])
Also tried setting in the vendor dacastro4 laravel-gmail package, but the database model is not accessible.
How can I set multiple Google credentials from the controller?
Thank You.
You can set this data using the config() method, seeing as that's how Laravel accesses .env variables.
Create a config file for your variables:
config/gmail.php
<?php
return [
'project_id' => env('GOOGLE_PROJECT_ID'),
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect_url' => env('GOOGLE_REDIRECT_URI', '/'),
]
Then set values in your controller on the go using:
config(['gmail.project_id' => $project_id]);
and retrieve the values using:
config('gmail.project_id');

Not receiving notifications from webhook - laravel & shopify

I am creating an app for merchants and Shopify using laravel. I have configured and installed webhooks to send admins notifications when new customers are created in config/shopify.php in my app.
shopify.php
use Oseintow\Shopify\Facades\Shopify;
use Laravel\Socialite\Facades\Socialite;
use App\User;
use App\Store;
use App\UserProvider;
use Auth;
$shopifyUser = Socialite::driver('shopify')->stateless()->user();
$shopUrl = $shopifyUser->nickname;
$accessToken = $shopifyUser->token;
Shopify::setShopUrl($shopUrl)->setAccessToken($accessToken)->post("admin/webhooks.json",
[
'webhook' =>
['topic' => 'customers/create',
'address' => 'https://shopify.kast.com/webhook',
'format' => 'json'
]
]);
Route
Route::post('/webhook', 'ReceiverController#webhook');
ReceiverController
public function webhook()
{
send sms/email to admin
}
Now when I configure the webhook in the shop admin settings and send a test notification or create a customer,I receive the SMS/emails
But when I delete the webhook settings from the admin page and create a new customer for the shop, I don't receive the SMS.
Is there any error in shopify.php (webhook configuration) for my app?
PS: shop domain is founz.myshopify.com and app is hosted https://shopify.kast.com
Most probably you didn't register a webhook using access token.
If you're using Oseintow\Shopify, your shopify.php file should look like:
<?php
return [
'key' => env("SHOPIFY_APIKEY", '0f20e4692981aefb8558etrgrh72thty5'),
'secret' => env("SHOPIFY_SECRET", 'fgghg55666585f1a09214drtg56454g')
];
Let it just holds your public app's credentials.
It looks like you haven't registered any webhook using access token. When you register a webhook using shopify admin, that webhook will be fired to all application. Don't do that unless you know what you're doing.
Instead try registering the same webhook using Postman with your access token and see if it is working. And then use your programming skills to automate it. Cheers!
There Can be two main reason for that.
1) Webhook could not created successfully. to check this Please make API call with
GET Request
GET /admin/api/2019-10/webhooks.json
If you did not get your desired webhook in the response please create it
2) In Laravel spacific development,you need to bypass VerifyCsrfToken middle-ware for your webhook route
as Laravel will not allow & blocks cross site requests default.to do so please follow below steps.
Go to app/http/middleware/VerifyCsrfToken & add your route in the $except array.
As Example :
protected $except = [
'/app/uninstalled-webhook-shopify/*',
'/products/create-webhook-shopify/*',
];

Request data from Laravel API into wordpress

I am working on a project on laravel 5.1, and i want to make it as a RESTFUL api so later we can use the same code and request data from mobile apps or other websites. The project is in its initial stages and i want to make it correct right from the beginning.
Suppose i have a simple route which is calling a the dashboard method on the AdminController. So after logging in it redirects the admin to the dashboard page with some data.
/******************** Laravel Project ***********************/
//Routes.php
Route::group(['middleware' => 'auth'], function () {
Route::get('dashboard', 'AdminController#dashboard');
});
// AdminController
public function index(){
$data = 'Some Data';
return view( 'superadmin.dashboard')->with('data', $data );
}
Now i want to get the same data in a wordpress project. How will i use this api to just fetch the data variable (without the view) ? I dont want to create another method for that, is there any way i can use the same function to fetch data as a json?
I read in another forum that we can access all the data as a REST like this. But this is not working.
http://admin:admin123#example.dev/dashboard
As always appreciate your help :)
Personally, I would create an application that is the API. In your case this is your Laravel application.
Then I'd make HTTP requests to the API from Wordpress, or a mobile application.
I find returning JSON from the API is easier to work with. Laravel makes this easy:
return Response::json(array(
'username' => 'superadmin',
'role' => 'admin',
'friends' => array(
'2345',
'884'
)
));
Also, don't send your username and password like that. HTTP auth is insecure. http://adrianotto.com/2013/02/why-http-basic-auth-is-bad/
I tend to use OAuth to secure my APIs.

Best practice of writing custom authentication mechanism on Yii2

I need to write a very specific authentication for my web application. There is API on the side which accepts login + password pair and returns the result (and, a token). I don't want to store any login information on the Yii2 side besides a login token i've got from API. And this must be the only way i auth my clients (so i don't use OAuth-like application).
What is the best practive to override "classic" code in Yii2? Just use filters and modify User model?
Example:
First, i recieve a token and save it somewhere for a session:
$token = GatewayAPI::login($user, $password);
Then, every internal request i do will look like this:
$result = GatewayAPI::addPosition($token, $data);
So, i don't have any database to work with, just cache and memory. Almost everything is handled on API side.
My task is to implement login check - if token is recieved from API - then it's considered as a success. And to store that token for use within current session (probably in memcache, it must not be opened to public).
As a matter of fact Yii2 does not require login/password anywhere.
You don't need to modify or extend User model if you mean \yii\web\User.
You need to create your own class implementing IdentityInterface and set this class as userIdentity in your config components->user->identityClass:
[
'components' => [
'user' => [
'class' => 'yii\web\User', // not necessary, this is by default
'identityClass' => 'my\namespace\User'
]
]
]
There are 5 methods in the interface and they are not about login/pass. This class of yours may store in your db everything you want.
For example you may copy any of popular user modules to your project, remove everything related to storing and searching by login/pass from that User model and add your API functionality - and it will work.
UPD.
Your added functionality will look like this:
$token = GatewayAPI::login($user, $password);
$user = \my\namespace\User::findOne(['token' => $token]);
Yii::$app->user->login($user);

How can I ensure users are logged in before accessing the Kohana Userguide & API Browser?

I'm realizing that I have a bit of a security hole on my sites, specifically when it's in development mode.
The problem is that you can access the User Guide / API Browser without being logged in. Now the User Guide isn't a big deal, but the API Browser is a bit of a concern as all of my code is visible through it. I'm a bit concerned because some of my development sites are available publicly so others can access then (although they've blocked from being indexed).
I've taken a look at Controller_Userguide and it isn't extended from another controller as other controllers as (such as template). Instead it's the final controller. This being the case doesn't allow me to extend the controller at and something to the before() method.
I thought of excluding the module when users aren't logged in, but I can't because the auth module isn't loaded yet.
I am already only including the user guide (and other modules) when on the development site, so this helps, but I wouldn't call this security.
Any other ideas on how to accomplish this?
Is there any reason to allow logged in users to view the userguide?
I would add something like this to the bootstrap
//Add modules that are only relevant to local development
if(Kohana::$environment == Kohana::DEVELOPMENT)
{
Kohana::modules(array_merge(Kohana::modules(), array(
'codebench' => MODPATH.'codebench', // Benchmarking tool
'userguide' => MODPATH.'userguide', // User guide and API documentation
'unittest' => MODPATH.'unittest', // Unit testing
)));
}
then any public facing sites just change the $environment to something else like STAGING or TESTING
Kohana::$environment = Kohana::TESTING //In the bootstrap file
Alternatively
SetEnv KOHANA_ENV TESTING //to the .htaccess file
OPTION 2 - Load the auth module first
I've just tried this, seems to work for me. In your bootstrap file, load the modules like this:
/**
* Enable modules. Modules are referenced by a relative or absolute path.
*/
Kohana::modules(array(
'auth' => MODPATH.'auth', // Basic authentication
'cache' => MODPATH.'cache', // Caching with multiple backends
'database' => MODPATH.'database', // Database access
'image' => MODPATH.'image', // Image manipulation
'orm' => MODPATH.'orm', // Object Relationship Mapping
));
//Add modules that are only relevant to testing
if(Kohana::$environment == Kohana::DEVELOPMENT and Auth::instance()->logged_in())
{
Kohana::modules(array_merge(Kohana::modules(), array(
'codebench' => MODPATH.'codebench', // Benchmarking tool
'userguide' => MODPATH.'userguide', // User guide and API documentation
'unittest' => MODPATH.'unittest', // Unit testing
)));
}
Option 3 - Isolating the API browser
There is a config option in the userguide config:
// Enable the API browser. TRUE or FALSE
'api_browser' => TRUE,
which you could set to false if the user isn't logged in, similar to the loading of the modules above. The is currently a bug with it that crashes the userguide template because it can't find the route to the API.
IF you want to go to the effort to get this to work (until there is an update), then copy /modules/userguide/views/userguide/template.php to /application/views/userguide/template.php and then replace lines 28 to 30 with this:
<li class="api">
<?php echo __('API Browser') ?>
</li>
and put this in /application/config/userguide.php:
<?php defined('SYSPATH') or die('No direct script access.');
$config = array();
if(Kohana::$environment == Kohana::DEVELOPMENT and Auth::instance()->logged_in())
{
$config['api_browser'] = FALSE;
}
return $config;

Categories