Move ServiceMix Kernel trunk into Felix

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@768912 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/jaas/jaas-config/pom.xml b/karaf/jaas/jaas-config/pom.xml
new file mode 100644
index 0000000..bc47433
--- /dev/null
+++ b/karaf/jaas/jaas-config/pom.xml
@@ -0,0 +1,95 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.jaas</groupId>
+        <artifactId>jaas</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.jaas</groupId>
+    <artifactId>org.apache.servicemix.kernel.jaas.config</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: JAAS Config</name>
+
+    <description>
+        Provides the JAAS Config
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.jaas</groupId>
+            <artifactId>org.apache.servicemix.kernel.jaas.boot</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.aopalliance</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            ${artifactId};version=${project.version};-split-package:=merge-first
+                        </Export-Package>
+                        <Import-Package>*</Import-Package>
+                        <Private-Package>${artifactId}.impl</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/JaasRealm.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/JaasRealm.java
new file mode 100644
index 0000000..b5237d1
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/JaasRealm.java
@@ -0,0 +1,28 @@
+/*
+ * 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.servicemix.kernel.jaas.config;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+public interface JaasRealm {
+
+    public String getName();
+
+    public int getRank();
+
+    public AppConfigurationEntry[] getEntries();
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeyIsLocked.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeyIsLocked.java
new file mode 100644
index 0000000..5ff4736
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeyIsLocked.java
@@ -0,0 +1,39 @@
+/*
+ * 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.servicemix.kernel.jaas.config;
+
+import java.security.GeneralSecurityException;
+
+public class KeyIsLocked extends GeneralSecurityException {
+
+    public KeyIsLocked() {
+        super();
+    }
+
+    public KeyIsLocked(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public KeyIsLocked(String msg) {
+        super(msg);
+    }
+
+    public KeyIsLocked(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreInstance.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreInstance.java
new file mode 100644
index 0000000..022d95b
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreInstance.java
@@ -0,0 +1,61 @@
+/*
+ * 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.servicemix.kernel.jaas.config;
+
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.TrustManager;
+
+/**
+ * Based on http://svn.apache.org/repos/asf/geronimo/trunk/modules/management/
+ *              src/java/org/apache/geronimo/management/geronimo/KeystoreInstance.java
+ *
+ * @version $Rev: $ $Date: $
+ */
+public interface KeystoreInstance {
+
+    String getName();
+
+    int getRank();
+
+    String[] listPrivateKeys();
+
+    String[] listTrustCertificates();
+
+    Certificate getCertificate(String alias);
+
+    String getCertificateAlias(Certificate cert);
+
+    Certificate[] getCertificateChain(String alias);
+
+    PrivateKey getPrivateKey(String alias);
+
+    boolean isKeystoreLocked();
+
+    boolean isKeyLocked(String keyAlias);
+
+    KeyManager[] getKeyManager(String algorithm, String keyAlias) throws NoSuchAlgorithmException,
+                                UnrecoverableKeyException, KeyStoreException, KeystoreIsLocked;
+
+    TrustManager[] getTrustManager(String algorithm) throws KeyStoreException, NoSuchAlgorithmException, KeystoreIsLocked;
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreIsLocked.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreIsLocked.java
new file mode 100644
index 0000000..34c9a2b
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreIsLocked.java
@@ -0,0 +1,39 @@
+/*
+ * 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.servicemix.kernel.jaas.config;
+
+import java.security.GeneralSecurityException;
+
+public class KeystoreIsLocked extends GeneralSecurityException {
+
+    public KeystoreIsLocked() {
+        super();
+    }
+
+    public KeystoreIsLocked(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public KeystoreIsLocked(String msg) {
+        super(msg);
+    }
+
+    public KeystoreIsLocked(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreManager.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreManager.java
new file mode 100644
index 0000000..74fa466
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreManager.java
@@ -0,0 +1,110 @@
+/*
+ * 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.servicemix.kernel.jaas.config;
+
+import java.security.GeneralSecurityException;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Based on http://svn.apache.org/repos/asf/geronimo/trunk/modules/management/
+ *                      src/java/org/apache/geronimo/management/geronimo/KeystoreManager.java
+ *
+ */
+public interface KeystoreManager {
+
+    KeystoreInstance getKeystore(String name);
+
+    /**
+     * Gets a SSLContext using one Keystore to access the private key
+     * and another to provide the list of trusted certificate authorities.
+     * @param provider
+     * @param protocol The SSL protocol to use
+     * @param algorithm The SSL algorithm to use
+     * @param keyStore The key keystore name as provided by listKeystores.  The
+     *                 KeystoreInstance for this keystore must be unlocked.
+     * @param keyAlias The name of the private key in the keystore.  The
+     *                 KeystoreInstance for this keystore must have unlocked
+     *                 this key.
+     * @param trustStore The trust keystore name as provided by listKeystores.
+     *                   The KeystoreInstance for this keystore must have
+     *                   unlocked this key.
+     *
+     * @throws KeystoreIsLocked Occurs when the requested key keystore cannot
+     *                          be used because it has not been unlocked.
+     * @throws KeyIsLocked Occurs when the requested private key in the key
+     *                     keystore cannot be used because it has not been
+     *                     unlocked.
+     */
+    SSLContext createSSLContext(String provider, String protocol,
+                                String algorithm, String keyStore,
+                                String keyAlias, String trustStore) throws GeneralSecurityException;
+
+    /**
+     * Gets a ServerSocketFactory using one Keystore to access the private key
+     * and another to provide the list of trusted certificate authorities.
+     * @param provider
+     * @param protocol The SSL protocol to use
+     * @param algorithm The SSL algorithm to use
+     * @param keyStore The key keystore name as provided by listKeystores.  The
+     *                 KeystoreInstance for this keystore must be unlocked.
+     * @param keyAlias The name of the private key in the keystore.  The
+     *                 KeystoreInstance for this keystore must have unlocked
+     *                 this key.
+     * @param trustStore The trust keystore name as provided by listKeystores.
+     *                   The KeystoreInstance for this keystore must have
+     *                   unlocked this key.
+     *
+     * @throws KeystoreIsLocked Occurs when the requested key keystore cannot
+     *                          be used because it has not been unlocked.
+     * @throws KeyIsLocked Occurs when the requested private key in the key
+     *                     keystore cannot be used because it has not been
+     *                     unlocked.
+     */
+    SSLServerSocketFactory createSSLServerFactory(String provider, String protocol,
+                                                  String algorithm, String keyStore,
+                                                  String keyAlias, String trustStore) throws GeneralSecurityException;
+
+    /**
+     * Gets a SocketFactory using one Keystore to access the private key
+     * and another to provide the list of trusted certificate authorities.
+     * @param provider The SSL provider to use, or null for the default
+     * @param protocol The SSL protocol to use
+     * @param algorithm The SSL algorithm to use
+     * @param keyStore The key keystore name as provided by listKeystores.  The
+     *                 KeystoreInstance for this keystore must be unlocked.
+     * @param keyAlias The name of the private key in the keystore.  The
+     *                 KeystoreInstance for this keystore must have unlocked
+     *                 this key.
+     * @param trustStore The trust keystore name as provided by listKeystores.
+     *                   The KeystoreInstance for this keystore must have
+     *                   unlocked this key.
+     *
+     * @throws KeystoreIsLocked Occurs when the requested key keystore cannot
+     *                          be used because it has not been unlocked.
+     * @throws KeyIsLocked Occurs when the requested private key in the key
+     *                     keystore cannot be used because it has not been
+     *                     unlocked.
+     * @throws GeneralSecurityException
+     */
+    SSLSocketFactory createSSLFactory(String provider, String protocol,
+                                      String algorithm, String keyStore,
+                                      String keyAlias, String trustStore) throws GeneralSecurityException;
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Config.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Config.java
new file mode 100644
index 0000000..7ad0b04
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Config.java
@@ -0,0 +1,109 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+import org.apache.servicemix.kernel.jaas.boot.ProxyLoginModule;
+import org.apache.servicemix.kernel.jaas.config.JaasRealm;
+import org.osgi.framework.BundleContext;
+import org.springframework.osgi.context.BundleContextAware;
+
+/**
+ * An implementation of JaasRealm which is created
+ * by the spring namespace handler.
+ */
+public class Config implements JaasRealm, BundleContextAware {
+
+    private String name;
+    private int rank;
+    private Module[] modules;
+    private BundleContext bundleContext;
+    private transient AppConfigurationEntry[] entries;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getRank() {
+        return rank;
+    }
+
+    public void setRank(int rank) {
+        this.rank = rank;
+    }
+
+    public Module[] getModules() {
+        return modules;
+    }
+
+    public void setModules(Module[] modules) {
+        this.modules = modules;
+        this.entries = null;
+    }
+
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public AppConfigurationEntry[] getEntries() {
+        if (this.entries == null && this.modules != null) {
+            Module[] modules = this.modules;
+            AppConfigurationEntry[] entries = new AppConfigurationEntry[modules.length];
+            for (int i = 0; i < modules.length; i++) {
+                Map<String,String> options = new HashMap<String,String>();
+                if (modules[i].getOptions() != null) {
+                    options.putAll(modules[i].getOptions());
+                }
+                options.put(ProxyLoginModule.PROPERTY_MODULE, modules[i].getClassName());
+                options.put(ProxyLoginModule.PROPERTY_BUNDLE, Long.toString(bundleContext.getBundle().getBundleId()));
+                entries[i] = new AppConfigurationEntry(ProxyLoginModule.class.getName(),
+                                                       getControlFlag(modules[i].getFlags()),
+                                                       options);
+            }
+            this.entries = entries;
+        }
+        return this.entries;
+    }
+
+    private AppConfigurationEntry.LoginModuleControlFlag getControlFlag(String flags) {
+        if ("required".equalsIgnoreCase(flags)) {
+            return AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
+        }
+        if ("optional".equalsIgnoreCase(flags)) {
+            return AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
+        }
+        if ("requisite".equalsIgnoreCase(flags)) {
+            return AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
+        }
+        if ("sufficient".equalsIgnoreCase(flags)) {
+            return AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
+        }
+        return null;
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ConfigParser.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ConfigParser.java
new file mode 100644
index 0000000..5f8e16a
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ConfigParser.java
@@ -0,0 +1,102 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.w3c.dom.Element;
+
+import org.apache.servicemix.kernel.jaas.boot.ProxyLoginModule;
+import org.apache.servicemix.kernel.jaas.config.JaasRealm;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedList;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean;
+import org.springframework.util.xml.DomUtils;
+
+public class ConfigParser extends AbstractSingleBeanDefinitionParser {
+
+    protected Class getBeanClass(Element element) {
+        return Config.class;
+    }
+
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        String name = element.getAttribute("name");
+        if (name == null || name.length() == 0) {
+            name = element.getAttribute("id");
+        }
+        builder.addPropertyValue("name", name);
+        String rank = element.getAttribute("rank");
+        if (rank != null && rank.length() > 0) {
+            builder.addPropertyValue("rank", Integer.parseInt(rank));
+        }
+        List childElements = DomUtils.getChildElementsByTagName(element, "module");
+        if (childElements != null && childElements.size() > 0) {
+            ManagedList children = new ManagedList(childElements.size());
+            for (int i = 0; i < childElements.size(); ++i) {
+                Element childElement = (Element) childElements.get(i);
+                BeanDefinitionBuilder bd = BeanDefinitionBuilder.genericBeanDefinition(Module.class);
+                bd.addPropertyValue("className", childElement.getAttribute("className"));
+                if (childElement.getAttribute("flags") != null) {
+                    bd.addPropertyValue("flags", childElement.getAttribute("flags"));
+                }
+                String options = DomUtils.getTextValue(childElement);
+                if (options != null && options.length() > 0) {
+                    Properties props = new Properties();
+                    try {
+                        props.load(new ByteArrayInputStream(options.getBytes()));
+                    } catch (IOException e) {
+                        throw new IllegalStateException("Can not load options for JAAS module "
+                                        + childElement.getAttribute("className") + " in config " + name);
+                    }
+                    bd.addPropertyValue("options", props);
+                }
+                children.add(bd.getBeanDefinition());
+            }
+            builder.addPropertyValue("modules", children);
+        }
+        // Publish to OSGi
+        String publish = element.getAttribute("publish");
+        if (Boolean.valueOf(publish)) {
+            // Publish Config
+            BeanDefinitionBuilder bd = BeanDefinitionBuilder.genericBeanDefinition(OsgiServiceFactoryBean.class);
+            bd.addPropertyValue("target", builder.getBeanDefinition());
+            bd.addPropertyValue("interfaces", new Class[] { JaasRealm.class });
+            Map<String,String> props = new HashMap<String,String>();
+            props.put(ProxyLoginModule.PROPERTY_MODULE, name);
+            bd.addPropertyValue("serviceProperties", props);
+            BeanDefinition def = bd.getBeanDefinition();
+            String id = parserContext.getReaderContext().generateBeanName(def);
+            BeanDefinitionHolder holder = new BeanDefinitionHolder(def, id);
+            registerBeanDefinition(holder, parserContext.getRegistry());
+            if (shouldFireEvents()) {
+                BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
+                postProcessComponentDefinition(componentDefinition);
+                parserContext.registerComponent(componentDefinition);
+            }
+        }
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Module.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Module.java
new file mode 100644
index 0000000..488f19a
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Module.java
@@ -0,0 +1,55 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import java.util.Map;
+
+/**
+ * POJO for a login module.
+ * It contains the class name, flags and a map of options.
+ */
+public class Module {
+
+    private String className;
+    private String flags;
+    private Map<String,String> options;
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getFlags() {
+        return flags;
+    }
+
+    public void setFlags(String flags) {
+        this.flags = flags;
+    }
+
+    public Map<String, String> getOptions() {
+        return options;
+    }
+
+    public void setOptions(Map<String, String> options) {
+        this.options = options;
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/NamespaceHandler.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/NamespaceHandler.java
new file mode 100644
index 0000000..d1b8192
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/NamespaceHandler.java
@@ -0,0 +1,29 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+public class NamespaceHandler extends NamespaceHandlerSupport {
+
+    public void init() {
+        registerBeanDefinitionParser("config", new ConfigParser());
+        registerBeanDefinitionParser("keystore", new ResourceKeystoreInstanceParser());
+    }
+
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiConfiguration.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiConfiguration.java
new file mode 100644
index 0000000..a2e6119
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiConfiguration.java
@@ -0,0 +1,71 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+import org.apache.servicemix.kernel.jaas.config.JaasRealm;
+
+public class OsgiConfiguration extends Configuration {
+
+    private List<JaasRealm> realms;
+
+    public void init() {
+        realms = new CopyOnWriteArrayList<JaasRealm>();
+        Configuration.setConfiguration(this);
+    }
+
+    public void close() {
+        realms.clear();
+        realms = null;
+        Configuration.setConfiguration(null);
+    }
+
+    public void register(JaasRealm realm, Map<String,?> properties) {
+        realms.add(realm);
+    }
+
+    public void unregister(JaasRealm realm, Map<String,?> properties) {
+        if (realms != null) {
+            realms.remove(realm);
+        }
+    }
+
+    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+        JaasRealm realm = null;
+        for (JaasRealm r : realms) {
+            if (r.getName().equals(name)) {
+                if (realm == null || r.getRank() > realm.getRank()) {
+                    realm = r;
+                }
+            }
+        }
+        if (realm != null) {
+            return realm.getEntries();
+        }
+        return null;
+    }
+
+    public void refresh() {
+        // Nothing to do, as we auto-update the configuration
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiKeystoreManager.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiKeystoreManager.java
new file mode 100644
index 0000000..41135c2
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiKeystoreManager.java
@@ -0,0 +1,92 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.apache.servicemix.kernel.jaas.config.KeystoreInstance;
+import org.apache.servicemix.kernel.jaas.config.KeystoreIsLocked;
+import org.apache.servicemix.kernel.jaas.config.KeystoreManager;
+
+/**
+ * Implementation of KeystoreManager
+ */
+public class OsgiKeystoreManager implements KeystoreManager {
+
+    private List<KeystoreInstance> keystores = new CopyOnWriteArrayList<KeystoreInstance>();
+
+    public void register(KeystoreInstance keystore, Map<String,?> properties) {
+        keystores.add(keystore);
+    }
+
+    public void unregister(KeystoreInstance keystore, Map<String,?> properties) {
+        keystores.remove(keystore);
+    }
+
+    public KeystoreInstance getKeystore(String name) {
+        KeystoreInstance keystore = null;
+        for (KeystoreInstance ks : keystores) {
+            if (ks.getName().equals(name)) {
+                if (keystore == null || keystore.getRank() < ks.getRank()) {
+                    keystore = ks;
+                }
+            }
+        }
+        return keystore;
+    }
+
+    public SSLContext createSSLContext(String provider, String protocol, String algorithm, String keyStore, String keyAlias, String trustStore) throws GeneralSecurityException {
+        KeystoreInstance keyInstance = getKeystore(keyStore);
+        if (keyInstance != null && keyInstance.isKeystoreLocked()) {
+            throw new KeystoreIsLocked("Keystore '" + keyStore + "' is locked");
+        }
+        if (keyInstance != null && keyInstance.isKeyLocked(keyAlias)) {
+            throw new KeystoreIsLocked("Key '" + keyAlias + "' in keystore '" + keyStore + "' is locked");
+        }
+        KeystoreInstance trustInstance = trustStore == null ? null : getKeystore(trustStore);
+        if (trustInstance != null && trustInstance.isKeystoreLocked()) {
+            throw new KeystoreIsLocked("Keystore '" + trustStore + "' is locked");
+        }
+        SSLContext context;
+        if (provider == null) {
+            context = SSLContext.getInstance(protocol);
+        } else {
+            context = SSLContext.getInstance(protocol, provider);
+        }
+        context.init(keyInstance == null ? null : keyInstance.getKeyManager(algorithm, keyAlias),
+                     trustInstance == null ? null : trustInstance.getTrustManager(algorithm), new SecureRandom());
+        return context;
+    }
+
+    public SSLServerSocketFactory createSSLServerFactory(String provider, String protocol, String algorithm, String keyStore, String keyAlias, String trustStore) throws GeneralSecurityException {
+        SSLContext context = createSSLContext(provider, protocol, algorithm, keyStore, keyAlias, trustStore);
+        return context.getServerSocketFactory();
+    }
+
+    public SSLSocketFactory createSSLFactory(String provider, String protocol, String algorithm, String keyStore, String keyAlias, String trustStore) throws GeneralSecurityException {
+        SSLContext context = createSSLContext(provider, protocol, algorithm, keyStore, keyAlias, trustStore);
+        return context.getSocketFactory();
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ProxyLoginModuleInitializer.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ProxyLoginModuleInitializer.java
new file mode 100644
index 0000000..f2b8c32
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ProxyLoginModuleInitializer.java
@@ -0,0 +1,35 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import org.apache.servicemix.kernel.jaas.boot.ProxyLoginModule;
+import org.osgi.framework.BundleContext;
+import org.springframework.osgi.context.BundleContextAware;
+
+public class ProxyLoginModuleInitializer implements BundleContextAware {
+
+    private BundleContext bundleContext;
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void init() {
+        BundleContext context = bundleContext.getBundle(0).getBundleContext();
+        ProxyLoginModule.init(context);
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstance.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstance.java
new file mode 100644
index 0000000..7974ed6
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstance.java
@@ -0,0 +1,289 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.kernel.jaas.config.KeystoreInstance;
+import org.apache.servicemix.kernel.jaas.config.KeystoreIsLocked;
+import org.springframework.core.io.Resource;
+
+/**
+ *
+ */
+public class ResourceKeystoreInstance implements KeystoreInstance {
+
+    private static final Log LOG = LogFactory.getLog(ResourceKeystoreInstance.class);
+    private static final String JKS = "JKS";
+
+    private String name;
+    private int rank;
+    private Resource path;
+    private String keystorePassword;
+    private Map keyPasswords = new HashMap();
+    private File keystoreFile; // Only valid after startup and if the resource points to a file
+
+    // The following variables are the state of the keystore, which should be chucked if the file on disk changes
+    private List privateKeys = new ArrayList();
+    private List trustCerts = new ArrayList();
+    private KeyStore keystore;
+    private long keystoreReadDate = Long.MIN_VALUE;
+
+    /**
+     * @return the keystoreName
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param keystoreName the keystoreName to set
+     */
+    public void setName(String keystoreName) {
+        this.name = keystoreName;
+    }
+
+    /**
+     * @return the rank
+     */
+    public int getRank() {
+        return rank;
+    }
+
+    /**
+     * @param rank the rank to set
+     */
+    public void setRank(int rank) {
+        this.rank = rank;
+    }
+
+    /**
+     * @return the keystorePath
+     */
+    public Resource getPath() {
+        return path;
+    }
+
+    /**
+     * @param keystorePath the keystorePath to set
+     */
+    public void setPath(Resource keystorePath) throws IOException {
+        this.path = keystorePath;
+        if (keystorePath.getURL().getProtocol().equals("file")) {
+            this.keystoreFile = keystorePath.getFile();
+        }
+    }
+
+    /**
+     * @param keystorePassword the keystorePassword to set
+     */
+    public void setKeystorePassword(String keystorePassword) {
+        this.keystorePassword = keystorePassword;
+    }
+
+    /**
+     * @param keyPasswords the keyPasswords to set
+     */
+    public void setKeyPasswords(String keyPasswords) {
+        if (keyPasswords != null) {
+            String[] keys = keyPasswords.split("\\]\\!\\[");
+            for (int i = 0; i < keys.length; i++) {
+                String key = keys[i];
+                int pos = key.indexOf('=');
+                this.keyPasswords.put(key.substring(0, pos), key.substring(pos + 1).toCharArray());
+            }
+        }
+    }
+
+    public Certificate getCertificate(String alias) {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        try {
+            return keystore.getCertificate(alias);
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to read certificate from keystore", e);
+        }
+        return null;
+    }
+
+    public String getCertificateAlias(Certificate cert) {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        try {
+            return keystore.getCertificateAlias(cert);
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to read retrieve alias for given certificate from keystore", e);
+        }
+        return null;
+    }
+
+    public Certificate[] getCertificateChain(String alias) {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        try {
+            return keystore.getCertificateChain(alias);
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to read certificate chain from keystore", e);
+        }
+        return null;
+    }
+
+    public KeyManager[] getKeyManager(String algorithm, String keyAlias) throws KeystoreIsLocked,
+                                    NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
+        if (isKeystoreLocked()) {
+            throw new KeystoreIsLocked("Keystore '" + name + "' is locked.");
+        }
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(algorithm);
+        keyFactory.init(keystore, (char[]) keyPasswords.get(keyAlias));
+        return keyFactory.getKeyManagers();
+    }
+
+    public PrivateKey getPrivateKey(String alias) {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        try {
+            if (isKeyLocked(alias)) {
+                return null;
+            }
+            Key key = keystore.getKey(alias, (char[]) keyPasswords.get(alias));
+            if (key instanceof PrivateKey) {
+                return (PrivateKey) key;
+            }
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to read private key from keystore", e);
+        } catch (NoSuchAlgorithmException e) {
+            LOG.error("Unable to read private key from keystore", e);
+        } catch (UnrecoverableKeyException e) {
+            LOG.error("Unable to read private key from keystore", e);
+        }
+        return null;
+    }
+
+    public TrustManager[] getTrustManager(String algorithm) throws KeyStoreException,
+                                            NoSuchAlgorithmException, KeystoreIsLocked {
+        if (isKeystoreLocked()) {
+            throw new KeystoreIsLocked("Keystore '" + name + "' is locked.");
+        }
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(algorithm);
+        trustFactory.init(keystore);
+        return trustFactory.getTrustManagers();
+    }
+
+    public boolean isKeyLocked(String keyAlias) {
+        return keyPasswords.get(keyAlias) == null;
+    }
+
+    public boolean isKeystoreLocked() {
+        return keystorePassword == null;
+    }
+
+    public String[] listPrivateKeys() {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        return (String[]) privateKeys.toArray(new String[privateKeys.size()]);
+    }
+
+    public String[] listTrustCertificates() {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        return (String[]) trustCerts.toArray(new String[trustCerts.size()]);
+    }
+
+    // ==================== Internals =====================
+
+    private boolean loadKeystoreData() {
+        // Check to reload the data if needed
+        if (keystoreFile != null && keystoreReadDate >= keystoreFile.lastModified()) {
+            return true;
+        }
+        // If not a file, just not reload the data if it has already been loaded
+        if (keystoreFile == null && keystore != null) {
+            return true;
+        }
+        // Check if the file is invalid
+        if (keystoreFile != null && (!keystoreFile.exists() || !keystoreFile.canRead())) {
+            throw new IllegalArgumentException("Invalid keystore file (" + path + " = " + keystoreFile.getAbsolutePath() + ")");
+        }
+        // Load the keystore data
+        try {
+            keystoreReadDate = System.currentTimeMillis();
+            privateKeys.clear();
+            trustCerts.clear();
+            if (keystore == null) {
+                keystore = KeyStore.getInstance(JKS);
+            }
+            InputStream in = new BufferedInputStream(path.getInputStream());
+            keystore.load(in, keystorePassword == null ? new char[0] : keystorePassword.toCharArray());
+            in.close();
+            Enumeration aliases = keystore.aliases();
+            while (aliases.hasMoreElements()) {
+                String alias = (String) aliases.nextElement();
+                if (keystore.isKeyEntry(alias)) {
+                    privateKeys.add(alias);
+                } else if (keystore.isCertificateEntry(alias)) {
+                    trustCerts.add(alias);
+                }
+            }
+            return true;
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to open keystore with provided password", e);
+        } catch (IOException e) {
+            LOG.error("Unable to open keystore with provided password", e);
+        } catch (NoSuchAlgorithmException e) {
+            LOG.error("Unable to open keystore with provided password", e);
+        } catch (CertificateException e) {
+            LOG.error("Unable to open keystore with provided password", e);
+        }
+        return false;
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstanceParser.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstanceParser.java
new file mode 100644
index 0000000..01f3531
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstanceParser.java
@@ -0,0 +1,89 @@
+/*
+ * 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.servicemix.kernel.jaas.config.impl;
+
+import org.w3c.dom.Element;
+
+import org.apache.servicemix.kernel.jaas.config.KeystoreInstance;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean;
+
+/**
+ * Spring parser for a keystore instance
+ */
+public class ResourceKeystoreInstanceParser extends AbstractSingleBeanDefinitionParser {
+
+    public static final String PUBLISH_ATTRIBUTE = "publish";
+
+    protected Class getBeanClass(Element element) {
+        return ResourceKeystoreInstance.class;
+    }
+
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        // Parse name
+        String name = element.getAttribute("name");
+        if (name == null || name.length() == 0) {
+            name = element.getAttribute("id");
+        }
+        if (name != null && name.length() > 0) {
+            builder.addPropertyValue("name", name);
+        }
+        // Parse rank
+        String rank = element.getAttribute("rank");
+        if (rank != null && rank.length() > 0) {
+            builder.addPropertyValue("rank", rank);
+        }
+        // Parse path
+        String path = element.getAttribute("path");
+        if (path != null && path.length() > 0) {
+            builder.addPropertyValue("path", path);
+        }
+        // Parse keystorePassword
+        String keystorePassword = element.getAttribute("keystorePassword");
+        if (keystorePassword != null && keystorePassword.length() > 0) {
+            builder.addPropertyValue("keystorePassword", keystorePassword);
+        }
+        // Parse keyPasswords
+        String keyPasswords = element.getAttribute("keyPasswords");
+        if (keyPasswords != null && keyPasswords.length() > 0) {
+            builder.addPropertyValue("keyPasswords", keyPasswords);
+        }
+        // Parse publish
+        String publish = element.getAttribute("publish");
+        if (Boolean.valueOf(publish)) {
+            // Publish Config
+            BeanDefinitionBuilder bd = BeanDefinitionBuilder.genericBeanDefinition(OsgiServiceFactoryBean.class);
+            bd.addPropertyValue("target", builder.getBeanDefinition());
+            bd.addPropertyValue("interfaces", new Class[] { KeystoreInstance.class });
+            BeanDefinition def = bd.getBeanDefinition();
+            String id = parserContext.getReaderContext().generateBeanName(def);
+            BeanDefinitionHolder holder = new BeanDefinitionHolder(def, id);
+            registerBeanDefinition(holder, parserContext.getRegistry());
+            if (shouldFireEvents()) {
+                BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
+                postProcessComponentDefinition(componentDefinition);
+                parserContext.registerComponent(componentDefinition);
+            }
+        }
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.handlers b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.handlers
new file mode 100644
index 0000000..fe59e34
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.handlers
@@ -0,0 +1,20 @@
+################################################################################
+#
+#    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.
+#
+################################################################################
+http\://servicemix.apache.org/jaas = org.apache.servicemix.kernel.jaas.config.impl.NamespaceHandler
+ 
\ No newline at end of file
diff --git a/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.schemas b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.schemas
new file mode 100644
index 0000000..3001be1
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.schemas
@@ -0,0 +1,19 @@
+################################################################################
+#
+#    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.
+#
+################################################################################
+http\://servicemix.apache.org/schema/servicemix-jaas.xsd = org/apache/servicemix/kernel/jaas/config/servicemix-jaas.xsd
diff --git a/karaf/jaas/jaas-config/src/main/resources/META-INF/spring/servicemix-jaas.xml b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring/servicemix-jaas.xml
new file mode 100644
index 0000000..eca5fbd
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring/servicemix-jaas.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+    <bean id="config"
+          class="org.apache.servicemix.kernel.jaas.config.impl.OsgiConfiguration"
+          init-method="init"
+          destroy-method="close"/>
+
+    <osgi:list id="realms"
+               interface="org.apache.servicemix.kernel.jaas.config.JaasRealm"
+               cardinality="0..N">
+        <osgi:listener ref="config" bind-method="register" unbind-method="unregister" />
+    </osgi:list>
+
+    <bean id="proxyLoginModuleInitializer"
+          class="org.apache.servicemix.kernel.jaas.config.impl.ProxyLoginModuleInitializer"
+          init-method="init"/>
+
+    <!-- Register the Straight-Through flow -->
+    <bean id="keystoreManager" class="org.apache.servicemix.kernel.jaas.config.impl.OsgiKeystoreManager" />
+    <osgi:service ref="keystoreManager">
+        <osgi:interfaces>
+            <value>org.apache.servicemix.kernel.jaas.config.KeystoreManager</value>
+        </osgi:interfaces>
+    </osgi:service>
+
+    <osgi:list id="keystores"
+               interface="org.apache.servicemix.kernel.jaas.config.KeystoreInstance"
+               cardinality="0..N">
+        <osgi:listener ref="keystoreManager" bind-method="register" unbind-method="unregister" />
+    </osgi:list>
+
+</beans>
diff --git a/karaf/jaas/jaas-config/src/main/resources/org/apache/servicemix/kernel/jaas/config/servicemix-jaas.xsd b/karaf/jaas/jaas-config/src/main/resources/org/apache/servicemix/kernel/jaas/config/servicemix-jaas.xsd
new file mode 100644
index 0000000..320e04d
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/resources/org/apache/servicemix/kernel/jaas/config/servicemix-jaas.xsd
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<xs:schema elementFormDefault='qualified'
+           targetNamespace='http://servicemix.apache.org/jaas'
+           xmlns:xs='http://www.w3.org/2001/XMLSchema'
+           xmlns:beans="http://www.springframework.org/schema/beans"
+           xmlns:tns='http://servicemix.apache.org/jaas'>
+
+    <xs:import namespace="http://www.springframework.org/schema/beans"/>
+
+    <xs:element name="config">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="beans:identifiedType">
+                    <xs:sequence>
+                        <xs:element name="module" minOccurs="0" maxOccurs="unbounded">
+                            <xs:complexType mixed="true">
+                                <xs:attribute name="className" use="required" type="xs:string" />
+                                <xs:attribute name="flags" default="required">
+                                    <xs:simpleType>
+                                        <xs:restriction base="xs:NMTOKEN">
+                                            <xs:enumeration value="required"/>
+                                            <xs:enumeration value="requisite"/>
+                                            <xs:enumeration value="sufficient"/>
+                                            <xs:enumeration value="optional"/>
+                                        </xs:restriction>
+                                    </xs:simpleType>
+                                </xs:attribute>
+                            </xs:complexType>
+                        </xs:element>
+                    </xs:sequence>
+                    <xs:attribute name="name" use="optional" type="xs:string" />
+                    <xs:attribute name="rank" use="optional" default="0" type="xs:int" />
+                    <xs:attribute name="publish" use="optional" default="true" type="xs:boolean" />
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+
+    <xs:element name="keystore">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="beans:identifiedType">
+                    <xs:attribute name="name" use="optional" type="xs:string" />
+                    <xs:attribute name="rank" use="optional" default="0" type="xs:int" />
+                    <xs:attribute name="publish" use="optional" default="true" type="xs:boolean" />
+                    <xs:attribute name="path" use="required" type="xs:string" />
+                    <xs:attribute name="keystorePassword" use="optional" type="xs:string" />
+                    <xs:attribute name="keyPasswords" use="optional" type="xs:string" />
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+    
+</xs:schema>
diff --git a/karaf/jaas/jaas-config/src/test/java/org/apache/servicemix/kernel/jaas/config/NamespaceHandlerTest.java b/karaf/jaas/jaas-config/src/test/java/org/apache/servicemix/kernel/jaas/config/NamespaceHandlerTest.java
new file mode 100644
index 0000000..fb282e9
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/test/java/org/apache/servicemix/kernel/jaas/config/NamespaceHandlerTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.servicemix.kernel.jaas.config;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.kernel.jaas.boot.ProxyLoginModule;
+import org.apache.servicemix.kernel.jaas.config.impl.Config;
+import org.easymock.EasyMock;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.aryEq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.osgi.context.support.BundleContextAwareProcessor;
+
+public class NamespaceHandlerTest extends TestCase {
+
+    public void testConfig() throws Exception {
+        final Dictionary headers = new Hashtable();
+        headers.put(Constants.BUNDLE_VERSION, "1.0.0.SNAPSHOT");
+
+        final BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        final Bundle bundle = EasyMock.createMock(Bundle.class);
+        final ServiceRegistration reg = EasyMock.createMock(ServiceRegistration.class);
+
+        expect(bundleContext.getBundle()).andReturn(bundle).anyTimes();
+        expect(bundle.getSymbolicName()).andReturn("symbolic-name").anyTimes();
+        expect(bundle.getBundleId()).andReturn(Long.valueOf(32)).anyTimes();
+        expect(bundle.getHeaders()).andReturn(headers).anyTimes();
+        expect(bundleContext.registerService(aryEq(new String[] { JaasRealm.class.getName() }),
+                                             anyObject(), EasyMock.<Dictionary>anyObject())).andReturn(reg);
+        expect(bundleContext.registerService(aryEq(new String[] { KeystoreInstance.class.getName() }),
+                                             anyObject(), EasyMock.<Dictionary>anyObject())).andReturn(reg);
+
+        replay(bundleContext, bundle);
+
+        AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] { "classpath:config.xml" }, false) {
+            protected DefaultListableBeanFactory createBeanFactory() {
+                DefaultListableBeanFactory f = super.createBeanFactory();
+                f.addBeanPostProcessor(new BundleContextAwareProcessor(bundleContext));
+                return f;
+            }
+        };
+        ctx.refresh();
+
+        verify(bundleContext, bundle);
+
+        // Test realm
+        Object obj = ctx.getBean("realm");
+        assertNotNull(obj);
+        assertTrue(obj instanceof Config);
+        Config cfg = (Config) obj;
+        assertNotNull(cfg.getBundleContext());
+        assertEquals("realm", cfg.getName());
+        assertNotNull(cfg.getModules());
+        assertEquals(1, cfg.getModules().length);
+        assertNotNull(cfg.getModules()[0]);
+        assertEquals("org.apache.servicemix.kernel.jaas.config.SimpleLoginModule", cfg.getModules()[0].getClassName());
+        assertEquals("required", cfg.getModules()[0].getFlags());
+        assertNotNull(cfg.getModules()[0].getOptions());
+        assertEquals(1, cfg.getModules()[0].getOptions().size());
+        assertEquals("value", cfg.getModules()[0].getOptions().get("key"));
+        AppConfigurationEntry[] entries = cfg.getEntries();
+        assertNotNull(entries);
+        assertEquals(1, entries.length);
+        assertNotNull(entries[0]);
+        assertEquals(ProxyLoginModule.class.getName(), entries[0].getLoginModuleName());
+        assertEquals(AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, entries[0].getControlFlag());
+        Map<String,?> options = entries[0].getOptions();
+        assertNotNull(options);
+        assertEquals(3, options.size());
+        assertEquals("value", options.get("key"));
+        assertEquals("org.apache.servicemix.kernel.jaas.config.SimpleLoginModule", options.get(ProxyLoginModule.PROPERTY_MODULE));
+        assertEquals("32", options.get(ProxyLoginModule.PROPERTY_BUNDLE));
+
+        // Test keystore
+        obj = ctx.getBean("keystore");
+        assertNotNull(obj);
+        assertTrue(obj instanceof KeystoreInstance);
+        KeystoreInstance ks = (KeystoreInstance) obj;
+        assertEquals("ks", ks.getName());
+        assertEquals(1, ks.getRank());
+        assertNotNull(ks.getPrivateKey("myalias"));
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/test/resources/config.xml b/karaf/jaas/jaas-config/src/test/resources/config.xml
new file mode 100644
index 0000000..868b7c7
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/test/resources/config.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:jaas="http://servicemix.apache.org/jaas"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://servicemix.apache.org/jaas
+  http://servicemix.apache.org/schema/servicemix-jaas.xsd">
+
+    <jaas:config id="realm">
+        <jaas:module className="org.apache.servicemix.kernel.jaas.config.SimpleLoginModule" flags="required">
+            key=value
+        </jaas:module>
+    </jaas:config>
+
+    <jaas:keystore id="keystore"
+                   name="ks"
+                   rank="1"
+                   path="classpath:privatestore.jks"
+                   keystorePassword="keyStorePassword"
+                   keyPasswords="myalias=myAliasPassword" />
+
+</beans>
diff --git a/karaf/jaas/jaas-config/src/test/resources/privatestore.jks b/karaf/jaas/jaas-config/src/test/resources/privatestore.jks
new file mode 100644
index 0000000..26fc0bc
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/test/resources/privatestore.jks
Binary files differ