Setting the session token '_t' on the entire domain, not just my subdomain


(Daniel Eklund) #1

Continuing the discussion from Encryption of _forum_session cookie:

I have a site set up at forum.wordadoplicus.com. When a user logs in, it sets a cookie ‘_t’ that I could use to look up user info in the database. However, the set-cookie command is being used for the subdomain itself, and not for other subdomains. This means that when a user navigates to something.wordadoplicus.com, this _t is not being sent.

Is there a configuration parameter somewhere I can change to affect this, so that post-login, the set-cookie response header sets it for “.wordadoplicus.com” instead of “forum.wordadoplicus.com” ?

thanks,
daniel


(Daniel Eklund) #2

Update.

I entered the Docker container, thinking that I could use some Nginx trickery to accomplish this. Nginx has what looks like a perfect directive to handle this: proxy_cookie_domain

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cookie_domain

But, as usual, Nginx is a tricky trickster. This only works if there is a ;domain= set in the cookie.

But the set-cookie headers coming back from discourse are sans domain. For instance
set-cookie:_forum_session=d2tpcUFWbHB0TXV4KzlzMWdTcnR4Z0U3UjNUN1FJRGdtTHdLRU1BYlN1N3dRNkFGK0d3dVNja2o3bHBvZHYzQ2NWSUdVMm9COFhCSjBzSTJIVThoOEdSdWFZMk9ucFhSVitWc0J3WCswdFNTMTJpYmZTSVR4K2JlT0xnaHNseEIvcDRub3Rla0FGZjNZMnVsWkhTbHVQSFRQSkVaUXZWTkxhQjNGUnBNM3didDkrMFFEV0M2OEdWQndlWWhvTXVmLS0wZkhMOGtmRGhjYXBOcnlqQzVVdzR3PT0%3D--036dcfb2a44bce0fafade7a2c46dd2b4e5e7b2fe; path=/two; HttpOnly

You can see in the above that I was able to use a proxy_cookie_path to change the path from ‘/’ to ‘/two’, but the lack of domain in the set-cookie does not allow me to do this in Nginx.

Can anyone point me to the ruby file that sets the cookie? I’ve scanned github and used find/xargs/grep like crazy on the source but can’t seem to find where this is being set.

daniel


(Daniel Eklund) #3

Just to explain my motivations for doing what is above, in case someone can ask me, “are you nuts?”

  1. I have installed discourse on forum.wordadoplicus.com (it exists in amazon, using elasticache and RDS/postgres for the db)

  2. I have a game-site I’ve developed on wordadoplicus.com. It exists on a different server (written in Erlang, fwiw).

  3. I want to use Discourse as my user management system, so that new users can register on the forum and then the game server can know what user is playing. (i.e. I don’t want to write from scratch the email-registration/verification/password-hashing/lost-password functionality that Discourse has already written so well)

  4. From my game-site I have access to the RDS db, so I should be able to
    SELECT id FROM users WHERE auth_token = '#{token}'
    once I have access to the token (_t)

  5. To get access to the token, I need _t to be sent back once someone goes to wordadoplicus.com.

  6. But the _t token is set on the specific forum.wordadoplicus.com, as I’ve described in the posts above.


There seem to be a lot of requests to get Discourse working together within a larger ecosystem. I considered using Discourse as my SSO provider, but using Discourse as a SSO provider is

  1. Complicated (since I would need to write the MD5 hashing, nonce-checking, base64 encoding protocol in Erlang)
  2. Not quite what I need… Here’s a scenario
    1. User registers on the forum
    2. User goes to wordadoplicus.com
    3. User has to go back to forum.wordadoplicus.com to get single-signed-on

This last point is everything. All I need is access to the “_t” token. It is the proxy for my user and something I can look up in the database to get user info and set my own session.

Am I alone in this need?

thanks a bunch


(Matt Palmer) #4

I don’t know about “alone”, but I think you’re likely to be in the extreme minority. The Discourse SSO route is the supported, stable way. There’s no guarantees that any cookie will keep the same format over time, so you’ll need to carefully test every update of Discourse to make sure the cookies are still in the format you expect.

