Verify user Twitter authorization when loading the Authorization cookie - asp.net-mvc

I'm creating an MVC web site, and I want to mix forms authentication (the built in authentication) with Twitter authentication in my site (eventually it will have Facebook/Google authentication too).
The approach I'm taking is this:
- I let the logic to create users and validate users/passwords from the Forms authentication as it comes out of the box.
- I created a new users table where I save the name of the user, the id of the user in my site and the authentication service of that user ("Forms", "Twitter", "Facebook").
- When the user logs in using any of the authentication methods, I create a standard Authentication cookie, adding the user id and authentication service to the UserData of the cookie.
Now, I want the user to be able to stay logged in after he closes the browser, no matter which service the user used to log in. With this I mean, that if the user opens the site again, he won't have to authorize Twitter again on the site.
Right now, with the cookies approach, MVC loads the user information from the cookie and the user seems logged in when he enters the site, exactly what I want.
The problem is that if the user revokes my site's access, the user's authentication cookie will still be valid, and the user will appear as logged in, even though the authorization for my site was revoked.
My question is, is there a way to validate the authorization in the moment MVC loads the information from the authorization cookie?. I know I can use a custom AuthorizeAttribute and validate this on the AuthorizeCore method, but this will be invoked only when the user is accessing a ActionMethod that requires authentication.
Thanks for your help.

Write an HTTP module that implements IHttpModule and handles the HttpApplication.AuthorizeRequest event.

Related

Sign Users Out of ASP.NET Application When They Logout From Okta Dashboard

We have an ASP.NET MVC application that uses Okta for user authentication.
When an unauthenticated user browses to our app, they are redirected to Okta to log in and are then redirected back to the application, authenticated. When they click "Logout" within the application, they are signed out of the application and signed out of Okta.
The issue is when we click "Logout" from the Okta dashboard. When a user clicks "Logout" from the Okta dashboard, they are signed out of Okta but not signed out of our application. When the user logs in with different credentials in Okta and opens the application, HttpContext.User.Identity still contains the previous user information.
Is it possible to set things up such that when a user clicks "Logout" within the Okta dashboard they are also logged out of the ASP.NET application? What's the best way to accomplish this?
This is the expected behavior, let me explain.
Let's assume a user is not logged into Okta OR your application. When a user visits your application and clicks "Log In", they are then redirected to Okta to authenticate. When they authenticate to Okta, a new session cookie is created so the user's identity is remembered on the Okta domain (for example, blah.okta.com).
Then the user is redirected BACK to your application (yourwebsite.com) where they will have an access token and a NEW session cookie (on the yourwebsite.com domain) which will keep them logged in there.
So at this point, there are two separate sessions that are active:
One on your domain (yourwebsite.com)
One on Okta's domain (blah.okta.com)
When a user logs out of Okta's dashboard, this means that their token is revoked and the session cookie is deleted (from the Okta blah.okta.com domain). BUT, there is no way for Okta to delete the session cookie from YOUR website (yourwebsite.com).
Therefore, when your user does something on your website (yourwebsite.com), the user's browser will STILL send the session cookie to your backend that contains an Okta access token.
And... Depending on how your web application is configured, it will do one of two things to verify that token:
It can either validate the token locally using a JSON web token library (which is the default behavior), in which case the token is still valid, so the user is considered "authenticated" and will continue to be able doing things even though their token has been revoked.
It can validate the token against Okta's authorization server (this is called token introspection), which is a bit slower as it requires an HTTP request to Okta. If this is done, then the user will indeed be recognized as logged out and their session will be destroyed.
So basically, to get the behavior you're talking about, you need to modify the way your web application is validating the user's tokens. You need to switch from using LOCAL VALIDATION to TOKEN INTROSPECTION.
Unfortunately, we don't yet have the option to use token introspection in our ASP.NET library. The author of the library has just added that to her backlog =)

How can I silently authenticate a user on a separate website when they're already logged-in on the central OAuth2 / OIDC site?

I have developed my own OAuth2 / OIDC web-application using IdentityServer4 which works fine. This is at https://myauthservice.com
I then have a separate website which is a registered client of my IdentityServer4 service which is located at https://mywebsite.com.
Both websites are made using ASP.NET Core 2.1.
The / (homepage) of https://mywebsite.com has no authorization rules applied to it.
However if a user is already logged-in if( this.User.Identity.IsAuthenticated ) then they're redirected to their account page (/account) which does have an authorization rule, if the user is not authorized (e.g. because they're unauthenticated) they're redirected to https://myauthservice.com's login page with a returnURL set.
The homepage also has a HTML Login to your account link which when clicked causes the login process described above to happen.
The problem is when a visitor has already logged-in to https://myauthservice.com but has not already visited https://mywebsite.com then they get redirected to https://myauthservice.com's login page, which sees they're already authenticated there (by checking the myauthservice.com cookies) and redirects them back to https://mywebsite.com with the right access_token.
I want to eliminate that step, so that users on https://mywebsite.com won't see the "Login to your account" page nor suffer two browser redirects if they're already logged-in to https://myauthservice.com - but https://mywebsite.com won't have the user's access_token so what's the solution?
I understand I could have a hidden <iframe> on https://mywebsite.com's homepage / that points to https://myauthservice.com's login page (with returnURL set) which would return the access_token correctly and then a client-side script would detect it and automatically redirect the user to the /account page, but this also feels like a hack.
Another option is to modify the login process on https://myauthservice.com to include a hidden reverse <iframe> that causes the browser to send the access_token to all websites I trust (not just https://mywebsite.com) to get the right cookies beforehand, so when they eventually do visit https://mywebsite.com they'll already have the auth cookie present and be redirected to /account on the first request.
What guidance from the IdentityServer4 team or OAuth2/OIDC community exists for this scenario?
Update: I now realise I'm basically asking how to implement true single-sign-on using IdentityServer4. StackExchange solved this problem back in 2010: https://stackoverflow.blog/2010/09/11/global-network-auto-login/ - I need to see how they did it.
Assuming you want to stick to using standard OpenID Connect stuff, you can use a prompt=none authorize request which will tell you if they’re already authenticated or not. This can work on client side (iframe) or server side redirect (no ui shown so user will be unaware). If you receive an error code of login_required you know to then initiate the regular sign in flow, otherwise you’ll receive the ID and access token and you can perform a local login as normal.
In practice it works well and isn’t a hack at all as this approach is part of the OIDC session management spec.

