Fork me on GitHub

Configuration

Configure Spring Web Application Context with Spring Security Configuration

First you need to configure Spring Web Application Context in your web.xml.

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <display-name>Example HST SITE Web Application</display-name>

  <!-- ... -->

  <!--
    Configure Spring Web Application Context configuration files.
    You should include your spring security configuration in any file(s) in the following.
  -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      /WEB-INF/applicationContext.xml
      /WEB-INF/applicationContext-security.xml
    </param-value>
  </context-param>

  <!-- ... -->

  <!--
    Configure Spring Security Filter.
    Usually you may just copy and paste the following into your web application descriptor.
  -->
  <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>

  <!-- ... -->

  <!--
    Configure Spring Security Filter Mapping.
    Usually you may just copy and paste the following into your web application descriptor.
  -->
  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>

  <!-- ... -->

  <!--
    Configure Spring Web Application Context Loader Listener.
  -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- ... -->

</web-app>
        

Configuring Spring Web Application Context

You may put any beans in your Spring Web Application Context configuration. In this example, we assume you will add your custom beans in /WEB-INF/applicationContext.xml.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/lang http://www.springframework.org/schema/beans/spring-lang.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

  <!-- You may add any beans here. -->

</beans>
        

Configuring Spring Security

Here's an example of Spring Security configuration in /WEB-INF/applicationContext-security.xml.

Note: In the following example, 'hippoAuthenticationProvider' bean is used as the default Spring Security authentication provider component. The 'hippoAuthenticationProvider' simply authenticates users against Hippo Repository user/group store. If you want to authenticate users against other security stores such as LDAP, RDBMS, etc., then you should configure other authentication provider component instead. Please refer to Spring Security documentation site for other available authentication providers.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
       xmlns:beans="http://www.springframework.org/schema/beans"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/lang http://www.springframework.org/schema/beans/spring-lang.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

  <!-- Static Resources -->
  <http pattern="/css/**" security="none"/>
  <http pattern="/images/**" security="none"/>
  <http pattern="/script/**" security="none"/>
  <http pattern="/binaries/**" security="none"/>
  <http pattern="/webfiles/**" security="none" />

  <!-- Channel Manager requests may bypass authentication -->
  <http pattern="/_rp/**" security="none"/>
  <http pattern="/_cmsrest/**" security="none"/>
  <http pattern="/_cmsinternal/**" security="none"/>
  <http pattern="/_cmssessioncontext/**" security="none"/>

  <http auto-config="true" use-expressions="true" disable-url-rewriting="false">

    <!--
      As of Spring Security 4.0, CSRF protection is enabled by default with XML configuration.
      If you would like to disable CSRF protection, uncomment the corresponding XML configuration below.
    -->
    <!--
    <csrf disabled="true"/>
    -->

    <!--
      SAMEORIGIN should be set for X-Frame-Options header to allow channel manager to load preview pages in iframe.
      See https://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html#headers-frame-options for detail.
    -->
    <headers>
      <frame-options policy="SAMEORIGIN" />
    </headers>

    <!-- Example configuration to allow anonymous access as well as authenticated access. -->
    <intercept-url pattern="/login.jsp*" access="isAnonymous() or hasRole('everybody')" />
    <intercept-url pattern="/logout*" access="isAnonymous() or hasRole('everybody')" />

    <!-- Example configuration to allow only authenticated access to users having 'ROLE_everybody'. -->
    <intercept-url pattern="/**" access="hasRole('everybody')" />

    <!-- Note: Enable http-basic element instead of form-login if you want to use Basic Authentication. -->
    <!--
    <http-basic />
    -->
    <form-login login-page="/login.jsp"
                default-target-url="/"
                always-use-default-target="true" />

    <logout invalidate-session="true" logout-success-url="/" logout-url="/logout" />

  </http>

  <!--
    Authentication Manager configuration with Hippo Repository based Authentication Provider configuration ('hippoAuthenticationProvider').
    However, you can use any other authentication provider(s) if you don't need to authenticate users against Hippo Repository.
  -->
  <authentication-manager>
    <authentication-provider ref="hippoAuthenticationProvider" />
  </authentication-manager>

  <!--
    Hippo Repository based Authentication Provider. This Authentication Provider provide authentication against Hippo Repository Security Store.
    If you don't need to authenticate users against Hippo Repository, you don't have to include the following bean.
  -->
  <beans:bean id="hippoAuthenticationProvider"
              class="org.onehippo.forge.security.support.springsecurity.authentication.HippoAuthenticationProvider">
  </beans:bean>

