Copying cookies from main domain to subdomain - ruby-on-rails

My application has a userspace which used to be accessed by a url like domain.com/~username, but I am in the process of converting that to using subdomains instead (username.domain.com). However, I am running into an issue that I'm hoping someone might have an idea of how to get around.
Currently, visitors to a user's site get a cookie of the form user<id>_authentication (where <id> is the user ID of the site they're visiting), which is set to have the domain www.domain.com. However, now that I'm switching to subdomains, I want to find those cookies and transfer them to a new cookie called authentication per subdomain, using the subdomain as the cookie domain. However, the rails cookies array does not find the main domain cookies.
I know that if the old cookies were using .domain.com as the domain instead, they'd apply to the subdomain and would be present in cookies, but these cookies are already existing, and I'm trying to make the change as seamless for a user as possible -- so if they had an authentication cookie already for a site, I want them to not have to reauthenticate if at all possible.
Is there any way I can get the cookies from the main domain or does anyone have another suggestion of how I can transfer the cookies?
Update: Sorry, I didn't make it clear before, the cookie is only set if the visitor actively authenticates themselves by submitting a form on the user's site.

If you change the cookie domain to be more permissive (applying to more sub domains) you have no way to read the old, more restricted cookies except from the top level domain that used to work.
You will have to read the cookie, authenticate, and then write a new more permissive cookie before the cookie can be read by the subdomain.
You can roll out your migration logic in advance of the feature and hope you get most people. The rest will have to re-authenticate manually.

Personally I think they should have to re-authenticate.. it will only happen once, then they'll have the new ".domain.com" cookie.
But... One way to achieve this would be to check for the new cookie and when failing to find it, redirect to a new page on the main domain, providing the return url.
In that new page, check for the old style cookie, set the new style cookie, and redirect to the original url. if they don't have the old style cookie, redirect to the login area.
hope this helps.

Related

Signing someone into a subdomain using Websecurity / .NET Forms Auth?

I have an WebApi controller that, when completed, redirects a user from abc.com to subdomain.abc.com. The subdomain is on the same application - it's just a different area of the site. Currently the user has to login again once redirected. I'd like to essentially copy the cookie with the same credentials over to subdomain.abc.com, though I'm not sure if "copying the cookie" is the correct approach.
I'm using forms auth with WebSecurity - typical login looks like this (from a different, MVC controller):
WebSecurity.Login(user.Username, model.Password, persistCookie: model.RememberMe)
I'm not trying to cover all subdomains with the same cookie; I'm just trying to programatically log this user into a subdomain one time, from this controller.
Is this possible?
Yes it is possible, but could be risky.
The ideal way to handle this would be to set the domain to .abc.com on your cookie, but as you said, you are not trying to cover all subs with the same cookie.
One way to do it would be to redirect them to a special URL that calls FormsAuthentication.SetAuthCookie. The problem with that approach is that you are opening up a URL that writes an auth cookie without receiving the actual password.
You could possibly encrypt the username before the redirect, and send it encrypted as a parameter to the URL at subdomain.abc.com, then unencrypt it there before writing the cookie.
Update after comments
AFAIK, you cannot have an ApiController that only accepts requests from another ApiController. Same goes for MVC Controllers. Even if you check the Request.UrlReferer property in the receiving controller, this is something that could be faked. It is much harder to fake encrypted data when you don't know the encryption cipher.
You are essentially asking how you can hijack authentication in your subdomain from your primary domain. If you do this, you are opening up others to be able to do the same hijacking. Like I said, the ideal solution is to have all domains that share authentication share the same cookie domain. If you don't do that, you are left with either forcing the user to re-authenticate to get a subdomain-specific cookie, or the hijacking scenario. If you go with the hijacking scenario, you can send the username as an encrypted string to the receiving controller, and decrypt it there before invoking SetAuthCookie.

How to authenticate from a token in a URL?

