Implementing a Symfony2 single-sign-on - symfony

I have a basic understanding of the security concept in Symfony2. Now I'm trying to implement a single-sign-on feature for a multi-domain website.
The SSO concept itself is rather straightforward:
Domain A is the cookie domain; people can log in on this domain
When logging in on domain B, the user is redirected to domain A, where a One-time password is requested. The user needs a session on domain A to get this password.
After obtaining the OTP, the user is returned to domain B, which will match the OTP to the session on domain A.
If matched, a session will be created for domain B. The session will be validated against the session on domain A for each subsequent request from this point on.
Implementing the firewall/authentication for domain A can be done as you normally would. In my understanding, I need to:
Set up a firewall for domain B
Create a listener for this firewall, that somehow redirects the user to domain A (more specific: an uri that requests an OTP)
Create an authentication provider that handles a OTP and creates a session for domain B
Create another listener that checks the session validity against the session on domain A
However I could really use some tips on how to do this in a bundle. If anyone can help me out here, that'd be great.
Also, I'm not yet sure how to implement the OTP, or how to compare the two sessions, and make sure they both are valid. That will come later, I need to get this workflow working first.

In order to get multidomain SSO you can implement a SAML solution. Take a look on simplesamlphp software and in this extension for symfony1 https://github.com/chtitux/sfSAMLPlugin
To resolve the OTP issue you can use for example LinOTP2 witch is compatible with simplesamlphp: https://github.com/lsexperts/simplesamlphp-linotp

Related

OAuth2 protected API. How to allow customer's to SSO using its own authorization server?

I have an Angular Single Page Application (SPA) talking to my ASP.NET API.
The API is protected by my own Oauth2 server (IdentityServer4).
One of my customers (let's call him X) wants SSO: Their users on my platform would sign in on their server instead of using the login form in my app that connects to my IdentityServer.
Each customer has its own subdomain for the Angular SPA (e.g. x.myapp.com). Therefore I can easily redirect X's users to their server's authorization page to approve my API, based on the hostname.
However the API itself uses one common hostname for all customers(api.myapp.com). Customers are distinguished by the Origin header of the API call (x.myapp.com) during the login call (and a few other unprotected calls) and by the Bearer token for protected calls to the API.
How does my API introspect the Bearer access token? Who should know which server to query ?
Is it the responsibility of the API server? Or can I tell my IdentityServer about X's oauth2 server ?
X's users would also be defined on my platform since we need specific info (such as config of roles on the platform). My current setup implies specific claims (such as user id) that allow my API to know what the user can do. Obviously, X's server will not provide the same claims. How can I connect the dots ? e.g. get some standard claim from X's server (username, email, whatever) and match it to my list of users.
Note: This question is similar but the answer is not accepted and seems to imply that the provider of both identity servers is the same (not the case here).
Formatting my comments as an answer:
From reading your question it's pretty much clear to me that you could benefit from what is know as Federated identity.
As you said, one of your customer want to achieve SSO - They want users to login using their existing accounts and be able to user your systems normally.
Since you already have an IdentityServer in your domain, what you can do is delegate the login part to the customer's side (whatever they do it). This is illustrated in the Identity server documentation Federation Gateway.
Basically, the approach is that upon hitting the "login" button in your front-end, you would redirect the users to your Identity Server passing some special params (prompt and acr_values for ex) which in turn, tells identity server to redirect the user's to the external Identity provider (the customer's). After a successful login, you have a chance in Identity Server to augment the claims, maybe using something they returned or anything really. Then the process is as normal - you return a JWT Token generated by your Identity Server
The benefit of doing this is:
Your SPA/API doesn't have to change. You will still work with your own bearer tokens and can continue doing authN/AuthZ as before.
You have a chance to add claims that might indicate where this user is coming from if needed
If your customer's server changes, you don't have to worry much, apart from maybe some tweaks related to returned claims
They don't necessarily need to use OpenId/OAuth on their side for this to work
Useful things you probably will need is some params to pass during the call to the authorize endpoint in Identity Server. (acr_values and prompt).
You can also check this in the quickstarts, by looking at Sign-in with external providers (which is pretty similar to what you want)
Now to your individual points:
Your Identity Server should be the "bridge" between you and the customer's "identity provider".
Upon a login from an external provider (X), you need to somehow identify the user on your platform. You could use email or, even better, if X is already using OpenId/OAuth they might give you the sub claim which is the user id on their side. At this point you need some sort of agreement with them otherwise this might be flaky/unreliable for both sides.
In a more "advanced note" you could also add to your tokens some sort of claim that tells you who is the source provider of this user. Here the source provider would be X. This is useful because you might want, for example, configure allowed identity providers in your app, or maybe enable features only for certain providers. Like, ppl logging in with Google might only see certain parts of the app.

