Is it possible to forward the current user's FormsAuthentication Identity to another Controller action? - asp.net

I'd like to use ASP.NET MVC's views as mail template engine. For that, I am calling one controller action from another controller action using a System.ComponentModel.Component.WebClient, parse the returned web page and send it via e-mail.
In this scenario, is it possible to forward the current user's login credentials (I am using FormsAuthentication) to the controller action requested by the WebClient? User passwords are encrypted, so I can't just create a new NetworkCredentials instance with his user name and password.

Yes, you can just copy the .ASPXAUTH cookie from your current Request object to the WebClient
EDIT: I haven't actually tried this myself, so maybe the .ASPXAUTH cookie is removed from the Request object for security reasons.
But since you have access to the machine key, you can create your own cookies on the fly. Here's the code that should do it (I can't find the project where I actually did that)
var ticket = new FormsAuthenticationTicket(User.Identity.Name, true, 5);
string aspxAuthCookieValue = FormsAuthentication.Encrypt(ticket);
This code creates a forms authentication cookie for your current user name and with an expiration time of 5 minutes.

Instead of performing a http request, aren't you looking for something like "rendering a view to a string"

Related

Create session with BASIC authentication

I want to write a servlet with which I can create a new session.
The servlet requires the user to authenticate with BASIC authentication and returns the standard session cookie (using HttpServletRequest#getSession(true)). However, if the client uses the received session cookie in his next request instead of BASIC authentication it is not authenticated. The server recognizes the session but it doesn't contain the user information.
I'm using Tomcat and after a bit of debugging the reason is also obvious: the user information (Principal) is added to session upon authentication. However when the first BASIC authentication is taking place no session exists yet as this will be created by the servlet. Does anyone have idea how to solve this problem?
After one night of sleep [1] I believe I have come up with a working solution myself. The following snippet (using JAX-RS, but it shouldn't be too difficult to translate it to plain servlet code) does the trick if the calling client will follow redirects:
public Response getSessionCookie() {
boolean sessionExists = m_servletRequest.getSession(false) != null;
if (sessionExists) {
return Response.noContent().build();
} else {
HttpSession session = m_servletRequest.getSession();
return Response.status(Status.TEMPORARY_REDIRECT)
.header("Location",
m_uriInfo.getAbsolutePathBuilder().matrixParam("jsessionid", session.getId()).build())
.build();
}
}
The first request will create a session and redirect the client to the same address but with the session ID in the URL (which is important). The client will follow the request and send the same BASIC authentication data again but now it will be registered in the existing session. The second invocation of the method above will simply return an empty response with the session cookie that can now be used for subsequent requests.
Note that the session cookie is different for me in the second response but looking at Tomcat code this seems to be deliberate (successful authentication will always create a new session).
[1] Sleep is highly underestimated!

ASP.NET MVC Temp Data and RedirectToAction in web form

In ASP.NET MVC from one controller in one area I am using:
TempData["Model"] = model;
then RedirectToAction to pass the model to another controller in another area. In the controller action method I immediately pull the data back out of the model.
I am concerned that if I deploy to a web farm then TempData's use of session state will cause issues but am not sure if I can get away with it in this case because I immediately pull the model out of TempData again in the action method I pass to?
You are right to be concerned, a RedirectToAction sends the client a 302 message containing a url of the redirected resource. This is then the clients responsibilty to create a new request to the redirected resource. There is no guarantee this resource will be served by the original server. The fact that the request is pulled immediately from TempData makes no difference to this approach, at some point it is going to error.
You need to have some means of managing sessions. You could configure HTTP session affinity so that requests served from a server will always return to the originating server.
You could use cookies for session state or implement a session state provider.
This blog post is also a good start on the overview of the options.
If you are using InProc session state you might run into problems because in the redirect you could be sent to another server where the same session will not be available.
Two possible options are to either implement a cookie based TempData provider or switch to another session-state mode. Note that cookie based TempData is completely visible to users, though there are implementations where you encrypt the data.
Try with cooke based instead of session tempdata
See below link
http://volaresystems.com/Blog/post/2011/06/30/Sessionless-MVC-without-losing-TempData
Avoid the use of TempData all together. If you are sending your model in the redirection then use something like
RedirectToAction("MyAction", new {model = myModel});
public actionresult MyAction(model model)
{
/// Mode Code
return View(MyView, model);
}
Assuming that you controller action will take the model as parameter.

HttpServletResponse: Keep, Save or Persist the response for later use...?

I am using Spring to create my webapp. I have a scenario like:
An ExternalService sends a GET request to my Controller that has a mapping /DoOperation with some user info as param. I get the param check the user if he is logged into my system or not if NOT i send him to OpenId verification with returnUrl, which is in same webapp say /Authenticated.
The ExternalService does not provide a returnUrl (Not related to OpenId returnUrl) and forces to respond the same request it made at /DoOperation.
Now, How could I keep the very HttpServletResponse (if there is a way, apparently there is not) so that I can write a response once I have gone somewhere else e.g. at OpenID page to verify user and then /Authenticate in this case... so that ExternalService could read it.
Could Servlet Filter help here?

ASP.NET Subdomain Cookie (parent and one subdomain)

I have an app with multiple subdomains, subone.parent.com, subtwo.parent.com.
I have a logon page at parent.com/login. When a user logs in I redirect them to the proper domain based on which one they are a member of. This works fine.
FormsAuthenticationTicket ticket = new FormsAuth...
string encTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
cookie.Domain = subone.parent.com
Response.Cookies.Add(cookie)
This properly authenticates the user for subone.parent.com and not subtwo.parent.com. However I would like to do the following.
If the user goes back to parent.com, I would like to know that they are logged in and redirect them back to subone.parent.com.
Is there a best practice for accomplishing this? Or do I have to set another cookie for parent.com?
I'm working in asp.net mvc if it matters.
THanks!
You can share cookies across domains like you are trying to do, but its not straight forward, example here.
Another options is to set the cookie to be ".parent.com" rather than specifying the sub-domain explicitly and use the cookie store the details of the sub-domain. Then you can access the cookie from any of your sub-domains (and parent assuming its www.parent.com).
If your using MVC, you can pretty easily create a custom filter and add to the www.parent.com controllers to check for the existence of the cookie, and if so redirect to the sub domain the cookie specifies. Further details of filters here.
I would set the cookie for the explicit domain as you have there because that maintains any security information within that specific domain's cookie. You can also add a non-encrypted cookie at the *.parent.com level that holds information about which domains have been authenticated. There is no real way to tie this together though without using maybe timestamps and having a logical connection between the applications (ie - sub2 has a session timeout of 20 minutes so if the domain + valid timestamp occur in the parent cookie it would be valid, however this is business logic).
I'm not sure the reasoning behind the disconnect between domains, but you might actually prefer to have a single cookie that has encrypted text behind encrypted text. EG:
1) Sub1 logs in, sets the parent.com cookie as valid. Sends a piece of user data to an authentication web service.
2) The authentication service recognizes sub1 as the sender, encrypts the user data, and adds it to a custom cookie object.
3) The custom cookie object constructs a composite string on a unique split character (or sequence) and makes it available to the service method.
4) The service, using the forms encryption, encrypts the entire ticket and sends it back to the original login.
That way each server would be able to unencrypt the global ticket, but each piece of data would be encrypted using a common algorithm but a server based salt. So if sub2 attempts to read the cookie data from sub1, it gets the encrypted version rather than raw data.
you could share the same session on all subdomains. That is the code we use to accomplish that :-)
void MasterPage_Unload(object sender, EventArgs e)
{
///ASP.NET uses one cookie per subdomain/domain,
///we need one cookie for _all_ subdomains.
if (Context.Response.Cookies["ASP.NET_SessionId"] == null)
return;
var sessionCookie = new HttpCookie("ASP.NET_SessionId", Context.Session.SessionID);
sessionCookie.Domain = ".yourdomain.com" ;
Context.Response.SetCookie(sessionCookie);
}
inside the Page_Load method is:
Unload += MasterPage_Unload;
it works great :-)
robert

