Symfony Guard Component and Stateless Authentication (Shibboleth) - php

It was required that my application uses a SSO Service called Shibboleth. So I used the existing shibboleth-bundle. Things have changed and we need to add a form authentication method for the user. So I decided to implement Shibboleth authentication with the new Guard Component. (See ShibbolethGuardBundle)
I found a problem during the development. Symfony calls the ShibbolethAuthenticator methods at the first request, creates a token and never calls any ShibbolethAuthenticator method on later requests. That means, if Shibboleth session ends the user is still authenticated using the Symfony session.
This is also a problem if you want to implement a token authentication. The user only need to send the token at the first request. Any other request is authenticated by the session.
This problem exist also with other SSO services. If you logout at Facebook you want to be logged out at any website that uses Facebook authentication. But if you implemented this with Guard you still have a valid session after the logout at facebook.
I found a quick solution by checking if the shibboleth header variables are set in my UserProvider on every request. If they are missing, an Exception is called and my ExceptionListener redirects to the login page.
I think this is not a good solution, because the ShibbolethGuardBundle should handle this problem. Does anyone has an idea how I could solve this in a more appropriate way?

The way I see it, authenticating the first time and sending the user data is to either create a user object or sign it for that website. After that, you have a session with Site A, using data from the SSO service, I think that's the intended behaviour. It is not to sync logins / logouts with the SSO service.
One workaround: In http://romain.pechayre.me/blog/2015/06/26/single-sign-out-problem/ it is described how Google might handle this (not sure if this is still current, but it's still relevant to your question):
When signing out from gmail a few days ago, I noticed my browser visited blogger.com for 0.5 second. I went back to blogger.com and realized I was logged out. Same on youtube.com. [...] The main idea is that the browser actually visits all website from Google on which I have the session and closes the session on all of them. [...] The main reason why signing out from several websites in one click is not well documented is because it is not a very common situation. When this problem arises it is probably fixed using a custom, in-house implementation.

Related

Laravel Authentication not remain

I created an API to login in my web app. After checking the parameters, use the Auth method: loginUsingId() with the id of the user to be logged in.
After that I get authenticated correctly, in fact doing an echo Auth::user() shows the user property correctly.
However, by making a redirect to another project page, I am no longer logged in the portal and shows me the login page.
It seems that the user's session does not remain or that is not created at all.
I use Laravel 5.6. I have no middleware for the route.
Each time your page accesses the API, it's essentially talking to a brand new instance of the API.
Think of it like this. Your "login" endpoint is not actually telling the API to log someone in. It's telling it to merely verify the caller's claim that the given password belongs to the given user, end of story. If you want to turn that authentication into actual "login" behavior from the UI perspective, there's other steps you need to take.
If Laravel is serving up Blade files for your site, then it's a different story. Out-of-the-box, it generates a Php session for you, and sends the session-key cookie to the browser for use in subsequent requests.
Similar to a session-key, for maintaining a session between a website and a separate API, you need each subsequent call to include a token. And you need the login endpoint to provide that token upon successful authentication.
Passport is one way to go, but it might be overkill for your situation. Passport is good for handling users, clients, and authorization permissions. But if all you want is authentication and you're not as concerned with controlling what they have access to beyond that, then I highly recommend Tymon JWT-Auth.
Both Passport and JWT-Auth use "bearer tokens" in the 'Authorization' header. There're other kinds though, like "basic tokens". A basic token is just an encoded concatenation of the username and password. Laravel supports this with a route middleware, but I do still recommend going with JWT.
One of the nice things about JWT is you can actually include extraneous data within the token itself. And it positions you better to lean into Passport (OAuth2) if/when you need it, by not requiring your client-side to change its authentication method.

Stateless Authentication - what really does it mean?

