cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject svn commit: r1166749 - in /cxf/trunk: rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/ rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/ rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/ sys...
Date Thu, 08 Sep 2011 15:32:46 GMT
Author: sergeyb
Date: Thu Sep  8 15:32:45 2011
New Revision: 1166749

URL: http://svn.apache.org/viewvc?rev=1166749&view=rev
Log:
[CXF-3588] Some improvements to do with validating saml tokens

Modified:
    cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java
    cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/SecurityContextProviderImpl.java
    cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java
    cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/saml/SamlCallbackHandler.java

Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java?rev=1166749&r1=1166748&r2=1166749&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java
(original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java
Thu Sep  8 15:32:45 2011
@@ -25,7 +25,6 @@ import java.io.InputStreamReader;
 import java.security.PublicKey;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
-import java.util.Arrays;
 import java.util.List;
 import java.util.logging.Logger;
 
@@ -34,7 +33,7 @@ import javax.ws.rs.core.Response;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-
+import org.w3c.dom.Node;
 
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.helpers.DOMUtils;
@@ -96,8 +95,9 @@ public abstract class AbstractSamlInHand
     protected void validateToken(Message message, Element tokenElement) {
         try {
             AssertionWrapper assertion = new AssertionWrapper(tokenElement);
+            
+            RequestData data = new RequestData();
             if (assertion.isSigned()) {
-                RequestData data = new RequestData();
                 WSSConfig cfg = WSSConfig.getNewInstance(); 
                 data.setWssConfig(cfg);
                 data.setCallbackHandler(SecurityUtils.getCallbackHandler(message, this.getClass()));
@@ -112,27 +112,15 @@ public abstract class AbstractSamlInHand
                     message.getContextualProperty(WSHandlerConstants.ENABLE_REVOCATION)));
                 assertion.verifySignature(data, null);
                 assertion.parseHOKSubject(data, null);
+            }
+            if (samlValidator != null) {
                 Credential credential = new Credential();
                 credential.setAssertion(assertion);
-                if (samlValidator != null) {
-                    samlValidator.validate(credential, data);
-                }
-                
-                Certificate[] tlsCerts = getTLSCertificates(message);
-                if (!checkHolderOfKey(message, assertion, tlsCerts)) {
-                    throwFault("Holder Of Key claim fails", null);
-                }
-                if (!checkSenderVouches(message, assertion, tlsCerts)) {
-                    throwFault("Sender vouchers claim fails", null);
-                }
-                if (!checkBearer(assertion, tlsCerts)) {
-                    throwFault("Bearer claim fails", null);
-                }
-            } else if (getTLSCertificates(message) == null) {
-                // alternatively ensure that the unsigned assertion inherits the signature
-                // from the xml-sig envelope which this assertion must be contained in 
-                throwFault("Unsigned Assertion can only be validated with two-way TLS", null);
+                samlValidator.validate(credential, data);
             }
+                
+            
+            checkSubjectConfirmationData(message, assertion);
             setSecurityContext(message, assertion);
             
         } catch (Exception ex) {
@@ -140,6 +128,19 @@ public abstract class AbstractSamlInHand
         }
     }
     
