cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject [2/3] cxf-fediz git commit: SAML Response refactoring
Date Mon, 21 Mar 2016 17:03:31 GMT
SAML Response refactoring


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

Branch: refs/heads/master
Commit: 6f06a082e2c09f1dbc35e1ca42888f29d8d727f1
Parents: d86ce5c
Author: Colm O hEigeartaigh <coheigea@apache.org>
Authored: Mon Mar 21 12:09:48 2016 +0000
Committer: Colm O hEigeartaigh <coheigea@apache.org>
Committed: Mon Mar 21 12:09:48 2016 +0000

----------------------------------------------------------------------
 .../idp/beans/samlsso/SamlResponseCreator.java  | 61 ++++++++++----------
 .../idp/samlsso/SAML2CallbackHandler.java       | 46 +++++++++++----
 .../WEB-INF/flows/saml-validate-request.xml     | 10 ++--
 .../apache/cxf/fediz/systests/idp/IdpTest.java  | 12 +++-
 4 files changed, 81 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6f06a082/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseCreator.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseCreator.java
b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseCreator.java
index 9e27a3a..a12f257 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseCreator.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseCreator.java
@@ -22,9 +22,6 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -49,10 +46,9 @@ import org.apache.wss4j.common.saml.bean.SubjectConfirmationDataBean;
 import org.apache.wss4j.common.util.DOM2Writer;
 import org.apache.wss4j.dom.WSConstants;
 import org.joda.time.DateTime;
-import org.opensaml.saml.saml2.core.AttributeStatement;
+import org.opensaml.saml.saml2.core.Assertion;
 import org.opensaml.saml.saml2.core.Response;
 import org.opensaml.saml.saml2.core.Status;