Detecting if the IdentityServer user is logged in while on a page which is available to anonymous users

Using an ASP.NET Core 2 application with IdentityServer 4 as an identity provider. Using two ASP.NET MVC 5 applications which use the the above mentioned application as the authority for authentication. Using the implicit flow for authentication.
The first application doesn't have any page available to anonymous users, so when unauthenticated users navigate to it, they are redirected to the IdSrv app to log in. Let's call it "Admin portal"
The second application's welcome page is available for anonymous users and unauthenticated users are not automatically redirected to the IdSrv app when visiting it.
If they try to visit some page which is not available to anonymous users however, the authentication component does its work and redirects users to IdSrv to authenticate first.
If authenticated users navigate to this welcome page, the application redirects them to some other page automatically (i.e. a dashboard page) which is not available to anonymous users. Let's call this second application "User portal".
Now to the problem.
Consider the scenario where a user logs in to the Admin portal and later goes to the User portal. Even though users had been logged in to the system by using the Admin portal, when they navigate to User portal they might do so via the welcome page which does not detect if users are logged in or not, since the welcome page allows anonymous access.
The desirable behavior would be, for an user which was already authenticated, to automatically be redirected from the welcome page to some dashboard page.
Is it possible for a page which allows anonymous access to somehow ask the IdentityServer whether the current user has been authenticated already? If not authenticated, it would just show the content, and if already authenticated, it would perform a redirect to some other page suitable for the authenticated user.
I had solved this previously (I haven't been using IdentityServer back then) by having the authentication service know which pages were allowed for anonymous users, and redirecting all unauthenticated users to the login page on each request. Then the authentication service would read the returnUrl value and if it matched one of the allowed pages, users would just be redirected back to the anonymous page, with added "anonymous=1" query parameter to prevent an infinite loop. Having "anonymous=1" query parameter would instruct the application to not redirect the unauthenticated users to the authentication service. But this seemed hacky.
Any thoughts?
As McGuireV10 mentions, you may be able to use the prompt=none approach from the client side here. You issue your authorize endpoint request in a hidden iframe and if the response comes back OK (i.e. not login_required) then you know the user is already authenticated on the IDP. It's a little fiddly to implement but it is an "official" approach and forms part of the session monitoring spec.

saml call back url with devise

I have to authenticate user either by saml or by database credentials depending on how user wishes to get authenticated .
I am stuck with two problems
1)I am receiving the saml response to the call back back url. I am not sure how to integrate it with devise.
2)I am not sure how to authenticate the user either by database or by saml response dynamically based on user choice.
Any suggestion would be really helpful
You will have to use a WebView to embed the logon page in your App.
If the user chooses Database logon you will have to challenge the user to submit their user name and password. Once the user is identified by your API, your business logic will be kicked in.
If the user chooses SAML login, it will be federated login and you will send the Authen Request to the Idp. The Idp page will be rendered in WebView within your app. Once the Idp will identify the user after logon process, they would redirect the page to the URL as specified in your Authen request for the attribute AssertionConsumerService. You will have to intercept the Request to extract the SAML token which you will have to eventually submit in a API service in your environment. The API service will have to do the token processing and will generate a User profile that is identical to the one generated by the database authentication.
I recently implemented SAML with Devise in my application, and found that the omniauth-saml gem is the quickest route to getting it to work. It will handle your callback flow, usage of the ruby-saml library, and all the other details that would be a pain to implement on your own. And if you need to handle an arbitrary number of SAML providers, omniauth-multi-provider-saml worked well for me.

How to get SSO and anonymous users with WIF and passive authentication?

I've got a web application that needs to implement SSO with WIF. There is a STS already set up for authentication, and I can use it to log on just fine.
However the application also needs to accommodate anonymous users. So when a user first arrives at the website, I need to somehow check with the STS if he is already logged on or not. If he is, the STS would return his token (simple), but if he isn't, he should be simply returned to the website without any further authentication, so he can continue browsing anonymousley (how do I do this?). If he later wants to authenticate, he clicks the login button and we do the typical WIF authentication dance, which I have already in place.
So... how do I tell an STS to do nothing if a user isn't authenticated?
There's nothing special really with WIF. You just define in your app what requires auth and what doesn't.
In MVC you would use the [Authorize] attribute on controllers. In ASP.NET you can use this: http://msdn.microsoft.com/en-us/library/b6x6shw7(v=vs.100).aspx
You shouldn't mix authentications on your web site (relaying party).
All authentication related issues should be handled by the STS.
To achieve your goal you should allow anonymous users on your STS and return token to your web site (RP) with claims indicating user as "Anonymous" (or whatever You want to call him).
So basicly you have to "authenticate" user as unauthenticated :D.
This way you do not decide your GUI looks and availability based on whether user is authenticated or not but whether he has specific role or not (obviously user "Anonymous" wouldn't have any roles). This seems to me like a better approach.
Hope this helps.

Resources