From c297508e7e3b4e69c0824a6faa846ab1e54cd9b1 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Tue, 11 Oct 2016 16:52:42 +0200 Subject: [PATCH 1/2] CXF-7084 Add a configurable KeyName value using the properties --- .../rs/security/xml/EncryptionProperties.java | 10 ++++++++- .../rs/security/xml/SignatureProperties.java | 10 ++++++++- .../rs/security/xml/XmlSecOutInterceptor.java | 10 +++++++-- .../cxf/rt/security/SecurityConstants.java | 22 ++++++++++++++++--- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/EncryptionProperties.java b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/EncryptionProperties.java index 06d3e111ecc..6b01ced823d 100644 --- a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/EncryptionProperties.java +++ b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/EncryptionProperties.java @@ -25,6 +25,7 @@ public class EncryptionProperties { private String encryptionSymmetricKeyAlgo; private String encryptionDigestAlgo; private String encryptionKeyIdType; + private String encryptionKeyName; public void setEncryptionKeyTransportAlgo(String encryptionKeyTransportAlgo) { this.encryptionKeyTransportAlgo = encryptionKeyTransportAlgo; @@ -50,5 +51,12 @@ public void setEncryptionKeyIdType(String encryptionKeyIdType) { public String getEncryptionKeyIdType() { return encryptionKeyIdType; } - + + public String getEncryptionKeyName() { + return encryptionKeyName; + } + + public void setEncryptionKeyName(String encryptionKeyName) { + this.encryptionKeyName = encryptionKeyName; + } } diff --git a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/SignatureProperties.java b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/SignatureProperties.java index f8a79803a76..21d2d8ca681 100644 --- a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/SignatureProperties.java +++ b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/SignatureProperties.java @@ -24,6 +24,7 @@ public class SignatureProperties { private String signatureC14nMethod; private String signatureC14nTransform; private String signatureKeyIdType; + private String signatureKeyName; public void setSignatureAlgo(String signatureAlgo) { this.signatureAlgo = signatureAlgo; @@ -71,5 +72,12 @@ public String getSignatureKeyIdType() { public void setSignatureKeyIdType(String signatureKeyIdType) { this.signatureKeyIdType = signatureKeyIdType; } - + + public String getSignatureKeyName() { + return signatureKeyName; + } + + public void setSignatureKeyName(String signatureKeyName) { + this.signatureKeyName = signatureKeyName; + } } diff --git a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSecOutInterceptor.java b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSecOutInterceptor.java index 1f5193d8886..28b8fd9a9ad 100644 --- a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSecOutInterceptor.java +++ b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSecOutInterceptor.java @@ -48,6 +48,7 @@ import org.apache.cxf.rs.security.common.CryptoLoader; import org.apache.cxf.rs.security.common.RSSecurityUtils; import org.apache.cxf.rt.security.SecurityConstants; +import org.apache.cxf.rt.security.utils.SecurityUtils; import org.apache.wss4j.common.crypto.Crypto; import org.apache.wss4j.common.ext.WSPasswordCallback; import org.apache.wss4j.common.ext.WSSecurityException; @@ -160,8 +161,7 @@ private void configureEncryption(Message message, XMLSecurityProperties properti if (encryptSymmetricKey) { X509Certificate sendingCert = null; String userName = - (String)org.apache.cxf.rt.security.utils.SecurityUtils.getSecurityPropertyValue( - SecurityConstants.ENCRYPT_USERNAME, message); + (String)SecurityUtils.getSecurityPropertyValue(SecurityConstants.ENCRYPT_USERNAME, message); if (RSSecurityUtils.USE_REQUEST_SIGNATURE_CERT.equals(userName) && !MessageUtils.isRequestor(message)) { sendingCert = @@ -193,6 +193,10 @@ private void configureEncryption(Message message, XMLSecurityProperties properti properties.setEncryptionKeyIdentifier( convertKeyIdentifier(encryptionProperties.getEncryptionKeyIdType())); + + String keyName = + (String)SecurityUtils.getSecurityPropertyValue(SecurityConstants.SIGNATURE_KEYNAME, message); + properties.setEncryptionKeyName(keyName == null ? encryptionProperties.getEncryptionKeyName() : keyName); if (encryptionProperties.getEncryptionKeyTransportAlgo() != null) { properties.setEncryptionKeyTransportAlgorithm( @@ -276,6 +280,7 @@ private void configureSignature( SecurityConstants.SIGNATURE_CRYPTO, SecurityConstants.SIGNATURE_PROPERTIES); String user = RSSecurityUtils.getUserName(message, crypto, userNameKey); + String keyName = RSSecurityUtils.getUserName(message, crypto, SecurityConstants.SIGNATURE_KEYNAME); if (StringUtils.isEmpty(user) || RSSecurityUtils.USE_REQUEST_SIGNATURE_CERT.equals(user)) { throw new Exception("User name is not available"); @@ -313,6 +318,7 @@ private void configureSignature( if (this.keyInfoMustBeAvailable) { properties.setSignatureKeyIdentifier( convertKeyIdentifier(sigProps.getSignatureKeyIdType())); + properties.setSignatureKeyName(keyName == null ? sigProps.getSignatureKeyName() : keyName); } else { properties.setSignatureKeyIdentifier(SecurityTokenConstants.KeyIdentifier_NoKeyInfo); } diff --git a/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java b/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java index 5ee526b21ac..d6f4962044e 100644 --- a/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java +++ b/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java @@ -336,9 +336,25 @@ public class SecurityConstants { */ public static final String STS_TOKEN_IMMINENT_EXPIRY_VALUE = "security.sts.token.imminent-expiry-value"; - + + /** + * This is a string that will be passed in the KeyInfo/KeyName field of the security + * header identifying the key to use for signature verification. This is a custom string + * so it needs to be supplied during configuration or at request time. The definition and + * interpretation of the content is a responsibility of higher layers. + */ + public static final String SIGNATURE_KEYNAME = "security.signature.keyname"; + + /** + * This is a string that will be passed in the KeyInfo/KeyName field of the security + * header identifying the key to use for de/encryption. This is a custom string so it + * needs to be supplied during configuration or at request time. The definition and + * interpretation of the content is a responsibility of higher layers. + */ + public static final String ENCRYPTION_KEYNAME = "security.encryption.keyname"; + public static final Set COMMON_PROPERTIES; - + static { Set s = new HashSet<>(Arrays.asList(new String[] { USERNAME, PASSWORD, SIGNATURE_USERNAME, ENCRYPT_USERNAME, @@ -351,7 +367,7 @@ public class SecurityConstants { DISABLE_STS_CLIENT_WSMEX_CALL_USING_EPR_ADDRESS, STS_TOKEN_CRYPTO, STS_TOKEN_PROPERTIES, STS_TOKEN_USERNAME, STS_TOKEN_ACT_AS, STS_TOKEN_ON_BEHALF_OF, STS_CLIENT, STS_APPLIES_TO, CACHE_ISSUED_TOKEN_IN_ENDPOINT, PREFER_WSMEX_OVER_STS_CLIENT_CONFIG, - STS_TOKEN_IMMINENT_EXPIRY_VALUE + STS_TOKEN_IMMINENT_EXPIRY_VALUE, SIGNATURE_KEYNAME, ENCRYPTION_KEYNAME })); COMMON_PROPERTIES = Collections.unmodifiableSet(s); } From 2562213e6c8710201a70e9dd40374af5521a9607 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Tue, 11 Oct 2016 18:45:02 +0200 Subject: [PATCH 2/2] CXF-7086 Use a map of KeyName and aliases to fill the KeyName lookup map in the XMLSecurityProperties --- .../rs/security/common/RSSecurityUtils.java | 27 ++++++++++++++ .../rs/security/xml/XmlSecInInterceptor.java | 35 ++++++++++++++++++- .../cxf/rt/security/SecurityConstants.java | 10 +++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/RSSecurityUtils.java b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/RSSecurityUtils.java index 34f6bea9a8a..8330328e99b 100644 --- a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/RSSecurityUtils.java +++ b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/RSSecurityUtils.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.math.BigInteger; import java.security.cert.X509Certificate; +import java.util.Map; import javax.security.auth.callback.CallbackHandler; @@ -165,5 +166,31 @@ public static CallbackHandler getCallbackHandler(Message message, throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex); } } + + public static String getAliasForKeyName(Message message, String keyName) throws WSSecurityException { + Object o = SecurityUtils.getSecurityPropertyValue(SecurityConstants.KEYNAME_LOOKUP_MAP, message); + if (o == null) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "stax.keyNotFoundForName", + new Object[] {keyName}); + } + + Map lookupMap = (Map)o; + String keyAlias = null; + if (lookupMap.containsKey(keyName)) { + keyAlias = lookupMap.get(keyName); + } + + if (keyAlias == null) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "stax.keyNotFoundForName", + new Object[] {keyName}); + } + + return keyAlias; + } + + public static Map getKeyNameAliasLookupMap(Message message) { + return (Map)SecurityUtils. + getSecurityPropertyValue(SecurityConstants.KEYNAME_LOOKUP_MAP, message); + } } diff --git a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSecInInterceptor.java b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSecInInterceptor.java index 98b9eb8a99e..f6ff9c43b54 100644 --- a/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSecInInterceptor.java +++ b/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSecInInterceptor.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -61,6 +62,7 @@ import org.apache.xml.security.stax.ext.XMLSec; import org.apache.xml.security.stax.ext.XMLSecurityConstants; import org.apache.xml.security.stax.ext.XMLSecurityProperties; +import org.apache.xml.security.stax.impl.securityToken.KeyNameSecurityToken; import org.apache.xml.security.stax.securityEvent.AlgorithmSuiteSecurityEvent; import org.apache.xml.security.stax.securityEvent.SecurityEvent; import org.apache.xml.security.stax.securityEvent.SecurityEventConstants; @@ -206,6 +208,17 @@ private void configureSignatureKeys( if (certs != null && certs.length > 0) { properties.setSignatureVerificationKey(certs[0].getPublicKey()); } + } else if (sigCrypto != null) { + Map keyNameAliasMap = RSSecurityUtils.getKeyNameAliasLookupMap(message); + for (Map.Entry mapping: keyNameAliasMap.entrySet()) { + CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS); + cryptoType.setAlias(mapping.getValue()); + X509Certificate[] certs = sigCrypto.getX509Certificates(cryptoType); + if (certs != null && certs.length > 0) { + properties.getKeyNameMap().put(mapping.getKey(), certs[0].getPublicKey()); + } + } + } } @@ -290,6 +303,11 @@ private void checkSignatureTrust( SecurityToken token = event.getSecurityToken(); if (token != null) { X509Certificate[] certs = token.getX509Certificates(); + + if (certs == null && token.getPublicKey() == null && token instanceof KeyNameSecurityToken) { + certs = getX509CertificatesForKeyName(sigCrypto, msg, (KeyNameSecurityToken)token); + } + PublicKey publicKey = token.getPublicKey(); X509Certificate cert = null; if (certs != null && certs.length > 0) { @@ -310,7 +328,22 @@ private void checkSignatureTrust( } } } - + + private X509Certificate[] getX509CertificatesForKeyName(Crypto sigCrypto, Message msg, KeyNameSecurityToken token) + throws XMLSecurityException { + X509Certificate[] certs; + KeyNameSecurityToken keyNameSecurityToken = token; + String keyName = keyNameSecurityToken.getKeyName(); + String alias = RSSecurityUtils.getAliasForKeyName(msg, keyName); + try { + certs = RSSecurityUtils.getCertificates(sigCrypto, alias); + } catch (Exception e) { + throw new XMLSecurityException("empty", new Object[] {"Error during Signature Trust " + + "validation: " + e.getMessage()}); + } + return certs; + } + protected void throwFault(String error, Exception ex) { LOG.warning(error); Response response = JAXRSUtils.toResponseBuilder(400).entity(error).build(); diff --git a/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java b/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java index d6f4962044e..dda9f21a8cb 100644 --- a/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java +++ b/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java @@ -353,6 +353,14 @@ public class SecurityConstants { */ public static final String ENCRYPTION_KEYNAME = "security.encryption.keyname"; + /** + * This is a map containing mappings from KeyName to alias. This needs to be used + * then KeyInfo/KeyName is used so the inbound handler can determine which key to use + * for signature verification or decryption. + */ + public static final String KEYNAME_LOOKUP_MAP = "security.keyname.mapping"; + + public static final Set COMMON_PROPERTIES; static { @@ -367,7 +375,7 @@ public class SecurityConstants { DISABLE_STS_CLIENT_WSMEX_CALL_USING_EPR_ADDRESS, STS_TOKEN_CRYPTO, STS_TOKEN_PROPERTIES, STS_TOKEN_USERNAME, STS_TOKEN_ACT_AS, STS_TOKEN_ON_BEHALF_OF, STS_CLIENT, STS_APPLIES_TO, CACHE_ISSUED_TOKEN_IN_ENDPOINT, PREFER_WSMEX_OVER_STS_CLIENT_CONFIG, - STS_TOKEN_IMMINENT_EXPIRY_VALUE, SIGNATURE_KEYNAME, ENCRYPTION_KEYNAME + STS_TOKEN_IMMINENT_EXPIRY_VALUE, SIGNATURE_KEYNAME, ENCRYPTION_KEYNAME, KEYNAME_LOOKUP_MAP })); COMMON_PROPERTIES = Collections.unmodifiableSet(s); }