You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by co...@apache.org on 2016/11/08 17:26:39 UTC

svn commit: r1768742 - in /santuario/xml-security-java/branches/2.0.x-fixes/src: main/java/org/apache/xml/security/resource/ main/java/org/apache/xml/security/stax/ext/ main/java/org/apache/xml/security/stax/impl/securityToken/ test/java/org/apache/xml...

Author: coheigea
Date: Tue Nov  8 17:26:39 2016
New Revision: 1768742

URL: http://svn.apache.org/viewvc?rev=1768742&view=rev
Log:
SANTUARIO-453 - Support selection of a signature validation certificate based on KeyName
 - Thanks to Hugo Trippaers for the patch.
 - This closes #8.

Added:
    santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/stax/
    santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/stax/impl/
    santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/stax/impl/securityToken/
    santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImplTest.java
    santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/stax/utils/KeyLoader.java
Modified:
    santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_de.properties
    santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_en.properties
    santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java
    santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImpl.java
    santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/dom/keys/keyresolver/DEREncodedKeyValueResolverTest.java

Modified: santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_de.properties
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_de.properties?rev=1768742&r1=1768741&r2=1768742&view=diff
==============================================================================
--- santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_de.properties [iso-8859-1] (original)
+++ santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_de.properties [iso-8859-1] Tue Nov  8 17:26:39 2016
@@ -186,4 +186,6 @@ stax.namedCurveMissing = NamedCurve fehl
 stax.encryption.securePartNotFound = Part zum Verschl\u00fcsseln nicht gefunden: {0}
 stax.signature.securePartNotFound = Part zum Signieren nicht gefunden: {0}
 stax.multipleSignaturesNotSupported = Mehrere Signaturen werden nicht unterstützt.
-stax.signature.keyNameMissing = KeyName nicht konfiguriert.
\ No newline at end of file
+stax.signature.keyNameMissing = KeyName nicht konfiguriert.
+stax.keyNotFoundForName = Kein Schl\u00fcssel für Schl\u00fcsselname konfiguriert: {0}
+stax.keyTypeNotSupported = Key vom Typ {0} nicht f\u00fcr einen Key-Namenssuche unterst\u00fctzt
\ No newline at end of file

Modified: santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_en.properties
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_en.properties?rev=1768742&r1=1768741&r2=1768742&view=diff
==============================================================================
--- santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_en.properties [iso-8859-1] (original)
+++ santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/resource/xmlsecurity_en.properties [iso-8859-1] Tue Nov  8 17:26:39 2016
@@ -186,4 +186,6 @@ stax.namedCurveMissing = NamedCurve is m
 stax.encryption.securePartNotFound = Part to encrypt not found: {0}
 stax.signature.securePartNotFound = Part to sign not found: {0}
 stax.multipleSignaturesNotSupported = Multiple signatures are not supported.
-stax.signature.keyNameMissing = KeyName not configured.
\ No newline at end of file
+stax.signature.keyNameMissing = KeyName not configured.
+stax.keyNotFoundForName = No key configured for KeyName: {0}
+stax.keyTypeNotSupported = Key of type {0} not supported for a KeyName lookup
\ No newline at end of file

Modified: santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java?rev=1768742&r1=1768741&r2=1768742&view=diff
==============================================================================
--- santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java (original)
+++ santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java Tue Nov  8 17:26:39 2016
@@ -22,9 +22,7 @@ import org.apache.xml.security.stax.secu
 
 import java.security.Key;
 import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
 
 import javax.xml.namespace.QName;
 