I need to create a website with non standard authorizaion logic (or rather not exactly the site. It should be separate Area in existing ASP.NET MVC3 application). Access to most of the pages sould be available only to authorized users. Authorization is carried out on the token passed in the link. After the user arrived to this area, the token should be checked and if it’s valid site will create a session key for 30 minutes (we already have our own mechanisms of session managment and it should be used).
Workflow example :
Third-party website generates a link for user, e.g. https://example.com/securedPage/?accountId=123456&token=XXXXX
Our site check this token (it depends on the page from URL, in this case https://example.com/securedPage/)
If the token is valid, example.com obtains a session key for the user and stores it in cookies.
Then user continues browsing whole website and only session is checked.
I’m new to MVC framework, so I’d like to ask several questions about architecture.
What is an apropriate place for this logic? ActionInvoker, Global.asax etc.?
Currently I'm trying to create my own ActionInvoker and keep this logic there, but I'm afraid that it could be a wrong way.
If I understand correctly you want yo extend the Action of the controller to inject/check your token.
I think the global action filters should help you.

How do I let a user sign in from a different domain on Authlogic?

[This is slightly different than a previous question about having multiple domains share the same cookie. It seemed like there wasn't an easy way to do that.]
I have a application at application.com. A customer has app.customer.com pointed at my site on Heroku, and I have everything set up so that it renders a specific version of app correctly. The issue is that I want a user at app.customer.com to be able to login. I believe authlogic is now setting the cookie on application.com, so while it verifies the credentials, no session on customer.com is ever created.
Since cookies cannot be shared across domains, you probably need to save an identifier in a database and also pass it through the url so when the client browser hits the new domain, it sends the token for the new domain session to see and match.
It should be a long cryptographically safe token, like a UUID to keep it from being guessed by attackers.
I'm not sure how the authlogic piece fits in though.

When does the .NET FormAuthentication ticket get checked and how do I tap into this event?

We are attempting to integrate an ASP.NET MVC site with our client's SSO system using PingFederate. I would like to use the built in FormsAuthentication framework to do this. The way I've gone about it so far is:
Set up my Web.config so that my FormsAuthentication LoginURL goes to my site's "BeginAuthentication" action on a "Security" controller. From this action, I set up some session variables (what URL was being accessed, for example, since Ping won't send this info back to me), and then redirect to our client's login page on an external site (www.client.com/Login for example).
From here, the authentication takes place and a cookie is generated on the same domain as the one that our application is running on which contains the unique identifier of the authenticated user, I've set it up so that once this happens, the Ping server will redirect to my "EndAuthentication" action on my "Security" controller.
In this action, I call my membership class's "ValidateUser" method which takes this unique identifier from the cookie and loads in the user on our application that this ID refers to. I save that logged in user in our Session (Session["LoggedInAs"], for example) and expire the cookie that contains the id of the authenticated user that the SSO system provided for me.
All of this works well. The issue I'm wondering about is what happens after our user has already authenticated and manually goes back to our client's login page (www.client.com/login) and logs in as another user. If they do that, then the flow from #2 above to number 3 happens as normal - but since there already exists an authenticated user on our site, it seems as though the FormsAuthentication system doesn't bother kicking off anything so I don't get a chance to check for the cookie I'm looking for to login as this new user. What I'd like to do is, somewhere in my Global.asax file (probably FormsAuthenticate_OnAuthenticate), check to see if the cookie that the SSO system sends to me exists, and if so, sign out of the application using FormsAuthentication.SignOut().
Another issue that seems to be related is that if I let my Session expire, the FormsAuthentication still seems to think I am authenticated and it lets me access a page even though no currently logged in user exists in my Session, so the page doesn't render correctly. Should I tap into the Session_End event and do FormsAuthentication.SignOut() here as well?
Basically, I want to know when the authentication ticket created by
System.Web.Security.FormsAuthentication.SetAuthCookie(..) gets checked in the flow of a request so that I can determine whether I need to SignOut() and force revalidation or not.
Thanks for any help. Sorry for the length of this message, trying to be as detailed as possible.
Mustafa
Welcome to the small section of Hades that is mixing session with formsauth.
If your needs are as complex as presented, you would get more sleep if you implement a full provider stack to share amongst the participating sites. Easier said than done, I know.
But to address your question:
from http://www.codeproject.com/Articles/39026/Exploring-Web-config-system-web-httpModules.aspx
On the way in....Check ticket and set identity #
app.AuthenticateRequest += System.Web.Security.FormsAuthenticationModule.OnEnter-->OnAuthenticate
On the way out... set the ticket and redirect as necessary
app.EndRequest += System.Web.Security.FormsAuthenticationModule.OnLeave
Reflector is your friend. ;-)
I don't know about a specific event for when the cookie is checked, but you could place the appropriate logic in Application_BeginRequest() and check the user's authentication state there.
Another issue that seems to be related
is that if I let my Session expire,
the FormsAuthentication still seems to
think I am authenticated and it lets
me access a page even though no
currently logged in user exists in my
Session, so the page doesn't render
correctly.
The life of the cookie (how long until ASP.NET feels it needs to ask for a password again) and how you are managing state are unrelated. The ASP.NET authentication is cookie based so that, should a developer want to, he could turn off viewstate, session, use no query strings or hidden fields and authentication still works.
If you want to tie the interval at which you request the password to how you are persisting data, then you will want your session expiration to be roughly the same as the cookie expiration, but they will never quite match up. It would be better to have two policies (one for how fast you throw away a users session data and one for how long you are willing to wait before you need to reask for a password)

