001 package org.springframework.richclient.security;
002
003 import java.lang.reflect.InvocationTargetException;
004 import java.lang.reflect.Method;
005 import java.util.Iterator;
006 import java.util.List;
007 import java.util.Map;
008 import java.util.Vector;
009
010 import org.apache.commons.logging.Log;
011 import org.apache.commons.logging.LogFactory;
012 import org.springframework.context.ApplicationContext;
013 import org.springframework.context.ApplicationEvent;
014 import org.springframework.context.ApplicationListener;
015 import org.springframework.remoting.caucho.BurlapProxyFactoryBean;
016 import org.springframework.remoting.caucho.HessianProxyFactoryBean;
017 import org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean;
018 import org.springframework.richclient.application.Application;
019 import org.springframework.security.Authentication;
020
021 /**
022 * Correctly configures the username and password on Spring's remoting proxy
023 * factory beans.
024 *
025 * <P>
026 * This bean works with "Spring Remoting Proxy Factories" defined in the
027 * application context. Presently this includes the following Spring classes:
028 * {@link HessianProxyFactoryBean},{@link BurlapProxyFactoryBean}and {@link
029 * JaxRpcPortProxyFactoryBean}.
030 * </p>
031 *
032 * <P>
033 * This bean listens for any <code>ClientSecurityEvent</code> and responds as
034 * follows:
035 * </p>
036 *
037 * <P>
038 * Upon receipt of a {@link LoginEvent}, any Spring Remoting Proxy Factories
039 * will be located. Each located bean will have its username and password
040 * methods set to the <code>LoginEvent</code>'s principal and credentials
041 * respectively.
042 * </p>
043 *
044 * <P>
045 * Upon receipt of a {@link LogoutEvent}, any Spring Remoting Proxy Factories
046 * will be located. Each located bean will have its username and password
047 * methods set to <code>null</code>.
048 * </p>
049 *
050 * @author Ben Alex
051 */
052 public class RemotingSecurityConfigurer implements ApplicationListener {
053 //~ Static fields/initializers
054 // =============================================
055
056 protected static final Log logger = LogFactory.getLog(RemotingSecurityConfigurer.class);
057
058 //~ Methods
059 // ================================================================
060
061 public void onApplicationEvent(ApplicationEvent event) {
062 if (logger.isDebugEnabled() && event instanceof ClientSecurityEvent) {
063 logger.debug("Processing event: " + event.toString());
064 }
065
066 if (event instanceof LoginEvent) {
067 Authentication authentication = (Authentication)event.getSource();
068 updateExporters(authentication.getPrincipal().toString(), authentication.getCredentials().toString());
069 }
070 else if (event instanceof LogoutEvent) {
071 updateExporters(null, null);
072 }
073 }
074
075 /**
076 * Get the list of proxy factory beans that need to be updated.
077 * @return Array of beans to update
078 */
079 private Object[] getExporters() {
080 ApplicationContext appCtx = Application.instance().getApplicationContext();
081 List list = new Vector();
082
083 Class[] types = new Class[] {
084 HessianProxyFactoryBean.class,
085 BurlapProxyFactoryBean.class,
086 JaxRpcPortProxyFactoryBean.class
087 };
088
089 for( int i = 0; i < types.length; i++ ) {
090 Map map = appCtx.getBeansOfType(types[i], false, true);
091 Iterator iter = map.entrySet().iterator();
092
093 while (iter.hasNext()) {
094 Map.Entry entry = (Map.Entry)iter.next();
095 String beanName = (String)entry.getKey();
096 if( beanName.startsWith("&") ) {
097 list.add(entry.getValue());
098 }
099 }
100 }
101
102 return list.toArray();
103 }
104
105 private void updateExporters(String username, String password) {
106 Object[] factories = getExporters();
107
108 for (int i = 0; i < factories.length; i++) {
109 if (logger.isDebugEnabled()) {
110 logger.debug("Updating " + factories[i].toString() + " to username: " + username
111 + "; password: [PROTECTED]");
112 }
113
114 try {
115 Method method = factories[i].getClass().getMethod("setUsername", new Class[] { String.class });
116 method.invoke(factories[i], new Object[] { username });
117 }
118 catch (NoSuchMethodException ignored) {
119 logger.error("Could not call setter", ignored);
120 }
121 catch (IllegalAccessException ignored) {
122 logger.error("Could not call setter", ignored);
123 }
124 catch (InvocationTargetException ignored) {
125 logger.error("Could not call setter", ignored);
126 }
127
128 try {
129 Method method = factories[i].getClass().getMethod("setPassword", new Class[] { String.class });
130 method.invoke(factories[i], new Object[] { password });
131 }
132 catch (NoSuchMethodException ignored) {
133 logger.error("Could not call setter", ignored);
134 }
135 catch (IllegalAccessException ignored) {
136 logger.error("Could not call setter", ignored);
137 }
138 catch (InvocationTargetException ignored) {
139 logger.error("Could not call setter", ignored);
140 }
141 }
142 }
143 }