/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.security.test;
import java.lang.reflect.UndeclaredThrowableException;
import java.rmi.RemoteException;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.login.LoginContext;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jboss.test.util.AppCallbackHandler;
import org.jboss.test.JBossTestCase;
import org.jboss.test.JBossTestSetup;
import org.jboss.test.security.interfaces.StatelessSession;
import org.jboss.test.security.interfaces.StatelessSessionHome;
import org.jboss.logging.Logger;
/** Test of the secure remote password(SRP) session key to perform crypto
operations.
@author Scott.Stark@jboss.org
@version $Revision: 81036 $
*/
public class SRPUnitTestCase extends JBossTestCase
{
static final String JAR = "security-srp.jar";
static String username = "scott";
static char[] password = "echoman".toCharArray();
LoginContext lc;
boolean loggedIn;
public SRPUnitTestCase(String name)
{
super(name);
}
/** Test that the echo method is secured by the SRPCacheLogin module
*/
public void testEchoArgs() throws Exception
{
log.debug("+++ testEchoArgs");
login("srp-test", username, password);
Object obj = getInitialContext().lookup("srp-jce.StatelessSession");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found StatelessSessionHome");
StatelessSession bean = home.create();
log.debug("Created srp-jce.StatelessSession");
try
{
log.debug("Bean.echo('Hello') -> "+bean.echo("Hello"));
}
catch(Exception e)
{
Throwable t = e;
if( e instanceof UndeclaredThrowableException )
{
UndeclaredThrowableException ex = (UndeclaredThrowableException) e;
t = ex.getUndeclaredThrowable();
}
else if( e instanceof RemoteException )
{
RemoteException ex = (RemoteException) e;
t = ex.detail;
}
log.error("echo failed", t);
boolean failure = true;
if( t instanceof SecurityException )
{
String msg = t.getMessage();
if( msg.startsWith("Unsupported keysize") )
{
/* The size of the srp session key is bigger than the JCE version
in use supports. Most likely the unlimited strength policy is
not installed so don't fail the test.
*/
failure = false;
log.info("Not failing test due to key size issue");
}
}
if( failure )
fail("Call to echo failed: "+t.getMessage());
}
logout();
}
/** Test that the echo method is secured by the SRPCacheLogin module when
* using multi-session srp with two threads
*/
public void testMultiUserEchoArgs() throws Exception
{
log.debug("+++ testMultiUserEchoArgs");
UserThread ut0 = new UserThread(log);
UserThread ut1 = new UserThread(log);
Thread t0 = new Thread(ut0, "UserThread#0");
t0.setDaemon(true);
t0.start();
Thread t1 = new Thread(ut1, "UserThread#1");
t1.setDaemon(true);
t1.start();
// Release the ut0 thread and wait for it to finish the first ejb call
synchronized( ut0 )
{
ut0.semaphore = true;
ut0.notify();
log.info("waiting on ut0 #1");
ut0.wait(5000);
}
log.info("released ut0 #1");
// Release the ut1 thread and wait for it to finish the first ejb call
synchronized( ut1 )
{
ut1.semaphore = true;
ut1.notify();
log.info("waiting on ut1 #1");
ut1.wait(5000);
}
log.info("released ut1 #1");
assertTrue("UserThread0.ex == null", ut0.ex == null);
// Release the ut1 thread and wait for it to finish the second ejb call
synchronized( ut1 )
{
ut1.semaphore = true;
ut1.notify();
log.info("waiting on ut1 #2");
ut1.wait(5000);
}
log.info("released ut1 #2");
assertTrue("UserThread1.ex == null", ut1.ex == null);
// Release the ut0 thread and wait for it to finish the second ejb call
synchronized( ut0 )
{
ut0.semaphore = true;
ut0.notify();
log.info("waiting on ut0 #2");
ut0.wait(5000);
}
log.info("released ut0 #2");
t0.join();
log.debug("UserThread0.ex", ut0.ex);
t1.join();
log.debug("UserThread1.ex", ut1.ex);
assertTrue("UserThread0.ex == null", ut0.ex == null);
assertTrue("UserThread1.ex == null", ut1.ex == null);
}
/** Login using the given confName login configuration with the provided
username and password credential.
*/
private void login(String confName, String username, char[] password)
throws Exception
{
if( loggedIn )
return;
lc = null;
AppCallbackHandler handler = new AppCallbackHandler(username, password);
log.debug("Creating LoginContext("+confName+")");
lc = new LoginContext(confName, handler);
lc.login();
log.debug("Created LoginContext, subject="+lc.getSubject());
loggedIn = true;
}
private void logout() throws Exception
{
if( loggedIn )
{
loggedIn = false;
lc.logout();
}
}
/**
* Setup the test suite.
*/
public static Test suite() throws Exception
{
TestSuite suite = new TestSuite();
suite.addTest(new TestSuite(SRPUnitTestCase.class));
// Create an initializer for the test suite
TestSetup wrapper = new JBossTestSetup(suite)
{
protected void setUp() throws Exception
{
super.setUp();
deploy(JAR);
// Establish the JAAS login config
String authConfPath = super.getResourceURL("security-srp/auth.conf");
System.setProperty("java.security.auth.login.config", authConfPath);
}
protected void tearDown() throws Exception
{
undeploy(JAR);
super.tearDown();
}
};
return wrapper;
}
class UserThread implements Runnable
{
boolean semaphore;
Throwable ex;
Logger log;
UserThread(Logger log)
{
this.log = log;
}
public synchronized boolean semaphore()
{
semaphore = true;
return semaphore;
}
public void run()
{
try
{
internalTestEchoArgs();
}
catch(Throwable t)
{
this.ex = t;
t.printStackTrace();
}
}
private synchronized void internalTestEchoArgs()
throws Exception
{
log.debug("+++ internalTestEchoArgs");
AppCallbackHandler handler = new AppCallbackHandler(username, password);
log.debug("Creating LoginContext(srp-test-multi)");
LoginContext lc = new LoginContext("srp-test-multi", handler);
lc.login();
log.debug("Created LoginContext, subject="+lc.getSubject());
Object obj = getInitialContext().lookup("srp.StatelessSession");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
// Wait for the test thread to tell use to continue
log.debug("Enter wait");
while( semaphore == false )
{
log.info("waiting for notification");
wait(1000);
}
semaphore = false;
log.debug("Notified, Found StatelessSessionHome");
StatelessSession bean = home.create();
log.debug("Created srp.StatelessSession");
log.debug("Bean.echo('Hello') -> "+bean.echo("Hello"));
notifyAll();
log.debug("Notified all, enter wait#2");
while( semaphore == false )
{
log.info("waiting for notification");
wait(1000);
}
log.debug("Notified, Bean.echo('Hello#2') -> "+bean.echo("Hello#2"));
notifyAll();
log.debug("Notified all, logging out");
lc.logout();
log.debug("Logout");
}
}
}