cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From owu...@apache.org
Subject svn commit: r1345768 [1/2] - in /cxf/fediz/trunk: ./ examples/simpleWebapp/src/main/webapp/META-INF/ examples/wsclientWebapp/webapp/ examples/wsclientWebapp/webapp/src/main/webapp/META-INF/ plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/ plu...
Date Sun, 03 Jun 2012 20:25:35 GMT
Author: owulff
Date: Sun Jun  3 20:25:34 2012
New Revision: 1345768

URL: http://svn.apache.org/viewvc?rev=1345768&view=rev
Log:
Support several trusted issuer, certstores, testcases refactored

Added:
    cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java
    cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/common/STSUtil.java
    cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
    cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/KeystoreCallbackHandler.java
    cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/SAML1CallbackHandler.java
    cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/SAML2CallbackHandler.java
    cxf/fediz/trunk/plugins/core/src/test/resources/stsrealm_a.jks   (with props)
    cxf/fediz/trunk/plugins/core/src/test/resources/stsrealm_b.jks   (with props)
Removed:
    cxf/fediz/trunk/plugins/core/src/test/resources/RSTR.xml
    cxf/fediz/trunk/plugins/core/src/test/resources/RSTR_old.xml
    cxf/fediz/trunk/plugins/core/src/test/resources/RSTR_replay.xml
    cxf/fediz/trunk/plugins/core/src/test/resources/fediz_test_config2.xml
Modified:
    cxf/fediz/trunk/examples/simpleWebapp/src/main/webapp/META-INF/context.xml
    cxf/fediz/trunk/examples/wsclientWebapp/webapp/pom.xml
    cxf/fediz/trunk/examples/wsclientWebapp/webapp/src/main/webapp/META-INF/context.xml
    cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
    cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java
    cxf/fediz/trunk/plugins/core/src/test/resources/fediz_test_config.xml
    cxf/fediz/trunk/plugins/core/src/test/resources/signature.properties
    cxf/fediz/trunk/pom.xml

Modified: cxf/fediz/trunk/examples/simpleWebapp/src/main/webapp/META-INF/context.xml
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/examples/simpleWebapp/src/main/webapp/META-INF/context.xml?rev=1345768&r1=1345767&r2=1345768&view=diff
==============================================================================
--- cxf/fediz/trunk/examples/simpleWebapp/src/main/webapp/META-INF/context.xml (original)
+++ cxf/fediz/trunk/examples/simpleWebapp/src/main/webapp/META-INF/context.xml Sun Jun  3 20:25:34 2012
@@ -1,5 +1,3 @@
 <Context>
-        <Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" configFile="conf/fediz_config.xml" />
-        <!--<Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" issuerURL="https://localhost:9443/fedizidp/" truststoreFile="conf/stsstore.jks" truststorePassword="stsspass" trustedIssuer=".*CN=www.sts.com.*" />-->
-        <!--Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" issuerCallbackHandler="org.apache.cxf.fediz.tomcat.DummyIDPCallbackHandler" truststoreFile="conf/stsstore.jks" truststorePassword="stsspass" />-->        
+        <Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" configFile="conf/fediz_config.xml" />        
 </Context>

Modified: cxf/fediz/trunk/examples/wsclientWebapp/webapp/pom.xml
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/examples/wsclientWebapp/webapp/pom.xml?rev=1345768&r1=1345767&r2=1345768&view=diff
==============================================================================
--- cxf/fediz/trunk/examples/wsclientWebapp/webapp/pom.xml (original)
+++ cxf/fediz/trunk/examples/wsclientWebapp/webapp/pom.xml Sun Jun  3 20:25:34 2012
@@ -92,6 +92,10 @@
 					<artifactId>wss4j</artifactId>
 					<groupId>org.apache.ws.security</groupId>
 				</exclusion>
+                                <exclusion>
+                                        <artifactId>ehcache-core</artifactId>
+                                        <groupId>net.sf.ehcache</groupId>
+                                </exclusion>
 			</exclusions>
 		</dependency>
 		<dependency>

Modified: cxf/fediz/trunk/examples/wsclientWebapp/webapp/src/main/webapp/META-INF/context.xml
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/examples/wsclientWebapp/webapp/src/main/webapp/META-INF/context.xml?rev=1345768&r1=1345767&r2=1345768&view=diff
==============================================================================
--- cxf/fediz/trunk/examples/wsclientWebapp/webapp/src/main/webapp/META-INF/context.xml (original)
+++ cxf/fediz/trunk/examples/wsclientWebapp/webapp/src/main/webapp/META-INF/context.xml Sun Jun  3 20:25:34 2012
@@ -1,5 +1,3 @@
 <Context>
-        <Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" configFile="conf/fediz_config.xml" />
-        <!--<Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" issuerURL="https://localhost:9443/fedizidp/" truststoreFile="conf/stsstore.jks" truststorePassword="stsspass" trustedIssuer=".*CN=www.sts.com.*" />-->
-        <!--Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" issuerCallbackHandler="org.apache.cxf.fediz.tomcat.DummyIDPCallbackHandler" truststoreFile="conf/stsstore.jks" truststorePassword="stsspass" />-->        
+        <Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" configFile="conf/fediz_config.xml" />   
 </Context>

Modified: cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java?rev=1345768&r1=1345767&r2=1345768&view=diff
==============================================================================
--- cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java (original)
+++ cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java Sun Jun  3 20:25:34 2012
@@ -20,9 +20,7 @@
 package org.apache.cxf.fediz.core.saml;
 
 import java.io.File;
-import java.io.IOException;
 import java.net.URI;
-import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -32,25 +30,22 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.StringTokenizer;
 
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
 import org.w3c.dom.Element;
 
 import org.apache.cxf.fediz.core.Claim;
 import org.apache.cxf.fediz.core.ClaimCollection;
 import org.apache.cxf.fediz.core.TokenValidator;
 import org.apache.cxf.fediz.core.TokenValidatorResponse;
+import org.apache.cxf.fediz.core.config.CertificateValidationMethod;
 import org.apache.cxf.fediz.core.config.FederationContext;
 import org.apache.cxf.fediz.core.config.FederationProtocol;
 import org.apache.cxf.fediz.core.config.KeyStore;
 import org.apache.cxf.fediz.core.config.TrustManager;
 import org.apache.cxf.fediz.core.config.TrustedIssuer;
+import org.apache.cxf.fediz.core.saml.SamlAssertionValidator.TRUST_TYPE;
 
 import org.apache.ws.security.SAMLTokenPrincipal;
 import org.apache.ws.security.WSDocInfo;
-import org.apache.ws.security.WSPasswordCallback;
 import org.apache.ws.security.WSSConfig;
 import org.apache.ws.security.WSSecurityException;
 import org.apache.ws.security.components.crypto.Crypto;
@@ -59,12 +54,9 @@ import org.apache.ws.security.handler.Re
 import org.apache.ws.security.saml.SAMLKeyInfo;
 import org.apache.ws.security.saml.ext.AssertionWrapper;
 import org.apache.ws.security.validate.Credential;
-import org.apache.ws.security.validate.SignatureTrustValidator;
 import org.joda.time.DateTime;
 import org.opensaml.common.SAMLVersion;
 import org.opensaml.xml.XMLObject;
-import org.opensaml.xml.validation.ValidationException;
-import org.opensaml.xml.validation.ValidatorSuite;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -87,29 +79,8 @@ public class SAMLTokenValidator implemen
     public TokenValidatorResponse validateAndProcessToken(Element token,
             FederationContext config) {
 
-        try {
-            String trustStoreFile;
-            String trustStorePw;
-            //[TODO] Support more than one truststore
-            TrustManager tm = config.getCertificateStores().get(0);
-            KeyStore ks = tm.getKeyStore();
-            if (ks.getFile() != null && !ks.getFile().isEmpty()) {
-                trustStoreFile = ks.getFile();
-                trustStorePw = ks.getPassword();
-            } else {
-                throw new IllegalStateException("No certificate store configured");
-            }
-            
-            File f = new File(trustStoreFile);
-            if (!f.exists() && config.getRelativePath() != null && !config.getRelativePath().isEmpty()) {
-                trustStoreFile = config.getRelativePath().concat(File.separator + trustStoreFile);
-            }
-            
-            Properties sigProperties = createCryptoProviderProperties(trustStoreFile, trustStorePw);
-
-            Crypto sigCrypto = CryptoFactory.getInstance(sigProperties);
+        try {          
             RequestData requestData = new RequestData();
-            requestData.setSigCrypto(sigCrypto);
             WSSConfig wssConfig = WSSConfig.getNewInstance();
             requestData.setWssConfig(wssConfig);
             // not needed as no private key must be read
@@ -124,44 +95,61 @@ public class SAMLTokenValidator implemen
             // Verify the signature
             assertion.verifySignature(requestData,
                     new WSDocInfo(token.getOwnerDocument()));
-            
-            // Validate the assertion against schemas/profiles
-            validateAssertion(assertion);
-            
-            // Validate Conditions
-            if (config.isDetectExpiredTokens() && !validateConditions(assertion, config)) {
-                throw new RuntimeException(
-                    "Error in validating conditions of the received Assertion"
-                );
-            }
 
             // Now verify trust on the signature
             Credential trustCredential = new Credential();
             SAMLKeyInfo samlKeyInfo = assertion.getSignatureKeyInfo();
             trustCredential.setPublicKey(samlKeyInfo.getPublicKey());
             trustCredential.setCertificates(samlKeyInfo.getCerts());
+            trustCredential.setAssertion(assertion);
 
-            SignatureTrustValidator trustValidator = new SignatureTrustValidator();
-            trustValidator.validate(trustCredential, requestData);
-
+            SamlAssertionValidator trustValidator = new SamlAssertionValidator();
+            trustValidator.setFutureTTL(config.getMaximumClockSkew().intValue());
+            
+            boolean trusted = false;
             String assertionIssuer = assertion.getIssuerString();
-
-            // Finally check that subject DN of the signing certificate matches
-            // a known constraint
-            X509Certificate cert = null;
-            if (trustCredential.getCertificates() != null) {
-                cert = trustCredential.getCertificates()[0];
-            }
-
-            // [TODO] Support more than one trusted issuer
+            
             List<TrustedIssuer> trustedIssuers = config.getTrustedIssuers();
-            TrustedIssuer ti = trustedIssuers.get(0);
-            List<String> subjectConstraints = Collections.singletonList(ti.getSubject());
-
-            CertConstraintsParser certConstraints = new CertConstraintsParser();
-            certConstraints.setSubjectConstraints(subjectConstraints);
-
-            if (!certConstraints.matches(cert)) {
+            for (TrustedIssuer ti : trustedIssuers) {
+                List<String> subjectConstraints = Collections.singletonList(ti.getSubject());
+                if (ti.getCertificateValidationMethod().equals(CertificateValidationMethod.CHAIN_TRUST)) {
+                    trustValidator.setSubjectConstraints(subjectConstraints);
+                    trustValidator.setSignatureTrustType(TRUST_TYPE.CHAIN_TRUST_CONSTRAINTS);
+                } else if (ti.getCertificateValidationMethod().equals(CertificateValidationMethod.PEER_TRUST)) {
+                    trustValidator.setSignatureTrustType(TRUST_TYPE.PEER_TRUST);
+                } else {
+                    throw new IllegalStateException("Unsupported certificate validation method: " 
+                                                    + ti.getCertificateValidationMethod());
+                }
+                try {
+                    for (TrustManager tm: config.getCertificateStores()) {
+                        try {
+                            Properties sigProperties = createCryptoProperties(config, tm);
+                            Crypto sigCrypto = CryptoFactory.getInstance(sigProperties);
+                            requestData.setSigCrypto(sigCrypto);
+                            trustValidator.validate(trustCredential, requestData);
+                            trusted = true;
+                            break;
+                        } catch (Exception ex) {
+                            if (LOG.isDebugEnabled()) {
+                                LOG.debug("Issuer '" + ti.getName() + "' not validated in keystore '"
+                                          + tm.getKeyStore().getFile() + "'");
+                            }
+                        }
+                    }
+                    if (trusted) {
+                        break;
+                    }
+                    
+                } catch (Exception ex) {
+                    if (LOG.isInfoEnabled()) {
+                        LOG.info("Issuer '" + assertionIssuer + "' doesn't match trusted issuer '" + ti.getName()
+                                 + "': " + ex.getMessage());
+                    }
+                }
+            }
+            
+            if (!trusted) {
                 throw new RuntimeException("Issuer '" + assertionIssuer
                         + "' not trusted");
             }
@@ -291,7 +279,11 @@ public class SAMLTokenValidator implemen
                     LOG.debug("parsing attribute: " + attribute.getName());
                 }
                 Claim c = new Claim();
-                c.setClaimType(URI.create(attribute.getName()));
+                if (attribute.getName().startsWith(c.getNamespace().toString())) {
+                    c.setClaimType(URI.create(attribute.getName().substring(c.getNamespace().toString().length() + 1)));
+                } else {
+                    c.setClaimType(URI.create(attribute.getName()));
+                }
                 c.setIssuer(assertion.getIssuer().getNameQualifier());
                 
                 List<String> valueList = new ArrayList<String>();
@@ -322,10 +314,12 @@ public class SAMLTokenValidator implemen
                 List<String> values = new ArrayList<String>();
                 values.add((String)oValue); //add existing value
                 values.addAll(valueList);
+                t.setValue(values);
             } else if (oValue instanceof List<?>) {
                 //more than one child element AttributeValue
                 List<String> values = (List<String>)oValue;
                 values.addAll(valueList);
+                t.setValue(values);
             } else {
                 throw new IllegalStateException("Invalid value type of Claim value");
             }
@@ -376,81 +370,38 @@ public class SAMLTokenValidator implemen
 
     }
 
-    protected Properties createCryptoProviderProperties(String truststoreFile,
-            String truststorePassword) {
+    private Properties createCryptoProperties(FederationContext config, TrustManager tm) {
+        String trustStoreFile = null;
+        String trustStorePw = null;
+        KeyStore ks = tm.getKeyStore();
+        if (ks.getFile() != null && !ks.getFile().isEmpty()) {
+            trustStoreFile = ks.getFile();
+            trustStorePw = ks.getPassword();
+        } else {
+            throw new IllegalStateException("No certificate store configured");
+        }
+        File f = new File(trustStoreFile);
+        if (!f.exists() && config.getRelativePath() != null && !config.getRelativePath().isEmpty()) {
+            trustStoreFile = config.getRelativePath().concat(File.separator + trustStoreFile);
+        }
+        
+        if (trustStoreFile == null || trustStoreFile.isEmpty()) {
+            throw new NullPointerException("truststoreFile not configured");
+        }
+        if (trustStorePw == null || trustStorePw.isEmpty()) {
+            throw new NullPointerException("trustStorePw not configured");
+        }
         Properties p = new Properties();
         p.put("org.apache.ws.security.crypto.provider",
                 "org.apache.ws.security.components.crypto.Merlin");
         p.put("org.apache.ws.security.crypto.merlin.keystore.type", "jks");
         p.put("org.apache.ws.security.crypto.merlin.keystore.password",
-                truststorePassword);
+              trustStorePw);
         p.put("org.apache.ws.security.crypto.merlin.keystore.file",
-                truststoreFile);
+              trustStoreFile);
         return p;
     }
     
-    /**
-     * Validate the assertion against schemas/profiles
-     */
-    protected void validateAssertion(AssertionWrapper assertion) throws WSSecurityException {
-        if (assertion.getSaml1() != null) {
-            ValidatorSuite schemaValidators = 
-                org.opensaml.Configuration.getValidatorSuite("saml1-schema-validator");
-            ValidatorSuite specValidators = 
-                org.opensaml.Configuration.getValidatorSuite("saml1-spec-validator");
-            try {
-                schemaValidators.validate(assertion.getSaml1());
-                specValidators.validate(assertion.getSaml1());
-            } catch (ValidationException e) {
-                LOG.debug("Saml Validation error: " + e.getMessage());
-                throw new WSSecurityException(WSSecurityException.FAILURE, "invalidSAMLsecurity");
-            }
-        } else if (assertion.getSaml2() != null) {
-            ValidatorSuite schemaValidators = 
-                org.opensaml.Configuration.getValidatorSuite("saml2-core-schema-validator");
-            ValidatorSuite specValidators = 
-                org.opensaml.Configuration.getValidatorSuite("saml2-core-spec-validator");
-            try {
-                schemaValidators.validate(assertion.getSaml2());
-                specValidators.validate(assertion.getSaml2());
-            } catch (ValidationException e) {
-                LOG.debug("Saml Validation error: " + e.getMessage());
-                throw new WSSecurityException(WSSecurityException.FAILURE, "invalidSAMLsecurity");
-            }
-        }
-    }
-    
-    protected boolean validateConditions(
-        AssertionWrapper assertion,
-        FederationContext config
-    ) {
-        DateTime validFrom = null;
-        DateTime validTill = null;
-        if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_20)) {
-            validFrom = assertion.getSaml2().getConditions().getNotBefore();
-            validTill = assertion.getSaml2().getConditions().getNotOnOrAfter();
-        } else {
-            validFrom = assertion.getSaml1().getConditions().getNotBefore();
-            validTill = assertion.getSaml1().getConditions().getNotOnOrAfter();
-        }
-        
-        if (validFrom != null) {
-            DateTime currentTime = new DateTime();
-            currentTime = currentTime.plusSeconds(config.getMaximumClockSkew().intValue());
-            if (validFrom.isAfter(currentTime)) {
-                LOG.warn("SAML Token condition (Not Before) not met");
-                return false;
-            }
-        }
-        
-        if (validTill != null && validTill.isBeforeNow()) {
-            LOG.debug("SAML Token condition (Not On Or After) not met");
-            return false;
-        }
-        
-        return true;
-    }
-    
     private Date getExpires(AssertionWrapper assertion) {
         DateTime validTill = null;
         if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_20)) {
@@ -465,25 +416,4 @@ public class SAMLTokenValidator implemen
         return validTill.toDate();
     }
 
-    // A sample MyHandler class
-    class PasswordCallbackHandler implements CallbackHandler {
-        private String password;
-
-        public PasswordCallbackHandler(String password) {
-            this.password = password;
-        }
-
-        public void handle(Callback[] callbacks) throws IOException,
-                UnsupportedCallbackException {
-            for (int i = 0; i < callbacks.length; i++) {
-                if (callbacks[i] instanceof WSPasswordCallback) {
-                    WSPasswordCallback nc = (WSPasswordCallback) callbacks[i];
-                    nc.setPassword(this.password);
-                } else {
-                    throw new UnsupportedCallbackException(callbacks[i],
-                            "Unrecognized Callback");
-                }
-            }
-        }
-    }
 }

Added: cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java?rev=1345768&view=auto
==============================================================================
--- cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java (added)
+++ cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java Sun Jun  3 20:25:34 2012
@@ -0,0 +1,573 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.fediz.core.saml;
+
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.components.crypto.CryptoType;
+import org.apache.ws.security.handler.RequestData;
+import org.apache.ws.security.saml.SAMLKeyInfo;
+import org.apache.ws.security.saml.ext.AssertionWrapper;
+import org.apache.ws.security.saml.ext.OpenSAMLUtil;
+import org.apache.ws.security.validate.Credential;
+import org.apache.ws.security.validate.Validator;
+import org.joda.time.DateTime;
+import org.opensaml.common.SAMLVersion;
+import org.opensaml.xml.validation.ValidationException;
+import org.opensaml.xml.validation.ValidatorSuite;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class validates a SAML Assertion, which is wrapped in an "AssertionWrapper" instance.
+ * It assumes that the AssertionWrapper instance has already verified the signature on the
+ * assertion (done by the SAMLTokenProcessor). It verifies trust in the signature, and also
+ * checks that the Subject contains a KeyInfo (and processes it) for the holder-of-key case,
+ * and verifies that the Assertion is signed as well for holder-of-key. 
+ */
+public class SamlAssertionValidator implements Validator {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(SamlAssertionValidator.class);
+    
+    public enum TRUST_TYPE { CHAIN_TRUST, CHAIN_TRUST_CONSTRAINTS, PEER_TRUST }
+    
+    /**
+     * The time in seconds in the future within which the NotBefore time of an incoming 
+     * Assertion is valid. The default is 60 seconds.
+     */
+    private int futureTTL = 60;
+
+    /**
+     * Defines the kind of trust which is required thus assertion signature validation is successful.
+     */
+    private TRUST_TYPE signatureTrustType = TRUST_TYPE.CHAIN_TRUST;
+        
+    /**
+     * a collection of compiled regular expression patterns for the subject DN
+     */
+    private Collection<Pattern> subjectDNPatterns = new ArrayList<Pattern>();
+    
+    
+    /**
+     * Set the time in seconds in the future within which the NotBefore time of an incoming 
+     * Assertion is valid. The default is 60 seconds.
+     */
+    public void setFutureTTL(int newFutureTTL) {
+        futureTTL = newFutureTTL;
+    }
+    
+    /**
+     * Set the kind of trust. The default is CHAIN_TRUST.
+     */
+    public void setSignatureTrustType(TRUST_TYPE trustType) {
+        this.signatureTrustType = trustType;
+    }
+
+    /**
+     * Set a list of Strings corresponding to regular expression constraints on
+     * the subject DN of a certificate
+     */
+    public void setSubjectConstraints(List<String> constraints) {
+        if (constraints != null) {
+            subjectDNPatterns = new ArrayList<Pattern>();
+            for (String constraint : constraints) {
+                try {
+                    subjectDNPatterns.add(Pattern.compile(constraint.trim()));
+                } catch (PatternSyntaxException ex) {
+                    // LOG.severe(ex.getMessage());
+                    throw ex;
+                }
+            }
+        }
+    }
+    
+    /**
+     * Validate the credential argument. It must contain a non-null AssertionWrapper. 
+     * A Crypto and a CallbackHandler implementation is also required to be set.
+     * 
+     * @param credential the Credential to be validated
+     * @param data the RequestData associated with the request
+     * @throws WSSecurityException on a failed validation
+     */
+    public Credential validate(Credential credential, RequestData data) throws WSSecurityException {
+        if (credential == null || credential.getAssertion() == null) {
+            throw new WSSecurityException(WSSecurityException.FAILURE, "noCredential");
+        }
+        AssertionWrapper assertion = credential.getAssertion();
+        
+        // Check HOK requirements
+        String confirmMethod = null;
+        List<String> methods = assertion.getConfirmationMethods();
+        if (methods != null && methods.size() > 0) {
+            confirmMethod = methods.get(0);
+        }
+        if (OpenSAMLUtil.isMethodHolderOfKey(confirmMethod)) {
+            if (assertion.getSubjectKeyInfo() == null) {
+                LOG.debug("There is no Subject KeyInfo to match the holder-of-key subject conf method");
+                throw new WSSecurityException(WSSecurityException.FAILURE, "noKeyInSAMLToken");
+            }
+            // The assertion must have been signed for HOK
+            if (!assertion.isSigned()) {
+                LOG.debug("A holder-of-key assertion must be signed");
+                throw new WSSecurityException(WSSecurityException.FAILURE, "invalidSAMLsecurity");
+            }
+        }
+        
+        // Check conditions
+        //[TODO] Commented out due to testcase issue
+        //checkConditions(assertion);
+        
+        // Validate the assertion against schemas/profiles
+        validateAssertion(assertion);
+
+        // Verify trust on the signature
+        if (assertion.isSigned()) {
+            verifySignedAssertion(assertion, data);
+        }
+        return credential;
+    }
+    
+    /**
+     * Verify trust in the signature of a signed Assertion. This method is separate so that
+     * the user can override if if they want.
+     * @param assertion The signed Assertion
+     * @param data The RequestData context
+     * @return A Credential instance
+     * @throws WSSecurityException
+     */
+    protected Credential verifySignedAssertion(
+        AssertionWrapper assertion,
+        RequestData data
+    ) throws WSSecurityException {
+        Credential credential = new Credential();
+        SAMLKeyInfo samlKeyInfo = assertion.getSignatureKeyInfo();
+        credential.setPublicKey(samlKeyInfo.getPublicKey());
+        credential.setCertificates(samlKeyInfo.getCerts());
+        
+        if (credential == null) {
+            throw new WSSecurityException(WSSecurityException.FAILURE, "noCredential");
+        }
+        X509Certificate[] certs = credential.getCertificates();
+        PublicKey publicKey = credential.getPublicKey();
+        Crypto crypto = getCrypto(data);
+        if (crypto == null) {
+            throw new WSSecurityException(WSSecurityException.FAILURE, "noSigCryptoFile");
+        }
+        
+        if (certs != null && certs.length > 0) {
+            validateCertificates(certs);
+            boolean trust = false;
+            boolean enableRevocation = data.isRevocationEnabled();
+            if (certs.length == 1) {
+                trust = verifyTrustInCert(certs[0], crypto, enableRevocation);
+            } else {
+                trust = verifyTrustInCerts(certs, crypto, enableRevocation);
+            }
+            if (trust) {
+                if (signatureTrustType.equals(TRUST_TYPE.CHAIN_TRUST_CONSTRAINTS)) {
+                    if (matches(certs[0])) {
+                        return credential;
+                    } else {
+                        throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+                    }
+                } else {
+                    return credential;
+                }
+            }
+        }
+        if (publicKey != null) {
+            boolean trust = validatePublicKey(publicKey, crypto);
+            if (trust) {
+                return credential;
+            }
+        }
+        throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+    }
+
+    protected Crypto getCrypto(RequestData data) {
+        return data.getSigCrypto();
+    }
+
+
+    /**
+     * Validate the certificates by checking the validity of each cert
+     * @throws WSSecurityException
+     */
+    protected void validateCertificates(X509Certificate[] certificates) 
+        throws WSSecurityException {
+        try {
+            for (int i = 0; i < certificates.length; i++) {
+                certificates[i].checkValidity();
+            }
+        } catch (CertificateExpiredException e) {
+            throw new WSSecurityException(
+                WSSecurityException.FAILED_CHECK, "invalidCert", null, e
+            );
+        } catch (CertificateNotYetValidException e) {
+            throw new WSSecurityException(
+                WSSecurityException.FAILED_CHECK, "invalidCert", null, e
+            );
+        }
+    }
+    
+    /**
+     * Evaluate whether a given certificate should be trusted.
+     * 
+     * Policy used in this implementation:
+     * 1. Search the keystore for the transmitted certificate
+     * 2. Search the keystore for a connection to the transmitted certificate
+     * (that is, search for certificate(s) of the issuer of the transmitted certificate
+     * 3. Verify the trust path for those certificates found because the search for the issuer 
+     * might be fooled by a phony DN (String!)
+     *
+     * @param cert the certificate that should be validated against the keystore
+     * @param crypto A crypto instance to use for trust validation
+     * @return true if the certificate is trusted, false if not
+     * @throws WSSecurityException
+     */
+    @Deprecated
+    protected boolean verifyTrustInCert(X509Certificate cert, Crypto crypto) 
+        throws WSSecurityException {
+        return verifyTrustInCert(cert, crypto, false);
+    }
+    
+    /**
+     * Evaluate whether a given certificate should be trusted.
+     * 
+     * Policy used in this implementation:
+     * 1. Search the keystore for the transmitted certificate
+     * 2. Search the keystore for a connection to the transmitted certificate
+     * (that is, search for certificate(s) of the issuer of the transmitted certificate
+     * 3. Verify the trust path for those certificates found because the search for the issuer 
+     * might be fooled by a phony DN (String!)
+     *
+     * @param cert the certificate that should be validated against the keystore
+     * @param crypto A crypto instance to use for trust validation
+     * @param enableRevocation Whether revocation is enabled or not
+     * @return true if the certificate is trusted, false if not
+     * @throws WSSecurityException
+     */
+    protected boolean verifyTrustInCert(
+        X509Certificate cert, 
+        Crypto crypto,
+        boolean enableRevocation
+    ) throws WSSecurityException {
+        String subjectString = cert.getSubjectX500Principal().getName();
+        String issuerString = cert.getIssuerX500Principal().getName();
+        BigInteger issuerSerial = cert.getSerialNumber();
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Transmitted certificate has subject " + subjectString);
+            LOG.debug(
+                "Transmitted certificate has issuer " + issuerString + " (serial " 
+                + issuerSerial + ")"
+            );
+        }
+
+        //
+        // FIRST step - Search the keystore for the transmitted certificate
+        //              If peer trust is enforced then validation fails if
+        //              certificate not found in keystore
+        //
+        boolean isInKeystore = isCertificateInKeyStore(crypto, cert);
+        if (!enableRevocation && isInKeystore) {
+            return true;
+        }
+        if (!isInKeystore && signatureTrustType.equals(TRUST_TYPE.PEER_TRUST)) {
+            return false;
+        }
+
+        //
+        // SECOND step - Search for the issuer cert (chain) of the transmitted certificate in the 
+        // keystore or the truststore
+        //
+        CryptoType cryptoType = new CryptoType(CryptoType.TYPE.SUBJECT_DN);
+        cryptoType.setSubjectDN(issuerString);
+        X509Certificate[] foundCerts = crypto.getX509Certificates(cryptoType);
+
+        // If the certs have not been found, the issuer is not in the keystore/truststore
+        // As a direct result, do not trust the transmitted certificate
+        if (foundCerts == null || foundCerts.length < 1) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug(
+                    "No certs found in keystore for issuer " + issuerString 
+                    + " of certificate for " + subjectString
+                );
+            }
+            return false;
+        }
+
+        //
+        // THIRD step
+        // Check the certificate trust path for the issuer cert chain
+        //
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(
+                "Preparing to validate certificate path for issuer " + issuerString
+            );
+        }
+        //
+        // Form a certificate chain from the transmitted certificate
+        // and the certificate(s) of the issuer from the keystore/truststore
+        //
+        X509Certificate[] x509certs = new X509Certificate[foundCerts.length + 1];
+        x509certs[0] = cert;
+        for (int j = 0; j < foundCerts.length; j++) {
+            x509certs[j + 1] = (X509Certificate)foundCerts[j];
+        }
+
+        //
+        // Use the validation method from the crypto to check whether the subjects' 
+        // certificate was really signed by the issuer stated in the certificate
+        //
+        if (crypto.verifyTrust(x509certs, enableRevocation)) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug(
+                    "Certificate path has been verified for certificate with subject " 
+                     + subjectString
+                );
+            }
+            return true;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(
+                "Certificate path could not be verified for certificate with subject " 
+                + subjectString
+            );
+        }
+        return false;
+    }
+    
+    /**
+     * Check to see if the certificate argument is in the keystore
+     * @param crypto A Crypto instance to use for trust validation
+     * @param cert The certificate to check
+     * @return true if cert is in the keystore
+     * @throws WSSecurityException
+     */
+    protected boolean isCertificateInKeyStore(
+        Crypto crypto,
+        X509Certificate cert
+    ) throws WSSecurityException {
+        String issuerString = cert.getIssuerX500Principal().getName();
+        BigInteger issuerSerial = cert.getSerialNumber();
+        
+        CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ISSUER_SERIAL);
+        cryptoType.setIssuerSerial(issuerString, issuerSerial);
+        X509Certificate[] foundCerts = crypto.getX509Certificates(cryptoType);
+
+        //
+        // If a certificate has been found, the certificates must be compared
+        // to ensure against phony DNs (compare encoded form including signature)
+        //
+        if (foundCerts != null && foundCerts[0] != null && foundCerts[0].equals(cert)) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug(
+                    "Direct trust for certificate with " + cert.getSubjectX500Principal().getName()
+                );
+            }
+            return true;
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(
+                "No certificate found for subject from issuer with " + issuerString 
+                + " (serial " + issuerSerial + ")"
+            );
+        }
+        return false;
+    }
+    
+    /**
+     * Evaluate whether the given certificate chain should be trusted.
+     * 
+     * @param certificates the certificate chain that should be validated against the keystore
+     * @param crypto  A Crypto instance to use for trust validation
+     * @return true if the certificate chain is trusted, false if not
+     * @throws WSSecurityException
+     */
+    @Deprecated
+    protected boolean verifyTrustInCerts(
+        X509Certificate[] certificates, 
+        Crypto crypto
+    ) throws WSSecurityException {
+        return verifyTrustInCerts(certificates, crypto, false);
+    }
+    
+    /**
+     * Evaluate whether the given certificate chain should be trusted.
+     * 
+     * @param certificates the certificate chain that should be validated against the keystore
+     * @param crypto A Crypto instance
+     * @param enableRevocation Whether revocation is enabled or not
+     * @return true if the certificate chain is trusted, false if not
+     * @throws WSSecurityException
+     */
+    protected boolean verifyTrustInCerts(
+        X509Certificate[] certificates, 
+        Crypto crypto,
+        boolean enableRevocation
+    ) throws WSSecurityException {
+        if (certificates == null || certificates.length < 2) {
+            return false;
+        }
+        
+        String subjectString = certificates[0].getSubjectX500Principal().getName();
+        //
+        // Use the validation method from the crypto to check whether the subjects' 
+        // certificate was really signed by the issuer stated in the certificate
+        //
+        if (crypto.verifyTrust(certificates, enableRevocation)) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug(
+                    "Certificate path has been verified for certificate with subject " 
+                    + subjectString
+                );
+            }
+            return true;
+        }
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(
+                "Certificate path could not be verified for certificate with subject " 
+                + subjectString
+            );
+        }
+            
+        return false;
+    }
+    
+    /**
+     * Validate a public key
+     * @throws WSSecurityException
+     */
+    protected boolean validatePublicKey(PublicKey publicKey, Crypto crypto) 
+        throws WSSecurityException {
+        return crypto.verifyTrust(publicKey);
+    }
+    
+    /**
+     * Check the Conditions of the Assertion.
+     */
+    protected void checkConditions(AssertionWrapper assertion) throws WSSecurityException {
+        DateTime validFrom = null;
+        DateTime validTill = null;
+        if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_20)
+            && assertion.getSaml2().getConditions() != null) {
+            validFrom = assertion.getSaml2().getConditions().getNotBefore();
+            validTill = assertion.getSaml2().getConditions().getNotOnOrAfter();
+        } else if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_11)
+            && assertion.getSaml1().getConditions() != null) {
+            validFrom = assertion.getSaml1().getConditions().getNotBefore();
+            validTill = assertion.getSaml1().getConditions().getNotOnOrAfter();
+        }
+        
+        if (validFrom != null) {
+            DateTime currentTime = new DateTime();
+            currentTime = currentTime.plusSeconds(futureTTL);
+            if (validFrom.isAfter(currentTime)) {
+                LOG.debug("SAML Token condition (Not Before) not met");
+                throw new WSSecurityException(WSSecurityException.FAILURE, "invalidSAMLsecurity");
+            }
+        }
+
+        if (validTill != null && validTill.isBeforeNow()) {
+            LOG.debug("SAML Token condition (Not On Or After) not met");
+            throw new WSSecurityException(WSSecurityException.FAILURE, "invalidSAMLsecurity");
+        }
+    }
+    
+    /**
+     * Validate the assertion against schemas/profiles
+     */
+    protected void validateAssertion(AssertionWrapper assertion) throws WSSecurityException {
+        if (assertion.getSaml1() != null) {
+            ValidatorSuite schemaValidators = 
+                org.opensaml.Configuration.getValidatorSuite("saml1-schema-validator");
+            ValidatorSuite specValidators = 
+                org.opensaml.Configuration.getValidatorSuite("saml1-spec-validator");
+            try {
+                schemaValidators.validate(assertion.getSaml1());
+                specValidators.validate(assertion.getSaml1());
+            } catch (ValidationException e) {
+                LOG.debug("Saml Validation error: " + e.getMessage(), e);
+                throw new WSSecurityException(
+                    WSSecurityException.FAILURE, "invalidSAMLsecurity", null, e
+                );
+            }
+        } else if (assertion.getSaml2() != null) {
+            ValidatorSuite schemaValidators = 
+                org.opensaml.Configuration.getValidatorSuite("saml2-core-schema-validator");
+            ValidatorSuite specValidators = 
+                org.opensaml.Configuration.getValidatorSuite("saml2-core-spec-validator");
+            try {
+                schemaValidators.validate(assertion.getSaml2());
+                specValidators.validate(assertion.getSaml2());
+            } catch (ValidationException e) {
+                LOG.debug("Saml Validation error: " + e.getMessage(), e);
+                throw new WSSecurityException(
+                    WSSecurityException.FAILURE, "invalidSAMLsecurity", null, e
+                );
+            }
+        }
+    }
+    
+    /**
+     * @return true if the certificate's SubjectDN matches the constraints
+     *         defined in the subject DNConstraints; false, otherwise. The
+     *         certificate subject DN only has to match ONE of the subject cert
+     *         constraints (not all).
+     */
+    public boolean matches(final java.security.cert.X509Certificate cert) {
+        if (!subjectDNPatterns.isEmpty()) {
+            if (cert == null) {
+                return false;
+            }
+            String subjectName = cert.getSubjectX500Principal().getName();
+            boolean subjectMatch = false;
+            for (Pattern subjectDNPattern : subjectDNPatterns) {
+                final Matcher matcher = subjectDNPattern.matcher(subjectName);
+                if (matcher.matches()) {
+                    subjectMatch = true;
+                    break;
+                }
+            }
+            if (!subjectMatch) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    
+}

Added: cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/common/STSUtil.java
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/common/STSUtil.java?rev=1345768&view=auto
==============================================================================
--- cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/common/STSUtil.java (added)
+++ cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/common/STSUtil.java Sun Jun  3 20:25:34 2012
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.fediz.common;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+public class STSUtil {
+    
+    public static final String SAMPLE_RSTR_MSG = 
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 
+        + "<SOAP-ENV:Envelope "
+        +   "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+        +   "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
+        +   "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" 
+        +   "<SOAP-ENV:Body>" 
+        +       "<add xmlns=\"http://ws.apache.org/counter/counter_port_type\">" 
+        +           "<value xmlns=\"\">15</value>" 
+        +       "</add>" 
+        +   "</SOAP-ENV:Body>" 
+        + "</SOAP-ENV:Envelope>";
+
+    
+    public static final String SAMPLE_RSTR_COLL_MSG = 
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+        + "<RequestSecurityTokenResponseCollection "
+        +   "xmlns=\"http://docs.oasis-open.org/ws-sx/ws-trust/200512\"> "
+        +   "<RequestSecurityTokenResponse>"
+        +     "<RequestedSecurityToken>"
+        +     "</RequestedSecurityToken>"
+        +   "</RequestSecurityTokenResponse>"
+        + "</RequestSecurityTokenResponseCollection>";
+    
+    
+    private static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+    
+    static {
+        factory.setNamespaceAware(true);
+    }
+    
+    protected STSUtil() {
+        
+    }
+    
+    /**
+     * Convert an XML document as a String to a org.w3c.dom.Document.
+     */
+    public static org.w3c.dom.Document toSOAPPart(String xml) throws Exception {
+        InputStream in = new ByteArrayInputStream(xml.getBytes());
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        return builder.parse(in);
+    }
+    
+}

Added: cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java?rev=1345768&view=auto
==============================================================================
--- cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java (added)
+++ cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java Sun Jun  3 20:25:34 2012
@@ -0,0 +1,282 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.fediz.core;
+
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.apache.ws.security.WSConstants;
+import org.apache.ws.security.message.WSSecEncryptedKey;
+import org.apache.ws.security.saml.ext.SAMLCallback;
+import org.apache.ws.security.saml.ext.bean.ActionBean;
+import org.apache.ws.security.saml.ext.bean.AttributeBean;
+import org.apache.ws.security.saml.ext.bean.AttributeStatementBean;
+import org.apache.ws.security.saml.ext.bean.AuthDecisionStatementBean;
+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.KeyInfoBean.CERT_IDENTIFIER;
+import org.apache.ws.security.saml.ext.bean.SubjectBean;
+import org.apache.ws.security.saml.ext.bean.SubjectConfirmationDataBean;
+import org.apache.ws.security.saml.ext.bean.SubjectLocalityBean;
+
+
+
+/**
+ * A base implementation of a Callback Handler for a SAML assertion. By default it creates an
+ * authentication assertion.
+ */
+public abstract class AbstractSAMLCallbackHandler implements CallbackHandler {
+    
+    public enum Statement {
+        AUTHN, ATTR, AUTHZ
+    };
+    
+    public enum MultiValue {
+        MULTI_VALUE, MULTI_ATTR, ENC_VALUE
+    };
+    
+    protected String subjectName;
+    protected String subjectQualifier;
+    protected String confirmationMethod;
+    protected X509Certificate[] certs;
+    protected Statement statement = Statement.AUTHN;
+    protected CERT_IDENTIFIER certIdentifier = CERT_IDENTIFIER.X509_CERT;
+    protected byte[] ephemeralKey;
+    protected String issuer;
+    protected String subjectNameIDFormat;
+    protected String subjectLocalityIpAddress;
+    protected String subjectLocalityDnsAddress;
+    protected String resource;
+    protected List<?> customAttributeValues;
+    protected ConditionsBean conditions;
+    protected SubjectConfirmationDataBean subjectConfirmationData;
+    protected List<String> roles = Arrays.asList("User", "Admin");
+    protected Map<String, String> claims;
+    protected MultiValue multiValueType = MultiValue.MULTI_VALUE;
+    protected String roleSeperator = ",";
+    
+    public void setSubjectConfirmationData(SubjectConfirmationDataBean subjectConfirmationData) {
+        this.subjectConfirmationData = subjectConfirmationData;
+    }
+    
+    public void setConditions(ConditionsBean conditionsBean) {
+        this.conditions = conditionsBean;
+    }
+    
+    public void setConfirmationMethod(String confMethod) {
+        confirmationMethod = confMethod;
+    }
+    
+    public void setStatement(Statement statement) {
+        this.statement = statement;
+    }
+    
+    public void setCertIdentifier(CERT_IDENTIFIER certIdentifier) {
+        this.certIdentifier = certIdentifier;
+    }
+    
+    public void setCerts(X509Certificate[] certs) {
+        this.certs = certs;
+    }
+    
+    public byte[] getEphemeralKey() {
+        return ephemeralKey;
+    }
+    
+    public void setIssuer(String issuer) {
+        this.issuer = issuer;
+    }
+    
+    public void setSubjectNameIDFormat(String subjectNameIDFormat) {
+        this.subjectNameIDFormat = subjectNameIDFormat;
+    }
+    
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+    
+    public void setSubjectLocality(String ipAddress, String dnsAddress) {
+        this.subjectLocalityIpAddress = ipAddress;
+        this.subjectLocalityDnsAddress = dnsAddress;
+    }
+    
+    public void setResource(String resource) {
+        this.resource = resource;
+    }
+    
+    public void setCustomAttributeValues(List<?> customAttributeValues) {
+        this.customAttributeValues = customAttributeValues;
+    }
+    
+    public void setRoles(List<String> roles) {
+        this.roles = roles;
+    }
+
+    public void setClaims(Map<String, String> claims) {
+        this.claims = claims;
+    }
+
+    public void setMultiValueType(MultiValue multiValueType) {
+        this.multiValueType = multiValueType;
+    }
+    
+    /**
+     * Note that the SubjectBean parameter should be null for SAML2.0
+     */
+    protected void createAndSetStatement(SubjectBean subjectBean, SAMLCallback callback) {
+        if (statement == Statement.AUTHN) {
+            AuthenticationStatementBean authBean = new AuthenticationStatementBean();
+            if (subjectBean != null) {
+                authBean.setSubject(subjectBean);
+            }
+            if (subjectLocalityIpAddress != null || subjectLocalityDnsAddress != null) {
+                SubjectLocalityBean subjectLocality = new SubjectLocalityBean();
+                subjectLocality.setIpAddress(subjectLocalityIpAddress);
+                subjectLocality.setDnsAddress(subjectLocalityDnsAddress);
+                authBean.setSubjectLocality(subjectLocality);
+            }
+            authBean.setAuthenticationMethod("Password");
+            callback.setAuthenticationStatementData(Collections.singletonList(authBean));
+        } else if (statement == Statement.ATTR) {
+            AttributeStatementBean attrStateBean = new AttributeStatementBean();
+            
+            if (this.multiValueType.equals(MultiValue.MULTI_VALUE)
+                || this.multiValueType.equals(MultiValue.ENC_VALUE)) {
+//              <saml:Attribute xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
+//                AttributeNamespace="http://schemas.xmlsoap.org/claims" AttributeName="roles">
+//                <saml:AttributeValue>Value1</saml:AttributeValue>
+//                <saml:AttributeValue>Value2</saml:AttributeValue>
+//              </saml:Attribute>
+//                 or                
+//              <saml:Attribute xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
+//              AttributeNamespace="http://schemas.xmlsoap.org/claims" AttributeName="roles">
+//              <saml:AttributeValue>Value1,Value2</saml:AttributeValue>
+//            </saml:Attribute>
+                AttributeBean attributeBean = new AttributeBean();
+                if (subjectBean != null) {
+                    attrStateBean.setSubject(subjectBean);
+                    attributeBean.setSimpleName("role");
+                    attributeBean.setQualifiedName(FederationConstants.DEFAULT_ROLE_URI.toString());
+                } else {
+                    attributeBean.setQualifiedName(FederationConstants.DEFAULT_ROLE_URI.toString());
+                }
+                if (this.multiValueType.equals(MultiValue.MULTI_VALUE)) {
+                    attributeBean.setAttributeValues(roles);
+                } else {
+                    StringBuffer sb = new StringBuffer();
+                    for (String role: roles) {
+                        sb.append(role).append(this.roleSeperator);
+                    }
+                    String value = sb.substring(0, sb.length() - this.roleSeperator.length());
+                    attributeBean.setAttributeValues(Collections.singletonList(value));
+                }
+                attrStateBean.setSamlAttributes(Collections.singletonList(attributeBean));
+            } else if (this.multiValueType.equals(MultiValue.MULTI_ATTR)) {
+//              <saml:Attribute xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
+//                AttributeNamespace="http://schemas.xmlsoap.org/claims" AttributeName="roles">
+//                <saml:AttributeValue>Value1</saml:AttributeValue>
+//              </saml:Attribute>
+//              <saml:Attribute xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
+//                AttributeNamespace="http://schemas.xmlsoap.org/claims" AttributeName="roles">
+//                <saml:AttributeValue>Value2</saml:AttributeValue>
+//              </saml:Attribute>
+                
+                List<AttributeBean> attrBeans = new ArrayList<AttributeBean>();
+                for (String role: roles) {
+                    AttributeBean attributeBean = new AttributeBean();
+                    if (subjectBean != null) {
+                        attrStateBean.setSubject(subjectBean);
+                        attributeBean.setSimpleName("role");
+                        attributeBean.setQualifiedName(FederationConstants.DEFAULT_ROLE_URI.toString());
+                    } else {
+                        attributeBean.setQualifiedName(FederationConstants.DEFAULT_ROLE_URI.toString());
+                    }
+                    attributeBean.setAttributeValues(Collections.singletonList(role));
+                    attrBeans.add(attributeBean);
+                }
+                attrStateBean.setSamlAttributes(attrBeans);
+            }
+            
+            callback.setAttributeStatementData(Collections.singletonList(attrStateBean));
+                       
+        } else {
+            AuthDecisionStatementBean authzBean = new AuthDecisionStatementBean();
+            if (subjectBean != null) {
+                authzBean.setSubject(subjectBean);
+            }
+            ActionBean actionBean = new ActionBean();
+            actionBean.setContents("Read");
+            authzBean.setActions(Collections.singletonList(actionBean));
+            authzBean.setResource("endpoint");
+            authzBean.setDecision(AuthDecisionStatementBean.Decision.PERMIT);
+            authzBean.setResource(resource);
+            callback.setAuthDecisionStatementData(Collections.singletonList(authzBean));
+        }
+    }
+    
+    protected KeyInfoBean createKeyInfo() throws Exception {
+        KeyInfoBean keyInfo = new KeyInfoBean();
+        if (statement == Statement.AUTHN) {
+            keyInfo.setCertificate(certs[0]);
+            keyInfo.setCertIdentifer(certIdentifier);
+        } else if (statement == Statement.ATTR) {
+            // Build a new Document
+            DocumentBuilderFactory docBuilderFactory = 
+                DocumentBuilderFactory.newInstance();
+            docBuilderFactory.setNamespaceAware(true);
+            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
+            Document doc = docBuilder.newDocument();
+                  
+            // Create an Encrypted Key
+            WSSecEncryptedKey encrKey = new WSSecEncryptedKey();
+            encrKey.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
+            encrKey.setUseThisCert(certs[0]);
+            encrKey.prepare(doc, null);
+            ephemeralKey = encrKey.getEphemeralKey();
+            Element encryptedKeyElement = encrKey.getEncryptedKeyElement();
+            
+            // Append the EncryptedKey to a KeyInfo element
+            Element keyInfoElement = 
+                doc.createElementNS(
+                    WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN
+                );
+            keyInfoElement.setAttributeNS(
+                WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
+            );
+            keyInfoElement.appendChild(encryptedKeyElement);
+            
+            keyInfo.setElement(keyInfoElement);
+        }
+        return keyInfo;
+    }
+}

Modified: cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java?rev=1345768&r1=1345767&r2=1345768&view=diff
==============================================================================
--- cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java (original)
+++ cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java Sun Jun  3 20:25:34 2012
@@ -19,44 +19,62 @@
 
 package org.apache.cxf.fediz.core;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.net.URL;
 
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
 import junit.framework.Assert;
 
+import org.apache.cxf.fediz.common.STSUtil;
 import org.apache.cxf.fediz.common.SecurityTestUtil;
+import org.apache.cxf.fediz.core.AbstractSAMLCallbackHandler.MultiValue;
 import org.apache.cxf.fediz.core.config.FederationConfigurator;
 import org.apache.cxf.fediz.core.config.FederationContext;
+import org.apache.cxf.fediz.core.config.FederationProtocol;
+import org.apache.ws.security.WSPasswordCallback;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.components.crypto.CryptoFactory;
+import org.apache.ws.security.saml.ext.AssertionWrapper;
+import org.apache.ws.security.saml.ext.SAMLParms;
+import org.apache.ws.security.saml.ext.bean.ConditionsBean;
+import org.apache.ws.security.saml.ext.builder.SAML2Constants;
+import org.apache.ws.security.util.DOM2Writer;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
+
 import static org.junit.Assert.fail;
 
 public class FederationProcessorTest {
     private static final String TEST_USER = "alice";
-    private static final String TEST_RSTR_ISSUER = "DoubleItSTSIssuer";
-
+    private static final String TEST_RSTR_ISSUER = "FedizSTSIssuer";
+    private static final String TEST_AUDIENCE = "https://localhost/fedizhelloworld";
+    
     private static final String CONFIG_FILE = "fediz_test_config.xml";
-    private static final String CONFIG_FILE_WRONG_ISSUER = "fediz_test_config2.xml";
-
-    private static String sRSTR;
-    private static String sRSTRREPLAY;
-
+    
+    private static Crypto crypto;
+    private static CallbackHandler cbPasswordHandler;
+    private static FederationConfigurator configurator;
+    
+    
     @BeforeClass
-    public static void readWResult() {
+    public static void init() {
         try {
-            sRSTR = loadResource("RSTR.xml");
-            sRSTRREPLAY = loadResource("RSTR_replay.xml");
+            crypto = CryptoFactory.getInstance("signature.properties");
+            cbPasswordHandler = new KeystoreCallbackHandler();
+            getFederationConfigurator();
         } catch (Exception e) {
             e.printStackTrace();
         }
-        Assert.assertNotNull("RSTR resource null", sRSTR);
-        Assert.assertNotNull(loadRootConfig());
+        Assert.assertNotNull(configurator);
 
     }
     
@@ -65,141 +83,378 @@ public class FederationProcessorTest {
         SecurityTestUtil.cleanup();
     }
     
-    private static String loadResource(String filename) throws IOException {
-        InputStream is = null;
-        try {
-            is = FederationProcessorTest.class.getResourceAsStream("/" + filename);
-            if (is == null) {
-                throw new FileNotFoundException("Failed to get RSTR.xml");
-            }
-            BufferedReader bufferedReader = new BufferedReader(
-                    new InputStreamReader(is));
-            StringBuilder stringBuilder = new StringBuilder();
-            String line = null;
-            while ((line = bufferedReader.readLine()) != null) {
-                stringBuilder.append(line + "\n");
-            }
-            bufferedReader.close();
-            return stringBuilder.toString();
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
 
-    private static FederationContext loadRootConfig() {
+    private static FederationConfigurator getFederationConfigurator() {
+        if (configurator != null) {
+            return configurator;
+        }
         try {
-            FederationConfigurator configurator = new FederationConfigurator();
+            configurator = new FederationConfigurator();
             final URL resource = Thread.currentThread().getContextClassLoader()
                     .getResource(CONFIG_FILE);
             File f = new File(resource.toURI());
             configurator.loadConfig(f);
-            return configurator.getFederationContext("ROOT");
+            return configurator;
         } catch (Exception e) {
             e.printStackTrace();
             return null;
         }
     }
 
-    private static FederationContext loadOtherIssuerRootConfig() {
-        try {
-            FederationConfigurator configurator = new FederationConfigurator();
-            final URL resource = Thread.currentThread().getContextClassLoader()
-                    .getResource(CONFIG_FILE_WRONG_ISSUER);
-            File f = new File(resource.toURI());
-            configurator.loadConfig(f);
-            return configurator.getFederationContext("ROOT");
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-
+    /**
+     * Validate SAML 2 token which includes the role attribute with 2 values
+     * Roles are encoded as a multi-value saml attribute
+     */
+    @org.junit.Test
+    public void validateSAML2Token() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey");
+        
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = getFederationConfigurator().getFederationContext("ROOT");
+        
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER,
+                            wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, wfRes.getAudience());
     }
-
+    
+    /**
+     * Validate SAML 2 token which includes the role attribute with 2 values
+     * Roles are encoded as a multiple saml attributes with the same name
+     */
     @org.junit.Test
-    public void validateSAML2Token() {
-
+    public void validateSAML2TokenRoleMultiAttributes() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setMultiValueType(MultiValue.MULTI_ATTR);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey");
+        
         FederationRequest wfReq = new FederationRequest();
         wfReq.setWa(FederationConstants.ACTION_SIGNIN);
-        wfReq.setWresult(sRSTR);
-        FederationContext config = loadRootConfig();
-        config.setDetectReplayedTokens(false);
-        config.setDetectExpiredTokens(false);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = getFederationConfigurator().getFederationContext("ROOT");
 
         FederationProcessor wfProc = new FederationProcessorImpl();
         FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
         Assert.assertEquals("Principal name wrong", TEST_USER,
-                wfRes.getUsername());
+                            wfRes.getUsername());
         Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
     }
 
+    /**
+     * Validate SAML 2 token which includes the role attribute with 2 values
+     * Roles are encoded as a single saml attribute with encoded value
+     */
     @org.junit.Test
-    public void validateSAML2TokenWithWrongIssuer() {
+    public void validateSAML2TokenRoleEncodedValue() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setMultiValueType(MultiValue.ENC_VALUE);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey");
+        
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = getFederationConfigurator().getFederationContext("ROOT");
+        FederationProtocol fp = (FederationProtocol)config.getProtocol();
+        fp.setRoleDelimiter(",");
 
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER,
+                            wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
+    }
+    
+    /**
+     * Validate SAML 2 token which includes the role attribute with 2 values
+     * The configured subject of the trusted issuer doesn't match with
+     * the issuer of the SAML token
+     */
+    @org.junit.Test
+    public void validateSAML2TokenUntrustedIssuer() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        
+        String rstr = createSamlToken(assertion, "mystskey");
         FederationRequest wfReq = new FederationRequest();
         wfReq.setWa(FederationConstants.ACTION_SIGNIN);
-        wfReq.setWresult(sRSTR);
-        FederationContext config = loadOtherIssuerRootConfig();
-        config.setDetectReplayedTokens(false);
-        config.setDetectExpiredTokens(false);
+        wfReq.setWresult(rstr);
+        
+        // Load and update the config to enforce an error
+        configurator = null;
+        FederationContext config = getFederationConfigurator().getFederationContext("ROOT");
+        config.getTrustedIssuers().get(0).setSubject("wrong-issuer-name");        
+        
         FederationProcessor wfProc = new FederationProcessorImpl();
         try {
             wfProc.processRequest(wfReq, config);
             Assert.fail("Processing must fail because of wrong issuer configured");
         } catch (RuntimeException ex) {
-            Assert.assertEquals("Exception expected", "Issuer '"
-                    + TEST_RSTR_ISSUER + "' not trusted", ex.getMessage());
+            // expected
         }
     }
 
+    /**
+     * Validate SAML 2 token twice which causes an exception
+     * due to replay attack
+     */
     @org.junit.Test
-    public void validateSAML2TokenForRoles() {
-
+    public void testReplayAttack() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey");
+        
         FederationRequest wfReq = new FederationRequest();
         wfReq.setWa(FederationConstants.ACTION_SIGNIN);
-        wfReq.setWresult(sRSTR);
-
-        FederationContext config = loadRootConfig();
-        config.setDetectReplayedTokens(false);
-        config.setDetectExpiredTokens(false);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = getFederationConfigurator().getFederationContext("ROOT");
 
         FederationProcessor wfProc = new FederationProcessorImpl();
         FederationResponse wfRes = wfProc.processRequest(wfReq, config);
         Assert.assertEquals("Principal name wrong", TEST_USER,
                 wfRes.getUsername());
         Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
-        Assert.assertEquals("One role must be found", 1, wfRes.getRoles()
-                .size());
+        
+        wfProc = new FederationProcessorImpl();
+        try {
+            wfProc.processRequest(wfReq, config);
+            fail("Failure expected on a replay attack");
+        } catch (Exception ex) {
+            // expected
+        }
     }
     
+    
+    /**
+     * Validate SAML 2 token which includes the role attribute with 2 values
+     * The configured subject of the trusted issuer doesn't match with
+     * the issuer of the SAML token
+     */
     @org.junit.Test
-    public void testReplayAttack() {
-
+    public void validateSAML2TokenSeveralCertStore() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        
+        String rstr = createSamlToken(assertion, "mystskey");
         FederationRequest wfReq = new FederationRequest();
         wfReq.setWa(FederationConstants.ACTION_SIGNIN);
-        wfReq.setWresult(sRSTRREPLAY);
-        FederationContext config = loadRootConfig();
-        config.setDetectExpiredTokens(false);
+        wfReq.setWresult(rstr);
+        
+        // Load and update the config to enforce an error
+        configurator = null;
+        FederationContext config = getFederationConfigurator().getFederationContext("ROOT2");
+        
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER,
+                            wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
+    }
 
+    /**
+     * Validate SAML 2 token which includes the role attribute with 2 values
+     * The configured subject of the trusted issuer doesn't match with
+     * the issuer of the SAML token
+     */
+    @org.junit.Test
+    public void validateSAML2TokenSeveralCertStoreTrustedIssuer() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        
+        String rstr = createSamlToken(assertion, "mystskey");
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        // Load and update the config to enforce an error
+        configurator = null;
+        FederationContext config = getFederationConfigurator().getFederationContext("ROOT3");
+        
         FederationProcessor wfProc = new FederationProcessorImpl();
         FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
         Assert.assertEquals("Principal name wrong", TEST_USER,
-                wfRes.getUsername());
+                            wfRes.getUsername());
         Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
+    }
+    
+    
+    private String createSamlToken(AssertionWrapper assertion, String alias) throws IOException,
+        UnsupportedCallbackException, WSSecurityException, Exception {
+        WSPasswordCallback[] cb = {new WSPasswordCallback(alias, WSPasswordCallback.SIGNATURE)};
+        cbPasswordHandler.handle(cb);
+        String password = cb[0].getPassword();
         
-        wfProc = new FederationProcessorImpl();
-        try {
-            wfProc.processRequest(wfReq, config);
-            fail("Failure expected on a replay attack");
-        } catch (Exception ex) {
-            // expected
+        assertion.signAssertion(alias, password, crypto, false);
+        Document doc = STSUtil.toSOAPPart(STSUtil.SAMPLE_RSTR_COLL_MSG);
+        Element token = assertion.toDOM(doc);
+             
+        Element e = FederationProcessorTest.findElement(doc, "RequestedSecurityToken",
+                                                        FederationConstants.WS_TRUST_13_NS);
+        e.appendChild(token);
+        return DOM2Writer.nodeToString(doc);
+    }
+    
+
+    
+    
+    /**
+     * Returns the first element that matches <code>name</code> and
+     * <code>namespace</code>. <p/> This is a replacement for a XPath lookup
+     * <code>//name</code> with the given namespace. It's somewhat faster than
+     * XPath, and we do not deal with prefixes, just with the real namespace URI
+     * 
+     * @param startNode Where to start the search
+     * @param name Local name of the element
+     * @param namespace Namespace URI of the element
+     * @return The found element or <code>null</code>
+     */
+    public static Element findElement(Node startNode, String name, String namespace) {
+        //
+        // Replace the formerly recursive implementation with a depth-first-loop
+        // lookup
+        //
+        if (startNode == null) {
+            return null;
         }
+        Node startParent = startNode.getParentNode();
+        Node processedNode = null;
+
+        while (startNode != null) {
+            // start node processing at this point
+            if (startNode.getNodeType() == Node.ELEMENT_NODE
+                && startNode.getLocalName().equals(name)) {
+                String ns = startNode.getNamespaceURI();
+                if (ns != null && ns.equals(namespace)) {
+                    return (Element)startNode;
+                }
+
+                if ((namespace == null || namespace.length() == 0)
+                    && (ns == null || ns.length() == 0)) {
+                    return (Element)startNode;
+                }
+            }
+            processedNode = startNode;
+            startNode = startNode.getFirstChild();
+
+            // no child, this node is done.
+            if (startNode == null) {
+                // close node processing, get sibling
+                startNode = processedNode.getNextSibling();
+            }
+            // no more siblings, get parent, all children
+            // of parent are processed.
+            while (startNode == null) {
+                processedNode = processedNode.getParentNode();
+                if (processedNode == startParent) {
+                    return null;
+                }
+                // close parent node processing (processed node now)
+                startNode = processedNode.getNextSibling();
+            }
+        }
+        return null;
     }
 
+    
 
 }

Added: cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/KeystoreCallbackHandler.java
URL: http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/KeystoreCallbackHandler.java?rev=1345768&view=auto
==============================================================================
--- cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/KeystoreCallbackHandler.java (added)
+++ cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/KeystoreCallbackHandler.java Sun Jun  3 20:25:34 2012
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.fediz.core;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.apache.ws.security.WSPasswordCallback;
+
+/**
+ * A Callback Handler implementation for the case of finding a password to access a 
+ * cert/private key in a keystore.
+ */
+public class KeystoreCallbackHandler implements CallbackHandler {
+    
+    private Map<String, String> users = new HashMap<String, String>();
+    
+    public KeystoreCallbackHandler() {
+        users.put("mystskey", "stskpass");
+        users.put("realma", "realma");
+        users.put("realmb", "realmb");
+    }
+    
+    public void handle(Callback[] callbacks)
+        throws IOException, UnsupportedCallbackException {
+        for (int i = 0; i < callbacks.length; i++) {
+            if (callbacks[i] instanceof WSPasswordCallback) {
+                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
+                pc.setPassword(users.get(pc.getIdentifier()));
+            } else {
+                throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
+            }
+        }
+    }
+}



Mime
View raw message