+    protected void checkSubjectConfirmationData(Message message, AssertionWrapper assertion)
{
+        Certificate[] tlsCerts = getTLSCertificates(message);
+        if (!checkHolderOfKey(message, assertion, tlsCerts)) {
+            throwFault("Holder Of Key claim fails", null);
+        }
+        if (!checkSenderVouches(message, assertion, tlsCerts)) {
+            throwFault("Sender vouchers claim fails", null);
+        }
+        if (!checkBearer(assertion, tlsCerts)) {
+            throwFault("Bearer claim fails", null);
+        }
+    }
+    
     protected void setSecurityContext(Message message, AssertionWrapper wrapper) {
         if (scProvider != null) {
             SecurityContext sc = scProvider.getSecurityContext(message, wrapper);
@@ -164,7 +165,7 @@ public abstract class AbstractSamlInHand
      * Check the sender-vouches requirements against the received assertion. The SAML
      * Assertion and the request body must be signed by the same signature.
      */
-    private boolean checkSenderVouches(
+    protected boolean checkSenderVouches(
         Message message,
         AssertionWrapper assertionWrapper,
         Certificate[] tlsCerts
@@ -182,16 +183,24 @@ public abstract class AbstractSamlInHand
         List<String> confirmationMethods = assertionWrapper.getConfirmationMethods();
         for (String confirmationMethod : confirmationMethods) {
             if (OpenSAMLUtil.isMethodSenderVouches(confirmationMethod)) {
-                XMLSignature sig = message.getContent(XMLSignature.class);
-                if (sig == null) {
-                    return false;
-                }
-                try {
-                    byte[] sigValue1 = sig.getSignatureValue();
-                    byte[] sigValue2 = assertionWrapper.getSignatureValue();
-                    return Arrays.equals(sigValue1, sigValue2);
-                } catch (Exception ex) {
-                    return false;
+                
+                Element signedElement = message.getContent(Element.class);
+                Node assertionParent = assertionWrapper.getElement().getParentNode();
+                
+                // if we have a shared parent signed node then we can assume both 
+                // this SAML assertion and the main payload have been signed by the same
+                // signature
+                if (assertionParent != signedElement) {
+                    // if not then try to compare if the same cert/key was used to sign SAML
token
+                    // and the payload
+                    XMLSignature signature = message.getContent(XMLSignature.class);
+                    if (signature == null) {
+                        return false;
+                    }
+                    SAMLKeyInfo subjectKeyInfo = assertionWrapper.getSignatureKeyInfo();
+                    if (!compareCredentials(subjectKeyInfo, signature, tlsCerts)) {
+                        return false;
+                    }
                 }
             }
         }
@@ -200,7 +209,7 @@ public abstract class AbstractSamlInHand
     
     
     
-    public boolean checkHolderOfKey(Message message,
+    protected boolean checkHolderOfKey(Message message,
                                     AssertionWrapper assertionWrapper,
                                     Certificate[] tlsCerts) {
         List<String> confirmationMethods = assertionWrapper.getConfirmationMethods();
@@ -267,13 +276,14 @@ public abstract class AbstractSamlInHand
         return false;
     }
     
-    private boolean checkBearer(AssertionWrapper assertionWrapper, Certificate[] tlsCerts)
{
+    protected boolean checkBearer(AssertionWrapper assertionWrapper, Certificate[] tlsCerts)
{
         List<String> confirmationMethods = assertionWrapper.getConfirmationMethods();
         for (String confirmationMethod : confirmationMethods) {
-            if (isMethodBearer(confirmationMethod)) {
-                // do some more validation - time based, etc
-                return true;
-            }
+            boolean isBearer = isMethodBearer(confirmationMethod);
+            if (isBearer && !assertionWrapper.isSigned() && (tlsCerts ==
null || tlsCerts.length == 0)) {
+                return false;
+            } 
+            // do some more validation - time based, etc
         }
         return true;
     }

Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/SecurityContextProviderImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/SecurityContextProviderImpl.java?rev=1166749&r1=1166748&r2=1166749&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/SecurityContextProviderImpl.java
(original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/authorization/SecurityContextProviderImpl.java
Thu Sep  8 15:32:45 2011
@@ -59,6 +59,6 @@ public class SecurityContextProviderImpl
         // parse/decipher subject name id, or check attributes like 
         // givenName, email, firstName, etc
         
-        // this can be overidden, but consider also introducing dedicated handlers 
+        // this can be overridden, but consider also introducing dedicated handlers 
     }
 }

Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java?rev=1166749&r1=1166748&r2=1166749&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java
(original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java
Thu Sep  8 15:32:45 2011
@@ -67,8 +67,8 @@ public class XmlSigInHandler extends Abs
         }
 
         Element root = doc.getDocumentElement();
-        Element sigElement = getSignatureElement(root);
-        if (sigElement == null) {
+        Element signatureElement = getSignatureElement(root);
+        if (signatureElement == null) {
             throwFault("XML Signature is not available", null);
         }
         
@@ -89,7 +89,7 @@ public class XmlSigInHandler extends Abs
         boolean valid = false;
         Reference ref = null;
         try {
-            XMLSignature signature = new XMLSignature(sigElement, "");    
+            XMLSignature signature = new XMLSignature(signatureElement, "");    
             // See also WSS4J SAMLUtil.getCredentialFromKeyInfo 
             KeyInfo keyInfo = signature.getKeyInfo();
             
@@ -104,13 +104,14 @@ public class XmlSigInHandler extends Abs
             }
             // is this call redundant given that signature.checkSignatureValue uses References
?
             ref = getReference(signature);
-            validateReference(root, ref);
+            Element signedElement = validateReference(root, ref);
             
             // validate trust 
             new TrustValidator().validateTrust(crypto, cert, keyInfo.getPublicKey());
             
             if (persistSignature) {
-                message.put(XMLSignature.class, signature);
+                message.setContent(XMLSignature.class, signature);
+                message.setContent(Element.class, signedElement);
             }
         } catch (Exception ex) {
             throwFault("Signature validation failed", ex);
@@ -122,7 +123,7 @@ public class XmlSigInHandler extends Abs
             if (!isEnveloping(root)) {
                 Element signedEl = getSignedElement(root, ref);
                 signedEl.removeAttribute("ID");
-                root.removeChild(sigElement);
+                root.removeChild(signatureElement);
             } else {
                 Element actualBody = getActualBody(root);
                 Document newDoc = DOMUtils.createDocument();
@@ -180,34 +181,30 @@ public class XmlSigInHandler extends Abs
         return null;
     }
     
-    protected void validateReference(Element root, Reference ref) {
-        boolean detached = false;
-        if (!isEnveloping(root)) {
-            String rootId = root.getAttribute("ID");
-            String refId = ref.getURI();
-            if (refId.length() == 0 && rootId.length() == 0) {
-                // or fragment must be expected ?
-                return;
-            }
-            if (!refId.startsWith("#") || refId.length() <= 1) {
-                throwFault("Only local Signature References are supported", null);
-            }
-            
-            Element signedEl = getSignedElement(root, ref);
-            if (signedEl != null) {
-                detached = signedEl != root;
-            } else {
-                throwFault("Signature Reference ID is invalid", null);
-            }
+    protected Element validateReference(Element root, Reference ref) {
+        boolean enveloped = false;
+        
+        String refId = ref.getURI();
+        
+        if (!refId.startsWith("#") || refId.length() <= 1) {
+            throwFault("Only local Signature References are supported", null);
         }
         
+        Element signedEl = getSignedElement(root, ref);
+        if (signedEl != null) {
+            enveloped = signedEl == root;
+        } else {
+            throwFault("Signature Reference ID is invalid", null);
+        }
+        
+        
         Transforms transforms = null;
         try {
             transforms = ref.getTransforms();
         } catch (XMLSecurityException ex) {
             throwFault("Signature transforms can not be obtained", ex);
         }
-        if (!isEnveloping(root) && !detached) {
+        if (enveloped) {
             boolean isEnveloped = false;
             for (int i = 0; i < transforms.getLength(); i++) {
                 try {
@@ -224,6 +221,7 @@ public class XmlSigInHandler extends Abs
                 throwFault("Only enveloped signatures are currently supported", null);
             }
         }
+        return signedEl;
     }
     
     private Element getSignedElement(Element root, Reference ref) {

Modified: cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/saml/SamlCallbackHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/saml/SamlCallbackHandler.java?rev=1166749&r1=1166748&r2=1166749&view=diff
==============================================================================
--- cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/saml/SamlCallbackHandler.java
(original)
+++ cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/saml/SamlCallbackHandler.java
Thu Sep  8 15:32:45 2011
@@ -20,12 +20,19 @@
 package org.apache.cxf.systest.jaxrs.security.saml;
 
 import java.io.IOException;
+import java.security.cert.X509Certificate;
 import java.util.Collections;
 
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.callback.UnsupportedCallbackException;
 
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.apache.cxf.rs.security.common.CryptoLoader;
+import org.apache.cxf.rs.security.common.SecurityUtils;
+import org.apache.cxf.ws.security.SecurityConstants;
+import org.apache.ws.security.components.crypto.Crypto;
 import org.apache.ws.security.saml.ext.SAMLCallback;
 import org.apache.ws.security.saml.ext.bean.AttributeBean;
 import org.apache.ws.security.saml.ext.bean.AttributeStatementBean;
@@ -33,6 +40,7 @@ import org.apache.ws.security.saml.ext.b
 import org.apache.ws.security.saml.ext.bean.AuthDecisionStatementBean.Decision;
 import org.apache.ws.security.saml.ext.bean.AuthenticationStatementBean;
 import org.apache.ws.security.saml.ext.bean.ConditionsBean;
+import org.apache.ws.security.saml.ext.bean.KeyInfoBean;
 import org.apache.ws.security.saml.ext.bean.SubjectBean;
 import org.apache.ws.security.saml.ext.builder.SAML1Constants;
 import org.apache.ws.security.saml.ext.builder.SAML2Constants;
@@ -78,7 +86,25 @@ public class SamlCallbackHandler impleme
                     new SubjectBean(
                         subjectName, subjectQualifier, confirmationMethod
                     );
-                // SubjectConfirmationData - not possible to set yet
+                if (SAML2Constants.CONF_HOLDER_KEY.equals(confirmationMethod)) {
+                    
+                    Message m = PhaseInterceptorChain.getCurrentMessage();
+                    try {
+                        CryptoLoader loader = new CryptoLoader();
+                        Crypto crypto = loader.getCrypto(m, 
+                                                         SecurityConstants.SIGNATURE_CRYPTO,
+                                                         SecurityConstants.SIGNATURE_PROPERTIES);
+                        X509Certificate cert = 
+                            SecurityUtils.getCertificates(crypto, 
+                                SecurityUtils.getUserName(m, crypto, "ws-security.signature.username"))[0];
+                        
+                        KeyInfoBean keyInfo = new KeyInfoBean();
+                        keyInfo.setCertificate(cert);
+                        subjectBean.setKeyInfo(keyInfo);
+                    } catch (Exception ex) {
+                        throw new RuntimeException(ex);
+                    }
+                }
                 callback.setSubject(subjectBean);
                 
                 ConditionsBean conditions = new ConditionsBean();



Mime
View raw message