FELIX-3935 - Testcases for JAAS integration

Done the basic setup required for using Pax Exam. The pattern used is similar to used in SCR module. As next step we just need to implement different scenarios supported by this module.

Also adding a constant class to collect constant required for using jAAS support

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1453297 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/jaas/pom.xml b/jaas/pom.xml
index 167b41e..e6c5fe0 100644
--- a/jaas/pom.xml
+++ b/jaas/pom.xml
@@ -40,6 +40,13 @@
     </scm>
 
     <properties>
+      <pax-exam.version>3.0.0</pax-exam.version>
+      <bundle.build.name>
+        ${basedir}/target
+      </bundle.build.name>
+      <bundle.file.name>
+        ${bundle.build.name}/${project.build.finalName}.jar
+      </bundle.file.name>
     </properties>
     
     <build>
@@ -133,6 +140,33 @@
                     </execution>
                 </executions>
             </plugin>
+          <!-- integration tests run with pax-exam -->
+            <plugin>
+              <artifactId>maven-failsafe-plugin</artifactId>
+              <version>2.12</version>
+              <executions>
+                <execution>
+                  <goals>
+                    <goal>integration-test</goal>
+                    <goal>verify</goal>
+                  </goals>
+                </execution>
+              </executions>
+              <configuration>
+                <systemPropertyVariables>
+                  <project.bundle.file>${bundle.file.name}</project.bundle.file>
+                  <felix.ca.version>${felix.ca.version}</felix.ca.version>
+                </systemPropertyVariables>
+              </configuration>
+            </plugin>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-javadoc-plugin</artifactId>
+              <configuration>
+                <encoding>${project.build.sourceEncoding}</encoding>
+                <excludePackageNames>*.internal</excludePackageNames>
+              </configuration>
+            </plugin>
         </plugins>
     </build>
 
@@ -170,6 +204,43 @@
             <scope>test</scope>
             <version>4.10</version>
         </dependency>
