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 }