Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
{span:style=font-size:2em;font-weight:bold} JAX-RS: SAML Web SSO{span}

 

Table of Contents

Introduction

...

Maven dependencies

Code Block
xml
xml

<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-security-sso-saml</artifactId>
  <version>2.6.1</version>
</dependency>

...

Here is an example of a typical filter protecting a custom JAX-RS endpoint:

Code Block
xml
xml

<bean id="serviceBean" class="org.apache.cxf.samlp.sso.BookStore"/>

<jaxrs:server address="/app1"> 
       <jaxrs:serviceBeans>
          <ref bean="serviceBean"/>
       </jaxrs:serviceBeans>
       <jaxrs:providers>
          <ref bean="redirectGetFilter"/>
       </jaxrs:providers>
</jaxrs:server>

<bean id="redirectGetFilter" class="org.apache.cxf.rs.security.saml.sso.SamlRedirectBindingFilter">
      <property name="idpServiceAddress" value="https://localhost:9443/idp"/>
      <!-- both relative and absolute URIs are supported -->
      <property name="assertionConsumerServiceAddress" value="/racs/sso"/>
      <property name="stateProvider" ref="stateManager"/>
</bean>


<bean id="stateManager" class="org.apache.cxf.rs.security.saml.sso.state.EHCacheSPStateManager">
    <constructor-arg ref="cxf"/>
</bean>

...

Here is an example of a typical filter protecting a custom JAX-RS endpoint.

Code Block
xml
xml

<bean id="serviceBean" class="org.apache.cxf.samlp.sso.BookStore"/>
<jaxrs:server address="/app2"> 
    <jaxrs:serviceBeans>
       <ref bean="serviceBean"/>
     </jaxrs:serviceBeans>
     <jaxrs:providers>
          <ref bean="ssoRedirectPOST"/>
          <ref bean="samlRequestFormCreator"/> 
     </jaxrs:providers>
       
</jaxrs:server>

<bean id="ssoRedirectPOST" class="org.apache.cxf.rs.security.saml.sso.SamlPostBindingFilter">
        <property name="idpServiceAddress" value="https://localhost:9443/idp"/>
        <property name="assertionConsumerServiceAddress" value="/racs/sso"/>
        <property name="stateProvider" ref="stateManager"/>

        <property name="useDeflateEncoding" value="true"/>
</bean>

<bean id="samlRequestFormCreator" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
      <property name="dispatcherName" value="jsp"/>
      <property name="useClassNames" value="true"/>
</bean>
    
<bean id="stateManager" class="org.apache.cxf.rs.security.saml.sso.state.EHCacheSPStateManager">
    <constructor-arg ref="cxf"/>
</bean>


...

Here is a typical JSP handler for binding org.apache.cxf.rs.security.saml.sso.SAMLRequestInfo to the view:

Code Block
xml
xml

<%@ page import="javax.servlet.http.HttpServletRequest,org.apache.cxf.rs.security.saml.sso.SamlRequestInfo" %>

<%
    SamlRequestInfo data = (SamlRequestInfo)request.getAttribute("samlrequestinfo");
%>
<html xmlns="http://www.w3.org/1999/xhtml">
<body onLoad="document.forms[0].submit();">
   <form action="<%= data.getIdpServiceAddress() %>" method="POST">
       <div>             
        <input type="hidden" name="SAMLRequest"
                value="<%= data.getSamlRequest() %>"/>
        <input type="hidden" name="RelayState"
                value="<%= data.getRelayState() %>"/>
       </div>
        <div>
         <input type="submit" value="Continue"/>
       </div>
   </form>
 
</body>
</html>

...

Either the "signatureCrypto" or "signaturePropertiesFile" properties must be set if "signRequest" is set to true. Similarly, either "callbackHandler" or "callbackHandlerClass" must be configured.

Example:

Code Block
xml
xml

<bean id="ssoSignedRedirectPOST" class="org.apache.cxf.rs.security.saml.sso.SamlPostBindingFilter">
        <property name="idpServiceAddress" value="https://localhost:9443/idp"/>
        <property name="assertionConsumerServiceAddress" value="/racs/sso"/>
        <property name="stateProvider" ref="stateManager"/>

        <property name="signRequest" value="true"/>

        <property name="callbackHandlerClass" value="org.apache.cxf.samlp.sso.SSOCallbackHandler"/>
        <property name="signatureUsername" value="myservicekey"/>
        <property name="signaturePropertiesFile" value="serviceKeystore.properties"/>
</bean> 

<bean id="stateManager" class="org.apache.cxf.rs.security.saml.sso.state.EHCacheSPStateManager">
    <constructor-arg ref="cxf"/>
</bean>

...

For example, here is a typical Set Cookie request issued by a web application to the browser:

Code Block
java
java

Set-Cookie: value; Domain=mydomain; Path=/accounts; Expires=Wed, 13-Jan-2021 22:23:01 GMT;

...

Here is a typical RACS consfiguration:

Code Block
xml
xml


<bean id="consumerService" class="org.apache.cxf.rs.security.saml.sso.RequestAssertionConsumerService">
        <property name="stateProvider" ref="stateManager"/>
        <!-- responses are expected to be deflated by default
        <property name="supportDeflateEncoding" value="false"/>
        -->
        <!-- 
           responses are expected to be base64 encoded by default
        -->
        <property name="supportBase64Encoding" value="false"/>
</bean>

<bean id="stateManager" class="org.apache.cxf.rs.security.saml.sso.state.EHCacheSPStateManager">
    <constructor-arg ref="cxf"/>
</bean>


<jaxrs:server address="/racs"> 
   <jaxrs:serviceBeans>
       <ref bean="consumerService"/> 
   </jaxrs:serviceBeans>
</jaxrs:server>

...

RACS can be setup to support verifying signed Responses, or signed Assertions contained in a Response. Similarly, either "callbackHandler" or "callbackHandlerClass" must be configured if you wish to support decrypting encrypted Assertions. For example:

Code Block
xml
xml

<bean id="consumerService" class="org.apache.cxf.rs.security.saml.sso.RequestAssertionConsumerService">
        <property name="stateProvider" ref="stateManager"/>
        <property name="supportBase64Encoding" value="false"/>

        <property name="signaturePropertiesFile" value="serviceKeystore.properties"/>
        <property name="enforceAssertionsSigned" value="false"/>
        <property name="callbackHandlerClass" value="org.apache.cxf.samlp.sso.SSOCallbackHandler"/>
</bean>

In this example the "enforceAssertionsSigned" enforcing that signed Assertions are contained in a Response is disabled by default and RACS will only verify that the actual Responses are signed.

Signature Key Info Validation

By default ds:Signature is expected to contain ds:KeyInfo element.

Setting a "keyInfoMustBeAvailable" property to false will lead to a default store alias being used to load the certificate for validating the signature.

SSO State Provider

SP Security Filters and RACS depend on the custom SPStateManager implementation for persisting the current request and security context state.

...

For example, by default, the EhCache provider will overflow the data to the system temp directory and will not persist the data across restarts. The following EhCache configuration can be used to change it:

Code Block
xml
xml

<ehcache xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true">

    <diskStore path="/home/username/work/ehcache"/>

    <defaultCache
            maxEntriesLocalHeap="5000"
            timeToIdleSeconds="3600"
            timeToLiveSeconds="3600"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="true"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
</ehcache>

Assuming this configuration is saved in WEB-INF/ehcache.xml, the EhCache provider can be configured as follows:

{code:xml}
<bean id="stateManager" class="org.apache.cxf.rs.security.saml.sso.state.EHCacheSPStateManager">
    <constructor-arg value="/WEB-INF/ehcache.xml"/>
</bean>

...

For example, the following jaxrs:endpoint can be deployed alongside the RACS endpoint running in its own web application:

Code Block
xml
xml

    <bean id="stateManager" class="org.apache.cxf.rs.security.saml.sso.state.HTTPSPStateManager"/>

    <bean id="consumerService" class="org.apache.cxf.rs.security.saml.sso.RequestAssertionConsumerService">
        <property name="stateProvider" ref="stateManager"/>
        <property name="signaturePropertiesFile" value="serviceKeystore.properties"/>
        <property name="callbackHandlerClass" value="oauth2.sso.SSOCallbackHandler"/>
    </bean>
    
    <jaxrs:server address="/"> 
       <jaxrs:serviceBeans>
          <ref bean="consumerService"/>
          <ref bean="stateManager"/> 
       </jaxrs:serviceBeans>
    </jaxrs:server>

Note that the RACS bean itself directly uses HTTPSPStateManager which is also available as an HTTP endpoint for all the SSO security filters to work with.
Here is an example of how the SPStateManagers at the individual SSO filter end can use this HTTP endpoint:

Code Block
xml
xml


<jaxrs:client id="stateManager"
         address="https://localhost:${racs.port}/racs"
         serviceClass="org.apache.cxf.rs.security.saml.sso.state.HTTPSPStateManager"/>
         
 <bean id="ssoRedirectURI" class="org.apache.cxf.rs.security.saml.sso.SamlRedirectBindingFilter">
    <property name="idpServiceAddress" value="${idp.address}"/>
    <property name="assertionConsumerServiceAddress" 
               value="https://localhost:${racs.port}/racs/sso"/>
    <property name="stateProvider" ref="stateManager"/>
    <property name="addWebAppContext" value="false"/> 
 </bean>

...