You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by otter606 <ri...@researchspace.com> on 2019/11/28 12:38:50 UTC

Using Shiro for long-running asynchronous tasks

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/

Re: Using Shiro for long-running asynchronous tasks

Posted by Richard Adams <ri...@researchspace.com>.
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 <br...@gmail.com> wrote:
> 
> Have you thought about using Shiro's "RunAs" feature?
> 
> On Tue, Dec 3, 2019 at 3:41 AM Richard Adams <richard@researchspace.com <ma...@researchspace.com>> 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 <brian.demers@gmail.com <ma...@gmail.com>> 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 <richard@researchspace.com <ma...@researchspace.com>> wrote:
>> Thanks 
>>> On 02 December 2019 at 21:49 Brian Demers <brian.demers@gmail.com <ma...@gmail.com>> 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 < richard@researchspace.com <ma...@researchspace.com>> 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/> 
>> 
>>  
> 


Re: Using Shiro for long-running asynchronous tasks

Posted by Brian Demers <br...@gmail.com>.
Have you thought about using Shiro's "RunAs" feature?

On Tue, Dec 3, 2019 at 3:41 AM Richard Adams <ri...@researchspace.com>
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 <br...@gmail.com> 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 <ri...@researchspace.com>
> wrote:
>
>> Thanks
>>
>> On 02 December 2019 at 21:49 Brian Demers <br...@gmail.com>
>> 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)
>>
>> 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 < richard@researchspace.com>
>> 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/
>>
>>
>>
>>
>
>

Re: Using Shiro for long-running asynchronous tasks

Posted by Richard Adams <ri...@researchspace.com>.
> 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 <br...@gmail.com> 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 <richard@researchspace.com <ma...@researchspace.com>> wrote:
> Thanks 
>> On 02 December 2019 at 21:49 Brian Demers <brian.demers@gmail.com <ma...@gmail.com>> 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 < richard@researchspace.com <ma...@researchspace.com>> 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/> 
> 
>  


Re: Using Shiro for long-running asynchronous tasks

Posted by Brian Demers <br...@gmail.com>.
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 <ri...@researchspace.com>
wrote:

> Thanks
>
> On 02 December 2019 at 21:49 Brian Demers <br...@gmail.com> 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)
>
> 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 < richard@researchspace.com>
> 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/
>
>
>
>

Re: Using Shiro for long-running asynchronous tasks

Posted by Richard Adams <ri...@researchspace.com>.
Thanks  

> On 02 December 2019 at 21:49 Brian Demers <br...@gmail.com> 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>)

>

>  
>

>

> 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 <
[richard@researchspace.com](mailto:richard@researchspace.com)> 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/>  
>

  



Re: Using Shiro for long-running asynchronous tasks

Posted by Brian Demers <br...@gmail.com>.
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.
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"?


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?

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)

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 <ri...@researchspace.com> 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/
>