-import org.opensaml.saml.saml2.core.Subject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
@@ -78,11 +74,15 @@ public class SamlResponseCreator {
         
         try {
             SamlAssertionWrapper wrapper = new SamlAssertionWrapper(samlTokens.get(0));
-            Subject subject = wrapper.getSaml2().getSubject();
-            List<AttributeStatement> attributeStatements = wrapper.getSaml2().getAttributeStatements();
+            if (wrapper.getSaml2() == null) {
+                throw new ProcessingException(TYPE.BAD_REQUEST);
+            }
+            
+            String remoteAddr = WebUtils.getHttpServletRequest(context).getRemoteAddr();
+            Assertion saml2Assertion = 
+                createSAML2Assertion(idp, wrapper, requestId, requestIssuer, remoteAddr,
consumerURL);
             
-            Element response = createResponse(context, idp, requestId, consumerURL, requestIssuer,
-                                              subject, attributeStatements);
+            Element response = createResponse(idp, requestId, saml2Assertion);
             return encodeResponse(response);
         } catch (Exception ex) {
             ex.printStackTrace();
@@ -91,32 +91,17 @@ public class SamlResponseCreator {
         }
     }
     
-    protected Element createResponse(RequestContext context, Idp idp, String requestID, 
-                                     String racs, String requestIssuer,
-                                     Subject subject,
-                                     List<AttributeStatement> attributeStatements)
throws Exception {
-        DocumentBuilderFactory docBuilderFactory;
-        docBuilderFactory = DocumentBuilderFactory.newInstance();
-        docBuilderFactory.setNamespaceAware(true);
-        
-        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
-        Document doc = docBuilder.newDocument();
-        
-        Status status = 
-            SAML2PResponseComponentBuilder.createStatus(
-                "urn:oasis:names:tc:SAML:2.0:status:Success", null
-            );
-        Response response = 
-            SAML2PResponseComponentBuilder.createSAMLResponse(requestID, idp.getRealm(),
status);
-        
+    private Assertion createSAML2Assertion(Idp idp, SamlAssertionWrapper receivedToken,
+                                           String requestID, String requestIssuer, 
+                                           String remoteAddr, String racs) throws Exception
{
         // Create an AuthenticationAssertion
         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
         callbackHandler.setIssuer(idp.getRealm());
-        callbackHandler.setSubject(subject);
+        callbackHandler.setSubject(receivedToken.getSaml2().getSubject());
         
         // Subject Confirmation Data
         SubjectConfirmationDataBean subjectConfirmationData = new SubjectConfirmationDataBean();
-        subjectConfirmationData.setAddress(WebUtils.getHttpServletRequest(context).getRemoteAddr());
+        subjectConfirmationData.setAddress(remoteAddr);
         subjectConfirmationData.setInResponseTo(requestID);
         subjectConfirmationData.setNotAfter(new DateTime().plusMinutes(5));
         subjectConfirmationData.setRecipient(racs);
@@ -131,6 +116,9 @@ public class SamlResponseCreator {
         conditions.setAudienceRestrictions(Collections.singletonList(audienceRestriction));
         callbackHandler.setConditions(conditions);
         
+        // Attributes
+        callbackHandler.setAttributeStatements(receivedToken.getSaml2().getAttributeStatements());
+        
         SAMLCallback samlCallback = new SAMLCallback();
         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
         SamlAssertionWrapper assertion = new SamlAssertionWrapper(samlCallback);
@@ -139,7 +127,20 @@ public class SamlResponseCreator {
         assertion.signAssertion(issuerCrypto.getDefaultX509Identifier(), idp.getCertificatePassword(),

                                 issuerCrypto, false);
         
-        response.getAssertions().add(assertion.getSaml2());
+        return assertion.getSaml2();
+    }
+    
+    protected Element createResponse(Idp idp, String requestID, Assertion assertion) throws
Exception {
+        Document doc = DOMUtils.newDocument();
+        
+        Status status = 
+            SAML2PResponseComponentBuilder.createStatus(
+                "urn:oasis:names:tc:SAML:2.0:status:Success", null
+            );
+        Response response = 
+            SAML2PResponseComponentBuilder.createSAMLResponse(requestID, idp.getRealm(),
status);
+        
+        response.getAssertions().add(assertion);
         
         Element policyElement = OpenSAMLUtil.toDom(response, doc);
         doc.appendChild(policyElement);

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6f06a082/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/samlsso/SAML2CallbackHandler.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/samlsso/SAML2CallbackHandler.java
b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/samlsso/SAML2CallbackHandler.java
index 1475dd4..9981253 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/samlsso/SAML2CallbackHandler.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/samlsso/SAML2CallbackHandler.java
@@ -37,12 +37,15 @@ import org.apache.wss4j.common.saml.bean.SubjectBean;
 import org.apache.wss4j.common.saml.bean.SubjectConfirmationDataBean;
 import org.apache.wss4j.common.saml.bean.Version;
 import org.apache.wss4j.common.saml.builder.SAML2Constants;
+import org.opensaml.core.xml.XMLObject;
+import org.opensaml.saml.saml2.core.Attribute;
+import org.opensaml.saml.saml2.core.AttributeStatement;
 import org.opensaml.saml.saml2.core.Subject;
 
 /**
  * A Callback Handler implementation for a SAML 2 assertion. By default it creates a SAML
2.0 Assertion with
- * an AuthenticationStatement. If a list of roles are also supplied, it will insert them
as part of an 
- * AttributeStatement.
+ * an AuthenticationStatement. If a list of AttributeStatements are also supplied it will
insert them into the
+ * Assertion.
  */
 public class SAML2CallbackHandler implements CallbackHandler {
     
@@ -51,22 +54,35 @@ public class SAML2CallbackHandler implements CallbackHandler {
     private String issuer;
     private ConditionsBean conditions;
     private SubjectConfirmationDataBean subjectConfirmationData;
-    private List<Object> roles = new ArrayList<>();
+    private List<AttributeStatement> attributeStatements;
     
     private void createAndSetStatement(SAMLCallback callback) {
         AuthenticationStatementBean authBean = new AuthenticationStatementBean();
         authBean.setAuthenticationMethod("Password");
         callback.setAuthenticationStatementData(Collections.singletonList(authBean));
 
-        if (!roles.isEmpty()) {
-            AttributeStatementBean attrBean = new AttributeStatementBean();
-            AttributeBean attributeBean = new AttributeBean();
-            attributeBean.setQualifiedName("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role");
-            attributeBean.setNameFormat(SAML2Constants.ATTRNAME_FORMAT_UNSPECIFIED);
-            attributeBean.setAttributeValues(roles);
+        if (attributeStatements != null && !attributeStatements.isEmpty()) {
+            List<AttributeStatementBean> attrStatementBeans = new ArrayList<>();
+            
+            for (AttributeStatement attrStatement : attributeStatements) {
+                AttributeStatementBean attrStatementBean = new AttributeStatementBean();
+                List<AttributeBean> attrBeans = new ArrayList<>();
                 
-            attrBean.setSamlAttributes(Collections.singletonList(attributeBean));
-            callback.setAttributeStatementData(Collections.singletonList(attrBean));
+                for (Attribute attribute : attrStatement.getAttributes()) {
+                    AttributeBean attributeBean = new AttributeBean();
+                    attributeBean.setQualifiedName(attribute.getName());
+                    attributeBean.setNameFormat(attribute.getNameFormat());
+                    List<Object> attributeValues = new ArrayList<>();
+                    for (XMLObject attrVal : attribute.getAttributeValues()) {
+                        attributeValues.add(attrVal.getDOM().getTextContent());
+                    }
+                    attributeBean.setAttributeValues(attributeValues);
+                    attrBeans.add(attributeBean);
+                }
+                attrStatementBean.setSamlAttributes(attrBeans);
+                attrStatementBeans.add(attrStatementBean);
+            }
+            callback.setAttributeStatementData(attrStatementBeans);
         }
     }
     
@@ -119,6 +135,14 @@ public class SAML2CallbackHandler implements CallbackHandler {
     public void setSubject(Subject subject) {
         this.subject = subject;
     }
+
+    public List<AttributeStatement> getAttributeStatements() {
+        return attributeStatements;
+    }
+
+    public void setAttributeStatements(List<AttributeStatement> attributeStatements)
{
+        this.attributeStatements = attributeStatements;
+    }
     
     
 }

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6f06a082/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml
----------------------------------------------------------------------
diff --git a/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml b/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml
index 701db0b..9014030 100644
--- a/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml
+++ b/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml
@@ -65,10 +65,6 @@
                       result="flowScope.realm"/>
             <evaluate expression="stsClientForRpAction.submit(flowRequestContext, flowScope.realm,
flowScope.homerealm)"
                       result="flowScope.rpTokenElement"/>
-            <evaluate expression="tokenSerializer.serialize(flowRequestContext, flowScope.rpTokenElement)"
-                      result="flowScope.rpToken"/>
-            <evaluate expression="authnRequestParser.retrieveConsumerURL(flowRequestContext)"

-                      result="flowScope.consumerURL"/>
         </on-entry>
         <evaluate expression="signinParametersCacheAction.storeRPConfigInSession(flowRequestContext)"/>
         <transition to="produceSAMLResponse" />
@@ -80,12 +76,14 @@
         <on-entry>
             <evaluate expression="authnRequestParser.retrieveRequestId(flowRequestContext)"

                       result="flowScope.requestId"/>
-           <evaluate expression="authnRequestParser.retrieveRequestIssuer(flowRequestContext)"

+            <evaluate expression="authnRequestParser.retrieveRequestIssuer(flowRequestContext)"

                       result="flowScope.requestIssuer"/>
+            <evaluate expression="authnRequestParser.retrieveConsumerURL(flowRequestContext)"

+                      result="flowScope.consumerURL"/>
         </on-entry>
         <evaluate expression="samlResponseCreator.createSAMLResponse(flowRequestContext,
flowScope.idpConfig, flowScope.rpTokenElement,
                                                                      flowScope.consumerURL,
flowScope.requestId, flowScope.requestIssuer)"
-                      result="flowScope.rpResponse"/>                                
              
+                  result="flowScope.rpResponse"/>                                    
          
         <transition to="formResponseView" />
     </action-state>
     

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6f06a082/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
----------------------------------------------------------------------
diff --git a/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
b/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
index 7acad0a..b0f2bea 100644
--- a/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
+++ b/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
@@ -40,6 +40,7 @@ import org.apache.catalina.LifecycleState;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.cxf.common.util.Base64Utility;
+import org.apache.cxf.fediz.core.ClaimTypes;
 import org.apache.cxf.fediz.core.util.DOMUtils;
 import org.apache.cxf.rs.security.saml.DeflateEncoderDecoder;
 import org.apache.cxf.rs.security.saml.sso.DefaultAuthnRequestBuilder;
@@ -225,6 +226,15 @@ public class IdpTest {
         org.opensaml.saml.saml2.core.Response samlResponseObject = 
             (org.opensaml.saml.saml2.core.Response)responseObject;
         Assert.assertTrue(authnRequest.getID().equals(samlResponseObject.getInResponseTo()));
+        
+        // Check claims
+        String parsedResponse = DOM2Writer.nodeToString(responseDoc);
+        String claim = ClaimTypes.FIRSTNAME.toString();
+        Assert.assertTrue(parsedResponse.contains(claim));
+        claim = ClaimTypes.LASTNAME.toString();
+        Assert.assertTrue(parsedResponse.contains(claim));
+        claim = ClaimTypes.EMAILADDRESS.toString();
+        Assert.assertTrue(parsedResponse.contains(claim));
 
         webClient.close();
     }
@@ -271,7 +281,7 @@ public class IdpTest {
         
         webClient.close();
     }
-        
+    
     private String encodeAuthnRequest(Element authnRequest) throws IOException {
         String requestMessage = DOM2Writer.nodeToString(authnRequest);
         


Mime
View raw message