WIF - optional authentication - single-sign-on

I'm working on a proof of concept app. The basic functionality works, where I can log into one website, link to another site that shares the same STS, and the partner site picks up the credentials properly.
However, the partner site only requests the token if the page that we link to requires authentication (which kind of makes sense I guess).
Ideally, I'd like to link to a partner page that does not require you to be authenticated, BUT if the user IS already authenticated, I'd like to at least be able to recognize them on the partner site.
Currently, if my partner landing page does not require authentication, it doesn't appear that the user is logged in when they arrive. As soon as the user requests a page on the partner site that does require authentication, it then grabs the token without requiring the user to log in.
I've tried playing around with the SecurityTokenReceived and RedirectingToIdentityProvider events, but so far I'm stumped.
Any thoughts are appreciated.

So, the problem you are running up against is in dealing with the SessionAuthenticationModule hijacking the request. This module is responsible for detecting if the user has a valid session (based on a cookie that is written upon a successful redirect from the STS) and if not, to redirect the user to the STS to fetch a valid token. The WSFederationAuthenticationModule supplies the eventing necessary to hook into various stages of the redirection/authentication process.
Based on your description, it sounds like you want the following to happen:
User clicks on a link that redirects to the partner site
At the partner site, the request is intercepted and the system determines if the user is signed-in to the STS or anonymous
If the user has a valid session with the STS, then pull the claims for that user
The problem is, your RP cannot know that the user has a valid session without sending the user to the STS first (the RP's do not talk to each other or the STS. The user's brower is used as the means of communication between the RP's and the STS in the form of WS-Fed directives and SAML tokens passed in the url during redirects). If the user is sent to the STS, then they must authenticate, which could be a problem for anonymous users.
So, I do not think there is a "trick" that you can pull via configuration or interception of the request to determine if the user has a valid session with the STS. You might be able to pass a hint, however, from the referrer that is intercepted by the partner site. This hint could take the form of a parameter on the url that indicates to the partner site that the current user has a valid session and to go ahead and redirect to the STS (absence of this hint would indicate an anonymous user). You could also build a system to "hand-off" knowledge of the signed-in user using a resource that both sites have access to (i.e. database).
As you are sure to learn soon, more often than not, WIF offers pieces to the puzzle, but every situation is different and you have to supply the other pieces on your own.
Hope this helps!

Related

Identity Server 3 - Silent sign-in / sign in without login page. Including single sign on

I have come across a number of articles that discuss a similar matter but I cannot find a definitive answer.
My company would like to begin using Identity Server 3, however one of the requirements is to be able to authenticate an external user without them having to manually enter their credentials.
This must be capable of providing single sign on capabilities also as we have 3 different systems and our users should only have to sign in once.
Essentially, the external user has their own CRM.
The CRM holds their username and password for our software.
They then click a button in their CRM to launch our application
This redirects them to our website with a payload containing their credentials
We call a web service to authenticate the user
It is fundamental that we do not change this process for our partners.
Can I implement a custom service provider to provide the authentication or is there some other way of achieving this? If so, could you point me in the right direction for how this can be done?
Many thanks
Craig
I would assume that you'd create a mechanism for their CRM to get a token at the time the client logs into their site and then have them send that token via url to your callback page. This would use the machine-to-machine type grant, or the client-credentials flow. Then that page could validate the token and log the user in. There would have to be some sort of unique identifier between the two systems like email or something. Just an idea.

django rest framework - understanding authentication and logging in

I am a beginner to django rest framework (and to REST in general) and I have a server side which (for now) has a UserViewSet which allows to register new users and I can POST to the url from my android app just fine (I get 201 CREATED).
I read a lot about it, but I don't seem to fully the understand the concept of Login and Authentication in REST frameworks and specifically in django rest framework, and how it works.
Do you "Log in" (like in facebook for example) and then you can make requests?
What I understand\heard off:
you can Login to a API\website using your username and password (assuming off course that you have registered as a user and you are in the user database).
After you are Logged in - you will be able to make requests to views that allow access only to logged in\authenticated users.
Is that somewhat correct? I mean, is there a "Log in" url where you login and that's it? you are authenticated?
Also read somewhere that there isn't actually a login url, and you have to add your username and password to each request and then the request has to check if your details are in the User database?
To sum up, I am not really sure how does authentication/logging in (same thing?) happens in django REST framework... and would really appreciate a good explanation or an example..
Thanks a lot!
In a normal web application (removing the API from the question), a user would "log" in with their credentials (username/password, social tokens, etc.) and would receive a session cookie (assigned by Django) that allows them to authenticate in future requests on behalf of a user (realistically, themselves). This session cookie stays on their system for a limited period of time (two weeks by default) and allows them to freely use the website without authenticating again. If the session cookie needs to be removed, such that the person can no longer authenticate, the web application typically destroys the session cookie (or clears the session) which effectives "logs them out".
In the case of an API, it all depends on how the authentication works.
SessionAuthentication works just like as described above, as it uses Django's internal session system.
TokenAuthentication remembers the authentication information through a database-backed token (which is transmitted in the Authorization header) instead of a session cookie.
BasicAuthentication authenticates on every session (no persistent session) by passing the username and password on every request (base64 encoded through the Authorization header).
Other authentication methods generally work in the same way as TokenAuthentication.
So, here are some answers to specific questions which were raised
Do you "Log in" (like in facebook for example) and then you can make requests?
Using BasicAuthentication, you "log in" on every request by providing your credentials. With token-based authentication (TokenAuthentication, OAuth 2, JWT, etc.), you "log in" to receive the initial token and then your authorization is confirmed on every request.
Also read somewhere that there isn't actually a login url, and you have to add your username and password to each request and then the request has to check if your details are in the User database?
This is basic access authentication which you can use in DRF using the BasicAuthentication class.

Is there any way to get LInkedIn company network updates w/o requiring user to authenticate via browser?

Since LinkedIn discontinued their network updates RSS feeds, I haven't been able to find any "simple" mechanism to gain access to update feeds w/o going through the oauth process requiring the user to authenticate first. The few examples I've seen posted here all assume you've obtained the auth token first. Is that even possible?
In case anyone else inquires: https://developer.linkedin.com/support/faq
If your application requires you to make API calls in an automated way
- without user interaction, you need to bootstrap the first access token request by manually signing in, and then ensure that your
application refreshes the token automatically prior to expiry to avoid
the need for additional human authentication.

How to authenticate without hitting the database?

A comment below an answer about state and REST recently piqued my interest. For clarity I'll quote the comment in full:
Nothing in my answer implies a solution based on database access on every request, if you think it does, it is a failing on your part to understand authentication and authorization at that scale. The authentication can be implicit in the state, do you think that facebook does a "database access" on every request of its REST API? Or Google for that matter? hint: no
I tried to think how one might authenticate without checking a user-provided value against a centrally-held one, even if one to know what data to display to the user, and came up blank. i freely admit this is a failing on my part to understand authentication and authorization at that scale. My question is therefore: how do sites like Facebook and Google accomplish this?
One way is claims based authentication. Simplified and somewhat loosely interpreted, it boils down to this;
Instead of the server application authenticating the user itself, an un-authenticated user is redirected to a separate authentication server.
The authentication server validates the user in any way it wants to (login+password, certificate, domain membership etc) and creates a signed "document" with the relevant user info (user id, name, roles, ...) It then redirects the user back to the server application with the document enclosed.
The server application validates the signature of the document, and if it trusts the signature, it can use the document contents to assume who the user is instead of accessing the database.
Normally, the server application caches the document in a cookie/session or similar so that the next access to the application does not have to bounce through the authentication server.
In this way, the server application does not need to concern itself with how the user is authenticated, just whether it trusts the judgement of the authentication server. If the authentication server (and possibly the client unless it's a browser) adds Facebook login support, the server application will automatically "just work" with the new login type.

Possible approach to secure a Rest API endpoints using Facebook OAuth

I've been reading a lot about the topic but all I find are obsolete or partial answers, which don't really help me that much and actually just confused me more.
I'm writing a Rest API (Node+Express+MongoDB) that is accessed by a web app (hosted on the same domain than the API) and an Android app.
I want the API to be accessed only by my applications and only by authorized users.
I also want the users to be able to signup and login only using their Facebook account, and I need to be able to access some basic info like name, profile pic and email.
A possible scenario that I have in mind is:
The user logs-in on the web app using Facebook, the app is granted
permission to access the user Facebook information and receives an
access token.
The web app asks the API to confirm that this user
is actually registered on our system, sending the email and the
token received by Facebook.
The API verifies that the user
exists, it stores into the DB (or Redis) the username, the token and
a timestamp and then goes back to the client app.
Each time the
client app hits one of the API endpoint, it will have to provide the
username and the token, other than other info.
The API each time
verifies that the provided pair username/token matches the most
recent pair username/token stored into the DB (using the timestamp
to order), and that no more than 1 hour has passed since we stored
these info (again using the timestamp). If that's the case, the API
will process the request, otherwise will issue a 401 Unauthorized
response.
Does this make sense?
Does this approach have any macroscopic security hole that I'm missing?
One problem I see using MongoDB to store these info is that the collection will quickly become bloated with old tokens.
In this sense I think it would be best to use Redis with an expire policy of 1 hour so that old info will be automatically removed by Redis.
I think the better solution would be this:
Login via Facebook
Pass the Facebook AccessToken to the server (over SSL for the
android app, and for the web app just have it redirect to an API endpoint
after FB login)
Check the fb_access_token given, make sure its valid. Get user_id,email and cross-reference this with existing users to
see if its a new or old one.
Now, create a random, separate api_access_token that you give back to the webapp and android app. If you need Facebook for
anything other than login, store that fb_access_token and in your
DB associate it with the new api_access_token and your user_id.
For every call hereafter, send api_access_token to authenticate it. If you need the fb_access_token for getting more info, you can
do so by retrieving it from the DB.
In summary: Whenever you can, avoid passing the fb_access_token. If the api_access_token is compromised, you have more control to see who the attacker is, what they're doing etc than if they were to get ahold of the fb_access_token. You also have more control over settings an expiration date, extending fb_access_tokens, etc
Just make sure whenever you pass a access_token of any sort via HTTP, use SSL.
I know I'm late to the party, but I'd like to add a visual representation of this process as I'm dealing with this problem right now (specifically in dealing with the communication between the mobile app and the web api by securing it with a 3rd party provider like facebook).
For simplicity, I haven't included error checks, this is mostly just to outline a reasonable approach. Also for simplicity, I haven't included Tommy's suggestion to only pass your own custom api token once the authorization flow is over, although I agree that this is probably a good approach.
Please feel free to criticize this approach though, and I'll update as necessary.
Also, in this scenario, "My App" refers to a mobile application.