Authenticating (setting cookies) on 2 separate domains - ruby-on-rails

I'd appreciate any thoughts/insight any of you might have on this...
I have two domains running the same applications e.g. mysite.com and mysite.org and I have a requirement that when a user logs into mysite.com then he should also be logged into mysite.org. Obviously, I can't set the cookie on another domain but I want to come up with a reasonable, secure solution. I think I have a solution (on paper), but I'd just like some feedback on how to improve & secure it.
My sessions table looks like this currently:
id: auto-incrementing; only used for by ActiveRecord
uuid: Universally Unique Identifier used for session lookup
user_id: the user this session belongs to
user_ip_address: the user's IP address
created_at: self-explanatory
updated_at: self-explanatory
My current logic for authenticating on one domain:
User tries to access mysite.com/some_protected_info; they are no authenticated so they are redirected to the login page (the referral URL is stored in a cookie)
User successfully authenticates on mysite.com; a session is created in the DB; a cookie for the mysite.com is created; user is redirected to the referral URL in the cookie i.e. mysite.com/some_protected_info.
My proposed logic for authenticating on two domains:
User tries to access mysite.com/some_protected_info; they are no authenticated so they are redirected to the login page (the referral URL is stored in a cookie)
User successfully authenticates on mysite.com; a session is created in the DB; a cookie for the mysite.com is created; user is then redirected to a mysite.org e.g. mysite.org/login/special
The login controller's special action looks up the session, sees that it's valid and sets the cookie on the mysite.org and redirects back to another controller action on mysite.com.
Given that the user is authenticated on mysite.com (and presumably mysite.org) the user will be redirected back the referral URL (mysite.com/some_protected_info).
Of note:
- Both sites are using SSL.
- Both sites are using the exact same code (mongrel instances) - the Apache config makes it accessible via different domains i.e. the config.action_controller.session settings on both domains are exactly the same.
Questions:
In (2) should I pass in the UUID via SSL or is that a security concern? Should I generate a new, random, temporary ID to lookup the session?
In (3) should I be passing the referral URL around (mysite.com/some_protected_info) or is it safe just to redirect back to the value of the cookie on mysite.com?
Any gotchas? Special situations that I'm overlooking?

This is not a real answer but if you own the two domains you can set your cookies using cookies cross domain policy:
for example you can create a crossdomain.xml on yourdomain.com:
<?xml version="1.0" ?>
<cross-domain-policy>
<allow-access-from domain="yourdomain.org" />
</cross-domain-policy>

A simple design for a sign-on system that works across domains depends on their being a single point for authentication that other domains can use to verify session information.
Typically the sign-in mechanism is an HTTPS protected page that is capable of verifying credentials and issuing a session ID that can be verified remotely. In practice one domain will forward the visitor to the sign-in page for authentication, then the sign-in process will redirect the visitor back to the original site with some kind of session-ID parameter passed along that can be assigned to a cookie by the original site.
For applications with only moderate security requirements, the session ID value can be encrypted or hashed using a "secret key" known to both the sign-in system and the other domains. This is used to prove that a user's session ID has been issued by the sign-in system and isn't just arbitrary. This is not unlike hashing a password with a salt for verification purposes.
While UUIDs may seem sufficiently unique, the generator may produce predictable numbers, or numbers with insufficient randomness. That is why sending a "signing" value is useful to preclude spoofing.
The idea you have seems fairly solid, but the details matter. It may be worth studying things like OpenID for how they handle session authentication via their protocol.

Related

In which order are pac4j client used

I have an application using pac4j and use multiple authentication clients to secure my routes (both direct and indirect) like this: Secure("AnonymousClient", "FacebookClient", "JWTClient").
I don't really understand in which order the clients are used though. It seems to be from right to left and 401 is returned if none of the clients could build a profile. Am I right?
Is it the same order for the authorizers?
Seems to be much more complicated than that. From the comments in DefaultSecurityLogic.java:
First, if the user is not authenticated (no profile) and if some
clients have been defined in the clients parameter, a login is tried
for the direct clients.
Then, if the user has profile, authorizations are checked according to
the authorizers configuration. If the authorizations are valid, the
user is granted access. Otherwise, a 403 error page is displayed.
Finally, if the user is still not authenticated (no profile), he is
redirected to the appropriate identity provider if the first defined
client is an indirect one in the clients configuration. Otherwise, a
401 error page is displayed.

What is the point of PostLogoutRedirectUri in Open Id/OAuth2.0 logout?

