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/> 
>> 
>>  
> 

Reply via email to