2015/03/02

Use Vaadin, Apache shiro and "Remember-me"

While there are numerous solutions to use apache shiro and vaadin, Mike Pilones this solution works well except the "Remember-me" functionality. The reason for this is when using this method, we have to refrain from using a servlet filter that initializes the security manager. Thus shiro is unable to get hold of the servlet response and set the "Remember-me" cookie.

To overcome this, we have to subclass the CookieRememberMeManager and override few methods to include ServletRequest and ServletResponse to be obtained from VaadinServletService.

public class VaadinShiroRememberMeManager extends org.apache.shiro.web.mgt.CookieRememberMeManager {
@Override
protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {
//base 64 encode it and store as a cookie:
String base64 = Base64.encodeToString(serialized);
Cookie template = getCookie(); //the class attribute is really a template for the outgoing cookies
Cookie cookie = new SimpleCookie(template);
cookie.setValue(base64);
cookie.saveTo(VaadinServletService.getCurrentServletRequest(),
VaadinServletService.getCurrentResponse().getHttpServletResponse());
}
@Override
protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {
String base64 = getCookie().readValue(VaadinServletService.getCurrentServletRequest(), VaadinServletService.getCurrentResponse().getHttpServletResponse());
// Browsers do not always remove cookies immediately (SHIRO-183)
// ignore cookies that are scheduled for removal
if (Cookie.DELETED_COOKIE_VALUE.equals(base64)) return null;
if (base64 != null) {
base64 = ensurePadding(base64);
byte[] decoded = Base64.decode(base64);
return decoded;
} else {
//no cookie set - new site visitor?
return null;
}
}
@Override
protected void forgetIdentity(Subject subject) {
forgetIdentity(VaadinServletService.getCurrentServletRequest(),
VaadinServletService.getCurrentResponse().getHttpServletResponse());
}
@Override
public void forgetIdentity(SubjectContext subjectContext) {
forgetIdentity(VaadinServletService.getCurrentServletRequest(),
VaadinServletService.getCurrentResponse().getHttpServletResponse());
}
private void forgetIdentity(HttpServletRequest request, HttpServletResponse response) {
getCookie().removeFrom(request, response);
}
private String ensurePadding(String base64) {
int length = base64.length();
if (length % 4 != 0) {
StringBuilder sb = new StringBuilder(base64);
for (int i = 0; i < length % 4; ++i) {
sb.append('=');
}
base64 = sb.toString();
}
return base64;
}
}
Now we have to set our custom remember me manager in the shiro Security manager as follows.
<bean id="rememberMeManager" class="com.xyz.VaadinShiroRememberMeManager"/>
<bean id="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
<property name="realms">
<list>
<ref bean="ldapRealm"/>
<ref bean="x509CertificateRealm"/>
<ref bean="jdbcAuthRealm"/>
</list>
</property>
<property name="sessionManager" ref="sessionManager"/>
<property name="authenticator.authenticationStrategy" ref="authcStrategy"/>
<!--<property name="sessionManager.sessionIdCookie.domain" value="${security.cookie.domain}"/>-->
<property name="rememberMeManager" ref="rememberMeManager"/>
<property name="rememberMeManager.cookie.name" value="Remember-me"/>
<property name="rememberMeManager.cookie.maxAge" value="500"/>
</bean>
view raw context.xml hosted with ❤ by GitHub

Now shiro security manager can set and retrieve any remember-me cookie using the VaadinServletService provided request and response objects.

No comments:

Post a Comment