We have built a J2EE application with a Swing GUI Rich Client (using the
J2EE
Reference Implementation application client container). When we added
security
to the EJBs, we found that if you call an EJB from a Swing event handler
the
security context is lost and the EJB container believes you to be guest.
However, if you make the call from the main method, or a separate thread
started from the main method, the security principal is propagated
correctly.
The output and code is included below. If anyone has seen anything like
this
before and knows why it may be happening, or better yet, what we can do
to make
it stop happening, your help would be greatly appreciated.
Regards,
Brett Beaumont
Dale V. Georg
================================
Dale V. Georg
Technical Manager
Indus Consultancy Services
[EMAIL PROTECTED]
(201) 261-3100 x229
================================
========= Output ==========
Initiating login ...
Looking up authenticator...
Binding name:`java:comp/env/com.ics.test.testAHome`
Running in this thread
bbeaumo
Running in another thread
bbeaumo
Now testing GUI
Button pressed
guest
Button pressed
guest
Out of wait loop
bbeaumo
Unbinding name:`java:comp/env/com.ics.test.testAHome`
=========== Client program (Class1Client.java) ============
package com.ics.test;
import java.util.Properties;
import javax.naming.*;
import javax.ejb.*;
import java.rmi.*;
import java.sql.SQLException;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* This package is EJB-part of project. It must contain the following:
* @Class com.ics.test.testAHome.java
* @Class com.ics.test.testA.java
*/
public class Class1Client extends WindowAdapter implements
Runnable,ActionListener {
private testAHome home;
/** Invoked when the button is pressed, this method callls the
* body of the client
*
* @param e Event
**/
public void actionPerformed(ActionEvent e) {
System.out.println("\nButton pressed");
try {
body();
} catch(Exception ex) {
System.out.println("Exception in body on button press");
}
}
/** Notifies the client that the main window has been closed
*
* @param e Event
**/
public synchronized void windowClosed(WindowEvent e) {
this.notify();
}
/** This method is required so that the the main method doesn't
* exit until the main window is closed
**/
public synchronized void waitForAWhile() {
try
{
this.wait();
} catch(Exception e) {
System.out.println("Interrupted");
}
}
/** Initialise the client. Looks up the home interface of the EJB
**/
public Class1Client() throws NamingException {
home = lookupHome();
}
/** Main method
*
* @param argv The command line parameters
**/
public static void main(String[] argv) {
// Create a client object
Class1Client client = null;
try {
client = new Class1Client();
}
catch(Exception e) {
System.out.println("Exception creating client : " +
e.getMessage());
System.exit(0);
}
try {
// Test security propagation from current thread - succeeds
System.out.println("Running in this thread");
client.body();
// Test security propagation from user created thread -
succeeds
System.out.println("Running in another thread");
Thread t = new Thread(client);
t.start();
t.join();
// Test security propagation from Swing GUI - fails
System.out.println("\n\nNow testing GUI");
client.makeWindow();
client.waitForAWhile();
// After window is closed, check if we can still propagate
the
// security context to the EJB container - succeeds
System.out.println("Out of wait loop");
client.body();
} catch (Exception e) {
e.printStackTrace();
}
}
/** Method used to test running EJBs from a normal thread **/
public void run() {
try {
body();
} catch(Exception e) {
System.out.println("Exception while running in second
thread");
}
}
public void body() throws CreateException, RemoteException,
RemoveException, SQLException, NamingException {
// Create the EJB
com.ics.test.testA ejb = home.create();
// Print out who the bean thinks I am
System.out.println(ejb.whoAmI());
ejb.remove();
}
/** Looks up the home interface of the test EJB
*
* @return Home interface of the testA EJB
**/
private testAHome lookupHome() throws NamingException {
Context ctx = getInitialContext();
com.ics.test.testAHome home = null;
try {
home = (com.ics.test.testAHome) ctx.lookup
("com.ics.test.testAHome");
} catch (NamingException e) {
e.printStackTrace();
}
return home;
}
/** Narrows the class **/
private Object narrow(Object obj, Class c) {
return javax.rmi.PortableRemoteObject.narrow(obj, c);
}
/** Retrieves the initial context
*
* @return The initial context
**/
private Context getInitialContext() throws NamingException {
Context ctx = null;
try {
ctx = new InitialContext();
} catch (NamingException e) {
e.printStackTrace();
}
return ctx;
}
/** Creates a simpe test window **/
public void makeWindow() {
// Create the window and its components
JFrame frame = new JFrame("Test Window");
JButton button = new JButton("Test");
// Add the event listeners
button.addActionListener(this);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.addWindowListener(this);
// Prepare window for display
frame.getContentPane().add(button);
frame.pack();
frame.show();
}
}
========= TestA EJB - Home Interface (TestAHome.java) =============
package com.ics.test;
import javax.ejb.*;
import java.rmi.RemoteException;
public interface testAHome extends EJBHome {
public testA create() throws RemoteException, CreateException;
}
========= TestA EJB - Remote Interface (TestA.java) ===============
package com.ics.test;
import javax.ejb.*;
import java.rmi.RemoteException;
public interface testAHome extends EJBHome {
public testA create() throws RemoteException, CreateException;
}
========== TestA EJB - Bean Implementation (testABean.java) =========
package com.ics.test;
import javax.ejb.*;
import javax.naming.*;
import java.rmi.RemoteException;
/**
* @ejbStateful Stateful
*/
public class testABean implements SessionBean {
private SessionContext ctx;
private transient boolean isDirty;
private transient boolean verboseMode = true;
/**
* Sets session context for bean
*/
public void setSessionContext(SessionContext context) throws
RemoteException {
if (verboseMode) System.out.println("Bean "+id()+";
setSessionContext
called");
ctx = context;
}
/**
* Called when bean is activated
*/
public void ejbActivate() throws RemoteException {
if (verboseMode) System.out.println("Bean "+id()+"; ejbActivate
called");
}
/**
* Called when bean is activated
*/
public void ejbPassivate() throws RemoteException {
if (verboseMode) System.out.println("Bean "+id()+"; ejbPasivate
called");
}
/**
* Remove bean
*/
public void ejbRemove() throws RemoteException {
setModified(false);
}
/**
* Create method
*/
public void ejbCreate() throws RemoteException, CreateException {
}
public int id() {
return System.identityHashCode(this);
}
/**
* Returns true if the bean was modified
*/
public boolean isModified() {
return isDirty;
}
/**
* Sets whether the bean was modified
*/
public void setModified(boolean flag) {
isDirty = flag;
}
public String whoAmI() {
return ctx.getCallerPrincipal().getName();
}
}
===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff EJB-INTEREST". For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".