cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject svn commit: r1165687 - 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/assertion/ rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/ rt/rs/s...
Date Tue, 06 Sep 2011 14:38:37 GMT
Author: sergeyb
Date: Tue Sep  6 14:38:36 2011
New Revision: 1165687

URL: http://svn.apache.org/viewvc?rev=1165687&view=rev
Log:
[CXF-3588] Prototyping some code for validating SAML tokens and using them for ACL decisions

Added:
    cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/
    cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claim.java
  (with props)
    cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claims.java
  (with props)
    cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Subject.java
  (with props)
    cxf/trunk/rt/rs/security/xml/src/test/java/org/
    cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/
    cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/
    cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/
    cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/
    cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/
    cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/authorization/
    cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/authorization/ClaimsAuthorizingInterceptorTest.java
  (with props)
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/SAMLUtils.java
    cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.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=1165687&r1=1165686&r2=1165687&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
Tue Sep  6 14:38:36 2011
@@ -35,6 +35,7 @@ import javax.ws.rs.core.Response;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.helpers.DOMUtils;
 import org.apache.cxf.jaxrs.ext.RequestHandler;
@@ -42,10 +43,12 @@ import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.rs.security.common.CryptoLoader;
 import org.apache.cxf.rs.security.common.SecurityUtils;
+import org.apache.cxf.rs.security.saml.authorization.SecurityContextProvider;
+import org.apache.cxf.rs.security.saml.authorization.SecurityContextProviderImpl;
+import org.apache.cxf.security.SecurityContext;
 import org.apache.cxf.security.transport.TLSSessionInfo;
 import org.apache.cxf.ws.security.SecurityConstants;
 import org.apache.ws.security.WSSConfig;
-import org.apache.ws.security.WSSecurityEngineResult;
 import org.apache.ws.security.handler.RequestData;
 import org.apache.ws.security.handler.WSHandlerConstants;
 import org.apache.ws.security.saml.SAMLKeyInfo;
@@ -54,6 +57,7 @@ import org.apache.ws.security.saml.ext.O
 import org.apache.ws.security.validate.Credential;
 import org.apache.ws.security.validate.SamlAssertionValidator;
 import org.apache.ws.security.validate.Validator;
+import org.apache.xml.security.signature.XMLSignature;
 
 
 public abstract class AbstractSamlInHandler implements RequestHandler {
@@ -66,11 +70,17 @@ public abstract class AbstractSamlInHand
     }
     
     private Validator samlValidator = new SamlAssertionValidator();
+    private SecurityContextProvider scProvider = new SecurityContextProviderImpl(); 
     
     public void setValidator(Validator validator) {
         samlValidator = validator;
     }
     
+    public void setSecurityContextProvider(SecurityContextProvider p) {
+        scProvider = p;
+    }
+    
+    
     protected void validateToken(Message message, InputStream tokenStream) {
         
         Document doc = null;
@@ -109,10 +119,10 @@ public abstract class AbstractSamlInHand
                 }
                 
                 Certificate[] tlsCerts = getTLSCertificates(message);
-                if (!checkHolderOfKey(assertion, null, tlsCerts)) {
+                if (!checkHolderOfKey(message, assertion, tlsCerts)) {
                     throwFault("Holder Of Key claim fails", null);
                 }
-                if (!checkSenderVouches(assertion, null, tlsCerts)) {
+                if (!checkSenderVouches(message, assertion, tlsCerts)) {
                     throwFault("Sender vouchers claim fails", null);
                 }
                 if (!checkBearer(assertion, tlsCerts)) {
@@ -123,11 +133,19 @@ public abstract class AbstractSamlInHand
                 // from the xml-sig envelope which this assertion must be contained in 
                 throwFault("Unsigned Assertion can only be validated with two-way TLS", null);
             }
+            setSecurityContext(message, assertion);
+            
         } catch (Exception ex) {
             throwFault("Assertion can not be validated", ex);
         }
     }
     
+    protected void setSecurityContext(Message message, AssertionWrapper wrapper) {
+        if (scProvider != null) {
+            SecurityContext sc = scProvider.getSecurityContext(message, wrapper);
+            message.setContent(SecurityContext.class, sc);
+        }
+    }
     
     private Certificate[] getTLSCertificates(Message message) {
         TLSSessionInfo tlsInfo = message.get(TLSSessionInfo.class);
@@ -142,83 +160,58 @@ public abstract class AbstractSamlInHand
         throw ex != null ? new WebApplicationException(ex, response) : new WebApplicationException(response);
     }
     
-    // TODO: Most of this code can make it into rt/security to minimize the duplication
-    //       between ws/security and rs/security
-    
-    // WSSecurityEngineResult is HashMap extension and can be used as such
     /**
      * 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(
+        Message message,
         AssertionWrapper assertionWrapper,
-        List<WSSecurityEngineResult> signedResults,
         Certificate[] tlsCerts
     ) {
         //
         // If we have a 2-way TLS connection, then we don't have to check that the
-        // assertion + SOAP body are signed
+        // assertion + body are signed
+        
+        // If no body is available (ex, with GET) then consider validating that
+        // the base64-encoded token is signed by the same signature
         //
         if (tlsCerts != null && tlsCerts.length > 0) {
             return true;
         }
-        return false;
-//        List<String> confirmationMethods = assertionWrapper.getConfirmationMethods();
-//        for (String confirmationMethod : confirmationMethods) {
-//            if (OpenSAMLUtil.isMethodSenderVouches(confirmationMethod)) {
-//                if (signedResults == null || signedResults.isEmpty()) {
-//                    return false;
-//                }
-//                if (!checkAssertionAndBodyAreSigned(assertionWrapper)) {
-//                    return false;
-//                }
-//            }
-//        }
-//        return true;
+        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;
+                }
+            }
+        }
+        return true;
     }
     
-    private boolean checkBearer(AssertionWrapper assertionWrapper, Certificate[] tlsCerts)
{
-        
-        // Check Recipient attribute. Perhaps, if STS validator is injected, then it can
forward 
-        // this assertion to IDP which will confirm being Recipient 
-        
-        // It seems if we have a signed assertion and a payload then bearer may get validated
same
-        // way as sender-vouches.
-        
-        if (tlsCerts != null && tlsCerts.length > 0) {
-            return true;
-        } 
-        
-        
-        return false;
-        
-        
-        //List<String> confirmationMethods = assertionWrapper.getConfirmationMethods();
-        //      for (String confirmationMethod : confirmationMethods) {
-        //          if (isMethodBearer(confirmationMethod)) {
-        //
-        //          }
-        //      }
-        
-         
-    }
     
-    //private boolean isMethodBearer(String confirmMethod) {
-    //    return confirmMethod != null && confirmMethod.startsWith("urn:oasis:names:tc:SAML:")

-    //            && confirmMethod.endsWith(":cm:bearer");
-    //}
     
-    public boolean checkHolderOfKey(AssertionWrapper assertionWrapper,
-                                    List<WSSecurityEngineResult> signedResults,
+    public boolean checkHolderOfKey(Message message,
+                                    AssertionWrapper assertionWrapper,
                                     Certificate[] tlsCerts) {
         List<String> confirmationMethods = assertionWrapper.getConfirmationMethods();
         for (String confirmationMethod : confirmationMethods) {
             if (OpenSAMLUtil.isMethodHolderOfKey(confirmationMethod)) {
-                if (tlsCerts == null && (signedResults == null || signedResults.isEmpty()))
{
+                XMLSignature sig = message.getContent(XMLSignature.class);
+                if (tlsCerts == null || sig == null) {
                     return false;
                 }
                 SAMLKeyInfo subjectKeyInfo = assertionWrapper.getSubjectKeyInfo();
-                if (!compareCredentials(subjectKeyInfo, signedResults, tlsCerts)) {
+                if (!compareCredentials(subjectKeyInfo, sig, tlsCerts)) {
                     return false;
                 }
             }
@@ -236,12 +229,11 @@ public abstract class AbstractSamlInHand
      */
     private boolean compareCredentials(
         SAMLKeyInfo subjectKeyInfo,
-        List<WSSecurityEngineResult> signedResults,
+        XMLSignature sig,
         Certificate[] tlsCerts
     ) {
         X509Certificate[] subjectCerts = subjectKeyInfo.getCerts();
         PublicKey subjectPublicKey = subjectKeyInfo.getPublicKey();
-        byte[] subjectSecretKey = subjectKeyInfo.getSecret();
         
         //
         // Try to match the TLS certs first
@@ -257,13 +249,10 @@ public abstract class AbstractSamlInHand
         //
         // Now try the message-level signatures
         //
-        for (WSSecurityEngineResult signedResult : signedResults) {
+        try {
             X509Certificate[] certs =
-                (X509Certificate[])signedResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
-            PublicKey publicKey =
-                (PublicKey)signedResult.get(WSSecurityEngineResult.TAG_PUBLIC_KEY);
-            byte[] secretKey =
-                (byte[])signedResult.get(WSSecurityEngineResult.TAG_SECRET);
+                new X509Certificate[] {sig.getKeyInfo().getX509Certificate()};
+            PublicKey publicKey = sig.getKeyInfo().getPublicKey();
             if (certs != null && certs.length > 0 && subjectCerts != null
                 && subjectCerts.length > 0 && certs[0].equals(subjectCerts[0]))
{
                 return true;
@@ -271,33 +260,26 @@ public abstract class AbstractSamlInHand
             if (publicKey != null && publicKey.equals(subjectPublicKey)) {
                 return true;
             }
-            if (checkSecretKey(secretKey, subjectSecretKey, signedResult)) {
-                return true;
-            }
+        } catch (Exception ex) {
+            // ignore
         }
+        
         return false;
     }
     
-    private boolean checkSecretKey(
-        byte[] secretKey,
-        byte[] subjectSecretKey,
-        WSSecurityEngineResult signedResult
-    ) {
-        if (secretKey != null && subjectSecretKey != null 
-            && Arrays.equals(secretKey, subjectSecretKey)) {
-            return true;
-//            else {
-//                Principal principal =
-//                    (Principal)signedResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
-//                if (principal instanceof WSDerivedKeyTokenPrincipal) {
-//                    secretKey = ((WSDerivedKeyTokenPrincipal)principal).getSecret();
-//                    if (Arrays.equals(secretKey, subjectSecretKey)) {
-//                        return true;
-//                    }
-//                }
-//            }
+    private 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;
+            }
         }
-        return false;
+        return true;
     }
     
+    private boolean isMethodBearer(String confirmMethod) {
+        return confirmMethod != null && confirmMethod.startsWith("urn:oasis:names:tc:SAML:")

+                && confirmMethod.endsWith(":cm:bearer");
+    }
 }

Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java?rev=1165687&r1=1165686&r2=1165687&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java
(original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java
Tue Sep  6 14:38:36 2011
@@ -20,6 +20,8 @@ package org.apache.cxf.rs.security.saml;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.logging.Logger;
 
 import javax.security.auth.callback.CallbackHandler;
@@ -31,11 +33,18 @@ import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.rs.security.common.CryptoLoader;
 import org.apache.cxf.rs.security.common.SecurityUtils;
+import org.apache.cxf.rs.security.saml.assertion.Claim;
+import org.apache.cxf.rs.security.saml.assertion.Claims;
+import org.apache.cxf.rs.security.saml.assertion.Subject;
 import org.apache.cxf.ws.security.SecurityConstants;
 import org.apache.ws.security.WSPasswordCallback;
 import org.apache.ws.security.components.crypto.Crypto;
 import org.apache.ws.security.saml.ext.AssertionWrapper;
 import org.apache.ws.security.saml.ext.SAMLParms;
+import org.opensaml.saml2.core.Attribute;
+import org.opensaml.saml2.core.AttributeStatement;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.xml.XMLObject;
 
 public final class SAMLUtils {
     private static final Logger LOG = 
@@ -45,6 +54,43 @@ public final class SAMLUtils {
         
     }
     
+    public static Subject getSubject(Message message, AssertionWrapper assertionW) {
+        org.opensaml.saml2.core.Subject s = assertionW.getSaml2().getSubject();
+        Subject subject = new Subject();
+        NameID nameId = s.getNameID();
+        subject.setNameQualifier(nameId.getNameQualifier());
+        // if format is transient then we may need to use STSClient
+        // to request an alternate name from IDP
+        subject.setNameFormat(nameId.getFormat());
+        
+        subject.setName(nameId.getValue());
+        subject.setSpId(nameId.getSPProvidedID());
+        subject.setSpQualifier(nameId.getSPNameQualifier());
+        return subject;
+    }
+    
+    
+    public static Claims getClaims(AssertionWrapper assertionW) {
+        // Should we just do a simple DOM parsing without even relying on
+        // OpenSaml
+        List<Claim> claims = new ArrayList<Claim>();
+        List<AttributeStatement> statements = assertionW.getSaml2().getAttributeStatements();
+        for (AttributeStatement as : statements) {
+            for (Attribute atr : as.getAttributes()) {
+                Claim claim = new Claim();
+                claim.setName(atr.getName());
+                claim.setNameFormat(atr.getNameFormat());
+                claim.setFriendlyName(atr.getFriendlyName());
+                for (XMLObject o : atr.getAttributeValues()) {
+                    String attrValue = o.getDOM().getTextContent();
+                    claim.getValues().add(attrValue);
+                }
+                claims.add(claim);
+            }
+        }
+        return new Claims(claims);
+    }
+    
     public static AssertionWrapper createAssertion(Message message) throws Fault {
         CallbackHandler handler = SecurityUtils.getCallbackHandler(
              message, SAMLUtils.class, SecurityConstants.SAML_CALLBACK_HANDLER);

Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java?rev=1165687&r1=1165686&r2=1165687&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java
(original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java
Tue Sep  6 14:38:36 2011
@@ -94,11 +94,10 @@ public class SamlEnvelopedOutInterceptor
         root.appendChild(docEl);
 
         if (signLater) {
-            // it appears all the above manipulation with 
-            // adopting and removing nodes
-            // leaves some stale refs/state and thus the digest ends uo being wrong 
-            // on the server side if XML sig is applied later in the enveloped mode
-            // TODO: this is not critical now - but figure iut if we can avoid copying
+            // It appears adopting and removing nodes
+            // leaves some stale refs/state with adopted nodes and thus the digest ends up
+            // being wrong on the server side if XML sig is applied later in the enveloped
mode
+            // TODO: this is not critical now - but figure out if we can avoid copying
             // DOMs
             CachedOutputStream bos = new CachedOutputStream();
             DOMUtils.writeXml(newDoc, bos);

Added: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claim.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claim.java?rev=1165687&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claim.java
(added)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claim.java
Tue Sep  6 14:38:36 2011
@@ -0,0 +1,90 @@
+/**
+ * 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.rs.security.saml.assertion;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Claim {
+    public static final String DEFAULT_ROLE_NAME = 
+        "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"; 
+    public static final String DEFAULT_NAME_FORMAT = 
+        "http://schemas.xmlsoap.org/ws/2005/05/identity/claims";
+    
+    private String nameFormat;
+    private String name;
+    private String friendlyName;
+    
+    private List<String> values = new ArrayList<String>();
+
+    public Claim() {
+        
+    }
+    
+    public Claim(String nameFormat, String name) {
+        this.nameFormat = nameFormat;
+        this.name = name;        
+    }
+    
+    public Claim(String nameFormat, String name, String value) {
+        this(nameFormat, name, Collections.singletonList(value));        
+    }
+    
+    public Claim(String nameFormat, String name, List<String> values) {
+        this.nameFormat = nameFormat;
+        this.name = name;
+        this.values = values;
+    }
+    
+    public void setNameFormat(String nameFormat) {
+        this.nameFormat = nameFormat;
+    }
+
+    public String getNameFormat() {
+        return nameFormat;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setFriendlyName(String friendlyName) {
+        this.friendlyName = friendlyName;
+    }
+
+    public String getFriendlyName() {
+        return friendlyName;
+    }
+
+    public void setValues(List<String> values) {
+        this.values = values;
+    }
+
+    public List<String> getValues() {
+        return values;
+    }
+    
+    
+    
+}

Propchange: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claim.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claim.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claims.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claims.java?rev=1165687&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claims.java
(added)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claims.java
Tue Sep  6 14:38:36 2011
@@ -0,0 +1,62 @@
+/**
+ * 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.rs.security.saml.assertion;
+
+import java.util.List;
+
+public class Claims {
+
+    private List<Claim> claims;
+    
+    public Claims(List<Claim> claims) {
+        this.claims = claims;
+    }
+
+    public List<Claim> getClaims() {
+        return claims;
+    }
+    
+    public Claim findClaimByFriendlyName(String friendlyName) {
+        for (Claim c : claims) {
+            if (c.getFriendlyName().equals(friendlyName)) {
+                return c;
+            }
+        }
+        return null;
+    }
+   
+    public Claim findClaimByName(String name) {
+        for (Claim c : claims) {
+            if (c.getName().equals(name)) {
+                return c;
+            }
+        }
+        return null;
+    }
+    
+    public Claim findClaimByFormatAndName(String format, String name) {
+        for (Claim c : claims) {
+            if (c.getName().equals(name)
+                && c.getNameFormat().equals(format)) {
+                return c;
+            }
+        }
+        return null;
+    }
+}

Propchange: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claims.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Claims.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Subject.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Subject.java?rev=1165687&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Subject.java
(added)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Subject.java
Tue Sep  6 14:38:36 2011
@@ -0,0 +1,85 @@
+/**
+ * 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.rs.security.saml.assertion;
+
+public class Subject {
+    private String nameFormat;
+    private String nameQualifier;
+    private String name;
+    private String spQualifier;
+    private String spId;
+    
+    private String alternateName;
+    
+    public Subject() {
+        
+    }
+    
+    public Subject(String name) {
+        this.name = name;
+    }
+    
+    public Subject(String nameFormat, String name) {
+        this.nameFormat = nameFormat;
+        this.name = name;
+    }
+    
+    public void setNameFormat(String nameFormat) {
+        this.nameFormat = nameFormat;
+    }
+    public String getNameFormat() {
+        return nameFormat;
+    }
+    public void setNameQualifier(String nameQualifier) {
+        this.nameQualifier = nameQualifier;
+    }
+    public String getNameQualifier() {
+        return nameQualifier;
+    }
+    public void setName(String name) {
+        this.name = name;
+    }
+    public String getName() {
+        return name;
+    }
+
+    public void setSpId(String spId) {
+        this.spId = spId;
+    }
+
+    public String getSpId() {
+        return spId;
+    }
+
+    public void setSpQualifier(String spQualifier) {
+        this.spQualifier = spQualifier;
+    }
+
+    public String getSpQualifier() {
+        return spQualifier;
+    }
+
+    public void setAlternateName(String alternateName) {
+        this.alternateName = alternateName;
+    }
+
+    public String getAlternateName() {
+        return alternateName;
+    }
+}

Propchange: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Subject.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/assertion/Subject.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

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=1165687&r1=1165686&r2=1165687&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
Tue Sep  6 14:38:36 2011
@@ -49,11 +49,15 @@ import org.apache.xml.security.utils.Con
 public class XmlSigInHandler extends AbstractXmlSecInHandler implements RequestHandler {
     
     private boolean removeSignature = true;
+    private boolean persistSignature = true;
     
     public void setRemoveSignature(boolean remove) {
         this.removeSignature = remove;
     }
     
+    public void setPersistSignature(boolean persist) {
+        this.persistSignature = persist;
+    }
     
     public Response handleRequest(Message message, ClassResourceInfo resourceClass) {
         
@@ -105,6 +109,9 @@ public class XmlSigInHandler extends Abs
             // validate trust 
             new TrustValidator().validateTrust(crypto, cert, keyInfo.getPublicKey());
             
+            if (persistSignature) {
+                message.put(XMLSignature.class, signature);
+            }
         } catch (Exception ex) {
             throwFault("Signature validation failed", ex);
         }

Added: cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/authorization/ClaimsAuthorizingInterceptorTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/authorization/ClaimsAuthorizingInterceptorTest.java?rev=1165687&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/authorization/ClaimsAuthorizingInterceptorTest.java
(added)
+++ cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/authorization/ClaimsAuthorizingInterceptorTest.java
Tue Sep  6 14:38:36 2011
@@ -0,0 +1,283 @@
+/**
+ * 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.rs.security.saml.authorization;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cxf.interceptor.security.AccessDeniedException;
+import org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor;
+import org.apache.cxf.message.ExchangeImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.rs.security.saml.assertion.Subject;
+import org.apache.cxf.security.SecurityContext;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class ClaimsAuthorizingInterceptorTest extends Assert {
+
+    private ClaimsAuthorizingInterceptor interceptor;
+    
+    @Before
+    public void setUp() {
+        interceptor = new ClaimsAuthorizingInterceptor();
+        interceptor.setNameAliases(
+            Collections.singletonMap("authentication", "http://authentication"));
+        interceptor.setFormatAliases(
+                Collections.singletonMap("claims", "http://claims"));
+        interceptor.setSecuredObject(new TestService());
+        
+    }
+    
+    @Test
+    public void testClaimDefaultNameAndFormat() throws Exception {
+        doTestClaims("claimWithDefaultNameAndFormat",
+                createDefaultClaim("admin", "user"), 
+                createClaim("http://authentication", "http://claims", "password"));
+        try {
+            doTestClaims("claimWithDefaultNameAndFormat",
+                    createDefaultClaim("user"), 
+                    createClaim("http://authentication", "http://claims", "password"));
+            fail("AccessDeniedException expected");
+        } catch (AccessDeniedException ex) {
+            // expected
+        }
+    }
+    
+    @Test
+    public void testClaimMatchAll() throws Exception {
+        doTestClaims("claimMatchAll",
+                createDefaultClaim("admin", "manager"), 
+                createClaim("http://authentication", "http://claims", "password"));
+        try {
+            doTestClaims("claimMatchAll",
+                    createDefaultClaim("admin"), 
+                    createClaim("http://authentication", "http://claims", "password"));
+            doTestClaims("claimMatchAll",
+                    createDefaultClaim("manager"), 
+                    createClaim("http://authentication", "http://claims", "password"));
+            fail("AccessDeniedException expected");
+        } catch (AccessDeniedException ex) {
+            // expected
+        }
+    }
+    
+    @Test
+    public void testMissingExpectedClaim() throws Exception {
+        doTestClaims("claimWithDefaultNameAndFormat",
+                createDefaultClaim("admin"), 
+                createClaim("http://authentication", "http://claims", "password"));
+        try {
+            doTestClaims("claimWithDefaultNameAndFormat",
+                    createDefaultClaim("admin"));
+            fail("AccessDeniedException expected");
+        } catch (AccessDeniedException ex) {
+            // expected
+        }
+    }
+    
+    @Test
+    public void testExtraNonExpectedClaim() throws Exception {
+        doTestClaims("claimWithDefaultNameAndFormat",
+                     createDefaultClaim("admin", "user"), 
+                     createClaim("http://authentication", "http://claims", "password"),
+                     createClaim("http://extra/claims", "http://claims", "claim"));
+    }
+    
+    @Test
+    public void testClaimSpecificNameAndFormat() throws Exception {
+        doTestClaims("claimWithSpecificNameAndFormat",
+                createClaim("http://cxf/roles", "http://claims", "admin", "user"), 
+                createClaim("http://authentication", "http://claims", "password"));
+        try {
+            doTestClaims("claimWithSpecificNameAndFormat",
+                    createDefaultClaim("admin", "user"), 
+                    createClaim("http://authentication", "http://claims", "password"));
+            fail("AccessDeniedException expected");
+        } catch (AccessDeniedException ex) {
+            // expected
+        }
+    }
+    
+    @Test
+    public void testClaimLaxMode() throws Exception {
+        doTestClaims("claimLaxMode",
+                createClaim("http://authentication", "http://claims", "password"));
+        doTestClaims("claimLaxMode");
+        try {
+            doTestClaims("claimLaxMode",
+                         createClaim("http://authentication", "http://claims", "smartcard"));
+            fail("AccessDeniedException expected");
+        } catch (AccessDeniedException ex) {
+            // expected
+        }
+    }
+    
+    @Test
+    public void testMultipleClaims() throws Exception {
+        doTestClaims("multipleClaims", 
+                     createDefaultClaim("admin"),
+                     createClaim("http://authentication", "http://claims", "smartcard"),
+                     createClaim("http://location", "http://claims", "UK"));
+        doTestClaims("multipleClaims", 
+                createDefaultClaim("admin"),
+                createClaim("http://authentication", "http://claims", "password"),
+                createClaim("http://location", "http://claims", "USA"));
+        try {
+            doTestClaims("multipleClaims", 
+                    createDefaultClaim("admin"),
+                    createClaim("http://authentication", "http://claims", "unsecuretransport"),
+                    createClaim("http://location", "http://claims", "UK"));
+            fail("AccessDeniedException expected");
+        } catch (AccessDeniedException ex) {
+            // expected
+        }
+    }
+    
+    @Test
+    public void testUserInRoleAndClaims() throws Exception {
+        SecureAnnotationsInterceptor in = new SecureAnnotationsInterceptor();
+        in.setAnnotationClassName(SecureRole.class.getName());
+        in.setSecuredObject(new TestService2());
+        
+        Message m = prepareMessage(TestService2.class, "test", 
+                createDefaultClaim("admin"),
+                createClaim("a", "b", "c"));
+        
+        in.handleMessage(m);
+        
+        ClaimsAuthorizingInterceptor in2 = new ClaimsAuthorizingInterceptor();
+        org.apache.cxf.rs.security.saml.assertion.Claim claim =
+            new org.apache.cxf.rs.security.saml.assertion.Claim("a", "b", "c");
+        in2.setClaims(Collections.singletonMap("test", 
+                Collections.singletonList(
+                   new ClaimBean(claim))));
+        in2.handleMessage(m);
+        
+        try {
+            in.handleMessage(prepareMessage(TestService2.class, "test", 
+                    createDefaultClaim("user")));
+            fail("AccessDeniedException expected");
+        } catch (AccessDeniedException ex) {
+            // expected
+        }
+    }
+    
+    
+    private void doTestClaims(String methodName,
+            org.apache.cxf.rs.security.saml.assertion.Claim... claim) 
+        throws Exception {
+        Message m = prepareMessage(TestService.class, methodName, claim);
+        interceptor.handleMessage(m);
+    }
+    
+    private Message prepareMessage(Class<?> cls,
+            String methodName,
+            org.apache.cxf.rs.security.saml.assertion.Claim... claim) 
+        throws Exception {
+        List<org.apache.cxf.rs.security.saml.assertion.Claim> claims =
+            new ArrayList<org.apache.cxf.rs.security.saml.assertion.Claim>(Arrays.asList(claim));
+        SecurityContext sc = new SAMLSecurityContext(
+                new Subject("user"), claims);
+        Message m = new MessageImpl();
+        m.setExchange(new ExchangeImpl());
+        m.put(SecurityContext.class, sc);
+        m.put("org.apache.cxf.resource.method", 
+               cls.getMethod(methodName, new Class[]{}));
+        return m;
+    }
+    
+    private org.apache.cxf.rs.security.saml.assertion.Claim createDefaultClaim(
+            String... values) {
+        return createClaim(org.apache.cxf.rs.security.saml.assertion.Claim.DEFAULT_ROLE_NAME,

+                           org.apache.cxf.rs.security.saml.assertion.Claim.DEFAULT_NAME_FORMAT,

+                           values);
+    }
+    
+    private org.apache.cxf.rs.security.saml.assertion.Claim createClaim(
+            String name, String format, String... values) {
+        org.apache.cxf.rs.security.saml.assertion.Claim claim = 
+            new org.apache.cxf.rs.security.saml.assertion.Claim();
+        claim.setName(name);
+        claim.setNameFormat(format);
+        claim.setValues(Arrays.asList(values));
+        return claim;
+    }
+    
+    @Claim(name = "authentication", format = "claims", 
+           value = "password")
+    public static class TestService {
+        // default name and format are used
+        @Claim({"admin", "manager" })
+        public void claimWithDefaultNameAndFormat() {
+            
+        }
+        
+        // explicit name and format
+        @Claim(name = "http://cxf/roles", format = "http://claims", 
+               value = {"admin", "manager" })
+        public void claimWithSpecificNameAndFormat() {
+            
+        }
+        
+        @Claim(name = "http://authentication", format = "http://claims", 
+               value = "password", mode = ClaimMode.LAX)
+        public void claimLaxMode() {
+             
+        }
+        
+        @Claims({
+            @Claim(name = "http://location", format = "http://claims", 
+                    value = {"UK", "USA" }),
+            @Claim(value = {"admin", "manager" }),
+            @Claim(name = "authentication", format = "claims", 
+                           value = {"password", "smartcard" })
+        })
+        public void multipleClaims() {
+             
+        }
+        
+        // user must have both admin and manager roles, default is 'or'
+        @Claim(value = {"admin", "manager" },
+               matchAll = true)
+        public void claimMatchAll() {
+            
+        }
+    }
+    public static class TestService2 {
+        @SecureRole("admin")
+        public void test() {
+            
+        }
+    }
+    @Target(ElementType.METHOD)
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface SecureRole {
+        String[] value();
+    }
+}

Propchange: cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/authorization/ClaimsAuthorizingInterceptorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/rs/security/xml/src/test/java/org/apache/cxf/rs/security/saml/authorization/ClaimsAuthorizingInterceptorTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

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=1165687&r1=1165686&r2=1165687&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
Tue Sep  6 14:38:36 2011
@@ -29,9 +29,14 @@ import javax.security.auth.callback.Unsu
 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;
+import org.apache.ws.security.saml.ext.bean.AuthDecisionStatementBean;
+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.SubjectBean;
 import org.apache.ws.security.saml.ext.builder.SAML1Constants;
 import org.apache.ws.security.saml.ext.builder.SAML2Constants;
+import org.joda.time.DateTime;
 import org.opensaml.common.SAMLVersion;
 
 /**
@@ -62,7 +67,8 @@ public class SamlCallbackHandler impleme
                 } else {
                     callback.setSamlVersion(SAMLVersion.VERSION_11);
                 }
-                callback.setIssuer("sts");
+                callback.setIssuer("https://idp.example.org/SAML2");
+                
                 String subjectName = "uid=sts-client,o=mock-sts.com";
                 String subjectQualifier = "www.mock-sts.com";
                 if (!saml2 && SAML2Constants.CONF_SENDER_VOUCHES.equals(confirmationMethod))
{
@@ -72,13 +78,33 @@ public class SamlCallbackHandler impleme
                     new SubjectBean(
                         subjectName, subjectQualifier, confirmationMethod
                     );
+                // SubjectConfirmationData - not possible to set yet
                 callback.setSubject(subjectBean);
                 
+                ConditionsBean conditions = new ConditionsBean();
+                conditions.setAudienceURI("https://sp.example.com/SAML2");
+                callback.setConditions(conditions);
+                
+                AuthDecisionStatementBean authDecBean = new AuthDecisionStatementBean();
+                authDecBean.setDecision(Decision.INDETERMINATE);
+                callback.setAuthDecisionStatementData(Collections.singletonList(authDecBean));
+                
+                AuthenticationStatementBean authBean = new AuthenticationStatementBean();
+                authBean.setSubject(subjectBean);
+                authBean.setAuthenticationInstant(new DateTime());
+                authBean.setSessionIndex("123456");
+                // AuthnContextClassRef is not set
+                authBean.setAuthenticationMethod(
+                        "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport");
+                callback.setAuthenticationStatementData(
+                    Collections.singletonList(authBean));
+                
                 AttributeStatementBean attrBean = new AttributeStatementBean();
                 attrBean.setSubject(subjectBean);
                 
                 AttributeBean attributeBean = new AttributeBean();
                 attributeBean.setSimpleName("subject-role");
+                attributeBean.setQualifiedName("urn:oid:1.3.6.1.4.1.5923.1.1.1.1");
                 attributeBean.setAttributeValues(Collections.singletonList("system-user"));
                 attrBean.setSamlAttributes(Collections.singletonList(attributeBean));
                 callback.setAttributeStatementData(Collections.singletonList(attrBean));



Mime
View raw message