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

Add User.revoke_sessions #20601

Merged
merged 5 commits into from
Oct 9, 2020
Merged

Conversation

NickLaMuro
Copy link
Member

@NickLaMuro NickLaMuro commented Sep 25, 2020

Built on top of #20477
Requires ManageIQ/manageiq-schema#503

Adds functionality to revoke all sessions (API, UI, etc.) from a given user.

Links

Steps for Testing/QA

I tested this locally by:

  1. Starting up a server
  2. Running a collection of API calls, where I first requested a token
  3. Looked up the user that was fetching said token
  4. Called this new method on that User instance (.revoke_sessions)

@NickLaMuro
Copy link
Member Author

cc @Fryguy @gtanzillo

@miq-bot miq-bot added the wip label Sep 25, 2020
@NickLaMuro NickLaMuro force-pushed the user-revoke-sessions branch 2 times, most recently from 7446bc3 to 580cfcb Compare September 28, 2020 16:22
Copy link
Member

@kbrock kbrock left a comment

Choose a reason for hiding this comment

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

this looks good nick

lib/token_store/sql_store.rb Show resolved Hide resolved
lib/token_store/sql_store.rb Outdated Show resolved Hide resolved
app/models/user.rb Show resolved Hide resolved
app/models/user.rb Outdated Show resolved Hide resolved
app/models/user.rb Outdated Show resolved Hide resolved
def revoke_sessions
current_sessions = Session.where(:user_id => id)
ManageIQ::Session.revoke(current_sessions.map(&:session_id))
current_sessions.destroy_all
Copy link
Member

Choose a reason for hiding this comment

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

Wondering if this should be in a transaction?

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably not a bad idea.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, I am going to hold off on this.

While a transaction would be nice, unfortunately, there is a possibility it will be not function as expected, since ManageIQ::Session could have a .store of memcached, so the transaction wouldn't be "fully reverted" if we were to wrap both .revoke and .destroy_all in a single transaction.

I think the .destroy_all would be in it's own transaction, but I could be wrong so I don't know if there is any value of wrapping just that line.

lib/token_store.rb Outdated Show resolved Hide resolved
if data[:userid]
user_tokens_cache_key = "tokens_for_#{data[:userid]}"
user_tokens_cache = read(user_tokens_cache_key) || []
user_tokens_cache << token
Copy link
Member

Choose a reason for hiding this comment

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

This is really tricky in a multi-threaded environment particularly with memcached. As two competing threads come in, they can't step on each other.

