Delivery Tier Authentication and Authorization Support - BloomReach Experience - Open Source CMS

Delivery Tier Authentication and Authorization Support

Introduction

Goal

Use authentication and authorization in the delivery tier.

Background

For authentication purpose, Hippo's delivery tier (HST) provides a default Hippo login module implementation. Login modules provide a standard way to expose authentication services for Java applications. More information about login modules can be found in the JDK LoginModule interface documentation.

Also, for authorization purpose, HST provides configurations to secure a mount with authorized roles or users.

Furthermore, HST provides various extensible options to customize the form login page and login error page.

There is an integration with Spring Security at  HST Spring Security Support forge project which provides an authentication provider against Hippo Repository and a Spring Security aware Security Valve in order to let you leverage Spring Security instead of the default JAAS based security module.

Contents

Hippo Login Module Configuration

To enable Hippo Login Module, add the following configuration in /WEB-INF/hst-config.properties:

# HST JAAS login configuration
java.security.auth.login.config = classpath:/org/hippoecm/hst/security/impl/login.conf

With the configuration above, HST Container will register the Hippo Login Module implementation as JAAS Login Module.

Realm Configuration

To configure Container Managed Security, you need to configure the Realm, which is normally configured in the application context configuration, for example at  /site/src/main/webapp/META-INF/context.xml. Make sure  not to configure the Context Realm element below in the  $CATALINA_BASE/conf/context.xml.

Please note that the Realm name must the same as the Realm name in your site/src/main/webapp/WEB-INF/web.xml.

In Tomcat, you can configure the Realm like the following in the context configuration file:

<?xml version="1.0" encoding="UTF-8" ?><Context crossContext="true">
  <Realm className="org.apache.catalina.realm.JAASRealm"
         appName="HSTSITE"
         userClassNames="org.hippoecm.hst.security.TransientUser"
         roleClassNames="org.hippoecm.hst.security.TransientRole"
         useContextClassLoader="true"
         debug="0"/>

  <Valve className="org.apache.catalina.authenticator.FormAuthenticator"
         characterEncoding="UTF-8" />

  <!-- You may use BASIC Authentication as well instead of FORM
       Authentication.
  <Valve className="org.apache.catalina.authenticator.BasicAuthenticator" />
  -->

</Context>
Add the above Realm to  /site/src/main/webapp/META-INF/context.xml and  not to the default /conf/context.xml 

In the configuration example above, you can normally use FORM Authentication option for more flexibility, but you may also use BASIC Authentication option as well by using the " org.apache.catalina.authenticator.BasicAuthenticator" valve instead of " org.apache.catalina.authenticator.FormAuthenticator" valve.

Form-based Authentication Configuration with LoginServlet

To use a Login Module in web environment with Form-based authentication, you should have the following servlet configuration in your site  web.xml.