@@ -74,6 +72,8 @@ public class XMLSecurityProperties {
     private int signaturePosition = 0;
 
     private QName idAttributeNS = XMLSecurityConstants.ATT_NULL_Id;
+
+    private final Map<String, Key> keyNameMap = new HashMap<String, Key>();
     
     public XMLSecurityProperties() {
     }
@@ -108,6 +108,7 @@ public class XMLSecurityProperties {
         this.idAttributeNS = xmlSecurityProperties.idAttributeNS;
         this.signatureKeyName = xmlSecurityProperties.signatureKeyName;
         this.encryptionKeyName = xmlSecurityProperties.encryptionKeyName;
+        this.keyNameMap.putAll(xmlSecurityProperties.keyNameMap);
     }
 
     public SecurityTokenConstants.KeyIdentifier getSignatureKeyIdentifier() {
@@ -450,4 +451,18 @@ public class XMLSecurityProperties {
     public void setEncryptionKeyName(String encryptionKeyName) {
         this.encryptionKeyName = encryptionKeyName;
     }
+
+    /**
+     * returns an immutable instance of the map that links KeyName values to actual keys
+     *
+     * @return keyNameMap set to the map containing KeyNames and Keys
+     */
+    public Map<String, Key> getKeyNameMap() {
+        return Collections.unmodifiableMap(keyNameMap);
+    }
+
+    public void addKeyNameMapping(String keyname, Key key) {
+        keyNameMap.put(keyname, key);
+    }
+
 }

Modified: santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImpl.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImpl.java?rev=1768742&r1=1768741&r2=1768742&view=diff
==============================================================================
--- santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImpl.java (original)
+++ santuario/xml-security-java/branches/2.0.x-fixes/src/main/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImpl.java Tue Nov  8 17:26:39 2016
@@ -36,6 +36,7 @@ import java.security.PublicKey;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.util.Map;
 
 /**
  * Factory to create SecurityToken Objects from keys in XML
@@ -72,9 +73,7 @@ public class SecurityTokenFactoryImpl ex
             final String keyName =
                     XMLSecurityUtils.getQNameType(keyInfoType.getContent(), XMLSecurityConstants.TAG_dsig_KeyName);
             if (keyName != null) {
-                KeyNameSecurityToken token =
-                        new KeyNameSecurityToken(keyName, inboundSecurityContext);
-                setTokenKey(securityProperties, keyUsage, token);
+                KeyNameSecurityToken token = getSecurityToken(keyName, securityProperties, inboundSecurityContext, keyUsage);
                 return token;
             }
         }
@@ -82,33 +81,53 @@ public class SecurityTokenFactoryImpl ex
         // Use a default key if it exists
         if (SecurityTokenConstants.KeyUsage_Signature_Verification.equals(keyUsage)
                 && securityProperties.getSignatureVerificationKey() != null) {
-            AbstractInboundSecurityToken token =
-                    new AbstractInboundSecurityToken(inboundSecurityContext, IDGenerator.generateID(null),
-                            SecurityTokenConstants.KeyIdentifier_NoKeyInfo, false) {
-                        @Override
-                        public TokenType getTokenType() {
-                            return SecurityTokenConstants.DefaultToken;
-                        }
-                    };
-            setTokenKey(securityProperties, keyUsage, token);
-            return token;
+            return getDefaultSecurityToken(securityProperties, inboundSecurityContext, keyUsage);
         } else if (SecurityTokenConstants.KeyUsage_Decryption.equals(keyUsage)
                 && securityProperties.getDecryptionKey() != null) {
-            AbstractInboundSecurityToken token =
-                    new AbstractInboundSecurityToken(inboundSecurityContext, IDGenerator.generateID(null),
-                            SecurityTokenConstants.KeyIdentifier_NoKeyInfo, false) {
-                        @Override
-                        public TokenType getTokenType() {
-                            return SecurityTokenConstants.DefaultToken;
-                        }
-                    };
-            setTokenKey(securityProperties, keyUsage, token);
-            return token;
+            return getDefaultSecurityToken(securityProperties, inboundSecurityContext, keyUsage);
         }
 
         throw new XMLSecurityException("stax.noKey", new Object[] {keyUsage});
     }
 
+    private InboundSecurityToken getDefaultSecurityToken(XMLSecurityProperties securityProperties, final InboundSecurityContext inboundSecurityContext, SecurityTokenConstants.KeyUsage keyUsage) {
+        AbstractInboundSecurityToken token =
+                new AbstractInboundSecurityToken(inboundSecurityContext, IDGenerator.generateID(null),
+                        SecurityTokenConstants.KeyIdentifier_NoKeyInfo, false) {
+                    @Override
+                    public TokenType getTokenType() {
+                        return SecurityTokenConstants.DefaultToken;
+                    }
+                };
+        setTokenKey(securityProperties, keyUsage, token);
+        return token;
+    }
+
+    private KeyNameSecurityToken getSecurityToken(String keyName, XMLSecurityProperties securityProperties, InboundSecurityContext inboundSecurityContext,
+            SecurityTokenConstants.KeyUsage keyUsage) throws XMLSecurityException {
+        KeyNameSecurityToken token =
+                new KeyNameSecurityToken(keyName, inboundSecurityContext);
+
+        // This if is here to preserve the current behaviour when the SignatureVerificationKey is set
+        if (SecurityTokenConstants.KeyUsage_Signature_Verification.equals(keyUsage)
+                && securityProperties.getSignatureVerificationKey() == null) {
+            Map<String, Key> keyNameMap = securityProperties.getKeyNameMap();
+            Key key = keyNameMap.get(keyName);
+            if (key == null) {
+                throw new XMLSecurityException("stax.keyNotFoundForName", new Object[] {keyName});
+            }
+
+            if (key instanceof PublicKey) {
+                token.setPublicKey((PublicKey)key);
+            } else {
+                throw new XMLSecurityException("stax.keyTypeNotSupported", new Object[] {key.getClass().getSimpleName()});
+            }
+        }
+
+        setTokenKey(securityProperties, keyUsage, token);
+        return token;
+    }
+
     private static InboundSecurityToken getSecurityToken(KeyValueType keyValueType,
             XMLSecurityProperties securityProperties,
             InboundSecurityContext inboundSecurityContext,

Added: santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImplTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImplTest.java?rev=1768742&view=auto
==============================================================================
--- santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImplTest.java (added)
+++ santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/stax/impl/securityToken/SecurityTokenFactoryImplTest.java Tue Nov  8 17:26:39 2016
@@ -0,0 +1,141 @@
+/**
+ * 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.xml.security.stax.impl.securityToken;
+
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+
+import javax.xml.bind.JAXBElement;
+
+import org.apache.xml.security.binding.xmldsig.KeyInfoType;
+import org.apache.xml.security.binding.xmldsig.ObjectFactory;
+import org.apache.xml.security.exceptions.XMLSecurityException;
+import org.apache.xml.security.stax.config.Init;
+import org.apache.xml.security.stax.ext.InboundSecurityContext;
+import org.apache.xml.security.stax.ext.XMLSecurityProperties;
+import org.apache.xml.security.stax.impl.InboundSecurityContextImpl;
+import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
+import org.apache.xml.security.stax.securityToken.SecurityTokenConstants;
+import org.apache.xml.security.stax.securityToken.SecurityTokenFactory;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.apache.xml.security.stax.securityToken.SecurityTokenConstants.KeyIdentifier_KeyName;
+import static org.apache.xml.security.test.stax.utils.KeyLoader.loadPublicKey;
+import static org.junit.Assert.*;
+
+public class SecurityTokenFactoryImplTest {
+    private KeyInfoType keyInfoType;
+    private XMLSecurityProperties xmlSecurityProperties;
+    private InboundSecurityContext inboundSecurityContext;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() throws Exception {
+        Init.init(null, this.getClass());
+
+        ObjectFactory of = new ObjectFactory();
+
+        JAXBElement<String> keyname = of.createKeyName("mykey");
+        keyInfoType = new KeyInfoType();
+        keyInfoType.setId("KeyName");
+        keyInfoType.getContent().add(keyname);
+
+        xmlSecurityProperties = new XMLSecurityProperties();
+
+        inboundSecurityContext = new InboundSecurityContextImpl();
+
+    }
+
+    @Test
+    public void testKeyNameToken() throws Exception {
+        SecurityTokenFactory factory = new SecurityTokenFactoryImpl();
+
+        SecurityTokenConstants.KeyUsage keyUsage = SecurityTokenConstants.KeyUsage_Signature_Verification;
+
+        xmlSecurityProperties.addKeyNameMapping("mykey", loadPublicKey("dsa.key", "DSA"));
+
+        InboundSecurityToken token =
+                factory.getSecurityToken(keyInfoType, keyUsage, xmlSecurityProperties, inboundSecurityContext);
+
+        assertEquals(KeyIdentifier_KeyName, token.getKeyIdentifier());
+        assertNotNull(token.getPublicKey());
+        assertEquals("DSA", token.getPublicKey().getAlgorithm());
+    }
+
+    @Test
+    public void testKeyNameTokenWithSignatureVerificationKeySet() throws Exception {
+        SecurityTokenFactory factory = new SecurityTokenFactoryImpl();
+
+        SecurityTokenConstants.KeyUsage keyUsage = SecurityTokenConstants.KeyUsage_Signature_Verification;
+
+        xmlSecurityProperties.addKeyNameMapping("mykey", loadPublicKey("dsa.key", "DSA"));
+        xmlSecurityProperties.setSignatureVerificationKey(loadPublicKey("rsa.key", "RSA"));
+
+        InboundSecurityContext inboundSecurityContext = new InboundSecurityContextImpl();
+
+        InboundSecurityToken token =
+                factory.getSecurityToken(keyInfoType, keyUsage, xmlSecurityProperties, inboundSecurityContext);
+
+        assertEquals(KeyIdentifier_KeyName, token.getKeyIdentifier());
+        assertNotNull(token.getPublicKey());
+        assertEquals("RSA", token.getPublicKey().getAlgorithm());
+    }
+
+    @Test
+    public void testKeyNameTokenWithoutKeyInMap() throws Exception {
+        expectedException.expect(XMLSecurityException.class);
+        expectedException.expectMessage("No key configured for KeyName: mykey");
+
+        SecurityTokenFactory factory = new SecurityTokenFactoryImpl();
+
+        SecurityTokenConstants.KeyUsage keyUsage = SecurityTokenConstants.KeyUsage_Signature_Verification;
+
+
+        InboundSecurityContext inboundSecurityContext = new InboundSecurityContextImpl();
+
+        factory.getSecurityToken(keyInfoType, keyUsage, xmlSecurityProperties, inboundSecurityContext);
+    }
+
+    @Test
+    public void testKeyNameTokenWithWrongKeyInMap() throws Exception {
+        expectedException.expect(XMLSecurityException.class);
+        expectedException.expectMessage("Key of type DSAPrivateKey not supported for a KeyName lookup");
+
+        SecurityTokenFactory factory = new SecurityTokenFactoryImpl();
+
+        SecurityTokenConstants.KeyUsage keyUsage = SecurityTokenConstants.KeyUsage_Signature_Verification;
+
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
+        KeyPair keyPair = keyGen.generateKeyPair();
+        Key privateKey = keyPair.getPrivate();
+
+        xmlSecurityProperties.addKeyNameMapping("mykey", privateKey);
+
+        InboundSecurityContext inboundSecurityContext = new InboundSecurityContextImpl();
+
+        factory.getSecurityToken(keyInfoType, keyUsage, xmlSecurityProperties, inboundSecurityContext);
+    }
+
+}

Modified: santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/dom/keys/keyresolver/DEREncodedKeyValueResolverTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/dom/keys/keyresolver/DEREncodedKeyValueResolverTest.java?rev=1768742&r1=1768741&r2=1768742&view=diff
==============================================================================
--- santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/dom/keys/keyresolver/DEREncodedKeyValueResolverTest.java (original)
+++ santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/dom/keys/keyresolver/DEREncodedKeyValueResolverTest.java Tue Nov  8 17:26:39 2016
@@ -18,39 +18,28 @@
  */
 package org.apache.xml.security.test.dom.keys.keyresolver;
 
-import java.io.FileInputStream;
 import java.lang.reflect.Constructor;
-import java.security.KeyFactory;
 import java.security.Provider;
 import java.security.PublicKey;
 import java.security.Security;
-import java.security.spec.X509EncodedKeySpec;
 
-import javax.xml.parsers.DocumentBuilder;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import org.apache.xml.security.Init;
 import org.apache.xml.security.keys.KeyInfo;
-import org.apache.xml.security.utils.Base64;
-import org.apache.xml.security.utils.JavaUtils;
-import org.apache.xml.security.utils.XMLUtils;
 import org.junit.Assert;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
 
-public class DEREncodedKeyValueResolverTest extends Assert {
-
-    private static final String BASEDIR = System.getProperty("basedir") == null ? "./": System.getProperty("basedir");
-    private static final String SEP = System.getProperty("file.separator");
+import static org.apache.xml.security.test.stax.utils.KeyLoader.loadPublicKey;
+import static org.apache.xml.security.test.stax.utils.KeyLoader.loadXML;
 
-    private DocumentBuilder documentBuilder;
+public class DEREncodedKeyValueResolverTest extends Assert {
 
     private PublicKey rsaKeyControl;
     private PublicKey dsaKeyControl;
     private PublicKey ecKeyControl;
 
     public DEREncodedKeyValueResolverTest() throws Exception {
-        documentBuilder = XMLUtils.createDocumentBuilder(false);
-
         //
         // If the BouncyCastle provider is not installed, then try to load it
         // via reflection.
@@ -113,26 +102,4 @@ public class DEREncodedKeyValueResolverT
         KeyInfo keyInfo = new KeyInfo(element, "");
         assertEquals(ecKeyControl, keyInfo.getPublicKey());
     }
-
-    // Utility methods
-
-    private String getControlFilePath(String fileName) {
-        return BASEDIR + SEP + "src" + SEP + "test" + SEP + "resources" +
-            SEP + "org" + SEP + "apache" + SEP + "xml" + SEP + "security" +
-            SEP + "keys" + SEP + "content" +
-            SEP + fileName;
-    }
-
-    private Document loadXML(String fileName) throws Exception {
-        return documentBuilder.parse(new FileInputStream(getControlFilePath(fileName)));
-    }
-
-    private PublicKey loadPublicKey(String filePath, String algorithm) throws Exception {
-        String fileData = new String(JavaUtils.getBytesFromFile(getControlFilePath(filePath)));
-        byte[] keyBytes = Base64.decode(fileData);
-        KeyFactory kf = KeyFactory.getInstance(algorithm);
-        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
-        return kf.generatePublic(keySpec);
-    }
-
 }

Added: santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/stax/utils/KeyLoader.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/stax/utils/KeyLoader.java?rev=1768742&view=auto
==============================================================================
--- santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/stax/utils/KeyLoader.java (added)
+++ santuario/xml-security-java/branches/2.0.x-fixes/src/test/java/org/apache/xml/security/test/stax/utils/KeyLoader.java Tue Nov  8 17:26:39 2016
@@ -0,0 +1,67 @@
+/**
+ * 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.xml.security.test.stax.utils;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.FileInputStream;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.w3c.dom.Document;
+
+import org.apache.xml.security.utils.Base64;
+import org.apache.xml.security.utils.JavaUtils;
+import org.apache.xml.security.utils.XMLUtils;
+
+public class KeyLoader {
+    private static final String BASEDIR = System.getProperty("basedir") == null ? "./": System.getProperty("basedir");
+    private static final String SEP = System.getProperty("file.separator");
+
+    private static DocumentBuilder documentBuilder;
+
+    static {
+        try {
+            documentBuilder = XMLUtils.createDocumentBuilder(false);
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static String getControlFilePath(String fileName) {
+        return BASEDIR + SEP + "src" + SEP + "test" + SEP + "resources" +
+                SEP + "org" + SEP + "apache" + SEP + "xml" + SEP + "security" +
+                SEP + "keys" + SEP + "content" +
+                SEP + fileName;
+    }
+
+    public static PublicKey loadPublicKey(String filePath, String algorithm) throws Exception {
+        String fileData = new String(JavaUtils.getBytesFromFile(getControlFilePath(filePath)));
+        byte[] keyBytes = Base64.decode(fileData);
+        KeyFactory kf = KeyFactory.getInstance(algorithm);
+        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+        return kf.generatePublic(keySpec);
+    }
+
+    public static Document loadXML(String fileName) throws Exception {
+        return documentBuilder.parse(new FileInputStream(getControlFilePath(fileName)));
+    }
+
+}