I use Socialite library in Laravel. In documentation tells one paragraph:
The stateless method may be used to disable session state verification. This is useful when adding social authentication to an API:
what really does it mean? When I should use that?
Actually, the basic authentication mechanism uses session to store the visitors identity so when you once get authenticated (providing credentials in a login form) the application doesn't ask for the password again when you visit another page after login. So, the session is used to keep the user's current state in the application. This is what happens in most of the cases.
On the other hand, the stateless authentication is used without using the session. In this case, the application doesn't keep any data into the session to identify the user on subsequent requests. Instead, it verifies every request independently.
When you gonna need this?
Basically, it's needed when you are going to build some kind of API which may serve resources as service to users where a user may send a request to your API to get data from anywhere, I mean the user may not be a registered user of your system but you may allow a user to consume data from your server depending on some sort of token based authentication.
This is not enough to describe the stateless auth but this may give you some idea. Further, you may check How to do stateless (session-less) & cookie-less authentication and this and also you'll find useful links if you search on Google using the term Stateless Authentication.

Custom login controller in Symfony2

For the last two days I read through multiple resources on authentication in Symfony2. I think I understand most parts, however I feel that I do not understand the whole thing. I successfully created two authentication providers and a UserProvider but I don't understand how to customize the login process.
What I try to do is writing a REST API that will be consumed by a client that I also write. The client will display a form and sent the credentials via Ajax. Therefore, I don't want to use HTTP basic auth (I don't want a browser window to pop up), I don't want to use OAuth or any token (but use credentials) and I don't want to use a form_login (the login form is rendered by Angular).
Using my custom authentication provider, I can verify that a client is logged in, using a cookie I set in the login controller. However, I don't understand how I would login (or what logged in means in Symfony) a user if I'd try to use the session/Symfony security bundle. I could just avoid all security things from Symfony and roll my own implementation but I would prefer to understand how Symfony expects the authentication provider and the login controller to work together.
What I want is one route where a client can check if it is logged in, login and logout.
GET /session # return the session if it exists, or 401
POST /session { session: { email: testy#mctest, password: test1234 }} # login
DELETE /session # destroy session
How would I achieve this in a "Symfony" way?
(Bonuspoints for explaining the general authentication concept in Symfony, outside of the authentication provider)
I'll try to make it the more verbose and simplest that I can from what I personally know :-).
This is what I understood from when I implemented my own Security layer based on the Symfony Security component. If something is not right, please tell me and I will correct it to make it more accurate.
The Security component works with firewalls. A firewall defined a "zone" that is under the responsibility of the Security Component.
For each firewall, you would usually match a pattern that would be matched with the current request. If it matches, then the Security Component tries to determine if the request is allowed to access the resource.
In order to do this, the Security component is divided into two steps :
First : authenticate the user. If the user is not authenticated, we cannot authorize him. So the component will go through its Authentication Manager in order to authenticate the user. Authenticating a user in the Symfony way means trying to create a Token (which is actually juste an instance of the TokenInterface class) matching the current request that is going to be authenticated, and then try to authenticate it.
This Token is supposed to be created thanks to Authentication Listener(s) (classes implementing the ListenerInterface interface). For instance, one will usually use a UserProvider to set a User into the Token object.
Then, when the token is created, it doesn't mean that the Token is authenticated. This Token will be authenticated thanks to the Authentication Manager. An often use kind of Authentication Managers is based on providers that will check if the credentials (or something else) is wrong with the current token. For example, a DaoAuthenticationProvider will check if the password given with the token user matches with the one in what our users provider gives to us. If not, it fails : either another provider can authenticate the current token, or this will be an authentication fail.
http://symfony.com/doc/current/components/security/firewall.html
Second : authorizing the user. For this, I suggest you to read the chapter about it in the Symfony documentation online. You can find it here. It is based on an AccessDecisionManager that will decide if the current user, based on the authenticated token, is now allowed to access the resource. This is usually made thanks to classes called Voters that will vote in order to decide if a user is allowed to access the current resource.
A voter could vote no, another could vote yes, and another could vote I don't know. The final decision is made from the AccessDecisionManager that will, based on how it is configured, determine if these votes will either allow the user ("Any yes allows the user" or forbid him ("Any no is strict").
I think that this is the basis of what you should understand, to me, about the Security component. Keep in mind that it can be very tricky to understand first, especially for the Authentication part.
Last but not least, I highly recommend you to read this whole chapter : Here !. It is the key and your bible if you want to understand what's happening inside this tricky but awesome component.
Now, for your login issue : what would be useful for you is to check how to create your custom Listener (see the authenticating part of my answer) in order to create your own business logic of "how do I authenticate my user based on the current request". Your form would be an entry point of a firewall zone that would be then pointing to this firewall zone. This listener would check if the information provided by your form is inside the request, and then create the Token. Then, you would have a custom way to authenticate your token thanks to the information you provide.
(Sorry for my english !)

Integrating SSO across differents Domains using WebService?

i have 3 différents domains domain-a.com and domain-b.com also domaine-c.com
and i want to use SSO, if you log in to one of these domains you have access to all other domains.
1 - using cookies is impossible because we can't share the same cookie with differents domains
2 - i'm thinking about using webservice, but i'm not good in that so i'm wondering if it's a good solution
If you have any suggestion or recommandation or any thing Please i need you.
You can't share cookies but you don't need to.
Let's say your SSO runs on sso.domain.com
You want to log in on a.domain.com:
Make an XMLHTTPRequest request to sso.domain.com to check if you have a session.
If you have a session and are logged in you get a login token back.
You pass the token to application A with an XMLHTTPRequest. It sends a request to sso.domain.com to verify the token and get the user credentials.
You are now logged in on a.domain.com
This setup requires Cross-Site-Resource-Sharing to be enabled on the sso domain. The CORS implementation allows you to do the login process under water, no redirect is required.
Your an indepth look at CORS see: http://fritsvancampen.wordpress.com/2013/02/03/cross-site-origin-requests-aka-cross-origin-resource-sharing/
I use SimpleSAMLPHP.. (https://simplesamlphp.org/)
This allows me to make a single place I can ask if users a logged in. The whole thing uses SAML2 which is a secure markup language(http://en.wikipedia.org/wiki/SAML_2.0).
It can be a steep learning curve to make it work but its very safe and everything is encrypted using certificates. The nice thing is that you can use all the IDP's(identity providers) you can think of. This means you can implement facebook, google etc. log-in's as well as custom log-in's.
Another great thing is that it provides SLO(single logout) as well. This will trigger log-out's in all the applications that are currently logged on..

Centralize Login System

At work, there are a few different websites and they all access to the websites on the network (Intranet), for example:
http://192.168.1.50 (Sales Panel)
http://192.168.1.52 (Other Panel)
http://192.168.1.53 (And different project)
I have to create a new account on each website and it become a bit of pain to use.
Then I thought why not create a Centralize Login System so each website can create and check the login account from a Centralize Login System.
For example, UserA have ability to login to http://192.168.1.50 or http://192.168.1.53 but not on http://192.168.1.52 (cookies is not needed, $_SESSION is fine).
How that should be implemented in regarding sending the request and response from a Centralize Login System?
Should I use HTTP GET for the request and response back a JSON object with several properties? For example
connect_status - "SUCCESS" - check was successful, "FAIL" - check was unsuccessful)
connect_id - UserId
connect_username - the username
If user successful logged in and user refresh the page - should it recheck the login or session via Centralize Login System?
How that should be implemented in regarding sending the request and response from a Centralize Login System?
That's entirely up to you. Just keep in mind that there are already many systems which were designed for very similar scenarios. Your use case is very similar to things that could be provided via kerberos, radius, or even ldap (if you have an existing AD) servers. If you have any of those around you already, it may be easier to query them rather than writing your own solution.
If you want your own, JSON response is as good as any other. Just make sure you verify the response is valid.
Should I use HTTP GET for the request and response back a JSON object with several properties?
Sounds pretty typical.
If user successful logged in and user refresh the page - should it recheck the login or session via Centralize Login System?
That depends on your backend technology and how quickly do you want to invalidate tickets. Are you ok with someone having access without authentication a couple of hours after changing the password, or disabling the account? Can you push a request to invalidate the authentication token / session files from the Auth controller to the app servers? How many requests per second do you get from all applications in total and can you handle all of the resulting auth requests in one place?
Answer some of those questions and you should get an idea of how you need to handle the rechecking / token caching / invalidation.
Also, in case you can/want to push some of the authentication handling to the client, have a look at protocols like oauth.

Categories