I don’t think the SSL works quite as you describe, though: while it’s true that the browser will go back to the forum to get signed on, it should be transparent to the user. The main site will redirect the browser to the forum for the auth check, the forum will validate the cookies as being correct, and then automatically redirect back to the right place on the main site. The user probably won’t even notice, let alone care that there’s a once-off redirect chain to get them signed in on the main site.


(Daniel Eklund) #5

Matt,

Thanks for taking the time to reply. I do understand that I might be in the minority in how I plan to use Discourse.

As I am trying to lower the appearances of a separate application between the forum and my main site, I think I will have to make the modifications on my own, and track closely new releases.

Even with SSO if the user has registered at the forum, (on forum.wordadoplicus.com), and is now going to the main site (wordadoplicus.com) for the first time, then, barring a cookie, I have to ask them to re-enter their credentials. I have no way of knowing who they are the very first time they come to the site.

For future reference, and for people who are looking to do the same thing,
I modified /var/www/discourse/lib/auth/default_current_user_provider.rb

  def log_on_user(user, session, cookies)
    unless user.auth_token && user.auth_token.length == 32
      user.auth_token = SecureRandom.hex(16)
      user.save!
    end
    cookies.permanent[TOKEN_COOKIE] = { value: user.auth_token, httponly: true ,
                                        secure: true,   domain:ENV["DISCOURSE_HOSTNAME"]}
    make_developer_admin(user)
    enable_bootstrap_mode(user)
    @env[CURRENT_USER_KEY] = user
  end

You can see that I added the domain attribute. This allows me to use Nginx’s proxy_cookie_domain directive to change forum.wordadoplicus.com to wordadoplicus.com as the response header makes its way back to the user (although I could have hardcoded the main domain there instead).

Additionally, as I don’t want this _t token to leak outside of https, I have added the secure flag, as per this discussion:
Secure Cookie flag

I think these two additions might benefit others, but appreciate Sam’s comment (in the other thread) that this would have to be heavily tested for backward’s compatibility.

Thanks for all the great work, Discourse team.

daniel


(Matt Palmer) #6

That’s… what the SSO is for. You see a user you don’t recognise, you redirect the user to Discourse SSO, asking “please tell me who is user is”. Discourse looks at the cookie that it gets sent, sees the user is already logged in, and redirects straight back to your app with the necessary info. No need for the user to log in, because they’re already logged in to Discourse.


(Daniel Eklund) #7

Matt,

I was all set to object to you, but I think I finally get it. However, I’m going to go through this just to make sure I finally (or really) understand this, (and to leave this as a historic record of my ignorance/learning that others might learn as well).

I was going to object to this statement:
Discourse looks at the cookie that it gets sent

and say, “but I didn’t set a cookie”. But, now I finally think I’m getting what you were trying to tell me:

  1. a user goes to the forum.wordadodplicus.com site (dicourse) and registers. Discourse sets both the _t (persistent) and the _forum_session (session) tokens.
  2. the user goes to my main site (non-discourse) but no discourse cookies come through – they can’t.
  3. my rules detect the lack of my cookies (not discourse’s)
  4. because of this, my process does a 302 (or 301) to DISCOURSE_ROOT_URL/session/sso_provider as per this discussion: Using Discourse as a SSO provider
  5. this redirection sends the discourse _t and _s cookies (along with all the other payload info) and Discourse sends user information back to my process
  6. I set my own cookie, indicating that we don’t need to redirect to Discourse SSO API, if the user comes back again (I could make it a session cookie, or a persistent cookie, depending on what I might implement in my own session-store/database with the returned information)

You said all this before in your earlier post:

The main site will redirect the browser to the forum for the auth check, the forum will validate the cookies as being correct, and then automatically redirect back to the right place on the main site,

but I was too heads-down to read your reply properly, especially the phrase:

the forum will validate the cookies as being correct.

thanks again,
daniel