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    }