I have a typical Spring MVC + GWT architecture with Apache Shiro as a security layer.
Problem:
No matter what protocol is used for a request to the App server, pages should be returned in the protocol specified in the request’s “X-Forwarded-Proto” header (so, app server can receive a HTTP request, but if the header says HTTPS, it should respond using HTTPS). Obviously, the configuration specified in the Shiro-Spring tutorial won’t work as it has nothing to do with the protocols (login.jsp will be returned using the protocol used in request):
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login.jsp"/>
<property name="filterChainDefinitions">
<value>
/** = authc
</value>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"/>
</bean>
<bean id="myRealm" class="com.myapp.security.DBRealm">
<property name="credentialsMatcher" ref="sha256Matcher"/>
</bean>
Possible solution:
Use @Controller to REDIRECT to the login view with the specified protocol:
@RequestMapping(value="/login", method=RequestMethod.GET)
public RedirectView doLogin(HttpServletRequest req) throws MalformedURLException {
URL originalURL = new URL(req.getRequestURL().toString());
return new RedirectView(new URL(req.getHeader("X-Forwarded-Proto"), originalURL.getHost(), "/login.jsp").toString());
}
and change the loginUrl in shiro configuration to point to /login, so that @controller catches it:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login"/>
... leave everything else the same
</bean>
But with this configuration, although I get the same login page, the myRealm (com.myapp.security.DBRealm) is not triggered at all (meaning, the credentials are not checked), and login always fails. Seems like the redirected page loses the “hook” to the realm.
Any ideas on what I am doing wrong?
The reason this is failing is because the Shiro
authcFilter (a FormAuthenticationFilter) expects theloginUrlto be the one where the login attempt occurs.That is, when
authcfilters a request that matches theloginUrl, it will automatically support form-based authentication. Because you are redirecting the end-user to a URL that does not match theloginUrl(i.e.loginUrl=/login, but you redirect them to/login.jsp), theauthcfilter won’t perform a login.Your best option IMO:
Subclass
FormAuthenticationFilterand override theredirectToLoginmethod to use yourX-Forwarded-Protologic. Then redefine ‘authc’ to be your custom subclass. For example, using shiro .ini:Also, if you want this behavior in Shiro directly (so Shiro looks for that header when performing a redirect by default) so you can remove your subclass, please open a feature request in Apache Shiro’s Jira.