OpenAM, OpenId, REST API, In-House applications: how do I connect them all?

I'm having trouble tying all of this together. Partially due to lack of understanding, and partially because I've not use OpenAM before.
I'm trying to implement Single Sign-on. Here are the players.
OpenAm. https://www.forgerock.com/en-us/products/access-management/
A 3rd party proprietary app that can use it's own username/password database, or authenticate against an SAML or OpenId provider.
Several In-house applications written in either angularjs or .net webforms.
An in-house REST API written in nodejs.
I need to be able to have a user sign-on/register in openam, and then they don't sign-in to any of the other applications. We see this all over the web, so the use-case is pretty normal, but I've never actually implemented it myself before.
See what I'm trying to do using the image below for starters.
Here's what I'm stuggling with:
For SSO purposes, OpenAM seems to store the authenticated user information in a cookie. How does my Proprietary app pick up this cookie and use it if it can only authenticate via openid or saml? It can't use the openam API by going through the /json/* endpoints.
With the in-house apps, I'm assuming I can just pass the cookie along and the appropriate parties can validate the cookie's session info or token and that's that. Is this correct, or am I looking at this wrong?
Can I have the user login to the OpenAm login page, and then use the /oauth2/* endpoints to validate the user's requests? I could see this working better, but am unsure if this is how it's supposed to happen.
Basically, I feel like I've scrambled my brain this last week trying to sort this out. I need some help to get some direction here. As I said above, a good portion of this is new. I've done front-end->rest api->database using a token, but this SSO scenario has given me a real headache.
Any help would be appreciated.
It sounds to me that you miss the "redirection" aspect of SAML SSO. I'll try to explain how it works in a nutshell:
Step 1:
When a user sends a request to one of your in house applications (call it the Service Provider, SP, from here), the SP detects that this is an unauthenticated request and redirects the browser to the OpenAM server (call it the Identity Provider, IdP, from here).
Step 2:
The IdP analyses the redirection request and expects to find a "SAML authnResponse", this is encoded XML metadata added in the redirection request by the SP. It finds out that your SP wants to authenticate a user. The IdP will respond to the request by showing a login page. Here the user can authenticate to the IdP. After the user succesfully authenticated to the IdP, it will redirect him back to the SP adding a "SAML authnResponse" to the request.
Step 3:
The SP will analyse this "SAML authnResponse", which is again just a form of XML metadata. If the validation of the signature is OK,find out which user successfully authenticated, create a session for him and redirect him to the resource he initially tried to access.
Remark 1:
In Step 2, if the user already authenticated to the IdP before, he will have an active session to the IdP. The IdP will not require him to login again but just inmediately redirect him back to the SP with a valid "SAML authnResponse". In this way the user will barely notice all these redirects and it will look like he 'seamlessly' got access to the SP.
Remark 2:
So don't worry to much about cookies, they're used by the IdP to recognize already authenticated user sessions etc. but you should only bother with redirects and analyzing the SAML Responses and Requests. Does this make sense?
Remark 3:
The way how the browser (GET 302 or JS POST) of the user will be redirected depends on your chosen "SAML Profile".

Sharing ASP.NET_SessionId and .ASPXAUTH cookie security risk

We're developing a SAAS solution for a big company in which doctors can view patients and make mutations, order products, provide licenses.
This project is for 4 separate companies under one umbrella company. For each company we developed a portal. All portals use the same code but have a strict separated database because the database contains all the patient information.
We're using Sitecore as CMS.
The client decided to use virtual folders instead of subdomains for the production environment. Our staging evironment url is for example: acc-portal1.umbrella.com. For the production environment they would like a URL such as: acc.umbrella.com/portal1. One SSL certificate is being used for all portals and requests.
We're using Membership Provider (forms authentication) for the authentication of users. Users can not log in with the same account in for example portal1 and portal3 because of the usage of separated databases.
Because we're using formsauthentication the ".ASPXAUTH" cookie is being used. Of course the "ASP.NET_SessionId" cookie is used also.
Because the client wants to use virtual folders instead of subdomains, the cookies are shared over all portals. It is possible to set the "path" on the node in web.config but this path is dynamically read by Sitecore and resolved in a pipeline. I did not find a way to override this path after it is being loaded in the web.config. Also I did not find a way to alter the ASP.NET_SessionId cookie path.
My question is: is it a (security) risk to share these cookies over multiple portals (remember, they should be separated completely)? Are there any other problems this setup could cause?
Hope somebody can help!
Yes, there is a huge security risk. What you do is called a multitenant application. You have to take special steps to ensure that cookies and other sensitive data cannot be shared.
My advice would be to store the tenant name (portal1) in the custom data section of the forms authentication cookie. You set the custom data when you issue the forms cookie.
Then, have a custom module or just a handler of the Application_AuthorizeRequest event, where the identity is already established based on the cookie.
In your handler, you decrypt the forms authentication ticket from the cookie, retrieve the user data and compare to the actual url. If there is a match - nothing happens. If there is no match, it means that user is authenticated in one portal but tries to access another. You can gently clear the response and render a message "well, this portal is not meant for you" or just log the user out.

SAML: Communication between Service Providers?

I've been tasked with writing a SP (Service Provider) for SAML v2.0 in ASP.NET, and I wonder the following;
If a user logs in on the main SP for a service (where my SP becomes accessible for a user as an anchor/link, unless previously bookmarked), and then requests access to my SP, how should I handle their login?
They will have logged in and become authorized by the IdP on the main SP, but how will that SP tell my SP that the user is logged in?
Will I have to send a new authorization request to the IdP to determine whether the user is logged in or should it be passed on as post data/redirect with a query string from the SP?
I've read the technical overview as well as the basics, but they don't cover this part.
I will contact the main SP and ask how to proceed, but I wanted to cover my bases first and see if there's a standard way on how to deal with this situation.
The easiest thing to do is to have the "main SP" construct the link so that IDP-Init SSO is initiated for users to log into your application. So the user would show up with a new Assertion from the IDP (customer) to your SP.
You could also have them directly link to your site to invoke SP-Init SSO for the given Identity Provider/Customer.
Either way you choose to do this will require you to handle multiple use cases and options for SAML 2.0. You can have this up and running in short order if you want to check out the SaaS Partner Program offered by Ping Identity. www.pingidentity.com
Let me know if you'd like more info on what we've seen other
In order to do SP-initiated SSO, you either need for there to be only one identity provider that you might need to send authentication requests to, or you need some means of determining the proper identity provider for a particular user -- either the user needs to provide some IdP-identifying info (such as StackOverflow does when you want to log in using your Google or other ID) or there may be something embedded in the URL. (For the app I work on, different clients have their own site domains, so IdPs get mapped to those.)
So, yes, if you're going to go the SP-initiated route, you will need to make an authentication request to the IdP to determine who the user is, and you will want to use RelayState to get them back to the originally requested page. If they're already authenticated at the IdP, then most likely this exchange will happen without requiring any input from the user.

Secure login with additional context information passed through (which also needs to be secure)

My web application will be launched through existing thick client applications. When launched, an HTTP POST request will be generated including information like the userID and additional context information (basically stuff like the target user's name, birthday, etc.).
My plan for authentication is for there to be a look-up table in the database. If the username is already there, automatically login the user, but if there is no entry in the database, redirect the user to an initial login page which will be used to create that database entry.
My question is how to secure this against MITM and other security holes. How can the request generated through the thick client be on an SSL connection? Doesn't an SSL connection have to be authenticated with the username (and password) first? And if so, will the additional context information be publicly exposed until the user is logged in?
Sorry if this is a basic security 101 question. References on where to read up on security basics would also be greatly appreciated.
No, SSL does not require any username or password to work. SSL only encrypts the data between the client and the server. You could serve an entirely anonymously accessed site via SSL. Most of the time, people equate SSL and logins because you want to encrypt your login credentials and any of the information accessed using those credentials.
If you want to use your method, simply post the User ID and other information to your SSL site. The post and any response will be encrypted. If using a web page, it would look something like this.
<form method="POST" action="https://mysite.com/login">
Generating from an application, just use the https:// when creating your URL to post to.
Regarding any other security concerns, we do not have enough information to speak about the overall security of your planned deployment, but the above should take care of your initial questions about SSL and encryption.

Resources