FELIX-3935 - Testcases for JAAS integration

Adding testcases for following authentication scenarios
-- With TCCL switch
-- With Felix JAAS related classes on bootclasspath
-- With LoginContextFactory

Removing JaasConstants class from API for now as these constants are only required by testcases

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1458707 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/jaas/pom.xml b/jaas/pom.xml
index 3496aa7..9cbc129 100644
--- a/jaas/pom.xml
+++ b/jaas/pom.xml
@@ -47,6 +47,9 @@
       <bundle.file.name>
         ${bundle.build.name}/${project.build.finalName}.jar
       </bundle.file.name>
+      <bundle.boot.file>
+        ${bundle.build.name}/${project.build.finalName}-boot.jar
+      </bundle.boot.file>
     </properties>
     
     <build>
@@ -155,7 +158,7 @@
               <configuration>
                 <systemPropertyVariables>
                   <project.bundle.file>${bundle.file.name}</project.bundle.file>
-                  <felix.ca.version>${felix.ca.version}</felix.ca.version>
+                  <project.boot.file>${bundle.file.name}</project.boot.file>
                 </systemPropertyVariables>
               </configuration>
             </plugin>
@@ -241,6 +244,12 @@
           <version>1.6.0</version>
           <scope>test</scope>
         </dependency>
