cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject svn commit: r1205892 - in /cxf/trunk/services/sts/sts-core/src: main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java main/java/org/apache/cxf/sts/token/realm/SAMLRealm.java test/java/org/apache/cxf/sts/operation/IssueSamlRealmUnitTest.java
Date Thu, 24 Nov 2011 15:49:19 GMT
Author: coheigea
Date: Thu Nov 24 15:49:18 2011
New Revision: 1205892

URL: http://svn.apache.org/viewvc?rev=1205892&view=rev
Log:
[CXF-3924] - Support to configure keystore per SAML realm
 - Patch applied, thanks.

Modified:
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/SAMLRealm.java
    cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlRealmUnitTest.java

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java?rev=1205892&r1=1205891&r2=1205892&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java
(original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java
Thu Nov 24 15:49:18 2011
@@ -28,6 +28,8 @@ import java.util.Properties;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.security.auth.callback.CallbackHandler;
+
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -35,6 +37,7 @@ import org.apache.cxf.common.logging.Log
 import org.apache.cxf.helpers.DOMUtils;
 import org.apache.cxf.sts.STSConstants;
 import org.apache.cxf.sts.STSPropertiesMBean;
+import org.apache.cxf.sts.SignatureProperties;
 import org.apache.cxf.sts.request.KeyRequirements;
 import org.apache.cxf.sts.request.TokenRequirements;
 import org.apache.cxf.sts.token.realm.SAMLRealm;
@@ -287,29 +290,41 @@ public class SAMLTokenProvider implement
         if (signToken) {
             STSPropertiesMBean stsProperties = tokenParameters.getStsProperties();
             
-            String alias = null;
+            // Initialise signature objects with defaults of STSPropertiesMBean
+            Crypto signatureCrypto = stsProperties.getSignatureCrypto();
+            CallbackHandler callbackHandler = stsProperties.getCallbackHandler();
+            SignatureProperties signatureProperties = stsProperties.getSignatureProperties();
+            String alias = stsProperties.getSignatureUsername();
+            
             if (samlRealm != null) {
-                alias = samlRealm.getSignatureAlias();
-            }
-            if (alias == null || "".equals(alias)) {
-                alias = stsProperties.getSignatureUsername();
-            }
-            if (alias == null || "".equals(alias)) {
-                Crypto signatureCrypto = stsProperties.getSignatureCrypto();
-                if (signatureCrypto != null) {
-                    alias = signatureCrypto.getDefaultX509Identifier();
-                    LOG.fine("Signature alias is null so using default alias: " + alias);
+                // If SignatureCrypto configured in realm then
+                // callbackhandler and alias of STSPropertiesMBean is ignored
+                if (samlRealm.getSignatureCrypto() != null) {
+                    LOG.fine("SAMLRealm signature keystore used");
+                    signatureCrypto = samlRealm.getSignatureCrypto();
+                    callbackHandler = samlRealm.getCallbackHandler();
+                    alias = samlRealm.getSignatureAlias();
+                }
+                // SignatureProperties can be defined independently of SignatureCrypto
+                if (samlRealm.getSignatureProperties() != null) {
+                    signatureProperties = samlRealm.getSignatureProperties();
                 }
+            } 
+            
+            // If alias not defined, get the default of the SignatureCrypto
+            if ((alias == null || "".equals(alias)) && (signatureCrypto != null))
{
+                alias = signatureCrypto.getDefaultX509Identifier();
+                LOG.fine("Signature alias is null so using default alias: " + alias);
             }
             // Get the password
             WSPasswordCallback[] cb = {new WSPasswordCallback(alias, WSPasswordCallback.SIGNATURE)};
             LOG.fine("Creating SAML Token");
-            stsProperties.getCallbackHandler().handle(cb);
+            callbackHandler.handle(cb);
             String password = cb[0].getPassword();
     
             LOG.fine("Signing SAML Token");
-            boolean useKeyValue = stsProperties.getSignatureProperties().isUseKeyValue();
-            assertion.signAssertion(alias, password, stsProperties.getSignatureCrypto(),
useKeyValue);
+            boolean useKeyValue = signatureProperties.isUseKeyValue();
+            assertion.signAssertion(alias, password, signatureCrypto, useKeyValue);
         }
         
         return assertion;

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/SAMLRealm.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/SAMLRealm.java?rev=1205892&r1=1205891&r2=1205892&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/SAMLRealm.java
(original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/SAMLRealm.java
Thu Nov 24 15:49:18 2011
@@ -19,15 +19,43 @@
 
 package org.apache.cxf.sts.token.realm;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.apache.cxf.resource.ResourceManager;
+import org.apache.cxf.sts.SignatureProperties;
+import org.apache.cxf.sts.StaticSTSProperties;
+import org.apache.cxf.ws.security.sts.provider.STSException;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.components.crypto.CryptoFactory;
+
 
 /**
  * This class defines some properties that are associated with a realm for the SAMLTokenProvider
and
  * SAMLTokenValidator.
  */
 public class SAMLRealm {
+    
+    private static final Logger LOG = LogUtils.getL7dLogger(SAMLRealm.class);
+    
     private String issuer;
     private String signatureAlias;
-
+    private Crypto signatureCrypto;
+    private SignatureProperties signatureProperties;
+    private String signaturePropertiesFile;
+    private String callbackHandlerClass;
+    private CallbackHandler callbackHandler;
+    
     /**
      * Get the issuer of this SAML realm
      * @return the issuer of this SAML realm
@@ -60,4 +88,151 @@ public class SAMLRealm {
         this.signatureAlias = signatureAlias;
     }
     
+    /**
+     * Set the signature Crypto object
+     * @param signatureCrypto the signature Crypto object
+     */
+    public void setSignatureCrypto(Crypto signatureCrypto) {
+        this.signatureCrypto = signatureCrypto;
+    }
+    
+    /**
+     * Set the String corresponding to the signature Properties class
+     * @param signaturePropertiesFile the String corresponding to the signature properties
file
+     */
+    public void setSignaturePropertiesFile(String signaturePropertiesFile) {
+        this.signaturePropertiesFile = signaturePropertiesFile;
+        LOG.fine("Setting signature properties: " + signaturePropertiesFile);
+    }
+    
+    /**
+     * Set the SignatureProperties to use.
+     * @param signatureProperties the SignatureProperties to use.
+     */
+    public void setSignatureProperties(SignatureProperties signatureProperties) {
+        this.signatureProperties = signatureProperties;
+    }
+    
+    /**
+     * Get the SignatureProperties to use.
+     * @return the SignatureProperties to use.
+     */
+    public SignatureProperties getSignatureProperties() {
+        return signatureProperties;
+    }
+    
+    
+    /**
+     * Get the signature Crypto object
+     * @return the signature Crypto object
+     */
+    public Crypto getSignatureCrypto() {
+        if (signatureCrypto == null && signaturePropertiesFile != null) {
+            Properties sigProperties = getProps(signaturePropertiesFile);
+            if (sigProperties == null) {
+                LOG.fine("Cannot load signature properties using: " + signaturePropertiesFile);
+                throw new STSException("Configuration error: cannot load signature properties");
+            }
+            try {
+                signatureCrypto = CryptoFactory.getInstance(sigProperties);
+            } catch (WSSecurityException ex) {
+                LOG.fine("Error in loading the signature Crypto object: " + ex.getMessage());
+                throw new STSException(ex.getMessage());
+            }
+        }
+        
+        return signatureCrypto;
+    }
+    
+    
+    /**
+     * Set the CallbackHandler object. 
+     * @param callbackHandler the CallbackHandler object. 
+     */
+    public void setCallbackHandler(CallbackHandler callbackHandler) {
+        this.callbackHandler = callbackHandler;
+        LOG.fine("Setting callbackHandler: " + callbackHandler);
+    }
+    
+    /**
+     * Set the String corresponding to the CallbackHandler class. 
+     * @param callbackHandlerClass the String corresponding to the CallbackHandler class.

+     */
+    public void setCallbackHandlerClass(String callbackHandlerClass) {
+        this.callbackHandlerClass = callbackHandlerClass;
+        LOG.fine("Setting callbackHandlerClass: " + callbackHandlerClass);
+    }
+    
+    /**
+     * Get the CallbackHandler object.
+     * @return the CallbackHandler object.
+     */
+    public CallbackHandler getCallbackHandler() {
+        if (callbackHandler == null && callbackHandlerClass != null) {
+            callbackHandler = getCallbackHandler(callbackHandlerClass);
+            if (callbackHandler == null) {
+                LOG.fine("Cannot load CallbackHandler using: " + callbackHandlerClass);
+                throw new STSException("Configuration error: cannot load callback handler");
+            }
+        }
+        return callbackHandler;
+    }
+    
+    private static Properties getProps(Object o) {
+        Properties properties = null;
+        if (o instanceof Properties) {
+            properties = (Properties)o;
+        } else if (o instanceof String) {
+            URL url = null;
+            Bus bus = PhaseInterceptorChain.getCurrentMessage().getExchange().getBus();
+            ResourceManager rm = bus.getExtension(ResourceManager.class);
+            url = rm.resolveResource((String)o, URL.class);
+            try {
+                if (url == null) {
+                    url = ClassLoaderUtils.getResource((String)o, StaticSTSProperties.class);
+                }
+                if (url == null) {
+                    url = new URL((String)o);
+                }
+                if (url != null) {
+                    properties = new Properties();
+                    InputStream ins = url.openStream();
+                    properties.load(ins);
+                    ins.close();
+                }
+            } catch (IOException e) {
+                LOG.fine(e.getMessage());
+                properties = null;
+            }
+        } else if (o instanceof URL) {
+            properties = new Properties();
+            try {
+                InputStream ins = ((URL)o).openStream();
+                properties.load(ins);
+                ins.close();
+            } catch (IOException e) {
+                LOG.fine(e.getMessage());
+                properties = null;
+            }            
+        }
+        return properties;
+    }
+    
+    private CallbackHandler getCallbackHandler(Object o) {
+        CallbackHandler handler = null;
+        if (o instanceof CallbackHandler) {
+            handler = (CallbackHandler)o;
+        } else if (o instanceof String) {
+            try {
+                handler = 
+                    (CallbackHandler)ClassLoaderUtils.loadClass((String)o, this.getClass()).newInstance();
+            } catch (Exception e) {
+                LOG.fine(e.getMessage());
+                handler = null;
+            }
+        }
+        return handler;
+    }
+    
+    
 }

Modified: cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlRealmUnitTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlRealmUnitTest.java?rev=1205892&r1=1205891&r2=1205892&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlRealmUnitTest.java
(original)
+++ cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlRealmUnitTest.java
Thu Nov 24 15:49:18 2011
@@ -47,6 +47,7 @@ import org.apache.cxf.sts.service.Static
 import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
 import org.apache.cxf.sts.token.provider.TokenProvider;
 import org.apache.cxf.sts.token.realm.SAMLRealm;
+import org.apache.cxf.ws.security.sts.provider.STSException;
 import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenResponseCollectionType;
 import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenResponseType;
 import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenType;
@@ -297,6 +298,187 @@ public class IssueSamlRealmUnitTest exte
         assertTrue(tokenString.contains("STS"));
     }
     
+    
+    /**
+     * Test to successfully issue a Saml 1.1 token in realm "B"
+     * using crypto definition in SAMLRealm
+     */
+    @org.junit.Test
+    public void testIssueSaml1TokenRealmBCustomCrypto() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+        
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        SAMLTokenProvider provider = new SAMLTokenProvider();
+        provider.setRealmMap(createRealms());
+        providerList.add(provider);
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+        
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        stsProperties.setRealmParser(new CustomRealmParser());
+        issueOperation.setStsProperties(stsProperties);
+        
+        // Set signature properties in SAMLRealm B
+        Map<String, SAMLRealm> samlRealms = provider.getRealmMap();
+        SAMLRealm realm = samlRealms.get("B");
+        realm.setSignatureCrypto(crypto);
+        realm.setCallbackHandler(new PasswordCallbackHandler());
+        
+        
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy"));
+        
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        msgCtx.put("url", "https");
+        msgCtx.put(
+            SecurityContext.class.getName(), 
+            createSecurityContext(new CustomTokenPrincipal("alice"))
+        );
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+        
+        // Issue a token - this will fail as the SAMLRealm configuration is inconsistent
+        // no signature alias defined
+        try {
+            issueOperation.issue(request, webServiceContext);
+            fail("Failure expected on no encryption name");
+        } catch (STSException ex) {
+            // expected
+        }
+        
+        realm.setSignatureAlias("mystskey");
+        
+        // Issue a token
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponse = 
+            response.getRequestSecurityTokenResponse();
+        assertTrue(!securityTokenResponse.isEmpty());
+        
+        // Test the generated token.
+        Element assertion = null;
+        for (Object tokenObject : securityTokenResponse.get(0).getAny()) {
+            if (tokenObject instanceof JAXBElement<?>
+                && REQUESTED_SECURITY_TOKEN.equals(((JAXBElement<?>)tokenObject).getName()))
{
+                RequestedSecurityTokenType rstType = 
+                    (RequestedSecurityTokenType)((JAXBElement<?>)tokenObject).getValue();
+                assertion = (Element)rstType.getAny();
+                break;
+            }
+        }
+        
+        assertNotNull(assertion);
+        String tokenString = DOM2Writer.nodeToString(assertion);
+        assertFalse(tokenString.contains("A-Issuer"));
+        assertTrue(tokenString.contains("B-Issuer"));
+        assertFalse(tokenString.contains("STS"));
+    }
+    
+    
+    /**
+     * Test to successfully issue a Saml 1.1 token in realm "B"
+     * using PKCS12 crypto definition with default key in SAMLRealm
+     */
+    @org.junit.Test
+    public void testIssueSaml1TokenRealmBCustomCryptoPKCS12() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+        
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        SAMLTokenProvider provider = new SAMLTokenProvider();
+        provider.setRealmMap(createRealms());
+        providerList.add(provider);
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+        
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        stsProperties.setRealmParser(new CustomRealmParser());
+        issueOperation.setStsProperties(stsProperties);
+        
+        // Set signature properties in SAMLRealm B
+        Map<String, SAMLRealm> samlRealms = provider.getRealmMap();
+        SAMLRealm realm = samlRealms.get("B");
+        realm.setSignatureCrypto(CryptoFactory.getInstance(getEncryptionPropertiesPKCS12()));
+        realm.setCallbackHandler(new PasswordCallbackHandler());
+        
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy"));
+        
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        msgCtx.put("url", "https");
+        msgCtx.put(
+            SecurityContext.class.getName(), 
+            createSecurityContext(new CustomTokenPrincipal("alice"))
+        );
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+        
+        // Issue a token
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponse = 
+            response.getRequestSecurityTokenResponse();
+        assertTrue(!securityTokenResponse.isEmpty());
+        
+        // Test the generated token.
+        Element assertion = null;
+        for (Object tokenObject : securityTokenResponse.get(0).getAny()) {
+            if (tokenObject instanceof JAXBElement<?>
+                && REQUESTED_SECURITY_TOKEN.equals(((JAXBElement<?>)tokenObject).getName()))
{
+                RequestedSecurityTokenType rstType = 
+                    (RequestedSecurityTokenType)((JAXBElement<?>)tokenObject).getValue();
+                assertion = (Element)rstType.getAny();
+                break;
+            }
+        }
+        
+        assertNotNull(assertion);
+        String tokenString = DOM2Writer.nodeToString(assertion);
+        assertFalse(tokenString.contains("A-Issuer"));
+        assertTrue(tokenString.contains("B-Issuer"));
+        assertFalse(tokenString.contains("STS"));
+    }
+    
+    
     /**
      * Create some SAML Realms
      */
@@ -354,5 +536,18 @@ public class IssueSamlRealmUnitTest exte
         return properties;
     }
     
+    private Properties getEncryptionPropertiesPKCS12() {
+        Properties properties = new Properties();
+        properties.put(
+            "org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin"
+        );
+        properties.put("org.apache.ws.security.crypto.merlin.keystore.password", "security");
+        properties.put("org.apache.ws.security.crypto.merlin.keystore.file", "x509.p12");
+        properties.put("org.apache.ws.security.crypto.merlin.keystore.type", "pkcs12");
+        properties.put("org.apache.ws.security.crypto.merlin.keystore.private.password",
"security");
+        
+        return properties;
+    }
+    
     
 }



Mime
View raw message