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

fix session sharing and simplify logout #1032

Merged
merged 18 commits into from Jan 31, 2019

Conversation

ahgittin
Copy link
Contributor

@ahgittin ahgittin commented Jan 27, 2019

have a shared session available for the various bundles

mainly to know if each other have authorized. see 1a15c36 for the main new code, in MultiSessionAttributeAdapter.
note this has some historic aborted stuff, in case we need to revisit. that can be ignored, best to evaluate this not commit-by-commit!

also...

this makes /logout just log out and simplifies it

previously it redirected to the user-specific logout; but some clients didn't respect that, and assumed the logout had happened.
not convinced there is a good reason for /logout/{user} ... and if there is, you can now use /logout/redirect to get to it.

calls SecurityProvider.logout and correctly invalildates everything on logout

previously that was neglected

CSRF fail returns 403 FORBIDDEN not 401 UNAUTHORIZED

it's more accurate, and allows clients to distinguish problems from auth fails

previously it redirected to the user-specific logout; but some clients didn't respect that, and assumed the logout had happened.
not convinced there is a good reason for /logout/{user} ... and if there is, you can now use /logout/redirect to get to it.
this takes the first encountered session handler and caches it,
also setting the sessonPath on the cookies so cookies are valid for all bundles.

some low-level hacking to work around pain that CXF doesn't let you configure session handling;
if there is a nicer way i'd love to see it, but i think it would require rewriting chunks of CXF
@ahgittin
Copy link
Contributor Author

experimenting to see what makes sense

the browser seems to keep the local cached creds, even on a 401 unauthorized, so not sure if there's much point in returning that

@ahgittin
Copy link
Contributor Author

ahgittin commented Jan 29, 2019

mostly fixes problem at #1033 and makes it nicer to work with from the uI, including invalidating locally-stored creds

still to do:

  • push the corresponding logout UI fixes
  • figure out whether the Authorization header being kept on the looping /extended call can be made to be dropped after the first call, so it doesn't cache the login, and confirm this means when you've logged out you are properly logged out
  • determine what code is creating a session when the user isn't authenticated
  • check if time-based invalidation (without manual cache deletion) causes the server to crash
  • invoke security provider's logout method

see MultiSessionAttributeAdapter.
this replaces the dodgy brittle request.setSession(...)
that we had tried previously.
@ahgittin ahgittin changed the title make /logout just log out fix session sharing and simplify logout Jan 29, 2019
@ahgittin
Copy link
Contributor Author

done most the list in previous comment. confirmed logout works nicely in browser (unless the /extended call is done in another tab), invalidation just works without problems using new method, and no extraneous sessions are created after logout.

one more issue i've noticed: unauthorized requests create a session which is kept; this is a memory leak and needless. i'll have a quick look to see if that can be undone.

remaining changes will be in PR(s) in other project (UI):

  • push corresponding logout UI fixes
  • figure out whether the Authorization header being kept on the looping /extended call can be made to be dropped after the first call, so it doesn't cache the creds in the app and re-log you in
  • check the ui-module bundles (e.g. module registry) have the same auth/filter and session management configuration

…Provider API

without this DOS attacks could hurt quite quickly

note that this requires further changes to the SecurityProvider implementations
(in addition to the requireUserPass() addition), giving them finer-grained access to the request and the session
@ahgittin
Copy link
Contributor Author

looking good. have updated all other items in the list above at:

(i can't make basic auth fully always disabled, but that's a well-known problem; i've done what i could and added some info about it)

also see minor change needed to brooklyn-dist itests:

these two PRs should be reviewed along with this one

all ready for review and (i hope) merge

Copy link
Member

@tbouron tbouron left a comment

Choose a reason for hiding this comment

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

Thank you @ahgittin, it looks great and clean, knowing the fact that cxf doesn't let you share sessions.

I'm going to test it locally with the other PRs to make sure it is working as expected but didn't want to hold my review in the meantime. I just a very small comments but the rest is brilliant

@@ -20,47 +20,4 @@
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

<Configure id="Server" class="org.eclipse.jetty.server.Server">
Copy link
Member

Choose a reason for hiding this comment

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

Do we even need this file now that we don't configure Jetty with these beans?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure; I think it might break if we remove it. Note that you can't configure the ServletContext / WebAppContext (where SessionHandler is set) at this jetty server-wide level.

@ApiOperation(value = "Logout and clean session")
Response logout(
@ApiParam(value = "Instead of 200 (the default) to indicate successful logout, "
+ "return a 401 with this value in a message key in the body (a 401 will cause browsers to clear some locally cached credentials)",
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 not too sure about returning a 401 for a successful operation, that is counter-intuitive. I got you on the argument that a 401 will make the browser clear the cache but should it be the responsibility of the REST API to take care of that? I don't think so IMO.

Cannot we return a 200 and handle the credential cache in the UI directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, if we return 200 browsers keep the credentials. But note that the API does return 200 unless this unauthorize parameter is supplied. This parameter really exists to help UI clients encourage the browser clear. Pretty sure that's the nicest pattern.

Have updated one comment in LogoutResource to explain better; in short there is no way that either the server or the client can 100% clear creds at present, but this appears to be the best we can do.

// ((Request)jreq).setSessionHandler(new TrackingSessionHandler(((Request)jreq).getSessionHandler()));
// } else {
// log.warn("UNABLE to swap request"+MultiSessionAttributeAdapter.info(jreq));
// }
Copy link
Member

Choose a reason for hiding this comment

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

Can be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd like to keep for the reasons noted in the comment in this section

        // if we need to intercept session creation then can use this
        // create TrackingSessionHandler which delegates (no-op if delegate==null esp in setSessionTrackingMode)
        // and log with stack trace in newHttpSession

I know we could restore it from history but unless/until we are really happy with this behaviour I think it is worth making it a little more prominent.

Added

        //   can remove this after we've been running happily with new session management model for a while

if (handlers != null) {
for (Handler handler: handlers) {
SessionHandler sh = (SessionHandler) handler;
ContextHandler.Context ctx = getContext(sh);
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 a bit concerned performance wise about this call, as getContext(sh) uses refection. This is done within a loop of handler which can be potentially big.

If I read this code correctly, this will be executed only during the session creation, if there is no other sessions marked as preferred, so it is somewhat mitigated. But still, I'm wondering if it could be a bottleneck

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is no other way I don't think. Reflection isn't that slow so I wouldn't expect a problem (CXF does it in a few places too, where the server version might be different). If performance analysis shows it as a bottleneck let's reconsider. But we don't do this often (wouldn't expect more than one per second, probably one per ten minutes in a normal-to-heavy server) on the UI. We do it more often with the CLI (every request) so it might be worth adding a header which says X-No-Session-Needed to suppress session creation (I'm 95% sure other aspects of session creation and management are more significant than this reflection call).

@ahgittin
Copy link
Contributor Author

Note as per #1034 I'v done a full rebuild including dist and it seems to be working great now.

Copy link
Member

@tbouron tbouron left a comment

Choose a reason for hiding this comment

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

LGTM, thanks @ahgittin.

Merging this now as the previous commit passed, and the new changes include only comments

@tbouron tbouron merged commit f54c1e2 into apache:master Jan 31, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants