cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache CXF Documentation > JAX-RS SAML
Date Thu, 03 Nov 2011 23:05:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/1/_/styles/combined.css?spaceKey=CXF20DOC&amp;forWysiwyg=true" type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+SAML">JAX-RS SAML</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~sergey_beryozkin">Sergey Beryozkin</a>
    </h4>
        <br/>
                         <h4>Changes (3)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >Now, what is interesting is to see if it is possible to use these claims with Role-Based Access-Control (for example, with endpoints relying on @RolesAllowed annotations) as well as with the more complex authorization logic (for example, let this resource be invoked only if Subject used a password to get authenticated at IDP). <br> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h2. Claims Based Access Control <br> <br></td></tr>
            <tr><td class="diff-unchanged" >CXF JAX-RS offers an extension letting users to enforce a new fine-grained Claims Based Access Control based on [Claim|http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/Claim.java] and [Claims|http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/Claims.java] annotations as well as [ClaimMode|http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/ClaimMode.java] enum class.    <br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">More to follow... <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">Here is a simple code fragment: <br>{code:java} <br>import org.apache.cxf.rs.security.saml.authorization.Claim; <br>import org.apache.cxf.rs.security.saml.authorization.Claims; <br> <br>@Path(&quot;/bookstore&quot;) <br>public class SecureClaimBookStore { <br> <br>    @POST <br>    @Path(&quot;/books&quot;) <br>    @Produces(&quot;application/xml&quot;) <br>    @Consumes(&quot;application/xml&quot;) <br>    @Claims({  <br>        @Claim({&quot;admin&quot; }), <br>        @Claim(name = &quot;http://claims/authentication-format&quot;,  <br>               format = &quot;http://claims/authentication&quot;,  <br>               value = {&quot;fingertip&quot;, &quot;smartcard&quot; }) <br>    }) <br>    public Book addBook(Book book) { <br>        return book; <br>    } <br> <br>} <br>{code} <br> <br>SecureClaimBookStore.addBook(Book) can only be invoked if Subject meets the following requirement: it needs to have a Claim with a value &quot;admin&quot; and another Claim confirming that it got authenticated using either a &#39;fingertip&#39; or &#39;smartcard&#39; method. Note that @Claim({&quot;admin&quot;}) has no name and format classifiers set - it relies on default name and format values, namely &quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role&quot; and &quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims&quot; respectively. These default values may change in the future depending on which claims are found to be used most often - but as you can see you can always provide name and format values which will scope a given claim value. <br> <br>Note that in the above example, a Claim with the name &quot;http://claims/authentication-format&quot; has two values, &#39;fingertip&#39; and &#39;smartcard&#39;. By default, in order to meet this Claim, Subject needs to have a Claim which has either a &#39;fingertip&#39; or &#39;smartcard&#39; value. If it is expected that Subject needs to have a Claim which has both &#39;fingertip&#39; and &#39;smartcard&#39; values, then the following change needs to be done: <br> <br>{code:java} <br>import org.apache.cxf.rs.security.saml.authorization.Claim; <br>import org.apache.cxf.rs.security.saml.authorization.Claims; <br> <br>@Path(&quot;/bookstore&quot;) <br>public class SecureClaimBookStore { <br> <br>    @POST <br>    @Path(&quot;/books&quot;) <br>    @Produces(&quot;application/xml&quot;) <br>    @Consumes(&quot;application/xml&quot;) <br>    @Claims({  <br>        @Claim({&quot;admin&quot; }), <br>        @Claim(name = &quot;http://claims/authentication-format&quot;,  <br>               format = &quot;http://claims/authentication&quot;,  <br>               value = {&quot;fingertip&quot;, &quot;smartcard&quot; }, <br>               matchAll = true) <br>    }) <br>    public Book addBook(Book book) { <br>        return book; <br>    } <br> <br>} <br>{code} <br> <br>Claims can be specified using individual @Claim annotation, they can be set at the class level and overridden at the method level and finally a lax mode of check can be specified: <br> <br>{code:java} <br>import org.apache.cxf.rs.security.saml.authorization.Claim; <br>import org.apache.cxf.rs.security.saml.authorization.Claims; <br> <br>@Path(&quot;/bookstore&quot;) <br>@Claim({&quot;user&quot;}) <br>public class SecureClaimBookStore { <br> <br>    @POST <br>    @Path(&quot;/books&quot;) <br>    @Produces(&quot;application/xml&quot;) <br>    @Consumes(&quot;application/xml&quot;) <br>    @Claims({  <br>        @Claim({&quot;admin&quot; }), <br>        @Claim(name = &quot;http://claims/authentication-format&quot;,  <br>               format = &quot;http://claims/authentication&quot;,  <br>               value = {&quot;fingertip&quot;, &quot;smartcard&quot; }, <br>               matchAll = true) <br>    }) <br>    public Book addBook(Book book) { <br>        return book; <br>    } <br> <br>    @GET <br>    @Claim(name = &quot;http://claims/authentication-format&quot;,  <br>               format = &quot;http://claims/authentication&quot;,  <br>               value = {&quot;password&quot; }, <br>               mode = ClaimMode.LAX) <br>    public Book getBook() { <br>        //... <br>    } <br> <br>    @GET <br>    public BookList getBookList() { <br>        //... <br>    } <br> <br> <br>} <br>{code} <br> <br>In the above example, getBookList() can be invoked if Subject has a Claim with the value &quot;user&quot;; addBook() has it overridden - &quot;admin&quot; is expected and the authentication format Claim too; getBook() can be invoked if Subject has a Claim with the value &quot;user&quot; and it also must have the authentication format Claim with the value &quot;password&quot; - or no such Claim at all.     <br> <br>Server Configuration Example: <br>{code:xml} <br> <br>&lt;bean id=&quot;serviceBeanClaims&quot; class=&quot;org.apache.cxf.systest.jaxrs.security.saml.SecureClaimBookStore&quot;/&gt; <br>&lt;bean id=&quot;samlEnvHandler&quot; class=&quot;org.apache.cxf.rs.security.saml.SamlEnvelopedInHandler&quot;&gt; <br> &lt;property name=&quot;securityContextProvider&quot;&gt; <br>    &lt;bean class=&quot;org.apache.cxf.systest.jaxrs.security.saml.CustomSecurityContextProvider&quot;/&gt; <br> &lt;/property&gt; <br>&lt;/bean&gt; <br> <br>&lt;bean id=&quot;claimsHandler&quot;  <br>     class=&quot;org.apache.cxf.rs.security.saml.authorization.ClaimsAuthorizingFilter&quot;&gt; <br>    &lt;property name=&quot;securedObject&quot; ref=&quot;serviceBeanClaims&quot;/&gt;    <br>&lt;/bean&gt; <br> <br>&lt;jaxrs:server address=&quot;/saml-claims&quot;&gt;  <br>       &lt;jaxrs:serviceBeans&gt; <br>          &lt;ref bean=&quot;serviceBeanClaims&quot;/&gt; <br>       &lt;/jaxrs:serviceBeans&gt; <br>       &lt;jaxrs:providers&gt; <br>          &lt;ref bean=&quot;samlEnvHandler&quot;/&gt; <br>          &lt;ref bean=&quot;claimsHandler&quot;/&gt; <br>       &lt;/jaxrs:providers&gt; <br>&lt;/jaxrs:server&gt; <br>{code} <br> <br>h2. Role Based Access Control <br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <p><span style="font-size:2em;font-weight:bold"> JAX-RS: SAML </span></p>


<div>
<ul>
    <li><a href='#JAX-RSSAML-Introduction'>Introduction</a></li>
    <li><a href='#JAX-RSSAML-Mavendependencies'>Maven dependencies</a></li>
    <li><a href='#JAX-RSSAML-EnvelopedSAMLassertions'>Enveloped SAML assertions</a></li>
    <li><a href='#JAX-RSSAML-SAMLassertionsinAuthorizationheader'>SAML assertions in Authorization header</a></li>
    <li><a href='#JAX-RSSAML-SAMLassertionsasFormvalues'>SAML assertions as Form values</a></li>
    <li><a href='#JAX-RSSAML-CreatingSAMLAssertions'>Creating SAML Assertions</a></li>
    <li><a href='#JAX-RSSAML-SAMLAssertionValidation'>SAML Assertion Validation</a></li>
    <li><a href='#JAX-RSSAML-SAMLAuthorization'>SAML Authorization</a></li>
<ul>
    <li><a href='#JAX-RSSAML-ClaimsBasedAccessControl'>Claims Based Access Control</a></li>
    <li><a href='#JAX-RSSAML-RoleBasedAccessControl'>Role Based Access Control</a></li>
</ul>
</ul></div>

<h1><a name="JAX-RSSAML-Introduction"></a>Introduction</h1>

<p>CXF 2.5.0 introduces an initial support for working with <a href="http://en.wikipedia.org/wiki/SAML_2.0" class="external-link" rel="nofollow">SAML2</a> assertions. So far the main focus has been put on making sure SAML assertions can be included in HTTP requests targeted at application endpoints: embedded inside XML payloads or passed as encoded HTTP header or form values. Support for advanced SAML features such as Web Browser SSO Profile will be coming in due time.</p>

<h1><a name="JAX-RSSAML-Mavendependencies"></a>Maven dependencies</h1>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;dependency&gt;</span>
  <span class="code-tag">&lt;groupId&gt;</span>org.apache.cxf<span class="code-tag">&lt;/groupId&gt;</span>
  <span class="code-tag">&lt;artifactId&gt;</span>cxf-rt-rs-security-xml<span class="code-tag">&lt;/artifactId&gt;</span>
  <span class="code-tag">&lt;version&gt;</span>2.5.0<span class="code-tag">&lt;/version&gt;</span>
<span class="code-tag">&lt;/dependency&gt;</span>
</pre>
</div></div>

<p>This module depends on CXF WS-Security and Apache WSS4J modules, due to them containing a lot of useful utility code.<br/>
We will see in time if it will make sense to exclude such dependencies or not. </p>

<h1><a name="JAX-RSSAML-EnvelopedSAMLassertions"></a>Enveloped SAML assertions</h1>

<p>Payload:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;env:Envelope <span class="code-keyword">xmlns:env</span>=<span class="code-quote">"http://org.apache.cxf/rs/env"</span>&gt;</span>

<span class="code-tag">&lt;Book ID=<span class="code-quote">"67ca6441-0c4e-4430-af0e-9463ce9226aa"</span>&gt;</span>
  <span class="code-tag">&lt;id&gt;</span>125<span class="code-tag">&lt;/id&gt;</span>
  <span class="code-tag">&lt;name&gt;</span>CXF<span class="code-tag">&lt;/name&gt;</span>
<span class="code-tag">&lt;/Book&gt;</span>
<span class="code-tag">&lt;ds:Signature <span class="code-keyword">xmlns:ds</span>=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#"</span>&gt;</span>
  <span class="code-tag"><span class="code-comment">&lt;!-- Book signature, omitted for brewity --&gt;</span></span>
<span class="code-tag">&lt;/ds:Signature&gt;</span>

<span class="code-tag"><span class="code-comment">&lt;!-- SAML assertion with an enveloped signature --&gt;</span></span> 
<span class="code-tag">&lt;saml2:Assertion <span class="code-keyword">xmlns:saml2</span>=<span class="code-quote">"urn:oasis:names:tc:SAML:2.0:assertion"</span> <span class="code-keyword">xmlns:xs</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema"</span> <span class="code-keyword">xmlns:xsi</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema-instance"</span> ID=<span class="code-quote">"_62D574706635C0B9F413203247720501"</span> IssueInstant=<span class="code-quote">"2011-11-03T12:52:52.050Z"</span> Version=<span class="code-quote">"2.0"</span> xsi:type=<span class="code-quote">"saml2:AssertionType"</span>&gt;</span>

<span class="code-tag">&lt;saml2:Issuer&gt;</span>https://idp.example.org/SAML2<span class="code-tag">&lt;/saml2:Issuer&gt;</span>

<span class="code-tag">&lt;ds:Signature <span class="code-keyword">xmlns:ds</span>=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#"</span>&gt;</span>
   <span class="code-tag">&lt;ds:SignedInfo&gt;</span>
    <span class="code-tag">&lt;ds:CanonicalizationMethod Algorithm=<span class="code-quote">"http://www.w3.org/2001/10/xml-exc-c14n#"</span>/&gt;</span>
    <span class="code-tag">&lt;ds:SignatureMethod Algorithm=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#rsa-sha1"</span>/&gt;</span>
    <span class="code-tag">&lt;ds:Reference URI=<span class="code-quote">"#_62D574706635C0B9F413203247720501"</span>&gt;</span>
      <span class="code-tag">&lt;ds:Transforms&gt;</span>
       <span class="code-tag">&lt;ds:Transform Algorithm=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#enveloped-signature"</span>/&gt;</span>
       <span class="code-tag">&lt;ds:Transform Algorithm=<span class="code-quote">"http://www.w3.org/2001/10/xml-exc-c14n#"</span>&gt;</span>
         <span class="code-tag">&lt;ec:InclusiveNamespaces <span class="code-keyword">xmlns:ec</span>=<span class="code-quote">"http://www.w3.org/2001/10/xml-exc-c14n#"</span> PrefixList=<span class="code-quote">"xs"</span>/&gt;</span>
       <span class="code-tag">&lt;/ds:Transform&gt;</span>
      <span class="code-tag">&lt;/ds:Transforms&gt;</span>
      <span class="code-tag">&lt;ds:DigestMethod Algorithm=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#sha1"</span>/&gt;</span>
      <span class="code-tag">&lt;ds:DigestValue&gt;</span>IDD9nFocVm/7FpUbiGI3ZvpY2ps=<span class="code-tag">&lt;/ds:DigestValue&gt;</span>
    <span class="code-tag">&lt;/ds:Reference&gt;</span>
   <span class="code-tag">&lt;/ds:SignedInfo&gt;</span>
   <span class="code-tag">&lt;ds:SignatureValue&gt;</span>JA2I7u/SmNsXGgWNdrLSovkipiM3JmGHsmpoP0EeIOwPwnLMx0WvV0C3xNGNiT1jOBe2uv8+WchtPoppGTC2JTJVX/t8PmKQCYZo4kVJo6Nmsjbn5kp7ejWuOYynvrUheQeTLU8e5CQmuS6L4VYaMVV2ETtb0VvpKjoQKHOC+co=<span class="code-tag">&lt;/ds:SignatureValue&gt;</span>
   <span class="code-tag">&lt;ds:KeyInfo&gt;</span>
    <span class="code-tag">&lt;ds:X509Data&gt;</span>
     <span class="code-tag">&lt;ds:X509Certificate&gt;</span><span class="code-tag"><span class="code-comment">&lt;!-- Omitted for brewity --&gt;</span></span> <span class="code-tag">&lt;/ds:X509Certificate&gt;</span>
    <span class="code-tag">&lt;/ds:X509Data&gt;</span>
   <span class="code-tag">&lt;/ds:KeyInfo&gt;</span>
 <span class="code-tag">&lt;/ds:Signature&gt;</span>

 <span class="code-tag">&lt;saml2:Subject&gt;</span>
   <span class="code-tag">&lt;saml2:NameID Format=<span class="code-quote">"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"</span> NameQualifier=<span class="code-quote">"www.mock-sts.com"</span>&gt;</span>uid=sts-client,o=mock-sts.com<span class="code-tag">&lt;/saml2:NameID&gt;</span>
   <span class="code-tag">&lt;saml2:SubjectConfirmation Method=<span class="code-quote">"urn:oasis:names:tc:SAML:2.0:cm:sender-vouches"</span>/&gt;</span>
 <span class="code-tag">&lt;/saml2:Subject&gt;</span>

 <span class="code-tag">&lt;saml2:Conditions NotBefore=<span class="code-quote">"2011-11-03T12:52:52.063Z"</span> NotOnOrAfter=<span class="code-quote">"2011-11-03T12:52:52.063Z"</span>&gt;</span>
  <span class="code-tag">&lt;saml2:AudienceRestriction&gt;</span>
   <span class="code-tag">&lt;saml2:Audience&gt;</span>https://sp.example.com/SAML2<span class="code-tag">&lt;/saml2:Audience&gt;</span>
  <span class="code-tag">&lt;/saml2:AudienceRestriction&gt;</span>
 <span class="code-tag">&lt;/saml2:Conditions&gt;</span>
 <span class="code-tag">&lt;saml2:AuthnStatement AuthnInstant=<span class="code-quote">"2011-11-03T12:52:51.981Z"</span> SessionIndex=<span class="code-quote">"123456"</span>&gt;</span>
    <span class="code-tag">&lt;saml2:AuthnContext&gt;</span><span class="code-tag">&lt;saml2:AuthnContextClassRef/&gt;</span><span class="code-tag">&lt;/saml2:AuthnContext&gt;</span>
 <span class="code-tag">&lt;/saml2:AuthnStatement&gt;</span>

 <span class="code-tag">&lt;saml2:AttributeStatement&gt;</span>
    &lt;saml2:Attribute FriendlyName=<span class="code-quote">"subject-role"</span> 
                     Name=<span class="code-quote">"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"</span> 
                     NameFormat=<span class="code-quote">"http://schemas.xmlsoap.org/ws/2005/05/identity/claims"</span>&gt;
       <span class="code-tag">&lt;saml2:AttributeValue xsi:type=<span class="code-quote">"xs:string"</span>&gt;</span>user<span class="code-tag">&lt;/saml2:AttributeValue&gt;</span>
    <span class="code-tag">&lt;/saml2:Attribute&gt;</span>
    &lt;saml2:Attribute Name=<span class="code-quote">"http://claims/authentication"</span> 
                     NameFormat=<span class="code-quote">"http://claims/authentication-format"</span>&gt;
       <span class="code-tag">&lt;saml2:AttributeValue xsi:type=<span class="code-quote">"xs:string"</span>&gt;</span>password<span class="code-tag">&lt;/saml2:AttributeValue&gt;</span>
    <span class="code-tag">&lt;/saml2:Attribute&gt;</span>
 <span class="code-tag">&lt;/saml2:AttributeStatement&gt;</span>
<span class="code-tag">&lt;/saml2:Assertion&gt;</span>
<span class="code-tag">&lt;/env:Envelope&gt;</span>
</pre>
</div></div>

<p>Note that Book and SAML assertion are individually signed but the envelope wrapper itself is not.</p>


<p>Here is another payload showing the whole enveloped signed including Book and SAML Assertion, this time only a single signature will be available:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;env:Envelope <span class="code-keyword">xmlns:env</span>=<span class="code-quote">"http://org.apache.cxf/rs/env"</span> ID=<span class="code-quote">"e795cdd1-c19d-4a5c-8d86-e8a781af4787"</span>&gt;</span>

<span class="code-tag">&lt;saml2:Assertion <span class="code-keyword">xmlns:saml2</span>=<span class="code-quote">"urn:oasis:names:tc:SAML:2.0:assertion"</span> <span class="code-keyword">xmlns:xsi</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema-instance"</span> ID=<span class="code-quote">"_C76E3D5BBEE4C4D87913203281641141"</span> IssueInstant=<span class="code-quote">"2011-11-03T13:49:24.114Z"</span> Version=<span class="code-quote">"2.0"</span> xsi:type=<span class="code-quote">"saml2:AssertionType"</span>&gt;</span>
<span class="code-tag">&lt;saml2:Issuer&gt;</span>https://idp.example.org/SAML2<span class="code-tag">&lt;/saml2:Issuer&gt;</span>
<span class="code-tag">&lt;saml2:Subject&gt;</span>
<span class="code-tag">&lt;saml2:NameID Format=<span class="code-quote">"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"</span> NameQualifier=<span class="code-quote">"www.mock-sts.com"</span>&gt;</span>uid=sts-client,o=mock-sts.com<span class="code-tag">&lt;/saml2:NameID&gt;</span>
<span class="code-tag">&lt;saml2:SubjectConfirmation Method=<span class="code-quote">"urn:oasis:names:tc:SAML:2.0:cm:sender-vouches"</span>/&gt;</span>
<span class="code-tag">&lt;/saml2:Subject&gt;</span>
<span class="code-tag">&lt;saml2:Conditions NotBefore=<span class="code-quote">"2011-11-03T13:49:24.127Z"</span> NotOnOrAfter=<span class="code-quote">"2011-11-03T13:49:24.127Z"</span>&gt;</span>
<span class="code-tag">&lt;saml2:AudienceRestriction&gt;</span>
<span class="code-tag">&lt;saml2:Audience&gt;</span>https://sp.example.com/SAML2<span class="code-tag">&lt;/saml2:Audience&gt;</span>
<span class="code-tag">&lt;/saml2:AudienceRestriction&gt;</span>
<span class="code-tag">&lt;/saml2:Conditions&gt;</span>
<span class="code-tag">&lt;saml2:AuthnStatement AuthnInstant=<span class="code-quote">"2011-11-03T13:49:24.044Z"</span> SessionIndex=<span class="code-quote">"123456"</span>&gt;</span>
<span class="code-tag">&lt;saml2:AuthnContext&gt;</span>
<span class="code-tag">&lt;saml2:AuthnContextClassRef/&gt;</span>
<span class="code-tag">&lt;/saml2:AuthnContext&gt;</span>
<span class="code-tag">&lt;/saml2:AuthnStatement&gt;</span>
<span class="code-tag">&lt;saml2:AttributeStatement&gt;</span>
<span class="code-tag">&lt;saml2:Attribute FriendlyName=<span class="code-quote">"subject-role"</span> Name=<span class="code-quote">"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"</span> NameFormat=<span class="code-quote">"http://schemas.xmlsoap.org/ws/2005/05/identity/claims"</span>&gt;</span>
<span class="code-tag">&lt;saml2:AttributeValue <span class="code-keyword">xmlns:xs</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema"</span> xsi:type=<span class="code-quote">"xs:string"</span>&gt;</span>user<span class="code-tag">&lt;/saml2:AttributeValue&gt;</span>
<span class="code-tag">&lt;/saml2:Attribute&gt;</span>
<span class="code-tag">&lt;saml2:Attribute Name=<span class="code-quote">"http://claims/authentication"</span> NameFormat=<span class="code-quote">"http://claims/authentication-format"</span>&gt;</span>
<span class="code-tag">&lt;saml2:AttributeValue <span class="code-keyword">xmlns:xs</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema"</span> xsi:type=<span class="code-quote">"xs:string"</span>&gt;</span>password<span class="code-tag">&lt;/saml2:AttributeValue&gt;</span>
<span class="code-tag">&lt;/saml2:Attribute&gt;</span>
<span class="code-tag">&lt;/saml2:AttributeStatement&gt;</span>
<span class="code-tag">&lt;/saml2:Assertion&gt;</span>

<span class="code-tag">&lt;Book&gt;</span>
<span class="code-tag">&lt;id&gt;</span>125<span class="code-tag">&lt;/id&gt;</span>
<span class="code-tag">&lt;name&gt;</span>CXF<span class="code-tag">&lt;/name&gt;</span>
<span class="code-tag">&lt;/Book&gt;</span>

<span class="code-tag">&lt;ds:Signature <span class="code-keyword">xmlns:ds</span>=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#"</span>&gt;</span><span class="code-tag">&lt;ds:SignedInfo&gt;</span><span class="code-tag">&lt;ds:CanonicalizationMethod Algorithm=<span class="code-quote">"http://www.w3.org/TR/2001/REC-xml-c14n-20010315"</span>/&gt;</span><span class="code-tag">&lt;ds:SignatureMethod Algorithm=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#rsa-sha1"</span>/&gt;</span><span class="code-tag">&lt;ds:Reference URI=<span class="code-quote">"#e795cdd1-c19d-4a5c-8d86-e8a781af4787"</span>&gt;</span><span class="code-tag">&lt;ds:Transforms&gt;</span><span class="code-tag">&lt;ds:Transform Algorithm=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#enveloped-signature"</span>/&gt;</span><span class="code-tag">&lt;ds:Transform Algorithm=<span class="code-quote">"http://www.w3.org/2001/10/xml-exc-c14n#"</span>/&gt;</span><span class="code-tag">&lt;/ds:Transforms&gt;</span><span class="code-tag">&lt;ds:DigestMethod Algorithm=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#sha1"</span>/&gt;</span><span class="code-tag">&lt;ds:DigestValue&gt;</span>GR1pHd2JpxYiCzl6ouCmTZjq/AA=<span class="code-tag">&lt;/ds:DigestValue&gt;</span><span class="code-tag">&lt;/ds:Reference&gt;</span><span class="code-tag">&lt;/ds:SignedInfo&gt;</span><span class="code-tag">&lt;ds:SignatureValue&gt;</span>C2qUDOFwart2GHFjX6kB3E3z73AMXtRR/6Qjgyp6XP/vTn/Fr2epDNub3q+gNdT0KgjLE2rSynM3QTcpHov9C8l9a8VQquItaalr0XA7BJcxdFMxB7KEATKR9XtrmIEkiw9efM8M83iVux/ufCOWrt0Te2RLz+nRwzyEY49VQOQ=<span class="code-tag">&lt;/ds:SignatureValue&gt;</span><span class="code-tag">&lt;ds:KeyInfo&gt;</span><span class="code-tag">&lt;ds:X509Data&gt;</span><span class="code-tag">&lt;ds:X509Certificate&gt;</span><span class="code-tag"><span class="code-comment">&lt;!-- Omitted for brewity --&gt;</span></span><span class="code-tag">&lt;/ds:X509Certificate&gt;</span><span class="code-tag">&lt;/ds:X509Data&gt;</span><span class="code-tag">&lt;ds:KeyValue&gt;</span><span class="code-tag">&lt;ds:RSAKeyValue&gt;</span><span class="code-tag">&lt;ds:Modulus&gt;</span>vu747/VShQ85f16DGSc4Ixh9PVpGguyEqrCsK8q9XHOYX9l9/g5wEC6ZcR2FwfNsoaHcKNPjd5sSTzVtBWmQjfBEfIqwTR7vuihOxyNTwEzVwIJzvo7p8/aYxk+VdBtQxq4UweIcf/iFkUbM1cZ1oiXRQzciRBi+C1BQCQE0qzs=<span class="code-tag">&lt;/ds:Modulus&gt;</span><span class="code-tag">&lt;ds:Exponent&gt;</span>AQAB<span class="code-tag">&lt;/ds:Exponent&gt;</span><span class="code-tag">&lt;/ds:RSAKeyValue&gt;</span><span class="code-tag">&lt;/ds:KeyValue&gt;</span><span class="code-tag">&lt;/ds:KeyInfo&gt;</span><span class="code-tag">&lt;/ds:Signature&gt;</span><span class="code-tag">&lt;/env:Envelope&gt;</span>
</pre>
</div></div>

<p>Server configuration fragment:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
    <span class="code-tag">&lt;bean id=<span class="code-quote">"serviceBean"</span> class=<span class="code-quote">"org.apache.cxf.systest.jaxrs.security.BookStore"</span>/&gt;</span>
    <span class="code-tag">&lt;bean id=<span class="code-quote">"samlHandler"</span> class=<span class="code-quote">"org.apache.cxf.rs.security.saml.SamlEnvelopedInHandler"</span>/&gt;</span>
    
    <span class="code-tag"><span class="code-comment">&lt;!-- only needed if the detached signature signing the application data is expected --&gt;</span></span> 
    <span class="code-tag">&lt;bean id=<span class="code-quote">"xmlSigHandler"</span> class=<span class="code-quote">"org.apache.cxf.rs.security.xml.XmlSigInHandler"</span>/&gt;</span>
    
    
    &lt;jaxrs:server 
       address=<span class="code-quote">"https://localhost:${testutil.ports.jaxrs-saml}/samlxml"</span>&gt; 
       <span class="code-tag">&lt;jaxrs:serviceBeans&gt;</span>
          <span class="code-tag">&lt;ref bean=<span class="code-quote">"serviceBean"</span>/&gt;</span>
       <span class="code-tag">&lt;/jaxrs:serviceBeans&gt;</span>
       <span class="code-tag">&lt;jaxrs:providers&gt;</span>
          <span class="code-tag">&lt;ref bean=<span class="code-quote">"xmlSigHandler"</span>/&gt;</span>
          <span class="code-tag">&lt;ref bean=<span class="code-quote">"samlHandler"</span>/&gt;</span>
       <span class="code-tag">&lt;/jaxrs:providers&gt;</span>
       
       <span class="code-tag">&lt;jaxrs:properties&gt;</span>
           &lt;entry key=<span class="code-quote">"ws-security.signature.properties"</span> 
                  value=<span class="code-quote">"org/apache/cxf/systest/jaxrs/security/alice.properties"</span>/&gt;
       <span class="code-tag">&lt;/jaxrs:properties&gt;</span>
        
    <span class="code-tag">&lt;/jaxrs:server&gt;</span>
</pre>
</div></div>

<p>Client code:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">private</span> WebClient createWebClient(<span class="code-object">String</span> address, 
                                  <span class="code-object">boolean</span> selfSigned) {
  JAXRSClientFactoryBean bean = <span class="code-keyword">new</span> JAXRSClientFactoryBean();
  bean.setAddress(address);
  
  Map&lt;<span class="code-object">String</span>, <span class="code-object">Object</span>&gt; properties = <span class="code-keyword">new</span> HashMap&lt;<span class="code-object">String</span>, <span class="code-object">Object</span>&gt;();
  properties.put(<span class="code-quote">"ws-security.callback-handler"</span>, 
                <span class="code-quote">"org.apache.cxf.systest.jaxrs.security.saml.KeystorePasswordCallback"</span>);
  properties.put(<span class="code-quote">"ws-security.saml-callback-handler"</span>, 
                 <span class="code-quote">"org.apache.cxf.systest.jaxrs.security.saml.SamlCallbackHandler"</span>);
  properties.put(<span class="code-quote">"ws-security.signature.username"</span>, <span class="code-quote">"alice"</span>);
  properties.put(<span class="code-quote">"ws-security.signature.properties"</span>, 
                 <span class="code-quote">"org/apache/cxf/systest/jaxrs/security/alice.properties"</span>);
  <span class="code-keyword">if</span> (selfSigned) {
     properties.put(<span class="code-quote">"ws-security.self-sign-saml-assertion"</span>, <span class="code-quote">"<span class="code-keyword">true</span>"</span>);
  }
  bean.setProperties(properties);
        
  bean.getOutInterceptors().add(<span class="code-keyword">new</span> SamlEnvelopedOutInterceptor(!selfSigned));
  XmlSigOutInterceptor xmlSig = <span class="code-keyword">new</span> XmlSigOutInterceptor();
  <span class="code-keyword">if</span> (selfSigned) {
      xmlSig.setStyle(XmlSigOutInterceptor.DETACHED_SIG);
  }
  <span class="code-keyword">return</span> bean.createWebClient();
}
</pre>
</div></div>

<p>In the above code, the "ws-security.self-sign-saml-assertion" property, if set to true, will require SamlEnvelopedOutInterceptor to get a SAML assertion self-signed, by adding an enveloped signature to it. When we also need to sign the application payload such as Book we need to make sure that a detached XML signature for Book is created. When the whole envelope is signed then SamlEnvelopedOutInterceptor needs to be placed before XmlSigOutInterceptor hence the "new SamlEnvelopedOutInterceptor(!selfSigned)" constructor is invoked.</p>

<h1><a name="JAX-RSSAML-SAMLassertionsinAuthorizationheader"></a>SAML assertions in Authorization header</h1>

<p>Logging output:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
Address: https:<span class="code-comment">//localhost:9000/samlheader/bookstore/books/123
</span>Http-Method: GET
Headers: {Accept=[application/xml], Authorization=[SAML eJydV1mTokgQfu9fYTCPrs2htGKMHVEcKq2gKOLxsoFQAsqhFAjNr99CW1ud7t2ZjdAwMisr68s7/YnMwGfaACEYJ14UVmSxQ/z9wjUlBrRYiWZZiWVYlqPrDFVnmhTbwL80UZERSqEcosQMkw7BUDRdwx+qrtP1dp1qs41nLLciKgaMEVaLRZ4popIHfojapyc7RBqH7chEHmqHZgBRO7HaU6AM21iybV7wXO7kqEO4SbJvk2SWZc9Z/TmKHZKhKJpcKMOp5cLA/JT1/lu45p3AWxDfQl47ed/DDvHgDB0zidefZ+7J4vi11IuwYs/eP8PcDPY+PGkvoTM/yTvZnzZqTz0nNJM0hh/g7O8MoUiKI7GMjTznB3G9C2053EQnUjDDKPQs0/cKs4SnwMSN7ArwnSj2Ejf41miaKhXXYG7VLLoR/iDIe2i/qegOYYzMGnJN+kPXBG5gDLE7K7OJ3CF+/HcKna7psRmiTRQH6J78MywwPEI/2kO7hi4mfcD6fYVfeOn1J7Tacmj5KfKOUC2TdG9aEFXGMdx4+dBDOPVzdEk7aP1RAMhbeA/k2Rui50CU/J/g3ATmrMQw/RS+Lod0s8c74oavDxsCSoueGs8H4zUQlp0TgFvhE+Ma1jP5kJDXBDrfABTXCxR7+UJ5clXM0XjN8LG9MQxG57bTMfB9rUkaXUNKJgsRzKl+f8R2q0qr/sLB+Ub3oGEPhrIMJTegkBOM+0E4nbCLjVXYXO6MHXYhDLMWtGjKtRtNGtirfrioTvXhhnM2zalRXdXDlVVPg2Oe0Sp4Ge/eWgdRiXQwOiZWtZEfjtSwm1aH46xzNecGf2nSAL5fzVuwFCeaiXklhLItbHAFJvBVkWWhtxUEsBw5IJN54MjS1Jg4QAcq7+wO7s7rcRnFA23WBSIolImSSdpSNDRtIGV71+p1t2Zvlq7rb+GTomWZ4JwOh1Km+uvAysUtUHhHNXig6PxcbawC1VX4xkLUrUwRpUzRAf7F326EeUoD8/KRDoonRdcylY4ypZB0hZd6gJ5JgqsMlgveXTKuPwy491UhKQqIzme5Iq7mbKhojUwEJxBYveGue/72aaULfFg8miR1ARjxWw1kznKHgUvgmDYbOLhTV2uxG/pF7E2thpy73NjY95z0XTrEAnoatA7coj9aLjifIx02k4SXlTVhutlGRZHZtwbqeGuzaKoXRsLPA2274aWNfMj0SfOYeu4of1f1TCqMTH4rno5Rc98izWW+qxo2n2j5oTHLoGxtSK+7m60V2lrRkbeYaIXlTXivKtC8JmgSdSiQADIJAFNpKuIuk3FQnowJNeX5KOvJ8lzfcbMFtRrPfE6b7TjJmKmz6YwbLWhDn+hgVgalP5EkUQdDx/HRmlGxr9yjVdcyUVu+PQ2ilYxJtfQTrwGx9I87zHZBtbVHg6ThhGtv1ysMSnf203nPmufzAQZYtBKZCV/cLmCP9Nbo981Gj3ty64gKc43RYVbACblrOoFjMEhutOqqEy/7gR4MB6bIzwuT2YN0lYqu1m/1gOS+mbtuMuDH1aokcLGq7ldP4eHQz/P6Yc0kc4Y9TBK+EIMBx9COw42VKFCsZnqYaOfqeMz4K/NcE+RttdxV02ViTtP1FlrJhSwbqCxWuri/mcn3459+pk8cz65tTqLtNER7aGEY0CYqpRYtxTMQk3GHKJtgEFm7GkrQsxUFxGvq2R1M1Czfg2HyV9S5Pb4M6DOWB6BCFG688sVyDzq33X/fUqygjWBow7h2jFK8VaBTX<span class="code-comment">//SeKzb9krFqKJGCQ+xafCbvYl+wXsTFhqFoxhsktLKb+Uu6kFqe2WbnuD2HXtW+dDj0XVzQZ+LC/bI/eJyFX5k3CkmH236fCtxw2mCsyXAvq+cyH9dEvFOgI2dQlQuiTJ2Zd4haKbeYF+IO534qQTmyVc8wcfLIp5T5A3m2xvkV9CuihJs1TpN4PcnlW6MPWD772XO4BXxHNdaHPnwnI3XgYxOiyV6xlMYt7P9aTJnqBzOLIk/no3Ve8k7afmmFyDyU8OlJP6XHuIXxKdpdrPV5njlxkehg4sDb7ZXj9zJv/7C/tUTd9Z+WGFiv5Z4LPO8rn9hz5eSH8X9R+j3ONJZFNu/b8Ej59cwY1CFiLtLmYCfmXvhdIgyKXENBh7ubfCmvq9/El7/AXoseyE=], ...}</span>
</pre>
</div></div>

<p>Note that the Authorization header has an encoded SAML Assertion as its value. The original SAML assertion has been optionally compressed using a deflated encoding and then base64-encoded. This encoded value can be signed itself - but it is not currently possible.</p>

<p>Server configuration is similar to the one from the Enveloped SAML Assertions section, the only difference is that a SAML handler needs to be replaced:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
    <span class="code-tag">&lt;bean id=<span class="code-quote">"serviceBean"</span> class=<span class="code-quote">"org.apache.cxf.systest.jaxrs.security.BookStore"</span>/&gt;</span>
    <span class="code-tag">&lt;bean id=<span class="code-quote">"samlHandler"</span> class=<span class="code-quote">"org.apache.cxf.rs.security.saml.SamlHeaderInHandler"</span>/&gt;</span>
    
    <span class="code-tag"><span class="code-comment">&lt;!-- same as in the Enveloped SAML Assertions section --&gt;</span></span> 
</pre>
</div></div>

<p>Client code:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">private</span> WebClient createWebClient(<span class="code-object">String</span> address, 
                                  <span class="code-object">boolean</span> selfSigned) {
  JAXRSClientFactoryBean bean = <span class="code-keyword">new</span> JAXRSClientFactoryBean();
  bean.setAddress(address);
  
  Map&lt;<span class="code-object">String</span>, <span class="code-object">Object</span>&gt; properties = <span class="code-keyword">new</span> HashMap&lt;<span class="code-object">String</span>, <span class="code-object">Object</span>&gt;();
  properties.put(<span class="code-quote">"ws-security.callback-handler"</span>, 
                <span class="code-quote">"org.apache.cxf.systest.jaxrs.security.saml.KeystorePasswordCallback"</span>);
  properties.put(<span class="code-quote">"ws-security.saml-callback-handler"</span>, 
                 <span class="code-quote">"org.apache.cxf.systest.jaxrs.security.saml.SamlCallbackHandler"</span>);
  properties.put(<span class="code-quote">"ws-security.signature.username"</span>, <span class="code-quote">"alice"</span>);
  properties.put(<span class="code-quote">"ws-security.signature.properties"</span>, 
                 <span class="code-quote">"org/apache/cxf/systest/jaxrs/security/alice.properties"</span>);
  <span class="code-keyword">if</span> (selfSigned) {
     properties.put(<span class="code-quote">"ws-security.self-sign-saml-assertion"</span>, <span class="code-quote">"<span class="code-keyword">true</span>"</span>);
  }
  bean.setProperties(properties);
        
  bean.getOutInterceptors().add(<span class="code-keyword">new</span> SamlHeaderOutInterceptor());
  
  <span class="code-keyword">return</span> bean.createWebClient();
}
</pre>
</div></div>


<h1><a name="JAX-RSSAML-SAMLassertionsasFormvalues"></a>SAML assertions as Form values</h1>

<p>Logging output:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
Address: https:<span class="code-comment">//localhost:9000/samlform/bookstore/books
</span>Encoding: ISO-8859-1
Http-Method: POST
Content-Type: application/x-www-form-urlencoded
Headers: {Accept=[application/xml], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[2206], content-type=[application/x-www-form-urlencoded], Host=[localhost:9000], Pragma=[no-cache], User-Agent=[Apache CXF ${project.version}]}
Payload: name=CXF&amp;id=125&amp;SAMLToken=eJydV1tzqkgQfs+vsDiPWcNFjWIdUzUIGqJgQMTLyxYOI6BclAFBfv0OGo16kt1ztkrL6p6eb77u6e5pf2Ir8Lk2wBjFiReFFVnsUH8zYqPFAAkwbOsZSK2eKLI1jqlxTY5p8PVnlqrIGKdIDnFihUmH4hiWrZIPUzPYWrtWa3ONJ2K3oComijGBJSZPDFXJAz/E7eORHSqNw3ZkYQ+3QytAuJ3A9hgowzaxbFtnPuc9Oe5QbpJs2zSdZdlTVnuKYofmGIalZ8pwDF0UWJ+23n8bV70jeYjILuy1k8MWdai7YBhESb38PGmPHscvJS4mwJ69fUK5FWx9dEQvqXM/6RvbnzZujz0ntJI0Rh/k7O8cYWiGp4mNjT3nB3XZi2w5XEVHsWuFUehBy/cKq6SnoMSN7ArwnSj2Ejf41mmWKYGrKIdVyNbDHxR9S+03gW4YxtiqYtdiP7B0tEIxIuGsTHS5Q/347xQ6bjNiK8SrKA7wrfhnXFC4R360RXYVn136oPX7gF9E6eUngm05hH6KvT1SyyTdWhDhynuMVl4+9DBJ/Ryf0w7BP7oA+prenXiKhug5CCf/53KuLuYEYlp+il5qDTNiWU3Hz3qxkBCzn0aanw8K7TDvHAlcGx8Vl2s9iXcJeUmg046Q1/bNx0AVHltzNp3pb/KwtizS/nZmHNYYvG6A5G44Bj4bw4msaTYCi93Q5NfL1cBgoBvCw9DbS0GPm43UQnzfJW9JfzUs6nQ/nQh7zXb7EltbPTKPXvSeRSuvvu/LIHWEjTJqJfom5qCJn0W7lSxg34LSPlSMOmitOLyUDNc2PGWpw169tTb5rHNx54p/6dIAHS7uzRoML1qJdRG6ZVtYkQpM0Isiy93+utsF85EDMlkAjiyNTd0BBlAFZ7NzN16fzxgBaJMeEEGh6EomaXPR1LSBlG1d2O+trf4kXdbewgdFy7Kuc1wcSpnqLwOYi2ugCI5qCkAxhKlaXwSqqwj1mWjATBGlTDEA+SXfXkR0Sp3o8pEBigfF0DKVjTKlkAxFkPqAnUhdVxnMZ4I751x/GPCHRSEpCohOa7kiLqaNUNHqmQiOJAi86S77/vphYXSFsLh3SeoBMBLWGsic+YYQl8A+bdabtDl2tVZjxT6L/TGsy7nLv5vbvpMepF3cxQ+D1o6fvY7mM97naaeRSd3nBdS5XrZScWS9woH6vrYbeGwUZiJMA229EqSVvMsMvblPPXeUH1Qjkwozk9+Kh33U3LZoa55vHk1bSLR8V59kSIYr2uttJkuFhQs28ma6VkBPF7zHLitoXU1idgXugkwCwFKairjJZHIpD6bOjAUhyvqyPDU2/GTGLN4nPq9NNrxkTtTJeMKPZqxp6AaYlJfyqkuSaICh4/h4yakkVu4e1rRM1OZvD4NoIRNRLeMkaEAs4+MOs03w2NriQVJ3wqW36RcmYzjb8bQPp/l0QAgWrUTmwme3Bxp7dm2+vlr1Pv/g1jAT5hpnoKxAOr1pOoFjcliut2qqE89fAyMYDixRmBYWtwXpIhVd7bXVJ6X2Zm16yUB4f3yUunysqtvFQ7jbveZ5bbfkkinX2OmJUIjBgOdYx+HflShQYDPd6dqpOu4z/qI81QR9XS031XR+Mcfpco1gchbLBiqLlR7pb1by/fPPPrFHjWdXV0fTdhriLYKEBrKpSomipeQNJGLcocomGERwU8UJfoJRQL2knt0hQhX6HgqTv6LO9fL5gT5xuSPajcKVV55YzkGntvvvUwoM2hiFNoqr+yglUwU+9vUvnSfYtlcC44oaJQIirqFv5qYGT+YmYjQKRzFYJaWX39qd4UFqe2Wb1kn7jj1YHnS/dJlc8OfgQiJyO7hcjO8VN8D0vU+fZyVuOE5ItgQk9pWj+K9DYqtZDoljhMshUSahzDsUy9XqjWfqBpMclaA8+UrX9cmwSN4p+orz9Q76K2oXoIR4tUwT9P1KpReTCNj+ocwZMiKe7rUaRz46ZePlQcbHwRI/kVeYtLPt8WXOcPk4N2jy8WwC7yUHGvqWF2D6E+FcEv8Lh/qF8fE1u5pqczJyk6XQIcVBJttLRG7sX35R/xqJG28/vLBIXEs+0DqN61/486XlR3H/Efstueksiu3f9+Be8+s1E1KFSLpLmYCfmXvWdKgyKUkNBh7pbeiqvi9/El7+Adcbfqw=
</pre>
</div></div>

<p>Note that only form 'name' and 'id' fields will remain after the SAML handler processes a SAML assertion encoded in the SAMLToken form field. The original SAML assertion has been optionally compressed using a deflated encoding and then base64-encoded. This encoded value can be signed - but it is not currently possible.</p>

<p>Server configuration is similar to the one from the Enveloped SAML Assertions section, the only difference is that a SAML handler needs to be replaced:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
    <span class="code-tag">&lt;bean id=<span class="code-quote">"serviceBean"</span> class=<span class="code-quote">"org.apache.cxf.systest.jaxrs.security.BookStore"</span>/&gt;</span>
    <span class="code-tag">&lt;bean id=<span class="code-quote">"samlHandler"</span> class=<span class="code-quote">"org.apache.cxf.rs.security.saml.SamlFormInHandler"</span>/&gt;</span>
    
    <span class="code-tag"><span class="code-comment">&lt;!-- same as in the Enveloped SAML Assertions section --&gt;</span></span> 
</pre>
</div></div>

<p>The client code is the same as in the SAML assertions in Authorization header section except than an instance of SamlFormOutInterceptor has to be registered: </p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
bean.getOutInterceptors().add(<span class="code-keyword">new</span> SamlFormOutInterceptor());
</pre>
</div></div>

<h1><a name="JAX-RSSAML-CreatingSAMLAssertions"></a>Creating SAML Assertions</h1>

<p>If you use CXF JAX-RS client API to experiment with SAML then all you need to do is to register an appropriate out interceptor as shown in the above code fragments. The interceptor will ensure that a SAML assertion is created and added inside the XML envelope, as a form or HTTP header value.<br/>
All of the SAML output interceptors depend on a "ws-security.saml-callback-handler" property linking to a custom javax.security.auth.callback.Callback implementation which in its handle(Callbacks) method provides the information which is needed to create a SAML assertion to a org.apache.ws.security.saml.ext.SAMLCallback Callback instance, for example, see this <a href="http://svn.apache.org/repos/asf/cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/saml/SamlCallbackHandler.java" class="external-link" rel="nofollow">custom implementation</a>.</p>

<p>More involved cases with SAML assertions being created by identity providers will be supported, with the help of CXF (WS) STSClient when needed.</p>

<h1><a name="JAX-RSSAML-SAMLAssertionValidation"></a>SAML Assertion Validation</h1>

<p>When SAML assertions are received on the server side, they are validated to make sure that the enveloped signatures are correct. SubjectConfirmation methods (sender-vouches, holder-of-key, bearer) are also checked. <br/>
The validation can be delegated to STS if needed. By default, server side SAML handlers have a "samlValidator" property set to an instance of org.apache.ws.security.validate.SamlAssertionValidator which does a thorough validation of the assertion. If needed org.apache.cxf.ws.security.trust.STSSamlAssertionValidator can be set instead which will use STS to validate the assertion.<br/>
Custom validators extending WSS4J SamlAssertionValidator and doing the additional application-specific validation can be registered if needed.</p>

<p>Note the fact that the default validation relies a lot on the code heavily utilized by the WS-Security implementation should be of no concern - it is an example of the integration on its own in order to get the validation done. For example, WS-* STS are heavily used in the enterprise today and it simply makes a complete sense to rely on it to validate a SAML assertion if it is possible.</p>

<p>SubjectConfirmation sender-vouches and holder-of-key methods can be easily validated with enveloped SAML assertions given that the embedded SAML signatures and key info can be checked against the signature used to sign the envelope or a custom payload like Book.</p>

<p>At the moment these methods can not be properly validated when the assertion is provided in a header or in the form, the additional signature signing the encoded SAML token will be needed - this will be supported in due time. Use "bearer" in those cases.</p>

<h1><a name="JAX-RSSAML-SAMLAuthorization"></a>SAML Authorization</h1>

<p>SAML assertions may contain so-called claims which are represented by a sequence of SAML AttributeStatements containing one or more Attributes, for example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;saml2:Assertion&gt;</span>
 <span class="code-tag"><span class="code-comment">&lt;!-- ... --&gt;</span></span>
 <span class="code-tag">&lt;saml2:AttributeStatement&gt;</span>
    &lt;saml2:Attribute NameFormat=<span class="code-quote">"http://schemas.xmlsoap.org/ws/2005/05/identity/claims"</span>
                 Name=<span class="code-quote">"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"</span> 
                 FriendlyName=<span class="code-quote">"subject-role"</span>&gt;
       <span class="code-tag">&lt;saml2:AttributeValue <span class="code-keyword">xmlns:xs</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema"</span> xsi:type=<span class="code-quote">"xs:string"</span>&gt;</span>user<span class="code-tag">&lt;/saml2:AttributeValue&gt;</span>
    <span class="code-tag">&lt;/saml2:Attribute&gt;</span>
    &lt;saml2:Attribute NameFormat=<span class="code-quote">"http://claims/authentication"</span>
                     Name=<span class="code-quote">"http://claims/authentication-format"</span>&gt;
        <span class="code-tag">&lt;saml2:AttributeValue <span class="code-keyword">xmlns:xs</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema"</span> xsi:type=<span class="code-quote">"xs:string"</span>&gt;</span>password<span class="code-tag">&lt;/saml2:AttributeValue&gt;</span>
    <span class="code-tag">&lt;/saml2:Attribute&gt;</span>
 <span class="code-tag">&lt;/saml2:AttributeStatement&gt;</span>
 <span class="code-tag"><span class="code-comment">&lt;!-- ... --&gt;</span></span>
<span class="code-tag">&lt;/saml2:Assertion&gt;</span>
</pre>
</div></div>

<p>An individual claim is scoped by NameFormat and Name attribute. NameFormat is similar to a namespace, while Name identifies what the value of this claim represents, for example, in the above fragment two claims are provided, one has a value "user" which represents a role of the assertion's Subject, another one has a value of "password" which identifies the way Subject authenticated itself, i.e, Subject provided its password (presumably to IDP).</p>

<p>Now, what is interesting is to see if it is possible to use these claims with Role-Based Access-Control (for example, with endpoints relying on @RolesAllowed annotations) as well as with the more complex authorization logic (for example, let this resource be invoked only if Subject used a password to get authenticated at IDP).</p>

<h2><a name="JAX-RSSAML-ClaimsBasedAccessControl"></a>Claims Based Access Control</h2>

<p>CXF JAX-RS offers an extension letting users to enforce a new fine-grained Claims Based Access Control based on <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/Claim.java" class="external-link" rel="nofollow">Claim</a> and <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/Claims.java" class="external-link" rel="nofollow">Claims</a> annotations as well as <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/ClaimMode.java" class="external-link" rel="nofollow">ClaimMode</a> enum class.   </p>

<p>Here is a simple code fragment:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> org.apache.cxf.rs.security.saml.authorization.Claim;
<span class="code-keyword">import</span> org.apache.cxf.rs.security.saml.authorization.Claims;

@Path(<span class="code-quote">"/bookstore"</span>)
<span class="code-keyword">public</span> class SecureClaimBookStore {
    
    @POST
    @Path(<span class="code-quote">"/books"</span>)
    @Produces(<span class="code-quote">"application/xml"</span>)
    @Consumes(<span class="code-quote">"application/xml"</span>)
    @Claims({ 
        @Claim({<span class="code-quote">"admin"</span> }),
        @Claim(name = <span class="code-quote">"http:<span class="code-comment">//claims/authentication-format"</span>, 
</span>               format = <span class="code-quote">"http:<span class="code-comment">//claims/authentication"</span>, 
</span>               value = {<span class="code-quote">"fingertip"</span>, <span class="code-quote">"smartcard"</span> })
    })
    <span class="code-keyword">public</span> Book addBook(Book book) {
        <span class="code-keyword">return</span> book;
    }
    
}
</pre>
</div></div>

<p>SecureClaimBookStore.addBook(Book) can only be invoked if Subject meets the following requirement: it needs to have a Claim with a value "admin" and another Claim confirming that it got authenticated using either a 'fingertip' or 'smartcard' method. Note that @Claim(</p>
<div class="error"><span class="error">Unknown macro: {&quot;admin&quot;}</span> </div>
<p>) has no name and format classifiers set - it relies on default name and format values, namely "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" and "http://schemas.xmlsoap.org/ws/2005/05/identity/claims" respectively. These default values may change in the future depending on which claims are found to be used most often - but as you can see you can always provide name and format values which will scope a given claim value.</p>

<p>Note that in the above example, a Claim with the name "http://claims/authentication-format" has two values, 'fingertip' and 'smartcard'. By default, in order to meet this Claim, Subject needs to have a Claim which has either a 'fingertip' or 'smartcard' value. If it is expected that Subject needs to have a Claim which has both 'fingertip' and 'smartcard' values, then the following change needs to be done:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> org.apache.cxf.rs.security.saml.authorization.Claim;
<span class="code-keyword">import</span> org.apache.cxf.rs.security.saml.authorization.Claims;

@Path(<span class="code-quote">"/bookstore"</span>)
<span class="code-keyword">public</span> class SecureClaimBookStore {
    
    @POST
    @Path(<span class="code-quote">"/books"</span>)
    @Produces(<span class="code-quote">"application/xml"</span>)
    @Consumes(<span class="code-quote">"application/xml"</span>)
    @Claims({ 
        @Claim({<span class="code-quote">"admin"</span> }),
        @Claim(name = <span class="code-quote">"http:<span class="code-comment">//claims/authentication-format"</span>, 
</span>               format = <span class="code-quote">"http:<span class="code-comment">//claims/authentication"</span>, 
</span>               value = {<span class="code-quote">"fingertip"</span>, <span class="code-quote">"smartcard"</span> },
               matchAll = <span class="code-keyword">true</span>)
    })
    <span class="code-keyword">public</span> Book addBook(Book book) {
        <span class="code-keyword">return</span> book;
    }
    
}
</pre>
</div></div>

<p>Claims can be specified using individual @Claim annotation, they can be set at the class level and overridden at the method level and finally a lax mode of check can be specified:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> org.apache.cxf.rs.security.saml.authorization.Claim;
<span class="code-keyword">import</span> org.apache.cxf.rs.security.saml.authorization.Claims;

@Path(<span class="code-quote">"/bookstore"</span>)
@Claim({<span class="code-quote">"user"</span>})
<span class="code-keyword">public</span> class SecureClaimBookStore {
    
    @POST
    @Path(<span class="code-quote">"/books"</span>)
    @Produces(<span class="code-quote">"application/xml"</span>)
    @Consumes(<span class="code-quote">"application/xml"</span>)
    @Claims({ 
        @Claim({<span class="code-quote">"admin"</span> }),
        @Claim(name = <span class="code-quote">"http:<span class="code-comment">//claims/authentication-format"</span>, 
</span>               format = <span class="code-quote">"http:<span class="code-comment">//claims/authentication"</span>, 
</span>               value = {<span class="code-quote">"fingertip"</span>, <span class="code-quote">"smartcard"</span> },
               matchAll = <span class="code-keyword">true</span>)
    })
    <span class="code-keyword">public</span> Book addBook(Book book) {
        <span class="code-keyword">return</span> book;
    }

    @GET
    @Claim(name = <span class="code-quote">"http:<span class="code-comment">//claims/authentication-format"</span>, 
</span>               format = <span class="code-quote">"http:<span class="code-comment">//claims/authentication"</span>, 
</span>               value = {<span class="code-quote">"password"</span> },
               mode = ClaimMode.LAX)
    <span class="code-keyword">public</span> Book getBook() {
        <span class="code-comment">//...
</span>    }

    @GET
    <span class="code-keyword">public</span> BookList getBookList() {
        <span class="code-comment">//...
</span>    }
    
    
}
</pre>
</div></div>

<p>In the above example, getBookList() can be invoked if Subject has a Claim with the value "user"; addBook() has it overridden - "admin" is expected and the authentication format Claim too; getBook() can be invoked if Subject has a Claim with the value "user" and it also must have the authentication format Claim with the value "password" - or no such Claim at all.    </p>

<p>Server Configuration Example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">

<span class="code-tag">&lt;bean id=<span class="code-quote">"serviceBeanClaims"</span> class=<span class="code-quote">"org.apache.cxf.systest.jaxrs.security.saml.SecureClaimBookStore"</span>/&gt;</span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"samlEnvHandler"</span> class=<span class="code-quote">"org.apache.cxf.rs.security.saml.SamlEnvelopedInHandler"</span>&gt;</span>
 <span class="code-tag">&lt;property name=<span class="code-quote">"securityContextProvider"</span>&gt;</span>
    <span class="code-tag">&lt;bean class=<span class="code-quote">"org.apache.cxf.systest.jaxrs.security.saml.CustomSecurityContextProvider"</span>/&gt;</span>
 <span class="code-tag">&lt;/property&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>
    
&lt;bean id=<span class="code-quote">"claimsHandler"</span> 
     class=<span class="code-quote">"org.apache.cxf.rs.security.saml.authorization.ClaimsAuthorizingFilter"</span>&gt;
    <span class="code-tag">&lt;property name=<span class="code-quote">"securedObject"</span> ref=<span class="code-quote">"serviceBeanClaims"</span>/&gt;</span>   
<span class="code-tag">&lt;/bean&gt;</span>

<span class="code-tag">&lt;jaxrs:server address=<span class="code-quote">"/saml-claims"</span>&gt;</span> 
       <span class="code-tag">&lt;jaxrs:serviceBeans&gt;</span>
          <span class="code-tag">&lt;ref bean=<span class="code-quote">"serviceBeanClaims"</span>/&gt;</span>
       <span class="code-tag">&lt;/jaxrs:serviceBeans&gt;</span>
       <span class="code-tag">&lt;jaxrs:providers&gt;</span>
          <span class="code-tag">&lt;ref bean=<span class="code-quote">"samlEnvHandler"</span>/&gt;</span>
          <span class="code-tag">&lt;ref bean=<span class="code-quote">"claimsHandler"</span>/&gt;</span>
       <span class="code-tag">&lt;/jaxrs:providers&gt;</span>
<span class="code-tag">&lt;/jaxrs:server&gt;</span>
</pre>
</div></div>

<h2><a name="JAX-RSSAML-RoleBasedAccessControl"></a>Role Based Access Control</h2>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action" class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+SAML">View Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=27830327&revisedVersion=9&originalVersion=8">View Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+SAML?showComments=true&amp;showCommentArea=true#addcomment">Add Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message