FELIX-3705 import new JAAS OSGi support (contributed by Chetan Mehrotra, thank you very much)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1399574 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/jaas/pom.xml b/jaas/pom.xml
new file mode 100644
index 0000000..8e5072e
--- /dev/null
+++ b/jaas/pom.xml
@@ -0,0 +1,230 @@
+<!--
+    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.
+-->
+<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">
+
+    <modelVersion>4.0.0</modelVersion>
+     <parent>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>felix-parent</artifactId>
+        <version>2.1</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.felix.jaas</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Felix JAAS Support</name>
+    <description />
+
+     <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/jaas</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/trunk/jaas</developerConnection>
+        <url>http://svn.apache.org/repos/asf/felix/jaas</url>
+    </scm>
+
+    <properties>
+    </properties>
+    
+    <build>
+        <plugins>
+            <!--
+                We do not use DS but the SCR plugin is used to generate the
+                metatype.xml from the SCR annotations
+            -->
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+                <version>1.7.4</version>
+                <executions>
+                    <execution>
+                        <id>generate-scr-scrdescriptor</id>
+                        <goals>
+                            <goal>scr</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.5.1</version>
+                <!-- We use the new JDK 1.6 ConfigurationSpi API so can set the version to 1.6-->
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.3.7</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>
+                            ${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Bundle-Vendor>
+                            The Apache Software Foundation
+                        </Bundle-Vendor>
+                        <Bundle-Activator>
+                            org.apache.felix.jaas.internal.Activator
+                        </Bundle-Activator>
+                        <_removeheaders>
+                            Embed-Dependency,Private-Package,Include-Resource
+                        </_removeheaders>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <!-- Create jar which can be put in boot classpath to enable use of
+            ProxyLoginModule in normal JAAS mode of authentication -->
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                <execution>
+                    <id>boot-library</id>
+                    <goals><goal>jar</goal></goals>
+                    <phase>package</phase>
+                    <configuration>
+                        <classifier>boot</classifier>
+                        <includes>
+                            <include>org/apache/felix/jaas/boot/*.class</include>
+                            <include>META-INF/NOTICE</include>
+                            <include>META-INF/DEPENDENCIES</include>
+                            <include>META-INF/LICENSE</include>
+                        </includes>
+                    </configuration>
+                </execution>
+            </executions>
+            </plugin>
+
+            <!-- Required for pax exam-->
+            <plugin>
+                <groupId>org.apache.servicemix.tooling</groupId>
+                <artifactId>depends-maven-plugin</artifactId>
+                <version>1.2</version>
+                <executions>
+                    <execution>
+                        <id>generate-depends-file</id>
+                        <goals>
+                            <goal>generate-depends-file</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <version>4.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>4.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>biz.aQute</groupId>
+            <artifactId>bndlib</artifactId>
+            <version>1.50.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <version>1.6.0</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.3</version>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+            <version>4.10</version>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <!--
+            copy the package such that IDEs may easily use it without
+            setting the system property
+        -->
+        <profile>
+            <id>ide</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>scr-file-create</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <target>
+                                        <copy file="${project.build.directory}/${project.build.finalName}.jar"
+                                              tofile="${project.build.directory}/jaas.jar" />
+                                        <copy file="${project.build.directory}/${project.build.finalName}-boot.jar"
+                                              tofile="${project.build.directory}/jaas-boot.jar" />
+                                    </target>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+
+        <profile>
+            <id>felix</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>org.apache.felix.framework</artifactId>
+                    <version>4.0.2</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>equinox</id>
+            <dependencies>
+                <dependency>
+                    <groupId>org.eclipse</groupId>
+                    <artifactId>osgi</artifactId>
+                    <version>3.7.1.R37x_v20110808-1106</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+</project>
diff --git a/jaas/src/main/java/org/apache/felix/jaas/LoginContextFactory.java b/jaas/src/main/java/org/apache/felix/jaas/LoginContextFactory.java
new file mode 100644
index 0000000..59e1143
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/LoginContextFactory.java
@@ -0,0 +1,33 @@
+/*
+ * 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.felix.jaas;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+
+public interface LoginContextFactory
+{
+
+    LoginContext createLoginContext(String realm, Subject subject, CallbackHandler handler) throws LoginException;
+
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/LoginModuleFactory.java b/jaas/src/main/java/org/apache/felix/jaas/LoginModuleFactory.java
new file mode 100644
index 0000000..a9edf97
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/LoginModuleFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.felix.jaas;
+
+import javax.security.auth.spi.LoginModule;
+
+
+/**
+ * User: chetanm
+ * Date: 7/9/12
+ * Time: 5:43 PM
+ */
+public interface LoginModuleFactory
+{
+
+    String JAAS_CONTROL_FLAG = "jaas.controlFlag";
+    String JAAS_REALM_NAME = "jaas.realmName";
+
+    LoginModule createLoginModule();
+
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/boot/ProxyLoginModule.java b/jaas/src/main/java/org/apache/felix/jaas/boot/ProxyLoginModule.java
new file mode 100644
index 0000000..c706c8f
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/boot/ProxyLoginModule.java
@@ -0,0 +1,78 @@
+/*
+ * 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.felix.jaas.boot;
+
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+
+public class ProxyLoginModule implements LoginModule
+{
+    public static final String PROP_LOGIN_MODULE_FACTORY = "org.apache.felix.jaas.LoginModuleFactory";
+
+    private LoginModule delegate;
+
+    public void initialize(Subject subject, CallbackHandler callbackHandler,
+        Map<String, ?> sharedState, Map<String, ?> options)
+    {
+        BootLoginModuleFactory factory = (BootLoginModuleFactory) options.get(PROP_LOGIN_MODULE_FACTORY);
+        if (factory == null)
+        {
+            throw new IllegalStateException("Specify LoginModuleFactory through ["
+                + PROP_LOGIN_MODULE_FACTORY
+                + "] property as part of configuration options");
+        }
+        delegate = factory.createLoginModule();
+        delegate.initialize(subject, callbackHandler, sharedState, options);
+    }
+
+    public boolean login() throws LoginException
+    {
+        return delegate.login();
+    }
+
+    public boolean commit() throws LoginException
+    {
+        return delegate.commit();
+    }
+
+    public boolean abort() throws LoginException
+    {
+        return delegate.abort();
+    }
+
+    public boolean logout() throws LoginException
+    {
+        return delegate.logout();
+    }
+
+    /**
+     * Factory interface to create LoginModule instance. This is exactly same as
+     * LoginModuleFactory. This is done to keep the boot package self sufficient
+     */
+    public static interface BootLoginModuleFactory
+    {
+        LoginModule createLoginModule();
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/boot/package-info.java b/jaas/src/main/java/org/apache/felix/jaas/boot/package-info.java
new file mode 100644
index 0000000..c39e890
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/boot/package-info.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provides support for performing JAAS based authentication in OSGi
+ *
+ * @version 1.0
+ */
+@Version("1.0")
+@Export(optional = "provide:=true")
+package org.apache.felix.jaas.boot;
+
+import aQute.bnd.annotation.Version;
+import aQute.bnd.annotation.Export;
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/Activator.java b/jaas/src/main/java/org/apache/felix/jaas/internal/Activator.java
new file mode 100644
index 0000000..b014e72
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/Activator.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.jaas.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator
+{
+
+    private BundleLoginModuleCreator loginModuleCreator;
+    private JaasConfigFactory jaasConfigFactory;
+    private ConfigSpiOsgi configSpi;
+    private JaasWebConsolePlugin webConsolePlugin;
+    private Logger logger;
+
+    @Override
+    public void start(BundleContext context) throws Exception
+    {
+        logger = new Logger(context);
+        loginModuleCreator = new BundleLoginModuleCreator(context, logger);
+        jaasConfigFactory = new JaasConfigFactory(context, loginModuleCreator, logger);
+        configSpi = new ConfigSpiOsgi(context, logger);
+        webConsolePlugin = new JaasWebConsolePlugin(context, configSpi,
+            loginModuleCreator);
+
+        logger.open();
+        loginModuleCreator.open();
+        configSpi.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception
+    {
+        if (loginModuleCreator != null)
+        {
+            loginModuleCreator.close();
+        }
+
+        if (configSpi != null)
+        {
+            configSpi.close();
+        }
+
+        if (logger != null)
+        {
+            logger.close();
+        }
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/BundleLoginModuleCreator.java b/jaas/src/main/java/org/apache/felix/jaas/internal/BundleLoginModuleCreator.java
new file mode 100644
index 0000000..4926049
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/BundleLoginModuleCreator.java
@@ -0,0 +1,212 @@
+/*
+ * 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.felix.jaas.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.security.auth.spi.LoginModule;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.BundleTracker;
+
+class BundleLoginModuleCreator extends BundleTracker implements LoginModuleCreator
+{
+
+    private static final String JAAS_MODULE_CLASS = "Jaas-ModuleClass";
+
+    private final Map<String, LoginModuleInfo> loginModuleInfo = new ConcurrentHashMap<String, LoginModuleInfo>();
+
+    private final Logger log;
+
+    public BundleLoginModuleCreator(BundleContext context, Logger log)
+    {
+        super(context, Bundle.ACTIVE, null /* customizer */);
+        this.log = log;
+    }
+
+    public LoginModule newInstance(String className)
+    {
+        LoginModuleInfo lmInfo = loginModuleInfo.get(className);
+
+        //TODO Rethink about exception handling. Probably introduce custom exception classes
+        if (lmInfo == null)
+        {
+            throw new AssertionError("No bundle exists to create LoginModule from "
+                + className);
+        }
+
+        try
+        {
+            return lmInfo.newInstance();
+        }
+        catch (IllegalAccessException e)
+        {
+            throw new RuntimeException("Error occurred while creating LoginModule for "
+                + className, e);
+        }
+        catch (InstantiationException e)
+        {
+            throw new RuntimeException("Error occurred while creating LoginModule for "
+                + className, e);
+        }
+    }
+
+    public Map<Bundle, Set<String>> getBundleToLoginModuleMapping()
+    {
+        //With R5 we could have used Map<Bundle, T> BundleTracker.getTracked()
+        //Determine the bundle -> login module classes map
+        Map<Bundle, Set<String>> bundleMap = new HashMap<Bundle, Set<String>>();
+        for (LoginModuleInfo e : loginModuleInfo.values())
+        {
+            Bundle b = e.getBundle();
+            @SuppressWarnings("unchecked")
+            Set<String> classNames = (Set<String>) getObject(b);
+
+            if (classNames == null)
+            {
+                continue;
+            }
+            bundleMap.put(b, classNames);
+        }
+        return bundleMap;
+    }
+
+    // ---------- BundleTracker integration ----------------------------------------------
+
+    @Override
+    public Object addingBundle(Bundle bundle, BundleEvent event)
+    {
+        if (providesLoginModule(bundle))
+        {
+            return registerBundle(bundle);
+        }
+        return null;
+    }
+
+    @Override
+    public void removedBundle(Bundle bundle, BundleEvent event, Object object)
+    {
+        @SuppressWarnings("unchecked")
+        Set<String> classNames = (Set<String>) object;
+
+        for (String className : classNames)
+        {
+            loginModuleInfo.remove(className);
+        }
+    }
+
+    private boolean providesLoginModule(Bundle bundle)
+    {
+        return bundle.getHeaders().get(JAAS_MODULE_CLASS) != null;
+    }
+
+    private Set<String> registerBundle(Bundle bundle)
+    {
+        Set<String> classNames = Util.parseHeader((String) bundle.getHeaders().get(
+            JAAS_MODULE_CLASS));
+        for (String className : classNames)
+        {
+            LoginModuleInfo bi = new LoginModuleInfo(className, bundle, log);
+            if (bi.isValid())
+            {
+
+                //Duplicate registration check
+                if (loginModuleInfo.containsKey(className))
+                {
+                    LoginModuleInfo existingInfo = loginModuleInfo.get(className);
+                    String msg = String.format(
+                        "LoginModule class %s is already registered with Bundle %s. Entry "
+                            + "from bundle %s would be ignored", className,
+                        existingInfo.getBundle(), bundle);
+                    log.log(LogService.LOG_WARNING, msg);
+                    continue;
+                }
+
+                loginModuleInfo.put(className, bi);
+                log.log(LogService.LOG_INFO, "Registering LoginModule class ["
+                    + className + "] from Bundle" + bundle);
+            }
+            else
+            {
+                log.log(LogService.LOG_WARNING,
+                    "Could not load LoginModule class " + bi.getClassName()
+                        + " from bundle " + bundle);
+            }
+        }
+        return classNames;
+    }
+
+    static final class LoginModuleInfo
+    {
+        private final String className;
+        private final Bundle bundle;
+        private final Class<LoginModule> clazz;
+
+        @SuppressWarnings("unchecked")
+        public LoginModuleInfo(String className, Bundle bundle, Logger log)
+        {
+            this.className = className;
+            this.bundle = bundle;
+
+            Class<LoginModule> clazz = null;
+            try
+            {
+                clazz = bundle.loadClass(className);
+            }
+            catch (ClassNotFoundException e)
+            {
+                log.log(LogService.LOG_WARNING, "Error loading class [" + className
+                    + "] from bundle " + bundle, e);
+            }
+            this.clazz = clazz;
+        }
+
+        public LoginModule newInstance() throws IllegalAccessException,
+            InstantiationException
+        {
+            if (clazz == null)
+            {
+                throw new IllegalStateException("LoginModule class not initialized");
+            }
+            return clazz.newInstance();
+        }
+
+        public boolean isValid()
+        {
+            return clazz != null;
+        }
+
+        public String getClassName()
+        {
+            return className;
+        }
+
+        public Bundle getBundle()
+        {
+            return bundle;
+        }
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/ConfigLoginModuleProvider.java b/jaas/src/main/java/org/apache/felix/jaas/internal/ConfigLoginModuleProvider.java
new file mode 100644
index 0000000..445712c
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/ConfigLoginModuleProvider.java
@@ -0,0 +1,88 @@
+/*
+ * 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.felix.jaas.internal;
+
+import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.security.auth.spi.LoginModule;
+
+
+final class ConfigLoginModuleProvider implements LoginModuleProvider
+{
+    private final Map options;
+    private final LoginModuleControlFlag controlFlag;
+    private final int ranking;
+    private final String realmName;
+    private final String className;
+    private final LoginModuleCreator moduleCreator;
+
+    @SuppressWarnings("unchecked")
+    ConfigLoginModuleProvider(String realmName, String className, Map options, LoginModuleControlFlag controlFlag, int order, LoginModuleCreator moduleCreator)
+    {
+        this.options = Collections.unmodifiableMap(options);
+        this.controlFlag = controlFlag;
+        this.ranking = order;
+        this.realmName = realmName;
+        this.className = className;
+        this.moduleCreator = moduleCreator;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Map<String, ?> options()
+    {
+        return options;
+    }
+
+    public LoginModuleControlFlag getControlFlag()
+    {
+        return controlFlag;
+    }
+
+    public int ranking()
+    {
+        return ranking;
+    }
+
+    public String realmName()
+    {
+        return realmName;
+    }
+
+    public String getClassName()
+    {
+        return className;
+    }
+
+    public LoginModule createLoginModule()
+    {
+        return moduleCreator.newInstance(className);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "ConfigLoginModuleProvider{" + "flag=" + controlFlag + ", ranking="
+            + ranking + ", realmName='" + realmName + '\'' + ", className='" + className
+            + '\'' + '}';
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/ConfigSpiOsgi.java b/jaas/src/main/java/org/apache/felix/jaas/internal/ConfigSpiOsgi.java
new file mode 100644
index 0000000..175046f
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/ConfigSpiOsgi.java
@@ -0,0 +1,591 @@
+/*
+ * 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.felix.jaas.internal;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.*;
+
+import org.apache.felix.jaas.LoginContextFactory;
+import org.apache.felix.jaas.LoginModuleFactory;
+import org.apache.felix.jaas.boot.ProxyLoginModule;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyOption;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+@Component(label = "%jaas.spi.name", description = "%jaas.spi.description", metatype = true, ds = false, name = "org.apache.felix.jaas.ConfigurationSpi", policy = ConfigurationPolicy.REQUIRE)
+public class ConfigSpiOsgi extends ConfigurationSpi implements ManagedService, ServiceTrackerCustomizer, LoginContextFactory
+{
+    /**
+     * Name of the algorithm to use to fetch JAAS Config
+     */
+    public static final String JAAS_CONFIG_ALGO_NAME = "JavaLoginConfig";
+
+    public static final String SERVICE_PID = "org.apache.felix.jaas.ConfigurationSpi";
+
+    private static enum GlobalConfigurationPolicy
+    {
+        DEFAULT, REPLACE, PROXY
+    }
+
+    private Map<String, Realm> configs = Collections.emptyMap();
+
+    private final Logger log;
+
+    @Property
+    private static final String JAAS_DEFAULT_REALM_NAME = "jaas.defaultRealmName";
+    private String defaultRealmName;
+
+    private static final String DEFAULT_CONFIG_PROVIDER_NAME = "FelixJaasProvider";
+    @Property(value = DEFAULT_CONFIG_PROVIDER_NAME)
+    private static final String JAAS_CONFIG_PROVIDER_NAME = "jaas.configProviderName";
+
+    @Property(value = "default", options = {
+            @PropertyOption(name = "default", value = "%jaas.configPolicy.default"),
+            @PropertyOption(name = "replace", value = "%jaas.configPolicy.replace"),
+            @PropertyOption(name = "proxy", value = "%jaas.configPolicy.proxy") })
+    static final String JAAS_CONFIG_POLICY = "jaas.globalConfigPolicy";
+
+    private final Configuration osgiConfig = new OsgiConfiguration();
+
+    private final Configuration originalConfig;
+
+    private final Configuration proxyConfig;
+
+    private volatile GlobalConfigurationPolicy globalConfigPolicy = GlobalConfigurationPolicy.DEFAULT;
+
+    private final Map<ServiceReference, LoginModuleProvider> providerMap = new ConcurrentHashMap<ServiceReference, LoginModuleProvider>();
+
+    private volatile String jaasConfigProviderName;
+
+    private final Object lock = new Object();
+
+    private final BundleContext context;
+
+    private final ServiceTracker tracker;
+
+    private ServiceRegistration spiReg;
+
+    public ConfigSpiOsgi(BundleContext context, Logger log)
+    {
+        this.context = context;
+        this.log = log;
+        this.tracker = new ServiceTracker(context, LoginModuleFactory.class.getName(),
+            this);
+
+        Properties props = new Properties();
+        props.setProperty(Constants.SERVICE_VENDOR, "Apache Software Foundation");
+        props.setProperty(Constants.SERVICE_PID, SERVICE_PID);
+
+        this.context.registerService(ManagedService.class.getName(), this, props);
+
+        //TODO Should this registration be made conditional i.e. service is only registered
+        //only if there active LoginModules present
+        this.context.registerService(LoginContextFactory.class.getName(), this, new Properties());
+
+        this.originalConfig = getGlobalConfiguration();
+        this.proxyConfig = new DelegatingConfiguration(osgiConfig, originalConfig);
+    }
+
+    @Override
+    public LoginContext createLoginContext(String realm, Subject subject,
+        CallbackHandler handler) throws LoginException
+    {
+        if (realm == null)
+        {
+            realm = defaultRealmName;
+        }
+
+        final Thread currentThread = Thread.currentThread();
+        final ClassLoader cl = currentThread.getContextClassLoader();
+        try
+        {
+            currentThread.setContextClassLoader(ProxyLoginModule.class.getClassLoader());
+            Configuration config = Configuration.getInstance("JavaLoginConfig", null,
+                jaasConfigProviderName);
+            return new LoginContext(realm, subject, handler, config);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new LoginException(e.getMessage());
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            throw new LoginException(e.getMessage());
+        }
+        finally
+        {
+            currentThread.setContextClassLoader(cl);
+        }
+    }
+
+    @Override
+    protected AppConfigurationEntry[] engineGetAppConfigurationEntry(String name)
+    {
+        Realm realm = configs.get(name);
+        if (realm == null)
+        {
+            log.log(LogService.LOG_WARNING, "No JAAS module configured for realm " + name);
+            return null;
+        }
+
+        return realm.engineGetAppConfigurationEntry();
+    }
+
+    Map<String, Realm> getAllConfiguration()
+    {
+        return configs;
+    }
+
+    private void recreateConfigs()
+    {
+        Map<String, Realm> realmToConfigMap = new HashMap<String, Realm>();
+        for (LoginModuleProvider lmp : providerMap.values())
+        {
+            String realmName = lmp.realmName();
+            if (realmName == null)
+            {
+                realmName = defaultRealmName;
+            }
+
+            Realm realm = realmToConfigMap.get(realmName);
+            if (realm == null)
+            {
+                realm = new Realm(realmName);
+                realmToConfigMap.put(realmName, realm);
+            }
+
+            realm.add(new AppConfigurationHolder(lmp));
+        }
+
+        for (Realm realm : realmToConfigMap.values())
+        {
+            realm.afterPropertiesSet();
+        }
+
+        //We also register the Spi with OSGI SR if any configuration is available
+        //This would allow any client component to determine when it should start
+        //and use the config
+        if (!realmToConfigMap.isEmpty() && spiReg == null)
+        {
+            Properties props = new Properties();
+            props.setProperty("providerName", "felix");
+
+            synchronized (lock)
+            {
+                spiReg = context.registerService(ConfigurationSpi.class.getName(), this,
+                    props);
+            }
+        }
+
+        synchronized (lock)
+        {
+            this.configs = Collections.unmodifiableMap(realmToConfigMap);
+        }
+    }
+
+    //--------------LifeCycle methods -------------------------------------
+
+    void open()
+    {
+        this.tracker.open();
+        this.configs = Collections.emptyMap();
+    }
+
+    void close()
+    {
+        this.tracker.close();
+        deregisterProvider(jaasConfigProviderName);
+
+        synchronized (lock)
+        {
+            providerMap.clear();
+            configs = null; //Cannot call clear as its an unmodifiable map
+        }
+
+        if (globalConfigPolicy != GlobalConfigurationPolicy.DEFAULT)
+        {
+            restoreOriginalConfiguration();
+        }
+    }
+
+    // --------------Config handling ----------------------------------------
+
+    @Override
+    public synchronized void updated(Dictionary properties) throws ConfigurationException
+    {
+        //TODO Do not know but for fresh install it is null
+        if (properties == null)
+        {
+            return;
+        }
+        String newDefaultRealmName = Util.toString(
+            properties.get(JAAS_DEFAULT_REALM_NAME), null);
+        if (newDefaultRealmName == null)
+        {
+            throw new IllegalArgumentException(
+                "Default JAAS realm name must be specified");
+        }
+
+        if (!newDefaultRealmName.equals(defaultRealmName))
+        {
+            defaultRealmName = newDefaultRealmName;
+            recreateConfigs();
+        }
+
+        String newProviderName = Util.toString(properties.get(JAAS_CONFIG_PROVIDER_NAME),
+            DEFAULT_CONFIG_PROVIDER_NAME);
+
+        deregisterProvider(jaasConfigProviderName);
+        registerProvider(newProviderName);
+        jaasConfigProviderName = newProviderName;
+
+        manageGlobalConfiguration(properties);
+    }
+
+    private void manageGlobalConfiguration(Dictionary props)
+    {
+        String configPolicy = Util.toString(props.get(JAAS_CONFIG_POLICY),
+                GlobalConfigurationPolicy.DEFAULT.name());
+        configPolicy = Util.trimToNull(configPolicy);
+
+        GlobalConfigurationPolicy policy = GlobalConfigurationPolicy.DEFAULT;
+        if (configPolicy != null)
+        {
+            policy = GlobalConfigurationPolicy.valueOf(configPolicy.toUpperCase());
+        }
+
+        this.globalConfigPolicy = policy;
+
+        if (policy == GlobalConfigurationPolicy.REPLACE)
+        {
+            Configuration.setConfiguration(osgiConfig);
+            log.log(LogService.LOG_INFO,
+                "Replacing the global JAAS configuration with OSGi based configuration");
+        }
+        else if (policy == GlobalConfigurationPolicy.PROXY)
+        {
+            Configuration.setConfiguration(proxyConfig);
+            log.log(
+                LogService.LOG_INFO,
+                "Replacing the global JAAS configuration with OSGi based proxy configuration. "
+                    + "It would look first in the OSGi based configuration and if not found would use the default global "
+                    + "configuration");
+        }
+        else if (policy == GlobalConfigurationPolicy.DEFAULT)
+        {
+            restoreOriginalConfiguration();
+        }
+    }
+
+    private void restoreOriginalConfiguration()
+    {
+        if (originalConfig == null)
+        {
+            return;
+        }
+
+        Configuration current = Configuration.getConfiguration();
+        if (current != originalConfig)
+        {
+            Configuration.setConfiguration(originalConfig);
+        }
+    }
+
+    // --------------JAAS/JCA/Security ----------------------------------------
+
+    private void registerProvider(String providerName)
+    {
+        Security.addProvider(new OSGiProvider(providerName));
+        log.log(LogService.LOG_INFO, "Registered provider " + providerName
+            + " for managing JAAS config with type " + JAAS_CONFIG_ALGO_NAME);
+    }
+
+    private void deregisterProvider(String providerName)
+    {
+        Security.removeProvider(providerName);
+        log.log(LogService.LOG_INFO, "Removed provider " + providerName + " type "
+            + JAAS_CONFIG_ALGO_NAME + " from Security providers list");
+    }
+
+    // ---------- ServiceTracker ----------------------------------------------
+
+    @Override
+    public Object addingService(ServiceReference reference)
+    {
+        LoginModuleFactory lmf = (LoginModuleFactory) context.getService(reference);
+        registerFactory(reference, lmf);
+        recreateConfigs();
+        return lmf;
+    }
+
+    @Override
+    public void modifiedService(ServiceReference reference, Object service)
+    {
+        recreateConfigs();
+    }
+
+    @Override
+    public void removedService(ServiceReference reference, Object service)
+    {
+        deregisterFactory(reference);
+        recreateConfigs();
+        context.ungetService(reference);
+    }
+
+    private void deregisterFactory(ServiceReference ref)
+    {
+        LoginModuleProvider lmp = providerMap.remove(ref);
+        if (lmp != null)
+        {
+            log.log(LogService.LOG_INFO, "Deregistering LoginModuleFactory " + lmp);
+        }
+    }
+
+    private void registerFactory(ServiceReference ref, LoginModuleFactory lmf)
+    {
+        LoginModuleProvider lmfExt;
+        if (lmf instanceof LoginModuleProvider)
+        {
+            lmfExt = (LoginModuleProvider) lmf;
+        }
+        else
+        {
+            lmfExt = new OsgiLoginModuleProvider(ref, lmf);
+        }
+        log.log(LogService.LOG_INFO, "Registering LoginModuleFactory " + lmf);
+        providerMap.put(ref, lmfExt);
+    }
+
+    private static Configuration getGlobalConfiguration()
+    {
+        try
+        {
+            return Configuration.getConfiguration();
+        }
+        catch (Exception e)
+        {
+            // means no JAAS configuration file OR no permission to read it
+        }
+        return null;
+    }
+
+    private class OSGiProvider extends Provider
+    {
+        public static final String TYPE_CONFIGURATION = "Configuration";
+
+        OSGiProvider(String providerName)
+        {
+            super(providerName, 1.0, "OSGi based provider for Jaas configuration");
+        }
+
+        @Override
+        public synchronized Service getService(String type, String algorithm)
+        {
+            if (TYPE_CONFIGURATION.equals(type)
+                && JAAS_CONFIG_ALGO_NAME.equals(algorithm))
+            {
+                return new ConfigurationService(this);
+            }
+            return super.getService(type, algorithm);
+        }
+    }
+
+    private class ConfigurationService extends Provider.Service
+    {
+
+        public ConfigurationService(Provider provider)
+        {
+            super(provider, OSGiProvider.TYPE_CONFIGURATION, //the type of this service
+                JAAS_CONFIG_ALGO_NAME, //the algorithm name
+                ConfigSpiOsgi.class.getName(), //the name of the class implementing this service
+                Collections.<String> emptyList(), //List of aliases or null if algorithm has no aliases
+                Collections.<String, String> emptyMap()); //Map of attributes or null if this implementation
+        }
+
+        @Override
+        public Object newInstance(Object constructorParameter)
+            throws NoSuchAlgorithmException
+        {
+            //constructorParameter is the one which is passed as Configuration.Parameters params
+            //for now we do not make use of that
+            return ConfigSpiOsgi.this;
+        }
+    }
+
+    //---------------------------- Global Configuration Handling
+
+    private class OsgiConfiguration extends Configuration
+    {
+
+        @Override
+        public AppConfigurationEntry[] getAppConfigurationEntry(String name)
+        {
+            return ConfigSpiOsgi.this.engineGetAppConfigurationEntry(name);
+        }
+    }
+
+    private class DelegatingConfiguration extends Configuration
+    {
+        private final Configuration primary;
+        private final Configuration secondary;
+
+        private DelegatingConfiguration(Configuration primary, Configuration secondary)
+        {
+            this.primary = primary;
+            this.secondary = secondary;
+        }
+
+        @Override
+        public AppConfigurationEntry[] getAppConfigurationEntry(String name)
+        {
+            // check if jaas-loginModule or fallback is configured
+            AppConfigurationEntry[] result = null;
+            try
+            {
+                result = primary.getAppConfigurationEntry(name);
+            }
+            catch (Exception e)
+            {
+                // means no JAAS configuration file OR no permission to read it
+            }
+
+            if (result == null)
+            {
+                try
+                {
+                    result = secondary.getAppConfigurationEntry(name);
+                }
+                catch (Exception e)
+                {
+                    // WLP 9.2.0 throws IllegalArgumentException for unknown appName
+                }
+            }
+
+            return result;
+        }
+    }
+
+    //-------------------------------------OSGi Config Management
+
+    static final class Realm
+    {
+        private final String realmName;
+        private AppConfigurationEntry[] configArray;
+        private List<AppConfigurationHolder> configs = new ArrayList<AppConfigurationHolder>();
+
+        Realm(String realmName)
+        {
+            this.realmName = realmName;
+        }
+
+        public void add(AppConfigurationHolder config)
+        {
+            configs.add(config);
+        }
+
+        public void afterPropertiesSet()
+        {
+            Collections.sort(configs);
+            configArray = new AppConfigurationEntry[configs.size()];
+            for (int i = 0; i < configs.size(); i++)
+            {
+                configArray[i] = configs.get(i).getEntry();
+            }
+            configs = Collections.unmodifiableList(configs);
+        }
+
+        public String getRealmName()
+        {
+            return realmName;
+        }
+
+        public List<AppConfigurationHolder> getConfigs()
+        {
+            return configs;
+        }
+
+        public AppConfigurationEntry[] engineGetAppConfigurationEntry()
+        {
+            return Arrays.copyOf(configArray, configArray.length);
+        }
+
+        @Override
+        public String toString()
+        {
+            return "Realm{" + "realmName='" + realmName + '\'' + '}';
+        }
+    }
+
+    static final class AppConfigurationHolder implements Comparable<AppConfigurationHolder>
+    {
+        private static final String LOGIN_MODULE_CLASS = ProxyLoginModule.class.getName();
+        private final LoginModuleProvider provider;
+        private final int ranking;
+        private final AppConfigurationEntry entry;
+
+        public AppConfigurationHolder(LoginModuleProvider provider)
+        {
+            this.provider = provider;
+            this.ranking = provider.ranking();
+
+            Map<String, Object> options = new HashMap<String, Object>(provider.options());
+            options.put(ProxyLoginModule.PROP_LOGIN_MODULE_FACTORY, provider);
+            this.entry = new AppConfigurationEntry(LOGIN_MODULE_CLASS,
+                provider.getControlFlag(), Collections.unmodifiableMap(options));
+        }
+
+        public int compareTo(AppConfigurationHolder that)
+        {
+            if (this.ranking == that.ranking)
+            {
+                return 0;
+            }
+            return this.ranking > that.ranking ? -1 : 1;
+        }
+
+        public AppConfigurationEntry getEntry()
+        {
+            return entry;
+        }
+
+        public LoginModuleProvider getProvider()
+        {
+            return provider;
+        }
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/ControlFlag.java b/jaas/src/main/java/org/apache/felix/jaas/internal/ControlFlag.java
new file mode 100644
index 0000000..de07d92
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/ControlFlag.java
@@ -0,0 +1,80 @@
+/*
+ * 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.felix.jaas.internal;
+
+import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
+
+/**
+ * User: chetanm
+ * Date: 7/9/12
+ * Time: 9:55 PM
+ */
+@SuppressWarnings("UnusedDeclaration")
+enum ControlFlag
+{
+
+    REQUIRED(LoginModuleControlFlag.REQUIRED), REQUISITE(LoginModuleControlFlag.REQUISITE), SUFFICIENT(
+        LoginModuleControlFlag.SUFFICIENT), OPTIONAL(LoginModuleControlFlag.OPTIONAL), ;
+
+    private final LoginModuleControlFlag flag;
+
+    private ControlFlag(LoginModuleControlFlag flag)
+    {
+        this.flag = flag;
+    }
+
+    public LoginModuleControlFlag flag()
+    {
+        return flag;
+    }
+
+    public static ControlFlag from(String val)
+    {
+        val = Util.trimToNull(val);
+        if (val == null)
+        {
+            return REQUIRED;
+        }
+
+        val = val.toUpperCase();
+        return ControlFlag.valueOf(val);
+    }
+
+    public static String toString(LoginModuleControlFlag flag)
+    {
+        if (flag == LoginModuleControlFlag.REQUIRED)
+        {
+            return "REQUIRED";
+        }
+        else if (flag == LoginModuleControlFlag.REQUISITE)
+        {
+            return "REQUISITE";
+        }
+        else if (flag == LoginModuleControlFlag.SUFFICIENT)
+        {
+            return "SUFFICIENT";
+        }
+        else if (flag == LoginModuleControlFlag.OPTIONAL)
+        {
+            return "OPTIONAL";
+        }
+        throw new IllegalArgumentException("Unknown flag " + flag);
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/JaasConfigFactory.java b/jaas/src/main/java/org/apache/felix/jaas/internal/JaasConfigFactory.java
new file mode 100644
index 0000000..476923a
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/JaasConfigFactory.java
@@ -0,0 +1,171 @@
+/*
+ * 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.felix.jaas.internal;
+
+import static org.apache.felix.jaas.internal.Util.trimToNull;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.felix.jaas.LoginModuleFactory;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyOption;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.log.LogService;
+
+@Component(label = "%jaas.name", description = "%jaas.description", metatype = true, ds = false, name = JaasConfigFactory.SERVICE_PID, configurationFactory = true)
+public class JaasConfigFactory implements ManagedServiceFactory
+{
+
+    public static final String SERVICE_PID = "org.apache.felix.jaas.Configuration.factory";
+
+    @Property
+    static final String JAAS_CLASS_NAME = "jaas.classname";
+
+    @Property(value = "required", options = {
+            @PropertyOption(name = "required", value = "%jaas.flag.required"),
+            @PropertyOption(name = "requisite", value = "%jaas.flag.requisite"),
+            @PropertyOption(name = "sufficient", value = "%jaas.flag.sufficient"),
+            @PropertyOption(name = "optional", value = "%jaas.flag.optional") })
+    static final String JAAS_CONTROL_FLAG = "jaas.controlFlag";
+
+    @Property(intValue = 0)
+    static final String JAAS_RANKING = "jaas.ranking";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    static final String JAAS_OPTIONS = "jaas.options";
+
+    @Property
+    static final String JAAS_REALM_NAME = "jaas.realmName";
+
+    private final Logger log;
+
+    private final LoginModuleCreator factory;
+
+    private final BundleContext context;
+
+    private final Map<String, ServiceRegistration> registrations = new ConcurrentHashMap<String, ServiceRegistration>();
+
+    public JaasConfigFactory(BundleContext context, LoginModuleCreator factory, Logger log)
+    {
+        this.context = context;
+        this.factory = factory;
+        this.log = log;
+
+        Properties props = new Properties();
+        props.setProperty(Constants.SERVICE_VENDOR, "Apache Software Foundation");
+        props.setProperty(Constants.SERVICE_PID, SERVICE_PID);
+        context.registerService(ManagedServiceFactory.class.getName(), this, props);
+    }
+
+    @Override
+    public String getName()
+    {
+        return "JaasConfigFactory";
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void updated(String pid, Dictionary config) throws ConfigurationException
+    {
+        String className = trimToNull(Util.toString(config.get(JAAS_CLASS_NAME), null));
+        String flag = trimToNull(Util.toString(config.get(JAAS_CONTROL_FLAG), "required"));
+        int ranking = Util.toInteger(config.get(JAAS_RANKING), 0);
+
+        String[] props = Util.toStringArray(config.get(JAAS_OPTIONS), new String[0]);
+        Map options = toMap(props);
+        String realmName = trimToNull(Util.toString(config.get(JAAS_REALM_NAME), null));
+
+        if (className == null)
+        {
+            log.log(LogService.LOG_WARNING,
+                "Class name for the LoginModule is required. Configuration would be ignored"
+                    + config);
+            return;
+        }
+
+        //Combine the config. As the jaas.options is required for capturing config
+        //via felix webconsole. However in normal usage people would like to provide
+        //key=value pair directly in config. So merge both to provide a combined
+        //view
+        Map combinedOptions = convertToMap(config);
+        combinedOptions.putAll(options);
+
+        LoginModuleProvider lmf = new ConfigLoginModuleProvider(realmName, className,
+            combinedOptions, ControlFlag.from(flag).flag(), ranking, factory);
+
+        ServiceRegistration reg = context.registerService(
+            LoginModuleFactory.class.getName(), lmf, new Properties());
+        registrations.put(pid, reg);
+    }
+
+    @Override
+    public void deleted(String pid)
+    {
+        ServiceRegistration reg = registrations.remove(pid);
+        if (reg != null)
+        {
+            reg.unregister();
+        }
+    }
+
+    //~----------------------------------- Utility Methods
+
+    private static Map<String, Object> toMap(String[] props)
+    {
+        //TODO support system property substitution e.g. ${user.home}
+        //in property values
+        Map<String, Object> result = new HashMap<String, Object>();
+        for (String kv : props)
+        {
+            int indexOfEqual = kv.indexOf('=');
+            if (indexOfEqual > 0)
+            {
+                String key = trimToNull(kv.substring(0, indexOfEqual));
+                String value = trimToNull(kv.substring(indexOfEqual + 1));
+                if (key != null && value != null)
+                {
+                    result.put(key, value);
+                }
+            }
+        }
+        return result;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Map convertToMap(Dictionary config)
+    {
+        Map copy = new HashMap();
+        Enumeration e = config.keys();
+        while (e.hasMoreElements())
+        {
+            Object key = e.nextElement();
+            Object value = config.get(key);
+            copy.put(key, value);
+        }
+        return copy;
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/JaasWebConsolePlugin.java b/jaas/src/main/java/org/apache/felix/jaas/internal/JaasWebConsolePlugin.java
new file mode 100644
index 0000000..03321da
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/JaasWebConsolePlugin.java
@@ -0,0 +1,292 @@
+/*
+ * 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.felix.jaas.internal;
+
+import static org.apache.felix.jaas.internal.ConfigSpiOsgi.AppConfigurationHolder;
+import static org.apache.felix.jaas.internal.ConfigSpiOsgi.Realm;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class JaasWebConsolePlugin extends HttpServlet
+{
+
+    private final ConfigSpiOsgi configSpi;
+
+    private final BundleLoginModuleCreator loginModuleCreator;
+
+    public JaasWebConsolePlugin(BundleContext context, ConfigSpiOsgi configSpi, BundleLoginModuleCreator loginModuleCreator)
+    {
+        this.configSpi = configSpi;
+        this.loginModuleCreator = loginModuleCreator;
+
+        Properties props = new Properties();
+        props.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
+        props.put(Constants.SERVICE_DESCRIPTION, "JAAS Web Console Plugin");
+        props.put("felix.webconsole.label", "jaas");
+        props.put("felix.webconsole.title", "JAAS");
+        props.put("felix.webconsole.configprinter.modes", "always");
+        context.registerService(Servlet.class.getName(), this, props);
+    }
+
+    @Override
+    protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        if (req.getPathInfo().endsWith("/data.json"))
+        {
+            getJson(resp);
+        }
+        else
+        {
+            getHtml(resp);
+        }
+
+    }
+
+    private void getHtml(HttpServletResponse resp) throws IOException
+    {
+        final PrintWriter pw = resp.getWriter();
+
+        printAppConfigurationDetails(pw);
+        printAvailableModuleDetails(pw);
+
+    }
+
+    private void printAvailableModuleDetails(PrintWriter pw)
+    {
+        Map<Bundle, Set<String>> bundleMap = getAvailableLoginModuleInfo();
+
+        pw.println("<p class=\"statline ui-state-highlight\">${Available LoginModules}</p>");
+        if (bundleMap.isEmpty())
+        {
+            return;
+        }
+
+        pw.println("<table class=\"nicetable\">");
+        pw.println("<thead><tr>");
+        pw.println("<th class=\"header\">${Bundle}</th>");
+        pw.println("<th class=\"header\">${Classes}</th>");
+        pw.println("</tr></thead>");
+
+        String rowClass = "odd";
+        for (Map.Entry<Bundle, Set<String>> e : bundleMap.entrySet())
+        {
+            Bundle b = e.getKey();
+            pw.print("<tr class=\"%s ui-state-default\">");
+            pw.printf("<td><a href=\"${pluginRoot}/../bundles/%s\">%s (%s)</a></td>",
+                b.getBundleId(), b.getSymbolicName(), b.getBundleId());
+            pw.printf("<td>");
+            for (String className : e.getValue())
+            {
+                pw.print(className);
+                pw.print("<br/>");
+            }
+            pw.print("</td>");
+            pw.println("</tr>");
+
+            if (rowClass.equals("odd"))
+            {
+                rowClass = "even";
+            }
+            else
+            {
+                rowClass = "odd";
+            }
+        }
+        pw.println("</table>");
+    }
+
+    private void printAppConfigurationDetails(PrintWriter pw)
+    {
+        Map<String, Realm> configs = getConfigurationDetails();
+        if (configs.isEmpty())
+        {
+            pw.println("No JAAS LoginModule registered");
+            return;
+        }
+
+        pw.println("<p class=\"statline ui-state-highlight\">${Registered LoginModules}</p>");
+
+        pw.println("<table class=\"nicetable\">");
+        pw.println("<thead><tr>");
+        pw.println("<th class=\"header\">${Realm}</th>");
+        pw.println("<th class=\"header\">${Rank}</th>");
+        pw.println("<th class=\"header\">${Control Flag}</th>");
+        pw.println("<th class=\"header\">${Type}</th>");
+        pw.println("<th class=\"header\">${Classname}</th>");
+        pw.println("</tr></thead>");
+
+        for (Realm r : configs.values())
+        {
+            String realmName = r.getRealmName();
+            pw.printf(
+                "<tr class=\"ui-state-default\"><td>%s</td><td colspan=\"4\"></td></tr>",
+                realmName);
+
+            String rowClass = "odd";
+            for (AppConfigurationHolder ah : r.getConfigs())
+            {
+                LoginModuleProvider lp = ah.getProvider();
+                String type = getType(lp);
+                pw.printf("<tr class=\"%s ui-state-default\"><td></td><td>%d</td>",
+                    rowClass, lp.ranking());
+                pw.printf("<td>%s</td>", ControlFlag.toString(lp.getControlFlag()));
+                pw.printf("<td>%s</td>", type);
+
+                pw.printf("<td>");
+                pw.print(lp.getClassName());
+
+                if (lp instanceof OsgiLoginModuleProvider)
+                {
+                    ServiceReference sr = ((OsgiLoginModuleProvider) lp).getServiceReference();
+                    Object id = sr.getProperty(Constants.SERVICE_ID);
+                    pw.printf("<a href=\"${pluginRoot}/../services/%s\">(%s)</a>", id, id);
+                }
+                else if (lp instanceof ConfigLoginModuleProvider)
+                {
+                    Map config = lp.options();
+                    Object id = config.get(Constants.SERVICE_PID);
+                    pw.printf("<a href=\"${pluginRoot}/../configMgr/%s\">(Details)</a>",
+                        id);
+                }
+                pw.printf("</td>");
+
+                pw.println("</tr>");
+                if (rowClass.equals("odd"))
+                {
+                    rowClass = "even";
+                }
+                else
+                {
+                    rowClass = "odd";
+                }
+            }
+        }
+        pw.println("</table>");
+    }
+
+    private String getType(LoginModuleProvider lp)
+    {
+        String type = "Service";
+        if (lp instanceof ConfigLoginModuleProvider)
+        {
+            type = "Configuration";
+        }
+        return type;
+    }
+
+    private void getJson(HttpServletResponse resp)
+    {
+
+    }
+
+    /**
+     * @see org.apache.felix.webconsole.ConfigurationPrinter#printConfiguration(java.io.PrintWriter)
+     */
+    @SuppressWarnings("UnusedDeclaration")
+    public void printConfiguration(final PrintWriter pw)
+    {
+        pw.println("JAAS Configuration Details:");
+        pw.println();
+        pw.println("Registered LoginModules");
+        Map<String, Realm> configs = getConfigurationDetails();
+        if (configs.isEmpty())
+        {
+            pw.println("No JAAS LoginModule registered");
+        }
+        else
+        {
+            for (Realm r : configs.values())
+            {
+                String realmName = r.getRealmName();
+                pw.printf("Realm : %s \n", realmName);
+                for (AppConfigurationHolder ah : r.getConfigs())
+                {
+                    addSpace(pw, 1);
+                    pw.printf("%s \n", ah.getProvider().getClassName());
+
+                    addSpace(pw, 2);
+                    pw.printf("Flag    : %s \n",
+                        ControlFlag.toString(ah.getProvider().getControlFlag()));
+                    addSpace(pw, 2);
+                    pw.printf("Type    : %s \n", getType(ah.getProvider()));
+                    addSpace(pw, 2);
+                    pw.printf("Ranking : %d \n", ah.getProvider().ranking());
+                }
+            }
+        }
+
+        pw.println();
+
+        Map<Bundle, Set<String>> bundleMap = getAvailableLoginModuleInfo();
+        pw.println("Available LoginModules");
+        if (bundleMap.isEmpty())
+        {
+            //Nothing to do
+        }
+        else
+        {
+            for (Map.Entry<Bundle, Set<String>> e : bundleMap.entrySet())
+            {
+                Bundle b = e.getKey();
+                pw.printf("%s (%s) \n", b.getSymbolicName(), b.getBundleId());
+                for (String className : e.getValue())
+                {
+                    addSpace(pw, 1);
+                    pw.println(className);
+                }
+            }
+        }
+    }
+
+    private static void addSpace(PrintWriter pw, int count)
+    {
+        for (int i = 0; i < count; i++)
+        {
+            pw.print("  ");
+        }
+    }
+
+    private Map<String, Realm> getConfigurationDetails()
+    {
+        return configSpi.getAllConfiguration();
+    }
+
+    private Map<Bundle, Set<String>> getAvailableLoginModuleInfo()
+    {
+        return loginModuleCreator.getBundleToLoginModuleMapping();
+    }
+
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/Logger.java b/jaas/src/main/java/org/apache/felix/jaas/internal/Logger.java
new file mode 100644
index 0000000..1d62dc2
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/Logger.java
@@ -0,0 +1,57 @@
+/*
+ * 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.felix.jaas.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+
+class Logger extends ServiceTracker
+{
+
+    public Logger(BundleContext context)
+    {
+        super(context, LogService.class.getName(), null);
+    }
+
+    public void log(int level, String message)
+    {
+        LogService log = getLog();
+        if (log != null)
+        {
+            log.log(level, message);
+        }
+
+    }
+
+    public void log(int level, String message, Throwable exception)
+    {
+        LogService log = getLog();
+        if (log != null)
+        {
+            log.log(level, message, exception);
+        }
+    }
+
+    private LogService getLog()
+    {
+        return (LogService) getService();
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/LoginModuleCreator.java b/jaas/src/main/java/org/apache/felix/jaas/internal/LoginModuleCreator.java
new file mode 100644
index 0000000..d5db0a4
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/LoginModuleCreator.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.felix.jaas.internal;
+
+import javax.security.auth.spi.LoginModule;
+
+
+/**
+ * User: chetanm
+ * Date: 7/9/12
+ * Time: 10:17 PM
+ */
+public interface LoginModuleCreator
+{
+
+    LoginModule newInstance(String className);
+
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/LoginModuleProvider.java b/jaas/src/main/java/org/apache/felix/jaas/internal/LoginModuleProvider.java
new file mode 100644
index 0000000..4e237f4
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/LoginModuleProvider.java
@@ -0,0 +1,41 @@
+/*
+ * 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.felix.jaas.internal;
+
+import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
+
+import java.util.Map;
+
+import org.apache.felix.jaas.LoginModuleFactory;
+import org.apache.felix.jaas.boot.ProxyLoginModule;
+
+public interface LoginModuleProvider extends LoginModuleFactory, ProxyLoginModule.BootLoginModuleFactory
+{
+
+    Map<String, ?> options();
+
+    LoginModuleControlFlag getControlFlag();
+
+    int ranking();
+
+    String realmName();
+
+    String getClassName();
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/OsgiLoginModuleProvider.java b/jaas/src/main/java/org/apache/felix/jaas/internal/OsgiLoginModuleProvider.java
new file mode 100644
index 0000000..57e29c2
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/OsgiLoginModuleProvider.java
@@ -0,0 +1,93 @@
+/*
+ * 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.felix.jaas.internal;
+
+import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.security.auth.spi.LoginModule;
+
+import org.apache.felix.jaas.LoginModuleFactory;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+final class OsgiLoginModuleProvider implements LoginModuleProvider
+{
+    private final LoginModuleFactory delegate;
+    private final int ranking;
+    private final LoginModuleControlFlag flag;
+    private final String realmName;
+    private final ServiceReference serviceReference;
+
+    public OsgiLoginModuleProvider(ServiceReference sr, LoginModuleFactory delegate)
+    {
+        this.delegate = delegate;
+        this.ranking = Util.toInteger(sr.getProperty(Constants.SERVICE_RANKING), 0);
+        this.flag = ControlFlag.from(
+            (String) sr.getProperty(LoginModuleFactory.JAAS_CONTROL_FLAG)).flag();
+        this.realmName = (String) sr.getProperty(LoginModuleFactory.JAAS_REALM_NAME);
+        this.serviceReference = sr;
+    }
+
+    public Map<String, ?> options()
+    {
+        return Collections.emptyMap();
+    }
+
+    public LoginModuleControlFlag getControlFlag()
+    {
+        return flag;
+    }
+
+    public int ranking()
+    {
+        return ranking;
+    }
+
+    public String realmName()
+    {
+        return realmName;
+    }
+
+    public LoginModule createLoginModule()
+    {
+        return delegate.createLoginModule();
+    }
+
+    public String getClassName()
+    {
+        return delegate.getClass().getName();
+    }
+
+    public ServiceReference getServiceReference()
+    {
+        return serviceReference;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "OsgiLoginModuleProvider{" + "className=" + delegate.getClass().getName()
+            + ", ranking=" + ranking + ", flag=" + flag + ", realmName='" + realmName
+            + '\'' + '}';
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/internal/Util.java b/jaas/src/main/java/org/apache/felix/jaas/internal/Util.java
new file mode 100644
index 0000000..515891f
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/internal/Util.java
@@ -0,0 +1,210 @@
+/*
+ * 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.felix.jaas.internal;
+
+import java.util.*;
+
+
+final class Util
+{
+
+    public static Set<String> parseHeader(String header)
+    {
+        //Could have used Sling commons ManifestHeader.parse
+        //but our requirement are simple
+
+        header = trimToNull(header);
+        if (header == null)
+        {
+            return new HashSet<String>();
+        }
+
+        String[] splits = header.split(",");
+        Set<String> values = new HashSet<String>();
+        for (String s : splits)
+        {
+            s = trimToNull(s);
+            if (s != null)
+            {
+                values.add(s);
+            }
+        }
+        return values;
+    }
+
+    //Instead of adding dependency on commons StringUtil we copy the used method below
+
+    public static String trimToNull(String str)
+    {
+        String ts = trim(str);
+        return isEmpty(ts) ? null : ts;
+    }
+
+    private static String trim(String str)
+    {
+        return str == null ? null : str.trim();
+    }
+
+    public static boolean isEmpty(String str)
+    {
+        return str == null || str.length() == 0;
+    }
+
+    //----------------Methods taken from org.apache.sling.commons.osgi.PropertiesUtil
+
+    //These are required to safely access properties from ConfigurationAdmin
+
+    /**
+     * Returns the parameter as a string or the
+     * <code>defaultValue</code> if the parameter is <code>null</code>.
+     * @param propValue the property value or <code>null</code>
+     * @param defaultValue the default string value
+     */
+    public static String toString(Object propValue, String defaultValue)
+    {
+        propValue = toObject(propValue);
+        return (propValue != null) ? propValue.toString() : defaultValue;
+    }
+
+    /**
+     * Returns the parameter as an integer or the
+     * <code>defaultValue</code> if the parameter is <code>null</code> or if
+     * the parameter is not an <code>Integer</code> and cannot be converted to
+     * an <code>Integer</code> from the parameter's string value.
+     * @param propValue the property value or <code>null</code>
+     * @param defaultValue the default integer value
+     */
+    public static int toInteger(Object propValue, int defaultValue)
+    {
+        propValue = toObject(propValue);
+        if (propValue instanceof Integer)
+        {
+            return (Integer) propValue;
+        }
+        else if (propValue != null)
+        {
+            try
+            {
+                return Integer.valueOf(String.valueOf(propValue));
+            }
+            catch (NumberFormatException nfe)
+            {
+                // don't care, fall through to default value
+            }
+        }
+
+        return defaultValue;
+    }
+
+    /**
+     * Returns the parameter as a single value. If the
+     * parameter is neither an array nor a <code>java.util.Collection</code> the
+     * parameter is returned unmodified. If the parameter is a non-empty array,
+     * the first array element is returned. If the property is a non-empty
+     * <code>java.util.Collection</code>, the first collection element is returned.
+     * Otherwise <code>null</code> is returned.
+     * @param propValue the parameter to convert.
+     */
+    private static Object toObject(Object propValue)
+    {
+        if (propValue == null)
+        {
+            return null;
+        }
+        else if (propValue.getClass().isArray())
+        {
+            Object[] prop = (Object[]) propValue;
+            return prop.length > 0 ? prop[0] : null;
+        }
+        else if (propValue instanceof Collection<?>)
+        {
+            Collection<?> prop = (Collection<?>) propValue;
+            return prop.isEmpty() ? null : prop.iterator().next();
+        }
+        else
+        {
+            return propValue;
+        }
+    }
+
+    /**
+     * Returns the parameter as an array of Strings. If
+     * the parameter is a scalar value its string value is returned as a single
+     * element array. If the parameter is an array, the elements are converted to
+     * String objects and returned as an array. If the parameter is a collection, the
+     * collection elements are converted to String objects and returned as an array.
+     * Otherwise (if the property is <code>null</code>) a provided default value is
+     * returned.
+     * @param propValue The object to convert.
+     * @param defaultArray The default array to return.
+     */
+    public static String[] toStringArray(Object propValue, String[] defaultArray)
+    {
+        if (propValue == null)
+        {
+            // no value at all
+            return defaultArray;
+
+        }
+        else if (propValue instanceof String)
+        {
+            // single string
+            return new String[] { (String) propValue };
+
+        }
+        else if (propValue instanceof String[])
+        {
+            // String[]
+            return (String[]) propValue;
+
+        }
+        else if (propValue.getClass().isArray())
+        {
+            // other array
+            Object[] valueArray = (Object[]) propValue;
+            List<String> values = new ArrayList<String>(valueArray.length);
+            for (Object value : valueArray)
+            {
+                if (value != null)
+                {
+                    values.add(value.toString());
+                }
+            }
+            return values.toArray(new String[values.size()]);
+
+        }
+        else if (propValue instanceof Collection<?>)
+        {
+            // collection
+            Collection<?> valueCollection = (Collection<?>) propValue;
+            List<String> valueList = new ArrayList<String>(valueCollection.size());
+            for (Object value : valueCollection)
+            {
+                if (value != null)
+                {
+                    valueList.add(value.toString());
+                }
+            }
+            return valueList.toArray(new String[valueList.size()]);
+        }
+
+        return defaultArray;
+    }
+}
diff --git a/jaas/src/main/java/org/apache/felix/jaas/package-info.java b/jaas/src/main/java/org/apache/felix/jaas/package-info.java
new file mode 100644
index 0000000..40828e5
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/package-info.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provides support for performing JAAS based authentication in OSGi
+ *
+ * @version 1.0
+ */
+@Version("1.0")
+@Export(optional = "provide:=true")
+package org.apache.felix.jaas;
+
+import aQute.bnd.annotation.Version;
+import aQute.bnd.annotation.Export;
diff --git a/jaas/src/main/resources/OSGI-INF/l10n/bundle.properties b/jaas/src/main/resources/OSGI-INF/l10n/bundle.properties
new file mode 100644
index 0000000..c458298
--- /dev/null
+++ b/jaas/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -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.
+#
+intro=JAAS Configuration Details
diff --git a/jaas/src/main/resources/OSGI-INF/metatype/metatype.properties b/jaas/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..029db59
--- /dev/null
+++ b/jaas/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,62 @@
+#
+# 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.
+#
+# suppress inspection "UnusedProperty" for whole file
+
+jaas.name=Apache Felix JAAS Configuration Factory
+jaas.description=Captures JAAS configuration with options, control flag and classname
+
+
+jaas.classname.name=Class Name
+jaas.classname.description=Fully qualified name of the LoginModule class
+
+jaas.controlFlag.name=Control Flag
+jaas.controlFlag.description=The Flag value controls the overall behavior as authentication proceeds down the stack
+
+jaas.flag.required=Required
+jaas.flag.requisite=Requisite
+jaas.flag.sufficient=Sufficient
+jaas.flag.optional=Optional
+
+jaas.ranking.name = Ranking
+jaas.ranking.description = The relative ranking of this configuration.
+
+jaas.options.name = Options
+jaas.options.description = Properties in the form of key value pairs that are passed on to the LoginModule(name=value pairs)
+
+jaas.realmName.name = Realm Name
+jaas.realmName.description = Name of the application
+
+jaas.spi.name = Apache Felix JAAS Configuration SPI
+jaas.spi.description= JAAS Configuration SPI implementation which provides configuration based on OSGi ConfigAdmin
+
+jaas.defaultRealmName.name = Default JAAS Realm
+jaas.defaultRealmName.description = Default realm name to use if no realm is explicitly defined for LoginModule
+
+jaas.configProviderName.name=JAAS Config Provider name
+jaas.configProviderName.description=Name of the provider used to register the OSGi based configuration provider
+
+jaas.globalConfigPolicy.name=Global Configuration Policy
+jaas.globalConfigPolicy.description=Policy to manage global configuration. (1) Default: Global configuration is not \
+  modified. (2). Replace Global Configuration: Global configuration is replaced with OSGi based configuration \
+  (3). Proxy Global Configuration: Global configuration would be replaced with proxy configuration. The proxy \
+  would check with OSGi based configuration. If no config is found it would look in default global configuration
+
+jaas.configPolicy.default=Default
+jaas.configPolicy.replace=Replace Global Configuration
+jaas.configPolicy.proxy=Proxy Global Configuration
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 62d4d5c..0b6f6e1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -122,6 +122,7 @@
         <module>webconsole-plugins/event</module>
         <module>fileinstall</module>
         <module>useradmin</module>
+        <module>jaas</module>
 
 		<module>gogo</module>