<servlet>
  <servlet-name>LoginServlet</servlet-name>
  <servlet-class>org.hippoecm.hst.security.servlet.LoginServlet
  </servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>LoginServlet</servlet-name>
  <url-pattern>/login/*</url-pattern>
</servlet-mapping>

And

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Login</web-resource-name>
    <url-pattern>/login/resource</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>everybody</role-name>
  </auth-constraint>
</security-constraint>
<login-config>
  <auth-method>FORM</auth-method>
  <realm-name>HSTSITE</realm-name>
  <form-login-config>
    <form-login-page>/login/login</form-login-page>
    <form-error-page>/login/error</form-error-page>
  </form-login-config>
</login-config>
<security-role>
  <description>Default role of Hippo Repository</description>
  <role-name>everybody</role-name>
</security-role>

With the configurations above, you set a default protected web resource path ( /login/resource), which is internally used by the LoginServlet, and FORM-based authentication with the internal login page path and error page path. Also, only for authentication purpose, the default role, ' everybody, is required for the default protected web resource path ( /login/resource).

Now, if you restart your application, you can test the login.

Https vs http login

By default, all HST login requests are over https. For local development, in case you don't want create locally a self-signed certificate and don't want to configure your container for SSL support, see for example Tomcat SSL howto, or have to have httpd configured for ssl support with mod_ssl enabled, you can easily set it to work over http. If you want to configure login over http, you have to change the default login sitemap item scheme from https --> http. You can find this property at:

+ hst:hst
  + hst:configurations
    + hst:default
      + hst:sitemap
        + login 
           - hst:scheme = https

If you want to automatically bootstrap hst:scheme for the login to go over http instead of https, you can add to your hippoecm-extension.xml the following instruction:

<sv:node sv:name="set-login-over-http">
  <sv:property sv:name="jcr:primaryType" sv:type="Name">
    <sv:value>hippo:initializeitem</sv:value>
  </sv:property>
  <sv:property sv:name="hippo:sequence" sv:type="Double">
    <sv:value>30000.0</sv:value>
  </sv:property>
  <sv:property sv:name="hippo:contentpropset" sv:type="String">
    <sv:value>http</sv:value>
  </sv:property>
  <sv:property sv:name="hippo:contentroot" sv:type="String">
    <sv:value>/hst:hst/hst:configurations/hst:default/hst:sitemap/login/hst:scheme</sv:value>
  </sv:property>
</sv:node>

Testing the login

Visit /login/form page path to try log on. For example, you can visit http://localhost:8080/site/login/form.

Then, enter a CMS username and password to sign in. You will be able to get authenticated.

By the way, you can check if you are authenticated by using HttpServletRequest#getUserPrincipal(). If the method returns a non-null value, then you are authenticated!

If you enter a wrong user name or password, then you will be redirected to the default error page, /login/error.

BASIC Authentication Configuration

If you want to use BASIC Authentication option instead of Form-based Authentication option, please follow this section.

Please note that you should use the following valve in the context configuration in order to use BASIC Authentication option in Tomcat. See the example in the comment block in the Section 3 above.

<Valve className="org.apache.catalina.authenticator.BasicAuthenticator" />

<!-- Commenting out the FormAuthenticator valve in order to use
     BasicAuthenticator valve.
<Valve className="org.apache.catalina.authenticator.FormAuthenticator"
       characterEncoding="UTF-8" />
-->

In your site web.xml, you need to add your security constraints like the following example. In the following example, let's suppose you want to protect all URL resources starting with /preview/.

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Preview</web-resource-name>
      <url-pattern>/preview/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>everybody</role-name>
    </auth-constraint>
  </security-constraint>

  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>HSTSITE</realm-name>
  </login-config>

  <security-role>
    <description>Default role of Hippo Repository</description>
    <role-name>everybody</role-name>
  </security-role>

With the configurations above, you set your protected web resource path ( /preview), which is protected by the servlet container with enabling BASIC Authentication. Also, only for demonstration purpose, the default role, ' everybody', is required for the protected web resource path ( /preview).

Please note that you should configure all the URL paths to protect when you are using BASIC Authentication option. Please see SRV.12.8 in the Servlet Specification for more detail.

Now, if you restart your application, you can test the login.

Visit /preview page path. For example, you can visit http://localhost:8080/site/preview.

Then, your browser will popup a login dialog. Enter a CMS username and password to sign in. You will be able to get authenticated.

By the way, you can check if you are authenticated by using HttpServletRequest#getUserPrincipal(). If the method returns a non-null value, then you are authenticated!

If you enter a wrong user name or password, then the servlet container will return HTTP 401 error.

Authorization Configuration

Web Application Level Authorization

You can secure a mount or sitemap item by setting " hst:authenticated (boolean)" property to true.

In order to secure the mount or sitemap item properly, you need to set " hst:roles" or " hst:users".

For example, if you set the following properties for either a mount or a sitemap item

- hst:authenticated = true
- hst:roles = editors, approvers

then, the mount will be allowed to users in 'editors' role or users in 'approvers' role. If a user is not authenticated and accesses this resource, then the request will meet HTTP Not Authenticated (401) error. Or if the user is authenticated but the user is in neither 'editors' nor 'approvers' role, then the request will meet a HTTP Forbidden error (403) by default.

HST Container checks the user's roles by the Servlet / JAAS standard APIs such as HttpServletRequest#isUserInRole(roleName). So, with the example above, HST Container will invoke request.isUserInRole("editors") and request.isUserInRole("approvers") at least.

Also, you can use or add " hst:users" property like this:

- hst:authenticated = true
- hst:users = editor1, approver1

With the example configuration above, HST Container checks if the user's principal name is included in the " hst:users" property values. HST Container will retrieve the user's principal name by using HttpServletRequest#getUserPrincipal().getName().

Finally, if you have both " hst:roles" and " hst:users", then HST Container will look up both property values in order to see if the user can access the resource. If the user has any role or the user's principal name is included, then the user will be allowed.

Note: " hst:authenticated" property must be type of Boolean!

Repository Level Authorization Integration

HST also provides Repository level authorization integration, meaning JCR session used during the request will be tightly integrated with the authenticated user's subject.

If you want this option, set the following property for a mount:

- hst:subjectbasedsession = true

With the configuration above, JCR session during the request processing is created with the JCR credentials of the authenticated user's subject per each request. In this case, JCR session is not borrowed from the internal JCR session pool.

Optionally, the JCR session with this option can be stored in HTTP session and reused in the following requests for more efficiency. To use this session stateful JCR session usage option, configure the following property for a mount:

- hst:sessionstateful = true

As you can imagine, this option should be used in limited environments, such as application with limited users because it can increase memory size at runtime when used without caution.

Note: " hst:subjectbasedsession" and " hst:sessionstateful" properties must be type of Boolean!

Repository level authorization integration is only supported when using form-based authentication with org.hippoecm.hst.security.servlet.LoginServlet.
It is not supported with Basic authentication or any other method (including form-based authentication if not using the LoginServlet).

Security Domain Configuration in the Repository

To configure security domains and roles, please refer to the page, Repository Authorization and Permissions.

Hippo Repository provides security domain based authorization, meaning security roles can be differently configured per each security domain.

Therefore, Hippo JAAS Login Module uses only one security domain for authentication. By default the security domain used is ' everywhere'.

If you want to use another security domain, you can configure the following property in /WEB-INF/hst-config.properties:

# Hippo Login Module Authentication Provider configurations
security.authentication.role.domain = everywhere

How to utilize the default Form Login Page

There are default built in login screens with script templates. These built in logins need some built in packaged css and images. Therefore, you need to add to the web.xml the following:

<servlet>
    <servlet-name>SecurityResourceServlet</servlet-name>
    <servlet-class>org.springframework.js.resource.ResourceServlet
    </servlet-class>
    <init-param>
    <param-name>jarPathPrefix</param-name>
    <param-value>/META-INF/hst/security</param-value>
    </init-param>
</servlet>

and

<servlet-mapping>
    <servlet-name>SecurityResourceServlet</servlet-name>
    <url-pattern>/login/hst/security/*</url-pattern>
</servlet-mapping>

If you want to only change the css, then you can override the existing css as follows

Add to your src/main/resource the following resources: /META-INF/hst/security/skin/. In this resource package create a file called screen.css

(Optional) How to customize Form Login Pages

Custom Form Login page for a mount

You can configure a custom form login page for a mount by configuring " hst:formloginpage" property. For example,

- hst:formloginpage = /examples/custom_form_login.jsp

So, when the mount is protected with the following properties:

- hst:authenticated = true
- hst:roles = everybody
- hst:formloginpage = /examples/custom_form_login.jsp

HST Container will redirect the request on the mount to the custom form login page ( custom_form_login.jsp) if the user is not authenticated yet.

By the way, in your custom form login page, you may use the following HttpSession attributes to display the previous user name and redirecting destination after signing in:

Attribute name

Example value

Code example

org.hippoecm.hst.security.servlet.username

admin

session.getAttribute("org.hippoecm.hst.security.servlet.username")

org.hippoecm.hst.security.servlet.destination

/site/preview

session.getAttribute("org.hippoecm.hst.security.servlet.destination")

Also, you can customize the default login error page by setting the following session attribute in your custom form login page:

Attribute name

Example value

Code example

org.hippoecm.hst.security.servlet.loginErrorPage

/examples/custom_form_login_error.jsp

session.setAttribute("org.hippoecm.hst.security.servlet.loginErrorPage", "/examples/custom_form_login_error.jsp");

NOTE: The custom form login error page can be set only in the custom form login page!

Configuring the default Form Login pages

The default form login page and form login error page are included in hst-security-2.yy.xx.jar as freemarker templates.

However, you may configure different pages through the following servlet init parameters. When you configure these init parameters manually, you should configure context relative paths which can be dispatched by the servlet context.

Init Parameter Name

Description

Example Value

Default Value

loginFormPagePath

The initial login form page path

/WEB-INF/login/login_form.jsp or /WEB-INF/login/login_form.ftl or jcr:/hst:hst/.../login_form.ftl

classpath:/org/hippoecm/hst/security/servlet/login_form.ftl

loginErrorPage

The login error page path

/WEB-INF/login/login_failure.jsp or /WEB-INF/login/login_failure.ftl or
jcr:/hst:hst/.../login_failure.ftl

classpath:/org/hippoecm/hst/security/servlet/login_failure.ftl

So, it is possible to customize the script templates simply by adding templates in your application classpath (e.g. /WEB-INF/classes) with the same names.

Customizing the default Form Login pages

The default form login page and form login error page are included in hst-security-2.yy.xx.jar as script templates:

The default form login page template:

classpath:/org/hippoecm/hst/security/servlet/login_form.ftl

The default form login error page template:

classpath:/org/hippoecm/hst/security/servlet/login_failure.ftl 

So, it is possible to customize the script templates simply by adding templates in your application classpath (e.g. /WEB-INF/classes) with the same names.

Adding redirect to login page.

If you want to have unauthorised requests forward to the login page, add/modify an "error-page" tag in your web.xml:

<error-page>
<error-code>401</error-code>
<location>/WEB-INF/jsp/errorpages/ErrorPage401.jsp</location>
</error-page>

The jsp page should forward to the login page. See the ErrorPage401.jsp for an example from the archetype

(Optional) How to customize AuthenticationProvider of HST Security Components

Hippo JAAS LoginModule depends on HST Security components, and HST Security Components are designed in a highly modular way.

One of the core components of HST Security Components is the AuthenticationProvider component, which is responsible for authenticating on login credentials and providing security roles for the authenticated user.

By default, the AuthenticationProvider component is defined like the following in a Spring Components assembly configuration:

<bean id="org.hippoecm.hst.security.AuthenticationProvider" class="org.hippoecm.hst.security.impl.HippoAuthenticationProvider">
  <!-- SNIP -->
</bean>

So, if you implement your custom AuthenticationProvider by implementing the following interface and configure it to override the default one, then Hippo JAAS LoginModule will use your custom AuthenticaitonProvider component!

package org.hippoecm.hst.security;

public interface AuthenticationProvider {

    /**
     * Authenticate a user.
     *
     * @param userName The user name.
     * @param password The user password.
     * @return the {@link User}
     */
    User authenticate(String userName, char [] password)
                                          throws SecurityException;

    /**
     * Returns security roles of the given username
     * @param user
     * @return
     */
    Set<Role> getRolesByUsername(String username) throws SecurityException;

}

For example, you may implement a custom AuthenticationProvider to use a Database, LDAP, or another security application framework such as Spring Security UserDetailsService for instance. Then just configure the bean in an HST Container Components Assembly Overriding XML file (e.g., classpath:/META-INF/hst-assembly/overrides/my-custom-auth-provider.xml) like the following example.

<bean id="org.hippoecm.hst.security.AuthenticationProvider"
      class="com.example.security.MyCustomAuthenticationProvider">
  <!-- Configure whatever to inject somethings for this bean here... -->
</bean>

With this customizability support for AuthenticationProvider component, you may have chances to use any kinds of users/roles security backend systems.

 

Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?