I've been using Identity Server 4.0 as my OpenId Connect provider. I can setup clients in Identity Server with Redirect Uris and Post Logout Redirect Uris. I've also been using the angular-auth-oidc-client to login/logout via the Identity server.
When logging in, my client library (angular-auth-oidc-client) does pass in the correct Uri specified in the config when calling the authorize endpoint. When I try to login with an incorrect Redirect Uri, Identity Server checks and validates that the Uri provided by the client is one of the accepted one for that client, and shows an error if it isnt (as expected).
When it comes to logout, none of it seems to be built in. My client library does not send the PostLogoutRedirectUri when calling the logout endpoint. Identity Server's sample code for logout does not except any URIs to be passed in. It's sample code simply gets the Post Logout Redirect Uri value from the database and creates a link on the logged out page. Not only does the sample code not allow the user to specify the Redirect Uri for logout, but it doesn't do any checks or even do a redirect (granted its only sample code and I can change it). I would expect my client library to pass the Uri along and Identity Server to redirect to the Uri after successful logout as long as its one of the "approved" Uris for the client.
My question is: What even is the point of PostLogoutRedirectUri? Neither Identity Server nor the OIDC client library I'm using do anything useful with it. There doesn't even seem to be an agreed upon convention for the name of the query string parameters to use to pass this Uri to Identity Server. And yet, both the Identity Server and the angular client library seem to have some support for it. So what's the point of this thing? Is it something that will be added or fleshed out later? Did I miss some documentation describing what its for and how to use it?
It's a draft standard and support differs between libraries and vendors, but here is a summary:
A client uses the post logout redirect URI to log out in a controlled way, typically redirecting to an application page that gives the user a link to sign in again
A client could potentially have more than one post_logout_redirect_uri and decide which to use based on runtime conditions
The post_logout_redirect_uri sent is meant to only be honoured if it is accompanied by an id_token_hint - and if it matches a configured value against the OAuth client. I believe OIDC will send the current id token but it is worth checking that this is happening in your browser tools.
If a post_logout_redirect_uri is not sent then the Authorization Server may use the default one configured
See the official IETF docs on how this is meant to work.
In my own application, I set it to the /Signout-callback-oidc URL of the client, like
PostLogoutRedirectUris = { "https://localhost:5001/signout-callback-oidc" },
The /signout-callback-oidc path is defined as in the source code here:
/// <summary>
/// The request path within the application's base path where the user agent will be returned after sign out from the identity provider.
/// See post_logout_redirect_uri from http://openid.net/specs/openid-connect-session-1_0.html#RedirectionAfterLogout.
/// </summary>
public PathString SignedOutCallbackPath { get; set; }
I hope this can give some clarification.
There are two sessions, one in the UI, and another on the server. It might need to call a URL on the backend to remove the user session on the server, otherwise the server won't know you are logged out on the UI.

Is it possible to get the domain of a user without Windows Authentication?

I believe I know the answer but my boss thinks otherwise. I need to be able to be able to pull the current visitors domain that they are currently signed into using User.Identity. I am certain windows authentication must be enabled but my boss believes he accomplished this feat before without it. I just want to confirm. The website must allow anonymous access, figure out which domain a user is coming from (AD domain) and redirect them to the appropriate sites.
Turned on widows auth, success. Turned on anonymous with win auth, failure. Turned off windows auth, turned on anonymous access failure.
Site has to be anonymous to allow all users to visit it due to the political nature of our business.
userInfo = User.Identity.Name.Split('\\');
if (userInfo.Length > 0)
{
domainName = userInfo[0];
userID = userInfo[1];
}
User.Identity is null when windows auth is off. Users are prompted to provide authentication when it is on.
Unless your site returns a 401 challenge (i.e. some authentication needed) then you will have no access to any identity data.
The user will always be anonymous.

Devise session does not persist on different URL

I have a rails application and I am using devise for authentication.
When I get logged in successfully on URL http://localhost:5000/,
I try to access http://127.0.0.1:5000/ in the same browser.
I expect to be logged in as soon as I access it on http://127.0.0.1:5000/ but application remains logged out. Whats going on I really cannot understand as I am trying to access both URLs in the same browser?
UPDATE:
my config/initializers/session_store.rb
Rails.application.config.session_store :cache_store, key: '_app'
The fact that you are logged in is store in the session which is stored in a cookie. For security reasons, the browser sends cookies only to the URLs from which the cookie was set.
From the browser's point of view, localhost and 127.0.0.1 are totally different URLs. Therefore the login information stored in the cookie on localhost is not sent to the server running at 127.0.0.1 and therefore the server running at 127.0.0.1 has no information about an existing session on localhost.
UPDATE:
Using the cache_store to store the session doesn't change anything because the information what session in the cache store belongs to the user is still stored in the cookie.
Imaging that your server needs to store all generated sessions somewhere. And if a user comes backs the server needs to know which session belongs to the user. A simplified solution to this problem might be to assign a random number to each session and give the user this number (stored in the cookie). When the user returns the cookie is returned too and that allows the server to load the session by that number.
And a cookie is bound to a domain. This is a security feature of the browser. If it didn't work that way all sessions would be sent to all domains: Google would know if you were logged in to Facebook, every website would know that you have a cookie from your bank...

