Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow authentication against the _vmdb_session cookie for UI only #543

Merged
merged 1 commit into from
Jan 17, 2019

Conversation

skateman
Copy link
Member

@skateman skateman commented Jan 15, 2019

We're consuming the API from our UI with token authentication, which is not the best because we have to poll the API to renew the token. This made the complexity of the login code unnecessarily high and also the token renewal floods the log with useless information every X seconds.

The API and the UI workers are both using the same memcached server to store short-living information, such as sessions or tokens. As the two workers are basically the same application, they implicitly have the same session cookie and so through memcached, sharing the access to the same session. However, the API was not using this session, for now.

I'm proposing a new authentication mechanism for the UI only (replaces #542) that will test if the CSRF header is set on the API request. This header will be used from the UI only and will also prevent from opening a HTTP basic auth dialog even if the session times out. This will make #542 completely obsolete.

I've discussed this with @Fryguy already and honestly, due to the simplicity of this feature I am afraid that this is too good to be true. Anyway, we will use this PR with @himdel to work further on the UI part and make changes if something goes wrong. The behavior of the API should not be affected by this change, however, we will be able to drop a few hunderd lines of JS from the UI.

When using external authentication, the apache would force basic auth on every unauthorized API request, but there's a fix for that here: ManageIQ/manageiq-appliance#224

@himdel
Copy link
Contributor

himdel commented Jan 16, 2019

This header will be used from the UI only and will prevent from opening a HTTP basic auth dialog if the session times out.

Looks like this is still missing the header code.

Without it, when the cookie expires, the request will be done without a cookie, auth_mechanism will return nil, and we will end up in when :basic, nil: request_http_basic_authentication...

@skateman
Copy link
Member Author

@himdel you're right, we're also missing the CSRF token validation ... the question is how we want to have them. I assume that GET requests to the API should be also verified against the CSRF token, but maybe i'm off the rails with this (pun intended). ping @martinpovolny

@skateman skateman force-pushed the cookie-auth branch 3 times, most recently from 72377e0 to 4b3da56 Compare January 16, 2019 19:20
@skateman
Copy link
Member Author

@martinpovolny I've added the CSRF token verification, it was way simpler than I thought. I assume we also want to verify the origin, but please let me know if not. cc @himdel

@miq-bot
Copy link
Member

miq-bot commented Jan 17, 2019

This pull request is not mergeable. Please rebase and repush.

@jvlcek
Copy link
Member

jvlcek commented Jan 17, 2019

I worked with @skateman to test these changes. The testing done was with SAML via Keycloak, External Auth and SSO (kerberos) via IPA. I believe this is a good test sampling. LGTM JoeV

@skateman skateman changed the title [WIP] Allow authentication against the _vmdb_session cookie for UI only Allow authentication against the _vmdb_session cookie for UI only Jan 17, 2019
@skateman
Copy link
Member Author

skateman commented Jan 17, 2019

@miq-bot rm_label unmergeable
@miq-bot add_reviewer @abellotti
@miq-bot add_label hammer/no

@Fryguy
Copy link
Member

Fryguy commented Jan 17, 2019

The behavior of the API should not be affected by this change, however, we will be able to drop a few hunderd lines of JS from the UI.

wow 😮

# only the CSRF token is being sent and we want the API to know that the request was
# initiated from the UI. Otherwise the response to a such request would force the
# browser to throw an undesired HTTP basic authentication dialog.
:cookie_ui
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm reading in your comment is that the CSRF token will always exist, so why have the check for the session cookie here at all. That is, it seems this code can just be

...
elsif request.x_csrf_token
  :cookie_ui
else
...

Copy link
Member

@Fryguy Fryguy Jan 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, that being said, where do we use the SESSION_COOKIE at all after this point? Even in your tests, I don't see you setting the cookie at all.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Fryguy in my tests the session cookie is sent automatically, that's AFAIK default rack behavior. You'll have a session cookie in Rails after your first request to the site, even if you're not logged in. But you're right, I'll simplify this part...

when :basic, :basic_ui, nil
when :cookie_ui
raise AuthenticationError unless valid_ui_session?
auth_user(session[:userid])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming the cookie check is in here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually happens earlier in the valid_ui_session? when validating the CSRF token as it is also part of the session.

@Fryguy
Copy link
Member

Fryguy commented Jan 17, 2019

I have a few questions but overall I'm ok with this approach. I would like another set of eyes though... @jrafanie ?

@jrafanie
Copy link
Member

I have a few questions but overall I'm ok with this approach. I would like another set of eyes though... @jrafanie ?

Yeah, I looked at it. @skateman and I chatted and I neglected to comment here. I'm good with the changes although I'm not sure what to do about the verifying of the origin.

@miq-bot
Copy link
Member

miq-bot commented Jan 17, 2019

Some comments on commit skateman@c8cfce3

spec/requests/authentication_spec.rb

  • ⚠️ - 220 - Detected expect_any_instance_of. This RSpec method is highly discouraged, please only use when absolutely necessary.
  • ⚠️ - 233 - Detected expect_any_instance_of. This RSpec method is highly discouraged, please only use when absolutely necessary.
  • ⚠️ - 240 - Detected expect_any_instance_of. This RSpec method is highly discouraged, please only use when absolutely necessary.

@miq-bot
Copy link
Member

miq-bot commented Jan 17, 2019

Checked commit skateman@c8cfce3 with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0
3 files checked, 1 offense detected

spec/requests/authentication_spec.rb

@skateman
Copy link
Member Author

@jrafanie I've added the origin verification, it doesn't hurt as it allows nil origin as well which is the standard Rails behavior. The browser sends the Origin header with POST requests only, so those will get validated (tested - works). We can append the header manually to other type of requests in the UI code, but that's a decision to make in the UI PR.

Copy link
Member

@jrafanie jrafanie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@Fryguy Fryguy merged commit b903640 into ManageIQ:master Jan 17, 2019
@Fryguy Fryguy added this to the Sprint 103 Ending Jan 21, 2019 milestone Jan 17, 2019
@skateman skateman deleted the cookie-auth branch January 17, 2019 20:44
@martinpovolny
Copy link
Member

martinpovolny commented Jan 18, 2019

As discussed f2f: when talking with the API from a browser there should be 2 secrets:

  • one in possession of the browser, but out of controll of the Javascript -- that is the (http-only) cookie.
  • second in possession of the Javascript code so that it does not get automatically added by the browser (unless requested by javascript code) -- that is some token.

The 1st is vulnerable to XSRF but relatively safe from XSS, the 2nd is vulnerable to XSS but relatively safe from XSRF.

Then together with CSP we should be safe. (We still have to work on making the CSP policy stricter.)

I have to confess that I have not read this PR in details but I believe that your solution is implemented as we discussed.

👍

@skateman
Copy link
Member Author

@martinpovolny yes it is, now it hangs on the UI side here: ManageIQ/manageiq-ui-classic#5164

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants