001    package org.esupportail.cas.server.util;
002    
003    import java.lang.reflect.Constructor;
004    import java.lang.reflect.InvocationTargetException;
005    import java.util.Iterator;
006    import java.util.LinkedList;
007    import java.util.List;
008    
009    import org.dom4j.Element;
010    
011    /**
012     * This abstract class implements a redundant handler, with a list 
013     * of servers that will be used for redundancy.
014     *
015     * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
016     */
017    public abstract class RedundantHandler extends BasicHandler {
018    
019            /**
020             * the list of servers to be used for authentication. Modified by
021             * addServer().
022             */
023            private LinkedList servers;
024    
025            
026            /**
027             * retrieve the list of the servers.
028             *
029             * @return the list of the servers used for authentication.
030             */
031            public final List getServers() {
032                    return servers;
033            }
034            
035            /**
036             * Constructor.
037             *
038             * @param handlerElement the XML element that declares the handler 
039             * in the configuration file
040             * @param configDebug debugging mode of the global configuration
041             */
042            protected RedundantHandler(
043                            final Element handlerElement, 
044                            final Boolean configDebug) {
045                    super(handlerElement, configDebug);
046                    traceBegin();
047                    servers = new LinkedList();
048                    traceEnd();
049            }
050            
051            /**
052             * Constructor.
053             *
054             * @param serverElementNeeded true to force the handler to have at least one server sub-element
055             * @param serverClassname the classname of the server to create for the handler
056             * @throws Exception Exception
057             */     
058            protected final void addServers(
059                            final boolean serverElementNeeded,
060                            final String serverClassname) throws Exception {
061                    traceBegin();
062    
063                    Element configElement = getConfigElement();
064                    
065                    // check if a config/server element is needed
066                    if (configElement == null) {
067                            if (serverElementNeeded) {
068                                    traceThrow(new MisconfiguredHandlerException(
069                                                    "A \"config\" element is needed by \"" 
070                                                    + getClass().getName() 
071                                                    + "\" handlers."));
072                            }
073                            return;
074                    }
075    
076                    trace("Looking for servers...");
077    
078                    // get the list of all the server elements              
079                    List serverElements = configElement.elements("server");
080                    
081                    // check that at least one server is declared 
082                    if (serverElementNeeded) {
083                            if (serverElements.isEmpty()) {
084                                    traceThrow(new MisconfiguredHandlerException(
085                                                    "At least one \"server\" element is needed to configure \"" 
086                                                    + getClass().getName() 
087                                                    + "\" handlers."));
088                            }
089                    }
090    
091                    for (Iterator i = serverElements.iterator(); i.hasNext();) {
092                            trace("Found a server.");
093    
094                            // load the server class
095                            Class serverClass = null;
096                            try {
097                                    trace("Getting the " + serverClassname + " class...");
098                                    serverClass = Class.forName(serverClassname);
099                            } catch (ClassNotFoundException e) {
100                                    // this should never happen
101                                    traceThrow(new MisconfiguredHandlerException(
102                                                    "Class \"" 
103                                                    + serverClassname 
104                                                    + "\" could not be loaded."));
105                            }
106    
107                            // get the constructor
108                            Class[] serverConstructorArgumentTypes = {
109                                            Boolean.class, 
110                                            RedundantHandler.class, 
111                                            Element.class};
112                            Constructor serverConstructor = null;
113                            try {
114                                    trace("Getting the constructor...");
115                                    serverConstructor = serverClass.getConstructor(serverConstructorArgumentTypes);
116                            } catch (Exception e) {
117                                    traceThrow(new MisconfiguredHandlerException(
118                                                    "The constructor of Class \"" 
119                                                    + serverClassname 
120                                                    + "\" could not be loaded because a \"" 
121                                                    + e.getClass().getName() 
122                                                    + "\" exception was raised: " 
123                                                    + e.getMessage()));
124                            }
125    
126                            // create an instance
127                            Object[] serverConstructorArguments = {new Boolean(isDebug()), this, i.next()};
128                            Server server = null;
129                            try {
130                                    trace("Creating a new instance...");
131                                    server = (Server) serverConstructor.newInstance(serverConstructorArguments);
132                            } catch (InvocationTargetException e) {
133                                    traceThrow(new MisconfiguredHandlerException(e.getCause().getMessage()));
134                            } catch (Exception e) {
135                                    traceThrow(new MisconfiguredHandlerException(
136                                                    "Class \"" 
137                                                    + serverClassname 
138                                                    + "\" could not be instanciated because a \"" 
139                                                    + e.getClass().getName() 
140                                                    + "\" exception was raised: " 
141                                                    + e.getMessage()));
142                            }
143    
144                            // add the newly created object to the list of servers
145                            servers.add(server);
146                            
147                            trace("Server added.");
148                    }
149    
150                    trace(servers.size() +  " servers found.");
151                    traceEnd();
152            }
153            
154            /**
155             * Tries to Authenticate a user by accessing all the servers.
156             *
157             * @param username the username to authenticate
158             * @param password the correspoding password
159             *
160             * @return BasicHandlerSUCCEDED on success, or 
161             * BasicHandler.FAILED_CONTINUE otherwise.
162             */
163             public final int authenticate(final String username,
164                            final String password) {
165                    traceBegin();
166                    
167                    for (Iterator i = servers.iterator(); i.hasNext();) {
168                            Server server = (Server) i.next();
169                            switch (server.authenticate(username, password)) {
170                                    case Server.AUTHENTICATE_SUCCESS:
171                                            trace("Server matched.");
172                                    traceEnd("SUCCEEDED");
173                                    return SUCCEEDED;
174                                    case Server.AUTHENTICATE_NOAUTH:
175                                            trace("Server did not match.");
176                                    traceEnd("FAILED_CONTINUE");
177                                    return FAILED_CONTINUE;
178                                    default:
179                                            trace("Server failure, trying next");
180                                    break;
181                            }           
182                    }
183                    trace("No server matched.");
184                    traceEnd("FAILED_CONTINUE");
185                    return FAILED_CONTINUE;
186            }
187            
188    }
189