+      <!-- Pax Exam Dependencies -->
+        <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-container-forked</artifactId>
+          <version>${pax-exam.version}</version>
+          <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-junit4</artifactId>
+          <version>${pax-exam.version}</version>
+          <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-link-mvn</artifactId>
+          <version>${pax-exam.version}</version>
+          <scope>test</scope>
+        </dependency>
+      <dependency>
+        <groupId>org.ops4j.pax.tinybundles</groupId>
+        <artifactId>tinybundles</artifactId>
+        <version>1.0.0</version>
+        <scope>test</scope>
+      </dependency>
+        <dependency>
+          <groupId>javax.inject</groupId>
+          <artifactId>javax.inject</artifactId>
+          <version>1</version>
+          <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-simple</artifactId>
+          <version>1.6.0</version>
+          <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <profiles>
diff --git a/jaas/src/main/java/org/apache/felix/jaas/JaasConstants.java b/jaas/src/main/java/org/apache/felix/jaas/JaasConstants.java
new file mode 100644
index 0000000..286288d
--- /dev/null
+++ b/jaas/src/main/java/org/apache/felix/jaas/JaasConstants.java
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+public interface JaasConstants {
+
+    String MODULE_CLASS = "Jaas-ModuleClass";
+}
diff --git a/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithTCCL.java b/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithTCCL.java
new file mode 100644
index 0000000..0957cd7
--- /dev/null
+++ b/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithTCCL.java
@@ -0,0 +1,54 @@
+/*
+ * 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.integration;
+
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class ITJaasWithTCCL extends JaasTestBase
+{
+    static
+    {
+        // uncomment to enable debugging of this test class
+        //        paxRunnerVmOption = DEBUG_VM_OPTION;
+
+    }
+
+    @Override
+    protected Option addExtraOptions()
+    {
+        return composite(streamBundle(createConfigBasedBundle()));
+    }
+
+    @Test
+    public void testJaasWithTCCL()
+    {
+
+    }
+}
diff --git a/jaas/src/test/java/org/apache/felix/jaas/integration/JaasTestBase.java b/jaas/src/test/java/org/apache/felix/jaas/integration/JaasTestBase.java
new file mode 100644
index 0000000..18b9d47
--- /dev/null
+++ b/jaas/src/test/java/org/apache/felix/jaas/integration/JaasTestBase.java
@@ -0,0 +1,133 @@
+/*
+ * 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.integration;
+
+import static org.ops4j.pax.exam.CoreOptions.frameworkProperty;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+import java.io.File;
+import java.io.InputStream;
+
+import javax.inject.Inject;
+
+import org.apache.felix.jaas.JaasConstants;
+import org.apache.felix.jaas.integration.common.SimpleCallbackHandler;
+import org.apache.felix.jaas.integration.common.SimplePrincipal;
+import org.apache.felix.jaas.integration.sample1.ConfigLoginModule;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.exam.ProbeBuilder;
+import org.ops4j.pax.exam.TestProbeBuilder;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.util.PathUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+public abstract class JaasTestBase
+{
+    @Inject
+    protected BundleContext bundleContext;
+
+    // the name of the system property providing the bundle file to be installed and tested
+    protected static final String BUNDLE_JAR_SYS_PROP = "project.bundle.file";
+
+    // the default bundle jar file name
+    protected static final String BUNDLE_JAR_DEFAULT = "target/jaas.jar";
+
+    // the default boot jar file name
+    protected static final String BOOT_JAR_DEFAULT = "target/jaas-boot.jar";
+
+    // the JVM option to set to enable remote debugging
+    protected static final String DEBUG_VM_OPTION = "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=31313";
+
+    // the actual JVM option set, extensions may implement a static
+    // initializer overwriting this value to have the configuration()
+    // method include it when starting the OSGi framework JVM
+    protected static String paxRunnerVmOption = null;
+
+    @Configuration
+    public Option[] config()
+    {
+        String baseDir = PathUtils.getBaseDir();
+        final String bundleFileName = System.getProperty(BUNDLE_JAR_SYS_PROP,
+            BUNDLE_JAR_DEFAULT);
+        final File bundleFile = new File(bundleFileName);
+        if (!bundleFile.canRead())
+        {
+            throw new IllegalArgumentException("Cannot read from bundle file "
+                + bundleFileName + " specified in the " + BUNDLE_JAR_SYS_PROP
+                + " system property");
+        }
+        Option[] base = options(
+            // the current project (the bundle under test)
+            CoreOptions.bundle(bundleFile.toURI().toString()),
+            mavenBundle("org.ops4j.pax.tinybundles", "tinybundles").versionAsInProject(),
+
+            frameworkProperty("osgi.clean").value("true"),
+            systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
+
+            junitBundles(),
+
+            streamBundle(createCommonTestUtilBundle()),
+
+            addExtraOptions());
+        final Option vmOption = (paxRunnerVmOption != null) ? CoreOptions.vmOption(paxRunnerVmOption)  : null;
+        return OptionUtils.combine(base, vmOption);
+    }
+
+    @ProbeBuilder
+    public TestProbeBuilder extendProbe(TestProbeBuilder builder)
+    {
+        builder.setHeader("Export-Package", "org.apache.felix.jaas.integration");
+        builder.setHeader("Bundle-ManifestVersion", "2");
+        return builder;
+    }
+
+    protected InputStream createConfigBasedBundle()
+    {
+        return TinyBundles.bundle()
+                .add(ConfigLoginModule.class)
+                .set(JaasConstants.MODULE_CLASS,"org.apache.felix.jaas.integration.sample1.ConfigLoginModule")
+                .set(Constants.BUNDLE_SYMBOLICNAME, "org.apache.felix.jaas.sample1")
+                .build(withBnd());
+    }
+
+    protected InputStream createCommonTestUtilBundle()
+    {
+        return TinyBundles.bundle().add(SimplePrincipal.class)
+                .add(SimpleCallbackHandler.class)
+                .set(Constants.BUNDLE_SYMBOLICNAME,"org.apache.felix.jaas.testcommon")
+                .set(Constants.EXPORT_PACKAGE,"org.apache.felix.jaas.integration.common")
+                .build(withBnd());
+    }
+
+    protected Option addExtraOptions()
+    {
+        return new DefaultCompositeOption();
+    }
+}
diff --git a/jaas/src/test/java/org/apache/felix/jaas/integration/common/SimpleCallbackHandler.java b/jaas/src/test/java/org/apache/felix/jaas/integration/common/SimpleCallbackHandler.java
new file mode 100644
index 0000000..916d87e
--- /dev/null
+++ b/jaas/src/test/java/org/apache/felix/jaas/integration/common/SimpleCallbackHandler.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.integration.common;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public class SimpleCallbackHandler implements CallbackHandler
+{
+    private final String username;
+    private final String password;
+
+    public SimpleCallbackHandler(String username, String password)
+    {
+        this.username = username;
+        this.password = password;
+    }
+
+    @Override
+    public void handle(Callback[] callbacks) throws IOException,
+        UnsupportedCallbackException
+    {
+        for (Callback c : callbacks)
+        {
+            if (c instanceof NameCallback)
+            {
+                ((NameCallback) c).setName(username);
+            }
+            if (c instanceof PasswordCallback)
+            {
+                ((PasswordCallback) c).setPassword(password.toCharArray());
+            }
+        }
+    }
+}
diff --git a/jaas/src/test/java/org/apache/felix/jaas/integration/common/SimplePrincipal.java b/jaas/src/test/java/org/apache/felix/jaas/integration/common/SimplePrincipal.java
new file mode 100644
index 0000000..723aba5
--- /dev/null
+++ b/jaas/src/test/java/org/apache/felix/jaas/integration/common/SimplePrincipal.java
@@ -0,0 +1,66 @@
+/*
+ * 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.integration.common;
+
+import java.security.Principal;
+
+public class SimplePrincipal implements Principal
+{
+    private final String name;
+
+    public SimplePrincipal(String name)
+    {
+        this.name = name;
+    }
+
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        SimplePrincipal that = (SimplePrincipal) o;
+
+        if (!name.equals(that.name))
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return name.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "SimplePrincipal{" + "name='" + name + '\'' + '}';
+    }
+}
diff --git a/jaas/src/test/java/org/apache/felix/jaas/integration/sample1/ConfigLoginModule.java b/jaas/src/test/java/org/apache/felix/jaas/integration/sample1/ConfigLoginModule.java
new file mode 100644
index 0000000..de383a5
--- /dev/null
+++ b/jaas/src/test/java/org/apache/felix/jaas/integration/sample1/ConfigLoginModule.java
@@ -0,0 +1,111 @@
+/*
+ * 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.integration.sample1;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.apache.felix.jaas.integration.common.SimplePrincipal;
+
+public class ConfigLoginModule implements LoginModule
+{
+    private Subject subject;
+    private CallbackHandler handler;
+    private Map<String, ?> options;
+    private Map<String, ?> sharedState;
+    private boolean succeeded;
+    private String name;
+
+    @Override
+    public void initialize(Subject subject, CallbackHandler callbackHandler,
+        Map<String, ?> sharedState, Map<String, ?> options)
+    {
+        this.subject = subject;
+        this.options = options;
+        this.handler = callbackHandler;
+        this.sharedState = sharedState;
+    }
+
+    @Override
+    public boolean login() throws LoginException
+    {
+        Callback[] callbacks = new Callback[2];
+        callbacks[0] = new NameCallback("Name");
+        callbacks[1] = new PasswordCallback("Name", false);
+
+        try
+        {
+            handler.handle(callbacks);
+        }
+        catch (IOException e)
+        {
+            throw new LoginException(e.getMessage());
+        }
+        catch (UnsupportedCallbackException e)
+        {
+            throw new LoginException(e.getMessage());
+        }
+
+        String name = ((NameCallback) callbacks[0]).getName();
+        char[] password = ((PasswordCallback) callbacks[0]).getPassword();
+
+        boolean result = Arrays.equals(name.toCharArray(), password);
+        succeeded = result;
+        this.name = name;
+        return result;
+    }
+
+    @Override
+    public boolean commit() throws LoginException
+    {
+        if (succeeded)
+        {
+            subject.getPrincipals().add(new SimplePrincipal(name));
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean abort() throws LoginException
+    {
+        if (succeeded)
+        {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean logout() throws LoginException
+    {
+        return false;
+    }
+}