Symfony2 User Provider from RESTful webservice - php

I'm trying to create a simple User Provider in Symfony 2, but i have no idea how this is supposed to work with a webservice. Authentication in my company is handled by a RESTful webservice, with various routes:
POST /user, GET /user, POST /login
So, when creating a Symfony 2 app, my user provider must consult the web service in order to verify credentials and permissions. Is this possible? Is there a bundle for something like this?
Also, how can i achieve a good performance on this? The way the Symfony user provider works, i guess it will consult the web service on EACH request, in order to get the user data. Can this be avoided?

There are two great bundles you can use:
For dealing REST reqs try FOSRestBundle (https://github.com/FriendsOfSymfony/FOSRestBundle),
And for User Provider try FOSUserBundle (https://github.com/FriendsOfSymfony/FOSUserBundle)
Those are good bundles, and you can get good documentation, too.

You can do this by implementing an authentication provider and user provider, each will handle the call to your web service for auth.
You could have a client class to make the web service calls, and cache the response somewhere to avoid having it called every request, although the need for that depends on how slow the web service is.
I have done this approach so can fill in the gaps if you need.

Related

How to Implement OAuth correctly in API with Laravel Passport?

I'm trying to create an API and use it in my own applications (web application and native mobile app) and make it available for third-party applications ( this is for future purposes).
I've read the Laravel Passport documentation, and I have some doubts that hopefully someone could help me with it.
As a developer, I always try to find the best and correct way to implement my projects and find the appropriate packages for the purposes of the projects.
Brief explanation of what I want to do:
I want to create an API and I will consume my own API in my web and mobile applications, my API has two endpoints for register and login for students and teachers. They can login with their email and password. Each user type has its own information. A teacher can have a CV, and students can see teachers' CV( the whole creating and reading CV's are handling in my API ), and they both user types can communicate with each other. I'm using laravel 6.x version to build my API. We have a section for developers in our subdomain which developers can register accounts and get/buy an access token to make requests to my API and use it, on the other hand, I want when students or teachers login to their accounts the API generates an access token for that user so then my application can use that token and pass that in every requests to make users be authenticated to access their private resources like their Dashboard as we know API's are stateless and we can't use sessions to store user credentials, so we need an access token for that.
Can Laravel Passport generate the both Developer access token, and User( teacher or student) access token?
Is it correct to use OAuth in here to develop my API?
Or can I just use tymondesigns/JWT package for these purposes?
I have to say that I'm new to Oauth and API based applications. I've read some articles about Oauth, and I'm a little bit familiar with Oauth terminology, but still, I don't know how to implement this project correctly.
So here are my questions:
What is exactly Oauth server? Is it my own server that is hosted by API?
After Laravel Passport configuration and database migration, Laravel Passport created some tables in my database, I would be really appreciated if you could tell me what is the purpose of each tables? table names are failed_jobs, oauth_access_tokens, oauth_auth_codes, oauth_clients, oauth_personal_access_clients, oauth_refresh_tokens.
I've configured my Laravel application to use the Laravel Passport and I created two Routes in my api.php file
Route::post('login','API\Auth\UserAuthController#login');
Route::post('register','API\Auth\UserAuthController#register');
and then, I created the UserAuthController.php file and wrote the login and register methods. They are working without any problem. After a user registers or login into their account, my code will generate a personal access token.
$token = $user->createToken('authentication')->accessToken;
and then students or teachers can access to the private resources of their own with this access token. Is it right to create a personal access token for my two types of users? What is exactly a personal access token?
I just know you can pass it into request header, and the server will authorize you to access private resources. what I mean by private resources is the endpoints which are protected by API middleware like this:
Route::post('/update-info','API\Auth\UserAuthController#update')->middleware('auth:api');
Am I doing right to create a personal access token when teachers and students login to their account or I should do another way to handle it?! this way works, but I'm looking for correct way if there is anything else.
The weird thing here is Laravel Passport create a token every time users login and it doesn't check if they have already created token or not? If someone can access the API endpoint, they can make a post request to /login endpoint and create a lot of tokens. Is it a problem? How to fix it?
When I create a personal access token I need to pass an argument to createToken($arg) method, and it stores in oauth_personal_access_clients table. what is the purpose of this? Is it just for Laravel Passport purpose, or maybe I need it in the future?
I have some endpoints which are not protected by auth:api middleware, for example, every user visit my application they can search for teachers name and lessons and ... , it's not necessary to make them login or register first. These endpoints are accessible to everyone in my application, and they are free to search and advance search for some information. My question is if I make it accessible to everyone, how can I protect these endpoints that only my first-party app and third-party app can access them. I mean I don't want people to access them by command line or postman or some kind of these tools without access token, I want to protect these endpoints from attackers not to make a huge requests to make my server down. How can I protect this kind of endpoints? I know I can limit requests per minute, but I don't know how much limit it? Is there any other way?
I see there is a term called clients in Oauth terminology, as I understand clients are the applications like web applications or native mobile app and any other applications that use my API are called clients. Am I right? And I think this is for third-party application authentication. I'm a little bit confused after reading Laravel Passport documentation about clients, and when I configured the Laravel Passport, it generates two clients and stored them in database. Do I need to create a client for my Applications?! How Can I ignore authorization flow just for first-party applications?
After Laravel Passport configuration, now I can see it generates some default route for clients.
/oauth/clients
/oauth/clients/{client-id}
/oauth/authorize
/oauth/token
What is the usage of these routes?! do I need them to create my first-party applications?
As I said the future purpose of this application is to make the API accessible by third-party applications, I have to create a web page that developers register an account and get/buy a token to access my API. is it possible to do it with Laravel Passport or I should write my own logic to make it work? Do I need to create a client for my third-party clients?
Thanks a lot for your help <3
It's going to take too long for me to answer each of your questions in depth, so I've
tried to link to the relevant sections in the RFC for further reading.
Essentially, I would recommend for you to use the password credentials grant flow for your first-party clients (your mobile app and web app). One of the clients that
Laravel would have created for you, would have been the "Laravel Password Grant Client" and its
documentation is available here.
You would still need to define your own "register" route, but you can use the oauth/token route
instead of your own /login route.
What is exactly Oauth server? Is it my own server that is hosted by API?
The OAuth server would be your server that is running Passport. Or in the official
terminology according to the RFC, the
OAuth server/Passport server would be called the "authorization server."
In your case, the "resource server", which your API that serves your content, would be
the same server as the "authorization server."
After Laravel Passport configuration and database migration, Laravel Passport created some tables in my database, I would be really appreciated if you could tell me what is the purpose of each tables? table names are failed_jobs, oauth_access_tokens, oauth_auth_codes, oauth_clients, oauth_personal_access_clients, oauth_refresh_tokens.
The failed_jobs table is not directly related to Passport. It's related to Laravel's queues. See Dealing With Failed Jobs.
The rest of the tables are all there so that Passport can keep track of the clients and codes it has created.
oauth_clients: See the RFC clients section.
oauth_access_tokens: See the RFC access tokens section.
oauth_auth_codes: See Authorization Code Grant.
oauth_personal_access_clients: Personal access clients don't seem to be part of the official specification, but it is basically a client for when a user wants to get an access token directly, instead of going through an app or website. Usually this would be a developer who wants to get an access token to be able to call API endpoints on their own account.
The personal access clients table stores clients that were specifically created for this purpose. Usually there would
only be one of them.
oauth_refresh_tokens: See the RFC refresh tokens section.
Is it right to create a personal access token for my two types of users? What is exactly a personal access token?
Every user would need to get their own access token, but not a personal access token.
Personal access tokens are just access tokens that were created specifically for users who wants to generate
and use the access token themselves. In Laravel Passport, specifically, they are access tokens
which are linked to the "Laravel Personal Access Client."
So in your case, your server would create "normal" access tokens for users and not "personal" access
tokens.
Am I doing right to create a personal access token when teachers and students login to their account or I should do another way to handle it?! this way works, but I'm looking for correct way if there is anything else.
See answer to question 3.
The weird thing here is Laravel Passport create a token every time users login and it doesn't check if they have already created token or not? If someone can access the API endpoint, they can make a post request to /login endpoint and create a lot of tokens. Is it a problem? How to fix it?
I don't think this is a problem. The oauth/token route is rate-limited. You can rate-limit it even more.
You can also listen to events and delete or revoke tokens
if want to limit the amount of tokens there may be for a single user.
When I create a personal access token I need to pass an argument to createToken($arg) method, and it stores in oauth_personal_access_clients table. what is the purpose of this? Is it just for Laravel Passport purpose, or maybe I need it in the future?
This table is just for Laravel Passport. It can also be of use for when you want to audit or debug something later on.
The row that you see in the oauth_personal_access_clients table, was created when you ran php artisan passport:install.
When you call createToken, a new row is inserted into oauth_access_tokens.
I have some endpoints which are not protected by auth:api middleware, for example, every user visit my application they can search for teachers name and lessons and ... , it's not necessary to make them login or register first. These endpoints are accessible to everyone in my application, and they are free to search and advance search for some information. My question is if I make it accessible to everyone, how can I protect these endpoints that only my first-party app and third-party app can access them. I mean I don't want people to access them by command line or postman or some kind of these tools without access token, I want to protect these endpoints from attackers not to make a huge requests to make my server down. How can I protect this kind of endpoints? I know I can limit requests per minute, but I don't know how much limit it? Is there any other way?
Yes, you'll have to do rate-limiting. You'll have to experiment and see what works for you.
I see there is a term called clients in Oauth terminology, as I understand clients are the applications like web applications or native mobile app and any other applications that use my API are called clients. Am I right? And I think this is for third-party application authentication. I'm a little bit confused after reading Laravel Passport documentation about clients, and when I configured the Laravel Passport, it generates two clients and stored them in database. Do I need to create a client for my Applications?! How Can I ignore authorization flow just for first-party applications?
Yes, clients are like web applications, mobile apps, etc. Usually you would have a new
client for every mobile app, web app, CLI, etc., but in addition to those apps, Laravel defines
the "Password Grant Client" and the "Personal Access Client" clients for you which have
specific purposes.
You can use the Laravel Password Grant Client for
both of your applications since they're first-party applications.
You can ignore the authorization flow for first-party applications by using the
/oauth/token route that is provided for
password grant clients.
The RFC section about the password credentials flow is available here.
You can read more about how the RFC defines clients here.
What is the usage of these routes? do I need them to create my first-party applications?
Needed for first-party applications:
/oauth/token
Not needed for first-party applications:
/oauth/clients: this is for a third-party developer to see which clients they have created.
/oauth/clients/{client-id}: for a third-party developer to update one of their clients.
/oauth/authorize: this route will be called by a third-party developer to start the
authorization grant flow with their client ID and secret.
You can read more about the above routes under the "JSON API" section in Managing clients.
As I said the future purpose of this application is to make the API accessible by third-party applications, I have to create a web page that developers register an account and get/buy a token to access my API. is it possible to do it with Laravel Passport or I should write my own logic to make it work? Do I need to create a client for my third-party clients?
Laravel Passport provides Vue components that you can use so that developers will be able to create clients. You can either use these components or you can create your own frontend and call
the JSON API routes from your own frontend.
Keep in mind that OAuth was designed originally for when third-party apps needs to access things on behalf of a user. So instead of getting access tokens, third-party apps will get a client ID and client secret and they will need to go through one of the authorization grant flows for each user that they want to act on behalf of.
If you're never going to have third-party apps that need to act on behalf of users, it might be worth considering other protocols like mentioned in the comments.

Searching for an way on how to have several services that login to an centralized login service in Symfony

I was already looking for quite some time for my issue:
have Several Independend Apps implemented in Symfony
Each uses an centralized API
Login should be handled by an own central Application
My Idea is
domain security.xxxxxx.xxx handles the login form and app
domain frontend.xxxxxx.xxx handles the working customer stuff
domain cms.xxxxxx.xxx is the non loged in users stuff
domain backend.xxxxxx.xxx handles staff administration stuff
domain support.xxxxxx.xxx handles user support related stuff
domain api.xxxxxx.xxx handles the central database related stuff for internal and third party applications
domain reg.xxxxx.xxx handles new user registrations
domain job.xxxxxx.xxx handles the job worker stuff
domain monitoring.xxxxx.xxx handles the monitoring of app data etc.
the main idea is that each system is handles by an unique server.
All are connected within the same network but each have different resources and services connected to it.
I tried to use lightSaml for symfony. But don't get the point in how to implement the server component for providing identities.
The security should be provider and authentication interface.
Kind of handling like my.atlassian.net.
This is an Service like I would love to implement.
Any hints are appreceated.
SingleSignOn can ba achieved in many ways and protocols:
SAMLv2
Oauth2
JWT
OpenID
etc
There is two considerations:
Work with tokens
Work with users
For business constraints I could not use a third party provider (Auth0, Okta, etc) which I really encourage.
Implementations: https://en.wikipedia.org/wiki/List_of_single_sign-on_implementations
Work with tokens in symfony
You store the access and refresh token (It may change the name on each implementation). This has the limitation that as the Symfony app is not constantly running only when you have a request you have to reload/refresh the user per request (Request to the Identity Provider server).
Benefits:
Single sign out as once you logout to the Identity Provider you invalidate the sessions.
Risks:
You will get a request to the Identity Provider for each request in your app.(You can make workarounds there it is a Symfony implementation limitation)
Working with users
You authenticate and authorize the user on the Identity provider and create a user in the microservice you have.
Benefits:
Full control of the user data you store. Once authenticated you do not need access to the identity provider.
Risks:
Once you logout of your app if you have not logged out from your SSO/Identity provider the user will automatically logged in back.
You have to keep user details in sync or do not allow the user to update their personal details that comes from the Identity provider in your microservice.
My case: OAuth2
I've personally choose working with users on the symfony services as I want to have more freedom on how I store the user details, which details I store and keep most of the traffic on the service.
Ideally I wanted to use SAMLv2 but I could not find any solution that I was willing to carry over for a long time implemented in PHP, there is many in JAVA.
Technical stack on the Identity Provider
Symfony 2.7 (We have planned to upgrade but it is not a priority now)
FOSOAuthServerBundle : https://github.com/FriendsOfSymfony/FOSOAuthServerBundle
MySQL
MsSQL
Technical stack on the Microservice
Symfony 3.4
MySQL
FOSUserBundle
HWIOAuthBundle https://github.com/hwi/HWIOAuthBundle
If you decide to work with OAuth2 I recommend you this guide: https://alexbilbie.com/guide-to-oauth-2-grants/

Using external data in Laravel 5.5

I'm building a site that has to display data collected from an external web service. This service provides multiple data endpoints that are all authenticated against via OAuth.
Rather than each view having to hit an internal method to generate this data (and login to the external service each time) it seems like it'd be much better to create a singleton that will (lazy) connect to the data provider service when a view needing the data is first loaded, and then the various methods supporting the views could just call this same service provider to get the data.
Would this be best in the Laravel world as a service provider? As a helper class with a singleton? Or some other way?
Your Laravel application boots from scratch every time it receives a request (you can cache objects from a previous request, but not an instantiated service), so it won't be possible to create a service that keeps running authenticated between requests (at least with PHP).
It's not uncommon to create a service and authenticate once per request.
That being said, you can create a service and bind it to the container using $app->bind() or $app->singleton().
Docs about it here: https://laravel.com/docs/5.5/container

Implement SAML 2.0 SSO different Idps

My website is used by multiple companies. These companies want to implement SSO. So they log into their company portal and click a link to my website. They go to my website's home page without logging in. My website is in php. The different companies can have their website in any language. We want this to be as general as possible so all companies can use it. It also needs to be secure for obvious reasons and also because we are a health company with phi.
I've read through a lot on simpleSAMLphp, but I'm just not sure if I'm right about how to implement this.
Do I just set up my website as an SP with simpleSAML and say to other companies "this is what I use make yourself an Idp and send me the correct data" ? Is there another way to go about this ?
Well, if you wanna provide a good service, guess you would have to support multiple SSO protocols, and let the clients choose. Beside SAML there are OAuth OpenID Connect and JWT I would mention as relatively simple and well adopted. I find JWT especially simple and easy to use.
Regarding SAML PHP implementation, I have tried with simpleSAML but it turned out to be too complicated to integrate it into an existing app. I prefer the lightSAML library, which is actually v2 of aerialship/lightsaml, especially because my app was in Symfony and lightsaml had a security bundle.
Yes - pretty much.
You send the companies your SP metadata and they import it and then they send you their IDP metadata and you import it.
The trick is the "primary key" i.e. how does the user in another system match a user in yours. NameID is usually used for this and it can have a number of formats.
Again, this is all in the metadata.
Another very useful part of being the Service Provider (SP) in a SAML integration, is to have a IdP Discovery Service. Since each one of your partners will exchange metadata with your organization, each is essentially a point-to-point SAML connection. The IdP Discovery Service uses something in the request to identify the partner and invoke a SAML SP-Initiated SSO transaction. One of the common strategies is to use URL naming such as yourpartner.company.com. Then the IdP Discovery Service detects the subdomain "yourpartner" in the URL and then invokes the proper SP transaction. There are other strategies, but I find this one works best for most organizations.

symfony working with Web Service

I am working in symfony. I am retrivind data from a web service.
Currently I am using "Listener" to get data using web service. Is it wring way to do through listeners?
Is there any concept of Models in symfony to get data using web service? rather than calling web service from listener!
Actually a listener isn't something that would fit your case. You need a regular service, because listeners are supposed to react to Symfony domain events.
On creating services, you should read the official documentation (though if you've created an EventListener then most parts of the manual would be familiar to you).
If you're wrapping a foreign API then you should definitely do some research on whether the API is already wrapped (packagist.org is a good start: here's a wrapper for Twitter's API for example). If it's not, then it's up to you to pick an HTTP client to communicate with the service, and wrap its API into a PHP class that you would then expose in your service.
To understand how exactly you want to do this, try searching Packagist for Symfony bundles that wrap some APIs. Here's a Foursquare API bundle that uses an abstracted client library for example. Note that it depends on Guzzle HTTP client, and also take a look at the Guzzle Client class.
Also, here's Google's official API client for PHP. You could grab some ideas from there, too.

Categories