This posts relates to Jive SBS version 4.5 series.
In most java J2EE web applications, filters are added in the web.xml file. When doing development on Jive SBS, while you are not completely restricted from making changes to the web.xml file, it is not within the scope of normal development which is limited to themeing and plugins.
We had a need for a filter to intercept all REST calls to make certain they were initiated from only certain specific locations. The solution was found in overidding the Spring Security context in a plugin. To do this, create a plugin using the normal approach as found in the jive documentation.
In the spring.xml file, find the spring-SecurityContext.xml file and copy these items.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- ********************************************************************************************** -->
<!-- Authentication configuration -->
<!-- ********************************************************************************************** -->
<!-- This bean is the main entry point of the Acegi Filter and a critical configuration point.
Filters referenced here are defined below. -->
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/upgrade/**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, upgradeAuthenticationFilter, upgradeExceptionTranslationFilter,jiveAuthenticationTranslationFilter, pluginPostFilterChain
/post-upgrade/**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, postUpgradeAuthenticationFilter, postUpgradeExceptionTranslationFilter,jiveAuthenticationTranslationFilter, pluginPostFilterChain
/admin/**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, sessionTrackingFilter, adminAuthenticationFilter, adminExceptionTranslationFilter,jiveAuthenticationTranslationFilter, pluginPostFilterChain
/dwr/call/plaincall/passwordstrength**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, jiveAuthenticationTranslationFilter, pluginPostFilterChain
/dwr/**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, jiveAuthenticationTranslationFilter, denyGuestAccessFilter, pluginPostFilterChain
/rpc/bridging/**=blockServices
/rpc/mobile/**=blockServices
/rpc/api/**=blockServices
/rpc/openclient/**=blockServices
/rpc/xmlrpc=pluginPreFilterChain, wsRequireSSLFilter, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, basicAuthenticationFilter, wsExceptionTranslator, jiveAuthenticationTranslationFilter, wsAccessTypeCheckFilter, pluginPostFilterChain
/rpc/rest/**=pluginPreFilterChain, wsRequireSSLFilter, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, basicAuthenticationFilter, wsExceptionTranslator, jiveAuthenticationTranslationFilter, wsAccessTypeCheckFilter, pluginPostFilterChain
/rpc/soap/**=pluginPreFilterChain, wsRequireSSLFilter, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, jiveAuthenticationTranslationFilter, pluginPostFilterChain
/__services/xmlrpc=blockServices
/__services/rest/**=blockServices
/__services/soap/**=blockServices
/__services/api/**=blockServices
/__services/openclient/**=blockServices
/__services/office/**=pluginPreFilterChain, dvRequireSSLFilter, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, jiveAuthenticationTranslationFilter, pluginPostFilterChain
/__services/bridging/**=pluginPreFilterChain, bridgeRequireSSLFilter, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, basicAuthenticationFilter, restExceptionTranslator, jiveAuthenticationTranslationFilter, wsBridgingAccessCheckFilter, pluginPostFilterChain
/__services/mobile/**=pluginPreFilterChain, mobileRequireSSLFilter, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, mobileBasicAuthenticationFilter, wsExceptionTranslator, mobileRememberMeProcessingFilter, jiveAuthenticationTranslationFilter, wsIphoneAccessCheckFilter, pluginPostFilterChain
/__services/v2/rest/**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, restExceptionTranslator, jiveAuthenticationTranslationFilter, pluginPostFilterChain
/__services/**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, basicAuthenticationFilter, wsExceptionTranslator, jiveAuthenticationTranslationFilter, pluginPostFilterChain
/api/openclient/**=pluginPreFilterChain, openClientRequireSSLFilter, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, basicAuthenticationFilter, openClientExceptionTranslator, jiveAuthenticationTranslationFilter, openClientAccessTypeCheckFilter, pluginPostFilterChain
/api/**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, basicAuthenticationFilter, wsExceptionTranslator, jiveAuthenticationTranslationFilter, pluginPostFilterChain
/**=pluginPreFilterChain, httpSessionContextIntegrationFilter, pluginPostSessionContextFilterChain, sessionTrackingFilter, formAuthenticationFilter, loginPopupFormAuthenticationFilter, rememberMeProcessingFilter, feedBasicAuthenticationFilter, exceptionTranslationFilter, jiveAuthenticationTranslationFilter,contextOptimizationFilter, termsAndConditionsAcceptanceFilter, pluginPostFilterChain
</value>
</property>
</bean>
Since we were working with rest, I needed to add a new filter to the /rpc/rest/**= line. To add the filter, create the class and make the dependency line in the spring.xml file.
<bean id="restLocationFilter" class="com.jivesoftware.community.aaa.RestLocationFilter">
</bean>
Add whatever dependencies you need to the bean definition for your class. Now create your class using any of the other Spring Security beans as a model. In this case it is called the RestLocationFilter.java. Here is the code.
package com.jivesoftware.community.aaa;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import com.jivesoftware.community.JiveGlobals;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RestLocationFilter implements Filter, InitializingBean {
private static final Log log = LogFactory.getLog(RestLocationFilter.class);
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) {
throw new ServletException("Can only process HttpServletRequest");
}
if (!(response instanceof HttpServletResponse)) {
throw new ServletException("Can only process HttpServletResponse");
}
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpRequest = (HttpServletRequest) request;
String locationFromRestCall = httpRequest.getHeader("RestLocation");
String configuredRequiredLocation = JiveGlobals.getJiveProperty("authentication.proxy.ip");
if(locationFromRestCall==null || !locationFromRestCall.equals(configuredRequiredLocation))
{
log.info("Webservice request not from required location");
httpResponse.sendRedirect(JiveGlobals.getJiveProperty("jiveURL") + "/restnotfromrequiredlocation.jspa");
}
chain.doFilter(request, response);
}
public void init(FilterConfig arg0) throws ServletException {}
}
You will notice that the response.sendRedirect is doing a redirect. An appropriate struts entry will be needed in the struts.xml file to properly handle the call.
struts.xml
<action name="restnotfromrequiredlocation" class="com.jivesoftware.community.action.RestNotFromRequiredLocationAction">
<result name="success">/template/restnotfromrequiredlocation.ftl</result>
</action>
Knowing that filters can be done this way is the key. You should be able to add any filter in Jive SBS by leveraging this process.
Comments