You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by jb...@apache.org on 2016/01/04 19:56:39 UTC

cxf-fediz git commit: [FEDIZ-141] Adding SAML Post Binding Systest

Repository: cxf-fediz
Updated Branches:
  refs/heads/master 35ab83126 -> 728e7bb80


[FEDIZ-141] Adding SAML Post Binding Systest


Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/728e7bb8
Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/728e7bb8
Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/728e7bb8

Branch: refs/heads/master
Commit: 728e7bb801c6a5b749ede68e002cc51f2bea6005
Parents: 35ab831
Author: Jan Bernhardt <jb...@talend.com>
Authored: Mon Jan 4 18:25:36 2016 +0100
Committer: Jan Bernhardt <jb...@talend.com>
Committed: Mon Jan 4 19:56:17 2016 +0100

----------------------------------------------------------------------
 .../cxf/fediz/samlsso/example/SamlSso.java      | 83 +++++++++++++++-----
 .../src/main/resources/TemplateSAMLResponse.xml | 29 +++++++
 systests/federation/samlsso/pom.xml             |  8 ++
 .../cxf/fediz/integrationtests/SAMLSSOTest.java | 48 ++++++++++-
 .../src/test/resources/entities-realma.xml      | 24 +++++-
 .../test/resources/fediz_config_saml_sso.xml    | 30 +++++++
 6 files changed, 197 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/728e7bb8/systests/federation/samlIdpWebapp/src/main/java/org/apache/cxf/fediz/samlsso/example/SamlSso.java
----------------------------------------------------------------------
diff --git a/systests/federation/samlIdpWebapp/src/main/java/org/apache/cxf/fediz/samlsso/example/SamlSso.java b/systests/federation/samlIdpWebapp/src/main/java/org/apache/cxf/fediz/samlsso/example/SamlSso.java
index cf43784..4d62d87 100644
--- a/systests/federation/samlIdpWebapp/src/main/java/org/apache/cxf/fediz/samlsso/example/SamlSso.java
+++ b/systests/federation/samlIdpWebapp/src/main/java/org/apache/cxf/fediz/samlsso/example/SamlSso.java
@@ -23,24 +23,34 @@ package org.apache.cxf.fediz.samlsso.example;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
 import java.util.Collections;
+import java.util.zip.DataFormatException;
 
+import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.UriBuilder;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.XMLStreamException;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+
+import org.apache.cxf.common.util.Base64Exception;
 import org.apache.cxf.common.util.Base64Utility;
+import org.apache.cxf.helpers.IOUtils;
 import org.apache.cxf.jaxrs.ext.MessageContext;
 import org.apache.cxf.rs.security.saml.DeflateEncoderDecoder;
 import org.apache.cxf.staxutils.StaxUtils;
 import org.apache.wss4j.common.crypto.Crypto;
 import org.apache.wss4j.common.crypto.CryptoFactory;
+import org.apache.wss4j.common.ext.WSSecurityException;
 import org.apache.wss4j.common.saml.OpenSAMLUtil;
 import org.apache.wss4j.common.saml.SAMLCallback;
 import org.apache.wss4j.common.saml.SAMLUtil;
@@ -72,17 +82,18 @@ public class SamlSso {
         docBuilderFactory.setNamespaceAware(true);
     }
     
