You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by alarinn <pd...@gmail.com> on 2012/08/23 21:09:41 UTC
Session Timeout doesn't redirect to login page
I have my applicationContext like this:
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/index.faces"/>
<property name="filterChainDefinitions">
<value>
/* = authc
</value>
</property>
</bean>
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="opacsRealm" />
</bean>
<bean id="lifecycleBeanPostProcessor"
class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<bean id="sha512Matcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="SHA-256" />
<property name="hashIterations" value="1024" />
</bean>
<bean id="opacsRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="dataSource" />
<property name="authenticationQuery"
value="select PASSWORD, SALT from SEC_USERS where NAME = ?" />
<property name="userRolesQuery"
value="SELECT ROLE_NAME FROM SEC_USERS_ROLES WHERE USER_NAME = ?" />
<property name="permissionsQuery"
value="SELECT permission FROM SEC_ROLES_PERMISSIONS WHERE ROLE_NAME = ?"
/>
<property name="permissionsLookupEnabled" value="true" />
<property name="saltStyle" value="COLUMN" />
<property name="credentialsMatcher" ref="sha512Matcher"/>
</bean>
What is happening is when the session times out, the app doesn't respond to
events like command buttons and ajax (Primefaces), which is good. But there
is no redirect to the index.faces page. It will do that if I refresh the
browser, but no other trigger will redirect. Is there anything else I need
to do to get Shiro to redirect to the login page whenever session time out
occurs? I am using the session timeout property in the web.xml so it's all
container-based. Thanks!
--
View this message in context: http://shiro-user.582556.n2.nabble.com/Session-Timeout-doesn-t-redirect-to-login-page-tp7577730.html
Sent from the Shiro User mailing list archive at Nabble.com.
Re: Session Timeout doesn't redirect to login page
Posted by Les Hazlewood <lh...@apache.org>.
Thanks for updating this thread with the solution. Hopefully this
will help other Primefaces users in the future!
Cheers,
--
Les Hazlewood | @lhazlewood
CTO, Stormpath | http://stormpath.com | @goStormpath | 888.391.5282
Stormpath wins GigaOM Structure Launchpad Award! http://bit.ly/MvZkMk
RE: Session Timeout doesn't redirect to login page
Posted by alarinn <pd...@gmail.com>.
FYI...the <pe> tags are from Primefaces Extensions, which is a separate
project from Primefaces.
--
View this message in context: http://shiro-user.582556.n2.nabble.com/Session-Timeout-doesn-t-redirect-to-login-page-tp7577730p7577752.html
Sent from the Shiro User mailing list archive at Nabble.com.
RE: Session Timeout doesn't redirect to login page
Posted by alarinn <pd...@gmail.com>.
With Marcus' help, I was able to get this to work. The issue is I'm using
JSF/Primefaces components which are Ajax-enabled by default. I could have
set them all to false but data table is ugly and one of the reasons why so
many developers like JSF are the ajax capabilities.
In order to redirect using Ajax components you have to change things up a
bit:
1). Create a new filter that extends from AccessControlFilter:
public class HTTPStatusCodeAuthenticationFilter extends AccessControlFilter
{
/**
* This method is copied from AuthenticationFilter
* <p>
* Determines whether the current subject is authenticated.
* <p/>
* The default implementation
* {@link #getSubject(javax.servlet.ServletRequest,
javax.servlet.ServletResponse)
* acquires} the currently executing Subject and then returns
* {@link org.apache.shiro.subject.Subject#isAuthenticated()
* subject.isAuthenticated()};
*
* @return true if the subject is authenticated; false if the subject is
* unauthenticated
*/
@Override
protected boolean isAccessAllowed(ServletRequest request,
ServletResponse response, Object mappedValue) {
Subject subject = getSubject(request, response);
boolean isAuthenticated = subject.isAuthenticated();
return isAuthenticated;
}
/**
* Takes responsibility for returning an appropriate response when access
is
* not allowed.
*/
@Override
protected boolean onAccessDenied(ServletRequest request,
ServletResponse response) throws Exception {
accessDeniedResponse(request, response);
return false;
}
/**
* Provides a 401 Not Authorized HTTP status code to the client with a
* custom challenge scheme that the client understands and can respond to.
*
* @param request
* @param response
* @throws Exception
*/
private void accessDeniedResponse(ServletRequest request,
ServletResponse response) throws Exception {
HttpServletResponse httpResponse = WebUtils.toHttp(response);
httpResponse.addHeader("WWW-Authentication", "ACME-AUTH");
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
You can change the "ACME-AUTH' to whatever works for you.
2. Then add an entry to the shiro.ini or if you use Spring like I do,
applicationContext.xml:
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
*<property name="loginUrl" value="/index.faces"/>*
<property name="unauthorizedUrl" value="/login.jsp"/>
<property name="filterChainDefinitions">
<value>
/index.faces = anon
/** = *ajaxFilter*
</value>
</property>
</bean>
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="opacsRealm" />
</bean>
*<bean id="ajaxFilter"
class="org.pds.opacs.listeners.HTTPStatusCodeAuthenticationFilter"/>*
<bean id="lifecycleBeanPostProcessor"
class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<bean id="sha512Matcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="SHA-256" />
<property name="hashIterations" value="1024" />
</bean>
<bean id="opacsRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="dataSource" />
<property name="authenticationQuery"
value="select PASSWORD, SALT from SEC_USERS where NAME = ?" />
<property name="userRolesQuery"
value="SELECT ROLE_NAME FROM SEC_USERS_ROLES WHERE USER_NAME = ?" />
<property name="permissionsQuery"
value="SELECT permission FROM SEC_ROLES_PERMISSIONS WHERE ROLE_NAME = ?"
/>
<property name="permissionsLookupEnabled" value="true" />
<property name="saltStyle" value="COLUMN" />
<property name="credentialsMatcher" ref="sha512Matcher"/>
</bean>
3. Then, in your client page:
<pe:ajaxStatus onerror="window.location.replace('index.faces');"/>
index.faces is wherever you want the login page
This takes care of everything except for a page refresh (F5) after session
timeout. I never could get that to work because the page results in a 401
Error Page. I tried various jQuery code snippets but never could get them
to fire off. The closest I got was using *onunload=* which does allow me to
redirect to the login page on a page refresh. Unfortunately, the jQuery
code never fires off and I need to catch it so only after a session timeout
the page is redirected to the login page. Here's a few jquery snippets I
tried to get to work, so maybe somebody has a better way of catching a
session timeout on a page refresh:
1.
jQuery(document).ready(function() {
var request = jQuery.ajax({
url: "viewJobActivity.faces",
type: "POST"
});
request.done(function(msg) {
alert('done');
});
request.fail(function(jqXHR, textStatus) {
alert( "Request failed: " + textStatus );
});
});
2.
jQuery.ajax(
{
// Define AJAX properties.
method: "get",
url: "viewJobActivity.faces",
// Define the succss method.
success: function(){
alert( "Success!" );
},
// Define the error method.
error: function( objAJAXRequest, strError ){
alert("Error! Type: " + strError);
}
}
);
3.
var url = "viewJobActivity.faces";
jQuery.ajax({
url: "viewJobActivity.faces",
complete: function(xhr, statusText){
alert(xhr.status);
}
});
--
View this message in context: http://shiro-user.582556.n2.nabble.com/Session-Timeout-doesn-t-redirect-to-login-page-tp7577730p7577750.html
Sent from the Shiro User mailing list archive at Nabble.com.
RE: Session Timeout doesn't redirect to login page
Posted by Marcus Bond <ma...@marcusbond.me.uk>.
Also commented on StackOverflow and sent a private mail with some code.
In case anyone else finds this of value here is the S/O answer:
====================================
What is happening is that the redirect is handled seamlessly by the browser in your Ajax call so Shiro does redirect to the login page and the end result of your Ajax request is the HTML content of the login page, which isn't really what you want!
The gist of how to work around this is to add a (custom) Shiro filter to your Ajax Api urls that checks the Subject for being authenticated and instead of redirecting to login return a response that your Ajax request understands to indicate that the user is not logged in. Client side handling of this response can then do a redirect to the login page (or perhaps the same page because Shiro will then redirect to login but can be configured to remember where you were trying to go and hence take the user back to the correct page upon successful login).
My filter implementation returns Http code 401 along with "WWW-Authentication" header and a custom "challenge scheme" (if you did a basic authentication challenge then the browser would pop up its basic authentication dialog - there is already a Shiro filter that does this).
In your Ajax call you need to detect this response, currently I have a clunky error callback that does it BUT I think it should be possible to modify the JavaScript library (JQuery, whatever) to handle this seamlessly.
====================================
-----Original Message-----
From: Jared Bunting [mailto:jared.bunting@peachjean.com]
Sent: 23 August 2012 23:14
To: user@shiro.apache.org
Cc: alarinn
Subject: Re: Session Timeout doesn't redirect to login page
Commented on your StackOverflow question[1], but the gist of it is, this is working as expected. There was another user recently who was encountering a similar issue [2].
-Jared
[1]
http://stackoverflow.com/questions/12099262/jsf-2-spring-3-shiro-session-timeout-doesnt-redirect-to-login-page
[2]
http://shiro-user.582556.n2.nabble.com/Web-Filter-to-return-HTTP-status-code-td7577672.html
On Thu 23 Aug 2012 02:09:41 PM CDT, alarinn wrote:
> I have my applicationContext like this:
>
> <bean id="shiroFilter"
> class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
> <property name="securityManager" ref="securityManager" />
> <property name="loginUrl" value="/index.faces"/>
> <property name="filterChainDefinitions">
> <value>
> /* = authc
> </value>
> </property>
> </bean>
> <bean id="securityManager"
> class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
> <property name="realm" ref="opacsRealm" />
> </bean>
>
> <bean id="lifecycleBeanPostProcessor"
> class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
>
> <bean id="sha512Matcher"
> class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
>
> <property name="hashAlgorithmName" value="SHA-256" />
> <property name="hashIterations" value="1024" />
> </bean>
>
>
>
> <bean id="opacsRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
> <property name="dataSource" ref="dataSource" />
> <property name="authenticationQuery"
> value="select PASSWORD, SALT from SEC_USERS where NAME = ?" />
> <property name="userRolesQuery"
> value="SELECT ROLE_NAME FROM SEC_USERS_ROLES WHERE USER_NAME = ?" />
> <property name="permissionsQuery"
> value="SELECT permission FROM SEC_ROLES_PERMISSIONS WHERE ROLE_NAME = ?"
> />
> <property name="permissionsLookupEnabled" value="true" />
> <property name="saltStyle" value="COLUMN" />
> <property name="credentialsMatcher" ref="sha512Matcher"/>
> </bean>
>
> What is happening is when the session times out, the app doesn't
> respond to events like command buttons and ajax (Primefaces), which is
> good. But there is no redirect to the index.faces page. It will do
> that if I refresh the browser, but no other trigger will redirect. Is
> there anything else I need to do to get Shiro to redirect to the login
> page whenever session time out occurs? I am using the session timeout
> property in the web.xml so it's all container-based. Thanks!
>
>
>
> --
> View this message in context:
> http://shiro-user.582556.n2.nabble.com/Session-Timeout-doesn-t-redirec
> t-to-login-page-tp7577730.html Sent from the Shiro User mailing list
> archive at Nabble.com.
Re: Session Timeout doesn't redirect to login page
Posted by Jared Bunting <ja...@peachjean.com>.
Commented on your StackOverflow question[1], but the gist of it is,
this is working as expected. There was another user recently who was
encountering a similar issue [2].
-Jared
[1]
http://stackoverflow.com/questions/12099262/jsf-2-spring-3-shiro-session-timeout-doesnt-redirect-to-login-page
[2]
http://shiro-user.582556.n2.nabble.com/Web-Filter-to-return-HTTP-status-code-td7577672.html
On Thu 23 Aug 2012 02:09:41 PM CDT, alarinn wrote:
> I have my applicationContext like this:
>
> <bean id="shiroFilter"
> class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
> <property name="securityManager" ref="securityManager" />
> <property name="loginUrl" value="/index.faces"/>
> <property name="filterChainDefinitions">
> <value>
> /* = authc
> </value>
> </property>
> </bean>
> <bean id="securityManager"
> class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
> <property name="realm" ref="opacsRealm" />
> </bean>
>
> <bean id="lifecycleBeanPostProcessor"
> class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
>
> <bean id="sha512Matcher"
> class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
>
> <property name="hashAlgorithmName" value="SHA-256" />
> <property name="hashIterations" value="1024" />
> </bean>
>
>
>
> <bean id="opacsRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
> <property name="dataSource" ref="dataSource" />
> <property name="authenticationQuery"
> value="select PASSWORD, SALT from SEC_USERS where NAME = ?" />
> <property name="userRolesQuery"
> value="SELECT ROLE_NAME FROM SEC_USERS_ROLES WHERE USER_NAME = ?" />
> <property name="permissionsQuery"
> value="SELECT permission FROM SEC_ROLES_PERMISSIONS WHERE ROLE_NAME = ?"
> />
> <property name="permissionsLookupEnabled" value="true" />
> <property name="saltStyle" value="COLUMN" />
> <property name="credentialsMatcher" ref="sha512Matcher"/>
> </bean>
>
> What is happening is when the session times out, the app doesn't respond to
> events like command buttons and ajax (Primefaces), which is good. But there
> is no redirect to the index.faces page. It will do that if I refresh the
> browser, but no other trigger will redirect. Is there anything else I need
> to do to get Shiro to redirect to the login page whenever session time out
> occurs? I am using the session timeout property in the web.xml so it's all
> container-based. Thanks!
>
>
>
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Session-Timeout-doesn-t-redirect-to-login-page-tp7577730.html
> Sent from the Shiro User mailing list archive at Nabble.com.