</beans:beans>
        

Configuring HippoUserDetailsService explicitly

The hippoAuthenticationProvider bean shown above creates a HippoUserDetailsService bean automatically with default property values if not provided explicitly through bean configurations.

You can also define HippoUserDetailsService bean explicitly like the following example and inject it to hippoAuthenticationProvider bean for more detailed configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
       xmlns:beans="http://www.springframework.org/schema/beans"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/lang http://www.springframework.org/schema/beans/spring-lang.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

  <!-- SNIP -->

  <beans:bean id="hippoUserDetailsService" class="org.onehippo.forge.security.support.springsecurity.authentication.HippoUserDetailsServiceImpl">
    <beans:property name="defaultRoleName" value="everybody" />
    <beans:property name="roleDomainName" value="everywhere" />
  </beans:bean>

  <beans:bean id="hippoAuthenticationProvider"
              class="org.onehippo.forge.security.support.springsecurity.authentication.HippoAuthenticationProvider">
    <beans:property name="hippoUserDetailsService" ref="hippoUserDetailsService" />
  </beans:bean>

</beans:beans>
        

Adding SpringSecurityValve into the Existing Pipeline(s)

In order to enable Spring Security Integration in your SITE application, you should insert 'SpringSecurityValve' into your existing pipelines.

Basically, SpringSecurityValve is responsible for reading the org.springframework.security.core.Authentication instance if exists, and establishing javax.security.auth.Subject for the whole HST-2 request processing by converting org.springframework.security.core.userdetails.UserDetails into a set of java.security.Principals (user principal and role principals from the collection of org.springframework.security.core.GrantedAuthority).

There can be three different pipelines in your project:

  • DefaultSitePipeline: The default website pipeline
  • JaxrsRestPlainPipeline: The Plain JAX-RS Service pipeline
  • JaxrsRestContentPipeline: The Content/Context Aware JAX-RS Service pipeline

In the example below, we append SpringSecurityValve to the initializing valves of the default pipeline only. If you want to enable Spring Security Integration in either of JAX-RS pipelines, you will need to copy and paste the second bean definition block with changing the pipeline name argument.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/lang http://www.springframework.org/schema/beans/spring-lang.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

  <!-- Defininig SpringSecurityValve -->
  <bean id="springSecurityValve" class="org.onehippo.forge.security.support.springsecurity.container.SpringSecurityValve">
    <property name="valveName" value="springSecurityValve" />
  </bean>

  <!--
    Inserting SpringSecurityValve into the default pipeline.
    You may copy and paste the following block to insert the SpringSecurityValve for more pipelines.
    'DefaultSitePipeline' is for the default website pipeline.
    'JaxrsRestContentPipeline' is for the Content/Context Aware JAX-RS Service pipeline.
    'JaxrsRestPlainPipeline' is for the Plain JAX-RS Service pipeline.
  -->
  <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
      <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="org.hippoecm.hst.core.container.Pipelines" />
        <property name="targetMethod" value="getPipeline" />
        <property name="arguments">
          <list>
            <!--
              You may use one of the following: 'DefaultSitePipeline', 'JaxrsRestContentPipeline' and 'JaxrsRestPlainPipeline'.
            -->
            <value>DefaultSitePipeline</value>
          </list>
        </property>
      </bean>
    </property>
    <property name="targetMethod" value="addInitializationValve" />
    <property name="arguments">
      <ref bean="springSecurityValve" />
    </property>
  </bean>

</beans>
        

Securing Your Site

Now, you can secure your web site by setting 'hst:authenticated', 'hst:roles' or 'hst:users' either 'hst:sitemapitem' node or 'hst:mount' node.

For example, if you have 'securedresource' sitemap item, and it has 'hst:authenticated=true' and 'hst:roles=ROLE_admin,ROLE_everybody', then any requests to the sitemap item will be allowed only authenticated users.

Note: Because the role name with Spring Security should be prefixed by 'ROLE_' by default, you will need to prefix the role name by the prefix when configuring the hst:roles property.

HST Spring Security Support supports the same feature for authorization as the default HST Security module provides. So, please refer to Delivery Tier Authentication Configuration in order to learn how to set authentication.

In case you need Repository Level Authorization and make use of Delivery Tier Authorization Configuration (using hst:subjectbasedsession property) you should set 'erase-credentials=false' in the authentication manager configuration.

Using Standard Security APIs

Also, you can use JavaEE standard Security APIs now in your components or servlet/filter for programmatic security checks such as:

  • javax.servlet.http.HttpServletRequest#getUserPrincipal()
  • javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String role)