07 January 2016

Understanding Spring Web-Flow in Apache Fediz - Part 1

When I started to work with Apache Fediz, most of the actions looked like magic to me, because I was not able to understand how Spring Security and Spring Web Flow have been used in Apache Fediz. After several hours of learning and investigation I finally understood how all this works together.

In this post I would like to share with you from what I understood of how Fediz works internally.
When you take a look inside the WEB-INF/web.xml you will find three URL mappings:
  • /services/* provides access to all REST services for updating the IDP configuration
  • /FederationMetadata/2007-06/FederationMetadata.xml provides access to the generated IDP metadata document which is usually used in application wizards to setup the correct IDP configuration
  • /federation provides access to the configured Spring Web-Flow

If you take a look inside the WEB-INF/web.xml you will see that the /federation URL is linked with org.springframework.web.servlet.DispatcherServlet. The initialization of the Spring Flow however takes place within the WEB-INF/idp-servlet.xml.
So how is the DispatcherServlet linked to the idp-servlet.xml?
The key to the answer is Spring MVC which uses Convention over Configuration (CoC). Spring will search for a file with the same name as the servlet-name and ending with "-servlet.xml". To apply this knowledge you can see that the /federation URL is mapped to the servlet name idp and thus the default configuration spring file which will be loaded from the DispatcherServlet is idp-servlet.xml

Spring Configuration

Within the idp-servlet.xml you will find a spring configuration to setup the Spring Web Flow.
First Spring will do a component scan to instantiate and autowire all beans with a @Component annotation located within the beans package. These beans usually provide specific actions which are executed within the flows.
<context:component-scan base-package="org.apache.cxf.fediz.service.idp.beans" />
Now the JSP views and HTML resources like images will be made available for the spring web flow:
<mvc:resources mapping="/images/**" location="/resources/images/" />
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="/federation/up/login" view-name="signinform" />

<bean id="viewResolver"
 <property name="prefix" value="/WEB-INF/views/" />
 <property name="suffix" value=".jsp" />

<bean id="viewFactoryCreator"
 <property name="viewResolvers">
   <ref local="viewResolver" />

<bean id="expressionParser"
 class="org.springframework.webflow.expression.WebFlowOgnlExpressionParser" />

<webflow:flow-builder-services id="builder"
 view-factory-creator="viewFactoryCreator" expression-parser="expressionParser" />
At next the actual spring web flows will get registered. All beans setup within this spring config will be available within the web flows.
<webflow:flow-registry id="flowRegistry"
        path="/WEB-INF/flows/federation-validate-request.xml" id="federation" />
        path="/WEB-INF/flows/federation-validate-request.xml" id="federation/up" />
        path="/WEB-INF/flows/federation-validate-request.xml" id="federation/krb" />
        path="/WEB-INF/flows/federation-validate-request.xml" id="federation/clientcert" />
        path="/WEB-INF/flows/federation-signin-request.xml" id="signinRequest" />
        path="/WEB-INF/flows/federation-signin-response.xml" id="signinResponse" />
Adding security restrictions to the flow will allow spring security to be included in the flow for user authentication.
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping" p:flowRegistry-ref="flowRegistry"

<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
        <webflow:always-redirect-on-pause value="false" />

        <webflow:listener ref="securityFlowExecutionListener" />

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter" p:flowExecutor-ref="flowExecutor" />

<bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener">
    <property name="accessDecisionManager" ref="accessDecisionManager" />

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <property name="decisionVoters">
            <bean class="org.springframework.security.access.vote.RoleVoter">
                <property name="rolePrefix" value="ROLE_" />
            <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
The spring security configuration can be found within the WEB-INF/security-config.xml file.