This was sort of what I was hinting at in the original proposal (#20378 (comment) - see the cross out section on memory_store), where I mentioned for memached we might need to use CAS.

These particular "create an extra index in the memory store" was what we were trying to avoid by storing all of the records in the sessions table regardless of the store type. I'm not against encoding an index in each one instead, but I think each one has nuances.

Copy link
Member

Choose a reason for hiding this comment

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

if we are using multiple memcached instances, then each server will have a unique list of session ids
and has a low likelihood of stepping on another server's toes. Also, every server can not clear the sessions on other memcached servers. Maybe the use cases for problems are simpler in terms of the session store and more complicated in terms of broadcasting to delete all of a user's sessions.

Yes. A single server could have multiple sessions coming live at the same time. Maybe via the api and rails at the same time? I am having trouble coming up with a use case that doesn't seem far fetched.

Before we go super complex on distributed memcached servers, can we entertain using a single session store? Just like we use a single data store (postgres).

@NickLaMuro NickLaMuro force-pushed the user-revoke-sessions branch 2 times, most recently from b4bf634 to 7b86b37 Compare September 30, 2020 15:13
@NickLaMuro
Copy link
Member Author

@Fryguy @kbrock @lpichler I think I have addressed all of your feedback, so please let me know if there is anything else.

@lpichler do these changes now work for you? I assume you had this pulled down locally previously.


@Fryguy So, I think the only outstanding item in this PR is the threading issues, which I think I would like to address in a followup, assuming you are okay with the approach we have now currently.

This isn't to say it isn't important, but since I am not sure how we want to tackle it, and if what we did is even helping, I think deferring the implementation of this would allow the rest of the effort to move forward while we mull over the details to address that particular issue.

That said, if you think how any of this is implemented currently might be at odds with a future "thread/process -safe" solution in the future, I am happy to address that now. The deferring of implementing the locking/mutex/CAS bits is what I am suggesting at the moment.

app/models/user.rb Outdated Show resolved Hide resolved
@lpichler
Copy link
Contributor

lpichler commented Sep 30, 2020

@lpichler do these changes now work for you? I assume you had this pulled down locally previously.

yes it works - otherwise I have two comments and it looks that those issues need to be solved:

thanks

@NickLaMuro
Copy link
Member Author

@lpichler thanks for taking a look! I should have addressed your issues now. Sorry for the derps...

@lpichler
Copy link
Contributor

lpichler commented Oct 1, 2020

@lpichler thanks for taking a look! I should have addressed your issues now. Sorry for the derps...

@NickLaMuro, it is working great, thanks!

it looks that CI failure is related to this PR.

@NickLaMuro
Copy link
Member Author

it looks that CI failure is related to this PR.

It was, though the way the spec was written, it probably was a scenario that wouldn't happen. Regardless, I added a guard clause (.try) to allow it to work properly.

@NickLaMuro NickLaMuro changed the title [WIP] Add User.revoke_sessions Add User.revoke_sessions Oct 1, 2020
@miq-bot miq-bot removed the wip label Oct 1, 2020
@NickLaMuro
Copy link
Member Author

NickLaMuro commented Oct 6, 2020

@Fryguy @kbrock I think you two are the outliers here that left reviews, but didn't follow up.

Are you good with the new changes? In particular, @Fryguy , are you good with the rationale I gave regarding the locking functionality and addressing it at another time? [ref]

@Fryguy
Copy link
Member

Fryguy commented Oct 6, 2020

I am good with deferring the theadsafety issues to another PR, but I think it has to be in relatively quickly. Puma by its nature is multi-threaded, so we will start seeing issues almost immediately, I'd expect. @jrafanie wdyt?

gtanzillo and others added 5 commits October 7, 2020 08:09
Implements methods for tracking user tokens for a given userid so they
can be deleted all at once.
Makes the instance variable `@token_store` of `TokenStore` a
`cattr_reader`, and then uses that to loop through each of the token
stores to delete all of the sessions associated with the currently
instanced userid.
@miq-bot
Copy link
Member

miq-bot commented Oct 7, 2020

Checked commits NickLaMuro/manageiq@0bd0c87~...7b4679d with ruby 2.6.3, rubocop 0.69.0, haml-lint 0.28.0, and yamllint
4 files checked, 0 offenses detected
Everything looks fine. 🍪

Copy link
Member

@kbrock kbrock left a comment

Choose a reason for hiding this comment

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

this is looking much nicer. thanks nick

@@ -1,20 +1,47 @@
class TokenStore
@token_caches = {} # Hash of Memory/Dalli Store Caches, Keyed by namespace
module KeyValueHelpers
Copy link
Member

Choose a reason for hiding this comment

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

thanks - this is much nicer than the individual monkey patches

if data[:userid]
user_tokens_cache_key = "tokens_for_#{data[:userid]}"
user_tokens_cache = read(user_tokens_cache_key) || []
user_tokens_cache << token
Copy link
Member

Choose a reason for hiding this comment

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

if we are using multiple memcached instances, then each server will have a unique list of session ids
and has a low likelihood of stepping on another server's toes. Also, every server can not clear the sessions on other memcached servers. Maybe the use cases for problems are simpler in terms of the session store and more complicated in terms of broadcasting to delete all of a user's sessions.

Yes. A single server could have multiple sessions coming live at the same time. Maybe via the api and rails at the same time? I am having trouble coming up with a use case that doesn't seem far fetched.

Before we go super complex on distributed memcached servers, can we entertain using a single session store? Just like we use a single data store (postgres).

@NickLaMuro
Copy link
Member Author

NickLaMuro commented Oct 8, 2020

Before we go super complex on distributed memcached servers, can we entertain using a single session store? Just like we use a single data store (postgres).

@kbrock I will not be "entertaining" anything like that until after this PR has been merged, and probably not even consider it myself until the next release. I already asked for this to be reviewed a few days ago now after it has been open for close to a couple of weeks, only for it to be made unmergable to "entertain a refactoring" that really solved nothing:

#20663

This is holding up other dependent work on being finished, so anything in he name of refactoring is a hard pass until the MVP of this feature is addressed.

@gtanzillo
Copy link
Member

@Fryguy Can this be merged? I think Nick addressed all of the comments

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.

6 participants