Context:
The company I'm working for would like to achieve Single-Sign-On capabilities with a third party that uses the authorization code grant. Our product right now is built in .NET Framework 4.0 using Forms Authentication in a ASP.NET Web Forms application.
Question:
Is there a way to achieve single sign-on with out the user having to sign in twice (once through forms auth, and another through the identity server)?
To elaborate, is there a way to have the identity server authenticate the user automatically after the user has successfully signed in through forms authentication?
Here's the IdSvr3 webforms client: https://github.com/IdentityServer/IdentityServer3.Samples/tree/master/source/Clients/WebFormsClient
From what I've read, IdentityServer3 clients (which are previous to .NET core) are supposed to work with IdentityServer4 (which has to run on .NET core) and will talk to IdentityServer4 successfully.
So I managed to work around my issue by sending the users credentials on login to the identity server via ajax. I made a webapi controller that authenticates the user and sends back 'set-cookie' response headers for the idsrv auth cookie.
So now I'm signed into the original application, as well as the identity server all without the user having to manually sign in twice.
You just have to deal with a bunch of Cross-Origin-Requests stuff. Have to set "AllowCredentials" when setting up the CORS policy for the application to make the ajax request so that the 'set-cookie' headers actually apply.
$.ajax({
method: 'GET',
url: 'https://localhost:44304/api/login?username=testing&password=testing',
crossDomain: true,
xhrFields: {
withCredentials: true
}
})
The api/login endpoint is defined in a Controller that just calls the HttpContext.SignInAsync() extension method.
Related
I have the following setup:
1) WebAPI that accepts JWT Bearer tokens for auth.
2) Portal (WebApp) that puts a nice face on the json output from this WebAPI. It does OpenIdConnect authentication and uses Cookies to persist login information. It is an ASP.NET Core MVC app.
3) The WebAPI and WebApp are on different domains.
4) The WebAPI layer is designed to be called by any 3rd party who can present a valid token - either via App auth (client_credential flow, for eg) OR Delegated User auth (implicit flow, for eg). The WebAPI also does RBAC auth.
At this point, the problem I have is this:
1) I want to be able to make AJAX calls from the WebApp controller pages (cshtml) to my WebAPI so that the pages are responsive and there are no POSTs. So I integrated ADAL.JS into the page for that purpose. It works from a functionality pov.
2) HOWEVER, this results in multiple authentication dialogs (web page popups).
-- 1st auth popup. Upon navigation to the Portal homepage, I get challenged and have to enter my credentials on my company login page (federated AD auth).
-- 2nd auth popup. Then when I invoke anything on the Portal pages that involves ADAL.JS (namely the AJAX calls), it causes another login dialog because ADAL.JS cannot see the login cookie from ADAL.NET layer. This dialog comes up and goes away without any input needed tho (because the cookies from (1) are sent along to the server automatically by the browser). At this point, I have the ID_TOKEN and an ACCESSTOKEN for the PortalApp's client_id show up in the ADAL localStorage area.
-- 3rd auth popup. Then another dialog pops up; it uses a Hello pin login (I assume this is due to 2-factor auth requirement enforced by my tenant). At this point, I see the ACCESS TOKEN for the WebAPIApp's client_id show up in the ADAL LocalStorage area.
And now my AJAX calls start working.
Is there a better way to do this so that I can get the benefits of AJAX and not have to resort to serverside POSTs and have only 1 auth dialog instead of 3?
(I thought of may be switching ALL authentication to be done by ADAL.JS for the entire site, but I like the paradigm of using the [Authorize] flags and RBAC for the Controllers. OR is there a way to make my WebAPI accept both JWT and Cookie authentication?
Thanks!
Currently I have created a WebAPI Project using identity framework and I have setup tokens to be returned when authenticating with the API.
So now I am looking at creating a standalone MVC application that will allow the user to make calls to the WebAPI to get back end data.
The goal is to separate functionality so that other applications can also start interacting with back end data through web calls.
So the confusion now is how do I setup my MVC project so that I can use the Authorize attributes on controllers with the token received from the WebAPI. I think I need to enable bearer tokens in the ConfigureAuth method in Startup.Auth.cs. However will that be sufficient enough? Or do I also need to enable the cookie authentication?
MVC and Web Api are fundamentally different when it comes to authentication. With Web Api, the bearer token has to be set in the header of the request, but this is not an issue as all API requests are done programmatically by the client, i.e. there's human-intervention involved in setting up the client to authenticate the request properly.
MVC is a different beast in that the actions are accessed generally via a web browser, which will not automatically affix a bearer token to the request header. What it will do is pass cookies set by the server back to the server. That's why cookie auth is used most typically for MVC web applications.
What you should do is enable cookie auth for the MVC site and then set up your sign in action to authenticate via the Web Api. When you get back a valid auth from the Web Api, then you can manually sign in the user via the Identity API:
await SignInManager.SignInAsync(user);
Trying to search for this results many many results for securing a WebAPI and how to secure an MVC application, but i could not find a solution.
What i want to achieve:
i have an MVC website with a modal Login form,
When the user enters he's credentials to the the form, an Ajax request is sent to a WebAPI with the credentials.
The WebAPI should return (i guess a ticket, since that is what i found).
The ticket would be then saved into the sessionStorage of the browser (no cookies),
Each page request to the website will check for the token, and enable/disable the parts that need to be secured.
All the examples i have found are showing either MVC only authentication,
or WebAPI authentication, but i could not find anything that does the described above.
The sessionStorage is available only for client-side use. You can manipulate or retrieve values from the storage using Javascript, but you can't directly read data from the server. Since MVC typically renders HTML Views server side, you have no options to send the token stored in the sessionStorage on each request.
The situation you described is an hybrid solution which can't be achieved without the use of cookies.
A simple solution is to set the login data (specifically the token if you will use a token-based approach) in a cookie issued by the Web API endpoint during the login phase.
I am trying to understand the security features of the VS2013 MVC5 SPA Template WebAPI.
In Startup.Auth.cs there is this -
TokenEndpointPath = new PathString("/Token")
and this -
AuthorizeEndpointPath = new PathString("/Account/Authorize")
In my understanding, the AuthorizeEndPointPath is for when your acting as a 3rd Party OAuth authorization server.
However how it is used in the template, the flow seems to be
Login via Forms Authentication
Redirect to a secure page
Javascript checks for a bearer token in the local storage, it doesn't exist, so it redirects to this Authorize endpoint.
window.location = "/Account/Authorize?client_id=web&response_type=token&state=" + encodeURIComponent(window.location.hash);
Logs into app with OAuth security, returns token, which will be passed on subsequent API requests.
The /Token endpoint never seems to be used. A prior version of this templated did an ajax post to /Token to login. I have a similar situation where the website is secured via Forms authentication/cookies but the WebApi is secured by Bearer token.
Is the Authorize endpoint being used correctly in this SPA template - is this the correct pattern to follow? It seems like the appropriate way to authenticate for bearer token security "internally" for the app would be a "client credentials grant" though not sure how to generate the "secret".
I am working on a Windows Phone 8 app and a ASP.NET MVC 5 website and each of these will access a WebApi service (WebApi 2). The website and WebApi are based on the templates provided by VS2013 RTM and have been setup using the "Individual Account" authentication option available in the project template.
The template sets up the WebApi project to enable bearer tokens, application cookies and external login cookies, etc, and the exposed actions have the Authorize attribute on them.
My two questions are:
1) If I were to use Azure Mobile Services to authenticate a user using Google/Twitter on the WP8 application how can I get the WebApi to allow the authenticated user to access the actions?
2) Same as #1, but from a ASP.NET MVC 5 website perspective?
From I what I can see it would appear that each request requires a bearer token. To get this token would I be correct in thinking that I would access the "token" endpoint exposed by the WebApi to get the token and that would need to be passed with each request?
For 1, you can use azure mobile service WP8 sdk to launch a browser control to authorize user from external site. The code should be similar with WebAuthenticationBroker in windows store app.
For 2, the web api template with individual auth is using an implicit flow in OAuth 2.0 to return the application access token back to client. In MVC app, you can redirect user to
http://<web api domain address>/api/account/externallogin?provider=Facebook&redirect_uri=<your callback url in MVC app>&response_type=token&client_id=mvc.
And in your MVC view, you need to use javascript to get access token from url fragment, which won't be sent to server. In your web api server, you need to allow the client id and the callback url in ApplicationOAuthProvider.
For both 1 and 2, you are not using token endpoint to get the token. You are using the authorize endpoint to get token by implicit flow.