Can I abandon an InProc ASP.NET session from a session different than one making the request?

We have an application that does single sign-on using a centralized authentication server (CAS). We'd like to do single sign-out, such that if the user logs out of one application (say a front-end portal), the user is automatically signed out of all applications using the same single sign-on ticket.
The expectation would be that each application would register a sign-out hook (URL) with the CAS at the time of logon to that application. When the CAS receives the sign out request from one of the applications, it invokes the sign-out hook for all the application sharing the SSO ticket.
My question is this: is there a way to abandon an InProc session from a different session? I presume, since the HTTP request will be coming from the CAS server, that it will get its own session, but it is the session of the user that I want to terminate. I have pretty good idea of how to do this using a separate session state server, but I'd like to know if it is possible using InProc session state.
Haha, well... It looks like you can. I was wondering myself if there was any way to do this, turns out, there is.
When you use InProc, the InProcSessionStateStore (internal class) persist the session state in an internal (non public) cache. You can access this cache through reflection and remove the session state manually.
using System;
using System.Reflection;
using System.Web;
object obj = typeof(HttpRuntime).GetProperty("CacheInternal",
BindingFlags.NonPublic | BindingFlags.Static)
.GetValue(null, null);
if (obj != null)
{
MethodInfo remove = obj.GetType()
.GetMethod("Remove", BindingFlags.NonPublic | BindingFlags.Instance,
Type.DefaultBinder, new Type[] { typeof(string) }, null);
object proc = remove.Invoke(obj, new object[] { "j" + state.SessionID });
}
The end result is, that the next request will take on the same SessionID, but the HttpSessionState will be empty. You'll still get the Session_Start and Session_End events.
After doing a bit of digging around and considering the answers provided so far I've come up with an alternative that lets me continue to use InProc session. Basically, it consists of extending the HttpModule that already handles single sign-on to detected CAS sign outs and redirect the browser to the application sign out page.
Outline:
Sign-On:
For each new single sign-on request, create a new SSO cookie and encode a unique value in it to identify the session (not the session id, so it isn't leaked).
Construct the the sign-out callback url, encoded with the identifier, and register it with the CAS server.
Sign-Out:
When a sign-out request is received from the CAS server, decode the identifier and store it in an application-wide cache. This needs to be pinned in the cache at least long enough for the session to expire naturally.
For each request, look for the SSO cookie and check its value against the cached, signed-out session identifiers. If there is a hit, remove the SSO cookie and redirect the browser to the application's sign-out url.
For each sign-out, check to see if there is an SSO cookie, if so, forward the sign-out request to the CAS. In any event, abandon the user's session, and sign them out of the application.
Page_Load:
Check for the presence of the SSO cookie. If there isn't one, redirect to the sign out page.
No can do.
http://forums.asp.net/p/416094/416094.aspx#416094
With InProc SessionState, you won't be able to access the data... With StateServer, you still will have a sticky scenario trying to access the correct API to remove the session.
You will most likely want to use a database backed state solution like the pre-packaged SqlServer state provider or a third party solution like DOTSS: http://codeplex.com/dotss
With the database backed solution, you will be able to lookup the state record in a table by session id and mark it as completed. These techniques will vary based on the provider you choose.

Resources