Ah, good idea! We do use that already for admins / support staff to impersonate users, but hadn't thought of its use here - we'll have an explore of how this could work...
> On 5 Dec 2019, at 22:47, Brian Demers <[email protected]> wrote: > > Have you thought about using Shiro's "RunAs" feature? > > On Tue, Dec 3, 2019 at 3:41 AM Richard Adams <[email protected] > <mailto:[email protected]>> wrote: >> Where are your permission checks located? Can you move to check into the >> request instead of checking late in the batch process? > Not really - a user's content is a series of documents which can contain > links to other documents; also documents belonging to other people that have > been shared; these linked /shared documents(that require permission checks) > are only identified during the traversal of user's content during the export > process. > It's possible we could do some initial scan to check permissions in the > request thread, and then switch off permission checking in the background > thread, but this initial scan is still likely to take some time and doesn't > solve the issue for really large exports where this would probably still be > too slow. > > Thanks Richard > >> On 3 Dec 2019, at 00:22, Brian Demers <[email protected] >> <mailto:[email protected]>> wrote: >> >> Where are your permission checks located? Can you move to check into the >> request instead of checking late in the batch process? >> >> On Mon, Dec 2, 2019 at 5:57 PM Richard Adams <[email protected] >> <mailto:[email protected]>> wrote: >> Thanks >>> On 02 December 2019 at 21:49 Brian Demers <[email protected] >>> <mailto:[email protected]>> wrote: >>> >>> A couple of things stick out: >>> >>> 1.) You shouldn't need to call `subject.login()` directly. This is almost >>> always handled by some framework for you (like the Shiro Servlet Filter). >>> The same can be said for `.logout()` though to a lesser extent. >> This just seems a good entry point to encapsulate authenticating the token - >> we have an ApiTokenRealm to authenticate the token and by using this >> approach we can reuse getAuthorizationInfo() method that we use for >> username-password logins. Also if authentication fails we want to throw a >> 401 status rather than redirect to a login page for the web UI which the >> ShiroServlet filter does >>> 2.) As for the "logout" issue, I think this is a misuse of logout. >>> If you truly don't have any session/state, then the "logout" doesn't >>> _really_ have anything to clean up (like a session cache, or container >>> related session) >>> You _shouldn't_ be logging a user out if you expect the subject to remain >>> active (as you still need the context of the given subject). My guess >>> (based on minimal data) is that you are forcing a logout, because you are >>> also managing the "login"? >> You are probably right, as much as anything it seems symmetrical, if we are >> logging users in, to log them out again after the response is generated >>> >>> Things get a little tricky when you with async tasks though, and the best >>> solution might depend on what you do when the processing is done. Are you >>> emailing the user some results? Does the user poll an endpoint until the >>> job is finished? >> In the web application, the user can continue using the application while >> the background job is running. When the job is finished, it notifies the >> user either by email, in-app messaging or slack depending on preferences. >> For API invocations, the client gets a jobId which they can use to query for >> progress - we implement a thin wrapper around Spring Batch which does the >> bulk of the job management. >> Our application is a specialist content management system for scientific >> researchers. The background job is an export task which iterates over user's >> content (typically 10s to 10_000s of items) and generates HTML, PDF or XML >> exports. The end result is a download link. For each candidate item to >> export we do a permissions lookup to see if the user has permission to read >> that item (hence the need for Shiro's permissions lookups). >> From what you are saying it sounds like we can just not call logout() for >> the API calls. But how to handle a user logging out of web application while >> background process is running? They may have a valid reason to logout(e.g. >> they are working on a shared computer and they have to leave it unattended) >> but would not want their background jobs to be stopped/cancelled. Is their >> some way to clone a Shiro subject and bind it to another thread? >> Thanks >> Richard >>> If the user does need to logout (and I can see some valid use cases for >>> this anyway, for example, If the job runs for 3 hours and the result is >>> emailed to the user) then there is no reason for a subject to be kept >>> alive. >>> There are a few ways to work around this, but can you give us some details >>> on your async task? And why you are calling login/logout? (Maybe because >>> you don't have a custom Filter? >>> https://shiro.apache.org/web.html#Web-DefaultFilters >>> <https://shiro.apache.org/web.html#Web-DefaultFilters>) >>> >>> NOTE: Shiro 1.5 will contain support for Bearer tokens headers >>> <https://github.com/apache/shiro/blob/master/web/src/main/java/org/apache/shiro/web/filter/authc/BearerHttpAuthenticationFilter.java> >>> which may make your life easier too. >>> >>> >>> On Thu, Nov 28, 2019 at 7:38 AM otter606 < [email protected] >>> <mailto:[email protected]>> wrote: >>> Hello >>> We have happily been using Shiro for some years now for our Spring MVC web >>> application authentication and authorisation using standard Shiro filters >>> to >>> login and logout users. >>> Recently we implemented an asynchronous 'export' feature where a request >>> launches a background thread to perform a possibly long running ( a few >>> minutes) task. The request returns a job ID that the client app can use to >>> interrogate progress. We bind the Subject to the Callable using <code>task >>> = subject.associateWith(task);</code> and it all works fine, as in the web >>> application the user generally remains logged in while the export is >>> happening. >>> >>> We now expose this export feature through an API. Here is where we get a >>> problem, maybe we are not using Shiro correctly here. >>> - We have implemented a Realm that checks for access token validity >>> - we have set noSessionCreation to be active as the API requests are >>> supposed to be stateless >>> - if all ok we call SecurityUtils.getSubject().login so that there is an >>> authenticated principal to do permissions checks on access to resources >>> that >>> are going to be exported. >>> - When the API call is finished, in a filter we call >>> SecurityUtils.getSubject().logout() before returning the response. This has >>> the effect of setting the principalsCollection to null, so all subsequent >>> permission lookups fail for the Subject. This means that permission lookups >>> performed by the background thread now fail. >>> >>> Does anyone have any suggestions for how to keep a subject usable in a >>> background thread after logout() has been called? There seem to be several >>> options: >>> >>> - not call logout() at the end of each API request. Would this be bad >>> practice? Would there be some accumulation of Subject or Http Session >>> instances over time and 000s of API requests? >>> - stop using Shiro for API permissions lookups - we would prefer to use the >>> same permissions mechanism for all clients, so this option is not >>> attractive >>> - Use reflection to set the PrincipalCollection back into the Subject after >>> calling logout - this seems a bit hacky and potentially fragile >>> >>> Any advice or examples of using Shiro to secure APIs would be greatly >>> appreciated, thanks Richard >>> >>> >>> >>> -- >>> Sent from: http://shiro-user.582556.n2.nabble.com/ >>> <http://shiro-user.582556.n2.nabble.com/> >> >> >
