Currently Being Moderated

Acegi Security in Elastic Path 6.1

Posted by Tony Bi on Mar 12, 2009 2:12:29 PM

Acegi Security is a security framework for J2EE applications. We use it to secure access to the Commerce Manager server and certain pages in the storefront. If you're doing any work in those areas, you'll want to get familiar with Acegi.

 

Note: Elastic Path 6.1 uses Acegi Security version 1.0.5. Acegi Security was integrated into more recent releases of the Spring framework and is now called Spring Security.

 

In general, security is concerned with two things:

  • authentication (determining who you are)

  • authorization (controlling what you are allowed to do in a system).

 

For authentication, Acegi supports a variety of flavors, including Basic Authentication, digest authentication, client certificate authentication, and form based authentication. You can also provide your own authentication system if you have special requirements. Elastic Path's security system relies mainly on form based authentication for the storefront and Basic Authentication for CM server access from the CM client.

 

For authorization, there are three main areas of interest: web requests, method invocations, and access to individual domain object instances. Elastic Path uses web request authorization (at the URL level) to control access to certain functionality.

 

Here is an example of one Acegi customization our team did. Our client needed to integrate their authentication system with the Elastic Path storefront. We needed to disable Elastic Path's login functionality so that the client's customers could only log in through their system, which would provide a link to redirect customers to the storefront. The link would contain some customer information that Elastic Path would use to authenticate the customer. If authentication was successful, the customer would be allowed to browse the store and purchase products. If authentication failed, the customer would be redirected to an error page with a link back to the client's system where they could try to log in again. Except for the error page, all pages needed to be displayed securely (HTTPS only). The following flow diagram shows how it looked.

 

Acegi blog diagram1-small.PNG

 

To summarize, the security requirements were as follows:

  1. The entire store must be secured, including category pages, product detail pages, etc.

  2. The error page must not be secured.

  3. Valid customers must be redirected to the landing page.

  4. Invalid customers must be redirected to the error page.

  5. Valid customers must be assigned to the ROLE_CUSTOMER role, which gives them access to all the store resources.

 

We needed to make several changes to the Acegi configuration files for the storefront, which are in WEB INF/conf/spring/security. They are named acegi.xml and acegi.xml.vm. (When you build the storefront webapp, acegi.xml is overwritten, so you should make your changes in acegi.xml.vm.)

 

Securing the store pages

We modified the channelProcessingFilter bean definition to force all pages to be secured. The regular expression \A/.*\Z matches all URLs and maps them to REQUIRES_SECURE_CHANNEL. This ensures that all pages are displayed over HTTPS only. (To match URLs, you can use either regular expressions or Ant-style paths.)

 

<bean id="channelProcessingFilter" class="org.acegisecurity.securechannel.ChannelProcessingFilter">

<property name="channelDecisionManager">

<ref bean="channelDecisionManager"/></property>

      <property name="filterInvocationDefinitionSource">

            <value>

            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

<!-- all of the pages are secured -->

                 \A/.*\Z=REQUIRES_SECURE_CHANNEL

      </value>

      </property>

</bean>

 

 

Customers must have ROLE_CUSTOMER to access store resources

In the filterInvocationInterceptor bean definition, we replaced the default URI patterns with a single wildcard pattern to map all URLs to ROLE_CUSTOMER. Now, only customers with the ROLE_CUSTOMER role are authorized to make web requests in the application.

<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">

<property name="authenticationManager">

<ref bean="authenticationManager"/>

</property>

      <property name="accessDecisionManager">

<ref local="accessDecisionManager"/>

</property>

     <property name="objectDefinitionSource">

           <value>

CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

\A/.*\Z=ROLE_CUSTOMER

     </value>

</property>

</bean>

 

Make the error page non-secure

The error page does not require authorization, so we did not want it to execute through the filterInvocationInterceptor. We added login-error.ep to the filterChainProxy bean to invoke all the other filters, as shown in the following example.

 

<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">

    <property name="filterInvocationDefinitionSource">

        <value>

        CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

        \A/login-error.ep.*\Z=channelProcessingFilter, httpSessionContextIntegrationFilter, logoutFilter, onePageLogoutFilter, authenticationProcessingFilter, exceptionTranslationFilter

 

        \A/google-callback.ep.*\Z=channelProcessingFilter, basicProcessingFilter, basicExceptionTranslationFilter, basicFilterInvocationInterceptor

        \A/.*\Z=channelProcessingFilter, httpSessionContextIntegrationFilter, logoutFilter, onePageLogoutFilter, authenticationProcessingFilter, exceptionTranslationFilter, filterInvocationInterceptor

        </value>

    </property>

</bean>

 

Remember that the order of URI patterns in filterChainProxy is critical; they are processed in order, so specific URI patterns must appear before generic, wildcard patterns. Now, when the error page was displayed, Acegi would not check to see if the customer has the required roles to access the current  resource.

 

Direct customers based on their validity

We wanted valid customers to be directed to landing.ep, while invalid customers would have to face an error page, login-error.ep. In the authenticationProcessingFilter bean, we set the authenticationFailureUrl to the error page, login-error.ep and we set the defaultTargetUrl to the landing page, landing.ep.

 

<bean id="authenticationProcessingFilter" class="com.elasticpath.sfweb.filters.EpXXXXAuthenticationProcessingFilter">

      <property name="webCustomerSessionService">

<ref bean="webCustomerSessionService"/>

</property>

<property name="requestHelper">

<ref bean="requestHelper"/>

</property>

<property name="authenticationManager">

<ref bean="authenticationManager"/>

</property>

      <property name="authenticationFailureUrl">

<value>/login-error.ep</value>

</property>

      <property name="defaultTargetUrl">

<value>/landing.ep</value>

</property>

      <property name="filterProcessesUrl">

<value>/j_acegi_security_check.ep</value>

</property>

</bean>

 

<!-- direct access to EP without login to client's system, will direct to login-error.ep -->

<bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">

    <property name="loginFormUrl">

<value>/login-error.ep</value>

</property>

      <property name="forceHttps">

<value>true</value>

</property>

</bean>

 

Other changes

We only needed to do a couple other things to complete the customization. We created the EpXXXXAuthenticationProcessingFilter controller to extract customer information from the URL and authenticate the customer. We removed sign-in.ep from url-mapping.xml to prevent access to the Elastic Path login page. That was it.

 

One of the great things about Acegi is that it can do a lot with only a few small configuration changes. For more information, go to the Acegi security site (http://www.acegisecurity.org).