+        <dependency>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>org.apache.felix.configadmin</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
deleted file mode 100644
index 286288d..0000000
--- a/jaas/src/main/java/org/apache/felix/jaas/JaasConstants.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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/ITJaasWithBootClasspath.java b/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithBootClasspath.java
new file mode 100644
index 0000000..ab4fe06
--- /dev/null
+++ b/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithBootClasspath.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.jaas.integration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+
+import org.apache.felix.jaas.integration.common.SimpleCallbackHandler;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+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;
+
+import static org.junit.Assert.assertFalse;
+import static org.ops4j.pax.exam.CoreOptions.bootDelegationPackage;
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.exam.CoreOptions.vmOption;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class ITJaasWithBootClasspath extends JaasTestBase
+{
+
+    // the default boot jar file name
+    protected static final String BOOT_JAR_DEFAULT = "target/jaas-boot.jar";
+
+    // the name of the system property providing the bundle file to be installed and tested
+    protected static final String BOOT_JAR_SYS_PROP = "project.boot.file";
+
+    @Rule
+    public TestName name= new TestName();
+
+    static
+    {
+        // uncomment to enable debugging of this test class
+//                paxRunnerVmOption = DEBUG_VM_OPTION;
+
+    }
+
+    @Override
+    protected Option addExtraOptions()
+    {
+        final String bundleFileName = System.getProperty(BOOT_JAR_SYS_PROP,
+                BOOT_JAR_DEFAULT);
+        final File bundleFile = new File(bundleFileName);
+        if (!bundleFile.canRead())
+        {
+            throw new IllegalArgumentException("Cannot read from boot file "
+                    + bundleFileName + " specified in the " + BUNDLE_JAR_SYS_PROP
+                    + " system property");
+        }
+        return composite(
+                vmOption("-Xbootclasspath/a:"+bundleFile.getAbsolutePath()),
+                bootDelegationPackage("org.apache.felix.jaas.boot"),
+                streamBundle(createConfigBasedBundle())
+        );
+    }
+
+
+    /**
+     * Creates the scenario where jaas-boot jar is placed in bootclasspath. With this the client
+     * code need not switch the TCCL
+     */
+    @Test
+    public void testJaasWithBoot() throws Exception
+    {
+        String realmName = name.getMethodName();
+        createConfigSpiConfig();
+        createLoginModuleConfig(realmName);
+        delay();
+
+        CallbackHandler handler = new SimpleCallbackHandler("foo", "foo");
+        Configuration config = Configuration.getInstance("JavaLoginConfig", null,"FelixJaasProvider");
+        Subject s = new Subject();
+
+        LoginContext lc = new LoginContext(realmName, s, handler, config);
+        lc.login();
+
+        assertFalse(s.getPrincipals().isEmpty());
+    }
+
+}
diff --git a/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithConfigBasedLoginModule.java b/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithConfigBasedLoginModule.java
new file mode 100644
index 0000000..7b76e05
--- /dev/null
+++ b/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithConfigBasedLoginModule.java
@@ -0,0 +1,126 @@
+/*
+ * 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 java.io.IOException;
+
+import javax.inject.Inject;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.felix.jaas.LoginContextFactory;
+import org.apache.felix.jaas.integration.common.SimpleCallbackHandler;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+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;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class ITJaasWithConfigBasedLoginModule extends JaasTestBase
+{
+
+    @Inject
+    private LoginContextFactory loginContextFactory;
+
+    @Rule
+    public TestName name= new TestName();
+
+    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() throws Exception {
+        String realmName = name.getMethodName();
+        createConfigSpiConfig();
+        createLoginModuleConfig(realmName);
+        delay();
+
+        CallbackHandler handler = new SimpleCallbackHandler("foo","foo");
+        Configuration config = Configuration.getInstance("JavaLoginConfig",null,"FelixJaasProvider");
+
+        Subject s = new Subject();
+        final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        try
+        {
+            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+            LoginContext lc = new LoginContext(realmName,s,handler,config);
+            lc.login();
+        }
+        finally
+        {
+            Thread.currentThread().setContextClassLoader(cl);
+        }
+
+        assertFalse(s.getPrincipals().isEmpty());
+    }
+
+    @Test
+    public void testJaasWithFactory() throws Exception
+    {
+        String realmName = name.getMethodName();
+        createConfigSpiConfig();
+        createLoginModuleConfig(realmName);
+        delay();
+
+        CallbackHandler handler = new SimpleCallbackHandler("foo", "foo");
+
+        Subject s = new Subject();
+
+        //Using LoginFactory we can avoid providing Configuration and switching TCCL
+        LoginContext lc = loginContextFactory.createLoginContext(realmName, s, handler);
+        lc.login();
+
+        assertFalse(s.getPrincipals().isEmpty());
+
+        //Negative case. Login fails with incorrect password
+        try
+        {
+            LoginContext lc2 = loginContextFactory.createLoginContext(realmName, s,
+                    new SimpleCallbackHandler("foo", "bar"));
+            lc2.login();
+            fail("Login should have failed");
+        }catch(LoginException e){
+
+        }
+    }
+}
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
deleted file mode 100644
index 0957cd7..0000000
--- a/jaas/src/test/java/org/apache/felix/jaas/integration/ITJaasWithTCCL.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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
index 18b9d47..7953c8c 100644
--- a/jaas/src/test/java/org/apache/felix/jaas/integration/JaasTestBase.java
+++ b/jaas/src/test/java/org/apache/felix/jaas/integration/JaasTestBase.java
@@ -19,20 +19,14 @@
 
 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.IOException;
 import java.io.InputStream;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
 
 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;
@@ -47,21 +41,30 @@
 import org.ops4j.pax.tinybundles.core.TinyBundles;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+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;
 
 public abstract class JaasTestBase
 {
     @Inject
     protected BundleContext bundleContext;
 
+    @Inject
+    protected ConfigurationAdmin ca;
+
     // 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";
 
@@ -87,6 +90,7 @@
             // the current project (the bundle under test)
             CoreOptions.bundle(bundleFile.toURI().toString()),
             mavenBundle("org.ops4j.pax.tinybundles", "tinybundles").versionAsInProject(),
+            mavenBundle( "org.apache.felix", "org.apache.felix.configadmin").versionAsInProject(),
 
             frameworkProperty("osgi.clean").value("true"),
             systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
@@ -112,7 +116,7 @@
     {
         return TinyBundles.bundle()
                 .add(ConfigLoginModule.class)
-                .set(JaasConstants.MODULE_CLASS,"org.apache.felix.jaas.integration.sample1.ConfigLoginModule")
+                .set("Jaas-ModuleClass","org.apache.felix.jaas.integration.sample1.ConfigLoginModule")
                 .set(Constants.BUNDLE_SYMBOLICNAME, "org.apache.felix.jaas.sample1")
                 .build(withBnd());
     }
@@ -126,8 +130,37 @@
                 .build(withBnd());
     }
 
+    protected String createConfigSpiConfig() throws IOException {
+        org.osgi.service.cm.Configuration config = ca.getConfiguration("org.apache.felix.jaas.ConfigurationSpi",null);
+        Properties p = new Properties();
+        config.update(p);
+        return config.getPid();
+    }
+
     protected Option addExtraOptions()
     {
         return new DefaultCompositeOption();
     }
+
+    protected static void delay()
+    {
+        try
+        {
+            TimeUnit.MILLISECONDS.sleep(300);
+        }
+        catch ( InterruptedException ie )
+        {
+            // dont care
+        }
+    }
+
+    protected String createLoginModuleConfig(String realmName) throws IOException {
+        org.osgi.service.cm.Configuration config =
+                ca.createFactoryConfiguration("org.apache.felix.jaas.Configuration.factory",null);
+        Properties p = new Properties();
+        p.setProperty("jaas.classname","org.apache.felix.jaas.integration.sample1.ConfigLoginModule");
+        p.setProperty("jaas.realmName",realmName);
+        config.update(p);
+        return config.getPid();
+    }
 }
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
index de383a5..a2964a2 100644
--- 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
@@ -74,7 +74,7 @@
         }
 
         String name = ((NameCallback) callbacks[0]).getName();
-        char[] password = ((PasswordCallback) callbacks[0]).getPassword();
+        char[] password = ((PasswordCallback) callbacks[1]).getPassword();
 
         boolean result = Arrays.equals(name.toCharArray(), password);
         succeeded = result;