Handling login functionality for native app connecting to web service

After extensive research, I have not been able to find a clear answer to my question. Firstly, can anyone tell me the basic logic of handling "login functionality" for a native iphone app connecting to a web service? For instance, the facebook app ask for a username and password immediately after launch, and from there you have full access to your account in all successive views of the app. Each time you post something etc, you do not have to re-login... Can someone please explain this process to me? Is it done through cookies or sessions? is Keychain involved?
I have a semi-working app right now but I'm almost positive I could be doing it better and more securely. Here is what I'm doing:
1) Set up a local server with a database of users (username and password columns and other tables etc.) using mysql. Wrote a simple web-service that takes in POST data and queries the database to check that the username exists... and if it does, that the passwords are equal. Using sha1 hashing. Echo true or false accordingly.
2) My app has an initial login screen with a 2 textfields (1 for username and 1 for password) and a button that calls the login method. My login method does the following:
init an *NSURL with a string (the url of my web service: #"http://webservice.com/login.php")
init an *ASIFormDataRequst with that url
set the post value with the password and email text in the text fields
set the delegate to itself
call startAsycronous on the request
implemented the requestFininshed method to retrieve the "true" or "false" echo-ed from the webservice
depending on the response, move forward to the next view, else, make an alert telling the user to retry
So, my questions are:
1) Is this secure for sending passwords? (via ASIHTTPRequest and the POST method?)
2) In the succeeding views, the user should be able to interact with their account (like posting messages and status's and pictures on the Facebook) How do I persist the user's logged in status so that every time the user interacts with the database, I can ensure that the user is still logged in and that it's the same user? For instance, the only way I can think of doing this is if I store a cookie on the users device with the username and password, and then every successive interaction with the web service / database, it does an authentication with the cookie values (username and password).
There has got to be a better way of doing this? Maybe sessions or cookies? or by using keychain??
Thanks for the help guys, and sorry for the long question!
Here are my thoughts based on what I know:
1) Is this secure for sending passwords? (via ASIHTTPRequest and the POST method?)
You need to make sure you are sending this information via https (SSL) and not a plain Http. The reason is, you don't have control over where the user wireless access point is. For all you know, the user could connect to open access point that is belong to a particular hacker. Having it transmitted will enable him to sniff the packet and get the required information to access the WebService even though the password is hashed. Having it send via https would ensure that the packet is encrypted with strong key. Even if a hacker manage to sniff the packet out, it will take him a long time before he/she is able to decrypt the message.
In the succeeding views, the user should be able to interact with their account (like posting > messages and status's and pictures on the Facebook) How do I persist the user's logged in status > so that every time the user interacts with the database, I can ensure that the user is still logged in
and that it's the same user?
One commonly employed method to do this is to get the session token after the user logged in. That is, you create a random generated ID that you return upon successful login. You would then map this token with the user id in the backend and it is associated with a session time out. You refresh this time out every time the user connects to a webservice and time it out after certain period to avoid breach of security. You would then persist the session token in your device and then used that for subsequent call. As long the session is alive then the user is logged in. As the token is associated with a specific user, you also ensure the identity of the caller.
To prevent someone else using other people token is the reason why you need SSL to secure the channel and prevent sniffing. Assuming that you have secured your connection channels, the only way to get the token is
to verify the identity via login
The phone is stolen by hackers who could take the token by inspecting the local storage.
The mapping is necessary so you could validate the token is a real token that has been associated with the user via login activity. Furthermore,for number 2, you can offer remote wipe out feature that basically kills the mapping and making that token invalid.
Another very important part of this token is the token cannot be guessable and have to be random cryptographically (see Randomness Recommendations for Security). If the token is only based on pseudo randomness, a clever hacker might be able to guess its algorithm and can guess its next/previous token and has a possibility of obtaining any valid token in the table.
There are many algorithm to generate this token. For example, Java Programming Language provides a SecureRandom class in order to provide cryptographically randomness and .NET has similar secure RandomGenerator class.
If you want to look at the algorithm OATH has proposed Time-Based One-Time Password Algorithm (TOTP) which is an extension of HOTP. Most of the languages/platforms would have the cryptographically strong random generator that you could leverage immediately though without you having to write it yourself.
Depending on your service implementation/platform, you might want to ask SO for a suitable class/module for cryptographically random generator such as the one asked here "How do you generate cryptographically secure random numbers with php"

Resources