+    @POST
+    public javax.ws.rs.core.Response login(@FormParam("SAMLRequest") String samlRequest,
+        @FormParam("RelayState") String relayState) throws Exception {
+        
+        return login(samlRequest, relayState, "POST");
+    }
+    
     @GET
     public javax.ws.rs.core.Response login(@QueryParam("SAMLRequest") String samlRequest,
-            @QueryParam("RelayState") String relayState) throws Exception {
-        
-        byte[] deflatedToken = Base64Utility.decode(samlRequest);
-        InputStream tokenStream = new DeflateEncoderDecoder().inflateToken(deflatedToken);
+            @QueryParam("RelayState") String relayState, @QueryParam("binding") String binding) throws Exception {
         
-        Document responseDoc = StaxUtils.read(new InputStreamReader(tokenStream, "UTF-8"));
-        AuthnRequest request = 
-            (AuthnRequest)OpenSAMLUtil.fromDom(responseDoc.getDocumentElement());
-        System.out.println(DOM2Writer.nodeToString(responseDoc));
+        AuthnRequest request = extractRequest(samlRequest);
 
         String racs = request.getAssertionConsumerServiceURL();
         String requestIssuer = request.getIssuer().getValue();
@@ -91,20 +102,19 @@ public class SamlSso {
         Element response = createResponse(request.getID(), racs, requestIssuer);
         String responseStr = encodeResponse(response);
         
-        // Perform Redirect to RACS
-        UriBuilder ub = UriBuilder.fromUri(racs);
-        ub.queryParam("SAMLResponse", responseStr);
-        ub.queryParam("RelayState", relayState);
-        
-        return javax.ws.rs.core.Response.seeOther(ub.build()).build();
+        if ("REDIRECT".equals(binding)) {
+            return redirectResponse(relayState, racs, responseStr);
+        } else {
+            return postBindingResponse(relayState, racs, responseStr);
+        }
     }
-    
+
     @Context 
     public void setMessageContext(MessageContext mc) {
         this.messageContext = mc;
     }
-
-    private Element createResponse(String requestID, String racs, String requestIssuer) throws Exception {
+    
+    protected Element createResponse(String requestID, String racs, String requestIssuer) throws Exception {
         DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
         Document doc = docBuilder.newDocument();
         
@@ -153,8 +163,8 @@ public class SamlSso {
         
         return policyElement;
     }
-    
-    private String encodeResponse(Element response) throws IOException {
+
+    protected String encodeResponse(Element response) throws IOException {
         String responseMessage = DOM2Writer.nodeToString(response);
         System.out.println("RESP: " + responseMessage);
 
@@ -163,6 +173,41 @@ public class SamlSso {
 
         return Base64Utility.encode(deflatedBytes);
     }
+    
+    protected AuthnRequest extractRequest(String samlRequest) throws Base64Exception, DataFormatException,
+        XMLStreamException, UnsupportedEncodingException, WSSecurityException {
+        byte[] deflatedToken = Base64Utility.decode(samlRequest);
+        InputStream tokenStream = new DeflateEncoderDecoder().inflateToken(deflatedToken);
+        
+        Document responseDoc = StaxUtils.read(new InputStreamReader(tokenStream, "UTF-8"));
+        AuthnRequest request = 
+            (AuthnRequest)OpenSAMLUtil.fromDom(responseDoc.getDocumentElement());
+        System.out.println(DOM2Writer.nodeToString(responseDoc));
+        return request;
+    }
+
+    protected javax.ws.rs.core.Response postBindingResponse(String relayState, String racs, String responseStr)
+        throws IOException {
+        InputStream inputStream = this.getClass().getResourceAsStream("/TemplateSAMLResponse.xml");
+        String responseTemplate = IOUtils.toString(inputStream, "UTF-8");
+        inputStream.close();        
+        
+        // Perform Redirect to RACS
+        responseTemplate = responseTemplate.replace("%RESPONSE_URL%", racs);
+        responseTemplate = responseTemplate.replace("%SAMLResponse%", responseStr);
+        responseTemplate = responseTemplate.replace("%RelayState%", relayState);
+        
+        return javax.ws.rs.core.Response.ok(responseTemplate).type(MediaType.TEXT_HTML).build();
+    }
+    
+    protected javax.ws.rs.core.Response redirectResponse(String relayState, String racs, String responseStr) {
+        // Perform Redirect to RACS
+        UriBuilder ub = UriBuilder.fromUri(racs);
+        ub.queryParam("SAMLResponse", responseStr);
+        ub.queryParam("RelayState", relayState);
+        
+        return javax.ws.rs.core.Response.seeOther(ub.build()).build();
+    }
 
 }
 

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/728e7bb8/systests/federation/samlIdpWebapp/src/main/resources/TemplateSAMLResponse.xml
----------------------------------------------------------------------
diff --git a/systests/federation/samlIdpWebapp/src/main/resources/TemplateSAMLResponse.xml b/systests/federation/samlIdpWebapp/src/main/resources/TemplateSAMLResponse.xml
new file mode 100644
index 0000000..027a712
--- /dev/null
+++ b/systests/federation/samlIdpWebapp/src/main/resources/TemplateSAMLResponse.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+    <head>
+        <title>SAML IDP Response Form</title>
+    </head>
+    <body onload="document.forms[0].submit()">
+        <noscript>
+            <p>
+                <strong>Note:</strong>
+                Since your browser does not support JavaScript,
+                you must press the Continue button once to proceed.
+            </p>
+        </noscript>
+        <form name="signinresponseform" action="%RESPONSE_URL%" method="post">
+            <div>
+                <input type="hidden" name="RelayState" value="%RelayState%" />
+                <input type="hidden" name="SAMLResponse"
+                    value="%SAMLResponse%" />
+            </div>
+            <noscript>
+                <div>
+                    <input type="submit" name="_eventId_submit" value="Continue" />
+                </div>
+            </noscript>
+        </form>
+    </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/728e7bb8/systests/federation/samlsso/pom.xml
----------------------------------------------------------------------
diff --git a/systests/federation/samlsso/pom.xml b/systests/federation/samlsso/pom.xml
index e604932..116527c 100644
--- a/systests/federation/samlsso/pom.xml
+++ b/systests/federation/samlsso/pom.xml
@@ -178,6 +178,14 @@
                                     <overWrite>true</overWrite>
                                     <outputDirectory>target/tomcat/rp/webapps/simpleWebapp</outputDirectory>
                                 </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.apache.cxf.fediz.systests.webapps</groupId>
+                                    <artifactId>fediz-systests-webapps-simple</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>war</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>target/tomcat/rp/webapps/simpleWebapp2</outputDirectory>
+                                </artifactItem>
                             </artifactItems>
                             <outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>
                             <overWriteSnapshots>true</overWriteSnapshots>

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/728e7bb8/systests/federation/samlsso/src/test/java/org/apache/cxf/fediz/integrationtests/SAMLSSOTest.java
----------------------------------------------------------------------
diff --git a/systests/federation/samlsso/src/test/java/org/apache/cxf/fediz/integrationtests/SAMLSSOTest.java b/systests/federation/samlsso/src/test/java/org/apache/cxf/fediz/integrationtests/SAMLSSOTest.java
index 39311a6..8c0510a 100644
--- a/systests/federation/samlsso/src/test/java/org/apache/cxf/fediz/integrationtests/SAMLSSOTest.java
+++ b/systests/federation/samlsso/src/test/java/org/apache/cxf/fediz/integrationtests/SAMLSSOTest.java
@@ -186,6 +186,8 @@ public class SAMLSSOTest {
                              + "test-classes" + File.separator + "fediz_config_saml_sso.xml");
             cxt.getPipeline().addValve(fa);
             
+            cxt = rpServer.addWebapp("/fedizhelloworld-post-binding", "simpleWebapp2");
+            cxt.getPipeline().addValve(fa);
             
             rpServer.start();
         } catch (Exception e) {
@@ -241,7 +243,38 @@ public class SAMLSSOTest {
         String password = "ECILA";
         
         final String bodyTextContent = 
-            login(url, user, password, idpSamlSSOHttpsPort, idpHttpsPort);
+            login(url, user, password, idpSamlSSOHttpsPort, idpHttpsPort, false);
+        
+        Assert.assertTrue("Principal not alice",
+                          bodyTextContent.contains("userPrincipal=alice"));
+        Assert.assertTrue("User " + user + " does not have role Admin",
+                          bodyTextContent.contains("role:Admin=false"));
+        Assert.assertTrue("User " + user + " does not have role Manager",
+                          bodyTextContent.contains("role:Manager=false"));
+        Assert.assertTrue("User " + user + " must have role User",
+                          bodyTextContent.contains("role:User=true"));
+
+        String claim = ClaimTypes.FIRSTNAME.toString();
+        Assert.assertTrue("User " + user + " claim " + claim + " is not 'Alice'",
+                          bodyTextContent.contains(claim + "=Alice"));
+        claim = ClaimTypes.LASTNAME.toString();
+        Assert.assertTrue("User " + user + " claim " + claim + " is not 'Smith'",
+                          bodyTextContent.contains(claim + "=Smith"));
+        claim = ClaimTypes.EMAILADDRESS.toString();
+        Assert.assertTrue("User " + user + " claim " + claim + " is not 'alice@realma.org'",
+                          bodyTextContent.contains(claim + "=alice@realma.org"));
+    }
+    
+    @org.junit.Test
+    public void testSAMLSSOPostBinding() throws Exception {
+        String url = "https://localhost:" + getRpHttpsPort() + "/fedizhelloworld-post-binding/secure/fedservlet";
+        // System.out.println("URL: " + url);
+        // Thread.sleep(60 * 2 * 1000);
+        String user = "ALICE";  // realm b credentials
+        String password = "ECILA";
+        
+        final String bodyTextContent = 
+            login(url, user, password, idpSamlSSOHttpsPort, idpHttpsPort, true);
         
         Assert.assertTrue("Principal not alice",
                           bodyTextContent.contains("userPrincipal=alice"));
@@ -264,7 +297,7 @@ public class SAMLSSOTest {
     }
     
     private static String login(String url, String user, String password, 
-                                String idpPort, String rpIdpPort) throws IOException {
+                                String idpPort, String rpIdpPort, boolean postBinding) throws IOException {
         //
         // Access the RP + get redirected to the IdP for "realm a". Then get redirected to the IdP for
         // "realm b".
@@ -278,8 +311,15 @@ public class SAMLSSOTest {
             new UsernamePasswordCredentials(user, password));
 
         webClient.getOptions().setJavaScriptEnabled(false);
-        final HtmlPage idpPage = webClient.getPage(url);
-        webClient.getOptions().setJavaScriptEnabled(true);
+        HtmlPage idpPage = webClient.getPage(url);
+        
+        if (postBinding) {
+            Assert.assertEquals("SAML IDP Response Form", idpPage.getTitleText());
+            final HtmlForm form = idpPage.getFormByName("signinresponseform");
+            final HtmlSubmitInput button = form.getInputByName("_eventId_submit");
+            idpPage = button.click();
+        }
+        
         Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText());
 
         // Now redirect back to the RP

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/728e7bb8/systests/federation/samlsso/src/test/resources/entities-realma.xml
----------------------------------------------------------------------
diff --git a/systests/federation/samlsso/src/test/resources/entities-realma.xml b/systests/federation/samlsso/src/test/resources/entities-realma.xml
index 86fd540..145d1a8 100644
--- a/systests/federation/samlsso/src/test/resources/entities-realma.xml
+++ b/systests/federation/samlsso/src/test/resources/entities-realma.xml
@@ -71,6 +71,7 @@
         <property name="trustedIdps">
             <util:list>
                 <ref bean="trusted-idp-realmB" />
+                <ref bean="trusted-idp-realmC" />
             </util:list>
         </property>
         <property name="claimTypesOffered">
@@ -87,7 +88,7 @@
         class="org.apache.cxf.fediz.service.idp.service.jpa.TrustedIdpEntity">
         <property name="realm" value="urn:org:apache:cxf:fediz:idp:realm-B" />
         <property name="cacheTokens" value="true" />
-        <property name="url" value="https://localhost:${idp.samlsso.https.port}/idp/samlsso" />
+        <property name="url" value="https://localhost:${idp.samlsso.https.port}/idp/samlsso?binding=REDIRECT" />
         <property name="certificate" value="realmb.cert" />
         <property name="trustType" value="PEER_TRUST" />
         <property name="protocol" value="urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser" />
@@ -101,6 +102,25 @@
             </util:map>
         </property>
     </bean>
+    
+    <bean id="trusted-idp-realmC"
+        class="org.apache.cxf.fediz.service.idp.service.jpa.TrustedIdpEntity">
+        <property name="realm" value="urn:org:apache:cxf:fediz:idp:realm-C" />
+        <property name="cacheTokens" value="true" />
+        <property name="url" value="https://localhost:${idp.samlsso.https.port}/idp/samlsso" />
+        <property name="certificate" value="realmb.cert" />
+        <property name="trustType" value="PEER_TRUST" />
+        <property name="protocol" value="urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser" />
+        <property name="federationType" value="FEDERATE_IDENTITY" />
+        <property name="name" value="Realm C" />
+        <property name="description" value="SAML Web Profile - Response POST Binding" />
+        <property name="parameters">
+            <util:map>
+                <entry key="sign.request" value="true" />
+                <entry key="support.deflate.encoding" value="true" />
+            </util:map>
+        </property>
+    </bean>
 
     <bean id="srv-fedizhelloworld" class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationEntity">
         <property name="realm" value="urn:org:apache:cxf:fediz:fedizhelloworld" />
@@ -111,7 +131,7 @@
         <property name="tokenType" value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" />
         <property name="lifeTime" value="3600" />
         <property name="passiveRequestorEndpointConstraint" 
-                  value="https://localhost:(\d)*/(\w)*helloworld(\w)*/secure/.*" />
+                  value="https://localhost:(\d)*/(\w)*helloworld.*/secure/.*" />
     </bean>
     
     <bean class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationClaimEntity">

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/728e7bb8/systests/federation/samlsso/src/test/resources/fediz_config_saml_sso.xml
----------------------------------------------------------------------
diff --git a/systests/federation/samlsso/src/test/resources/fediz_config_saml_sso.xml b/systests/federation/samlsso/src/test/resources/fediz_config_saml_sso.xml
index 7bd3cb7..89f158b 100644
--- a/systests/federation/samlsso/src/test/resources/fediz_config_saml_sso.xml
+++ b/systests/federation/samlsso/src/test/resources/fediz_config_saml_sso.xml
@@ -52,5 +52,35 @@
         <logoutURL>/secure/logout</logoutURL>
         <logoutRedirectTo>/index.html</logoutRedirectTo>
     </contextConfig>
+    <contextConfig name="/fedizhelloworld-post-binding">
+        <audienceUris>
+            <audienceItem>urn:org:apache:cxf:fediz:fedizhelloworld</audienceItem>
+        </audienceUris>
+        <certificateStores>
+            <trustManager>
+                <keyStore file="test-classes/clienttrust.jks"
+                          password="storepass" type="JKS" />
+            </trustManager>
+        </certificateStores>
+        <trustedIssuers>
+            <issuer certificateValidation="PeerTrust" />
+        </trustedIssuers>
+        <maximumClockSkew>1000</maximumClockSkew>
+        <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:type="federationProtocolType" version="1.0.0">
+            <realm>urn:org:apache:cxf:fediz:fedizhelloworld</realm>
+            <issuer>https://localhost:${idp.https.port}/fediz-idp/federation</issuer>
+            <roleDelimiter>,</roleDelimiter>
+            <roleURI>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</roleURI>
+            <freshness>10</freshness>
+            <homeRealm type="String">urn:org:apache:cxf:fediz:idp:realm-C</homeRealm>
+            <claimTypesRequested>
+                <claimType type="a particular claim type"
+                           optional="true" />
+            </claimTypesRequested>
+        </protocol>
+        <logoutURL>/secure/logout</logoutURL>
+        <logoutRedirectTo>/index.html</logoutRedirectTo>
+    </contextConfig>
 </FedizConfig>