Session vs Cookie vs Custom IPrincipal

I'm working on a project where certain logged in users have a dedicated page which they can choose the url of. When a user logins in i would like to display a link "View my page". I was just wondering what is the best way to store this baring in mind it needs to be accessible for as long as the user is logged in (The site has a remember me feature as well). Would a session variable surfice? or a cookie? Or a custom IPrincipal?
Many thanks
Matt
UPDATE:
What do you guys thing of using the UserData string you can store with the authentication cookie? It seems to satisfy my requirements, but i can't say I know a lot about it.
Forms authentication (based on cookie) should be enough. Here you can read about using FormsAuthentication with custom IPrincipal:
ASP.NET 2.0 Forms authentication - Keeping it customized yet simple
This page is about how forms authentication works:
Explained: Forms Authentication in ASP.NET 2.0
When you use forms authentication, you have Authorize attribute to limit access to controllers and action. It works pretty well. Your own IPrincipal is not necessary. I wouldn't use Session, because it can be easily lost.
Thanks guys, however I have ended up using the UserData string that you can store along with the authentication cookie. This way I know the data will always be available while the user is authenticated. And since I only need to remember simple data (the users url), this seems like a good solution.
Anybody with the same problem can find more info here:
http://www.asp.net/learn/security/tutorial-03-cs.aspx (See step 4)
If what you mean is that you want to display a different custom URL for each user and you simply want to cache that URL then there's a few things to consider:
If you use a session value or a cookie then you need code for the possibility of the value not being present. Both the server session or the browser session could expire and the user could still be logged in.
If you use a cookie you could consider setting the cookie expiry to the same as the authentication cookie expiry but this still doesn't guarantee availability.
A cookie value will not be secure, it could be modified. A session value will be secure.
If you're using custom forms authentication then you could store the URL in the authentication cookie itself and then load it into a custom IPrincipal. I would advise against that as I don't feel it's the right place.
If you're just trying to cache the URL then as long as your code re-fetches the data when the value is not present then a session value or a cookie will be fine depending on the level of security required.
If I have read that wrong and you just want to show/hide a link to depending on whether a user is authorized or not you can simple use
<% if (User.Identity.IsAuthenticated) { %>
view my page
<% } %>
And have your MyPage action in your controller render the dedicated page for the user.

Resources