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