001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.console.securitymanager.realm;
018    
019    import java.io.Serializable;
020    import java.io.InputStream;
021    import java.io.IOException;
022    import java.util.List;
023    import java.util.ArrayList;
024    import java.util.Properties;
025    import java.util.Iterator;
026    import java.util.Map;
027    import java.util.HashMap;
028    import java.util.Collections;
029    import java.util.Comparator;
030    import org.apache.commons.logging.Log;
031    import org.apache.commons.logging.LogFactory;
032    
033    /**
034     * Describes an available login module, including how to create and configure it.
035     * Reads the list of available login modules from a properties file on the class path.
036     *
037     * @version $Rev: 476061 $ $Date: 2006-11-17 01:36:50 -0500 (Fri, 17 Nov 2006) $
038     */
039    public class MasterLoginModuleInfo implements Serializable {
040        private final static Log log = LogFactory.getLog(MasterLoginModuleInfo.class);
041        private static MasterLoginModuleInfo[] allModules;
042        private String name;
043        private String className;
044        private boolean testable = true;
045        private OptionInfo[] options = new OptionInfo[0];
046    
047        private MasterLoginModuleInfo(String name, String className) {
048            this.name = name;
049            this.className = className;
050        }
051    
052        public OptionInfo[] getOptions() {
053            return options;
054        }
055    
056        public Map getOptionMap() {
057            Map map = new HashMap();
058            for (int i = 0; i < options.length; i++) {
059                OptionInfo info = options[i];
060                map.put(info.getName(), info);
061            }
062            return map;
063        }
064    
065        public String getName() {
066            return name;
067        }
068    
069        public String getClassName() {
070            return className;
071        }
072    
073        public boolean isTestable() {
074            return testable;
075        }
076    
077        private void setTestable(boolean testable) {
078            this.testable = testable;
079        }
080    
081        private void setOptions(OptionInfo[] options) {
082            this.options = options;
083        }
084    
085        public static MasterLoginModuleInfo[] getAllModules() {
086            if(allModules == null) {
087                allModules = loadModules();
088            }
089            return allModules;
090        }
091    
092        private static MasterLoginModuleInfo[] loadModules() {
093            List list = new ArrayList();
094            Map map = new HashMap(), fieldMap = new HashMap();
095            InputStream in = MasterLoginModuleInfo.class.getResourceAsStream("/login-modules.properties");
096            if(in == null) {
097                log.error("Unable to locate login module properties file");
098                return null;
099            }
100            Properties props = new Properties();
101            try {
102                props.load(in);
103            } catch (IOException e) {
104                log.error("Unable to read login module properties file", e);
105            } finally {
106                try {
107                    in.close();
108                } catch (java.io.IOException ignored) {
109                    // ignore
110                }
111            }
112            for (Iterator it = props.keySet().iterator(); it.hasNext();) {
113                String key = (String) it.next();
114                if(key.startsWith("module.")) {
115                    String name = key.substring(7, key.indexOf('.', 7));
116                    MasterLoginModuleInfo info = (MasterLoginModuleInfo) map.get(name);
117                    if(info == null) {
118                        info = new MasterLoginModuleInfo(props.getProperty("module."+name+".name"),
119                                props.getProperty("module."+name+".class"));
120                        String test = props.getProperty("module."+name+".testable");
121                        if(test != null) {
122                            info.setTestable(new Boolean(test.trim()).booleanValue());
123                        }
124                        map.put(name, info);
125                        list.add(info);
126                    }
127                    String prefix = "module."+name+".field.";
128                    if(key.startsWith(prefix)) {
129                        String fieldName = key.substring(prefix.length(), key.indexOf('.', prefix.length()));
130                        List fields = (List) fieldMap.get(name);
131                        if(fields == null) {
132                            fields = new ArrayList();
133                            fieldMap.put(name, fields);
134                        }
135                        OptionInfo option = null;
136                        for (int i = 0; i < fields.size(); i++) {
137                            OptionInfo opt = (OptionInfo) fields.get(i);
138                            if(opt.getName().equals(fieldName)) {
139                                option = opt;
140                                break;
141                            }
142                        }
143                        if(option == null) {
144                            option = new OptionInfo(fieldName, props.getProperty(prefix+fieldName+".displayName"),
145                                    props.getProperty(prefix+fieldName+".description"));
146                            String test = props.getProperty(prefix+fieldName+".password");
147                            if(test != null) {
148                                option.setPassword(true);
149                            }
150                            test = props.getProperty(prefix+fieldName+".length");
151                            if(test != null) {
152                                option.setLength(Integer.parseInt(test.trim()));
153                            }
154                            test = props.getProperty(prefix+fieldName+".displayOrder");
155                            if(test != null) {
156                                option.setDisplayOrder(Integer.parseInt(test.trim()));
157                            }
158                            test = props.getProperty(prefix+fieldName+".blankAllowed");
159                            if(test != null) {
160                                option.setBlankAllowed("true".equalsIgnoreCase(test.trim()));
161                            }
162                            fields.add(option);
163                        }
164                    }
165                }
166            }
167            for (Iterator it = map.keySet().iterator(); it.hasNext();) {
168                String name = (String) it.next();
169                MasterLoginModuleInfo info = (MasterLoginModuleInfo) map.get(name);
170                List fields = (List) fieldMap.get(name);
171                if(fields != null) {
172                    Collections.sort(fields);
173                    info.setOptions((OptionInfo[]) fields.toArray(new OptionInfo[fields.size()]));
174                }
175            }
176            Collections.sort(list, new Comparator() {
177                public int compare(Object o1, Object o2) {
178                    MasterLoginModuleInfo m1 = (MasterLoginModuleInfo) o1, m2 = (MasterLoginModuleInfo) o2;
179                    if(m1.getName().equals("Other")) {
180                        return 1;
181                    } else if(m2.getName().equals("Other")) {
182                        return -1;
183                    } else {
184                        return m1.getName().compareTo(m2.getName());
185                    }
186                }
187            });
188            return (MasterLoginModuleInfo[]) list.toArray(new MasterLoginModuleInfo[list.size()]);
189        }
190    
191        public final static class OptionInfo implements Serializable, Comparable {
192            private final String name;
193            private final String displayName;
194            private final String description;
195            private boolean password = false;
196            private int length = 30;
197            private int displayOrder = 1;
198            private boolean blankAllowed = false;
199    
200            public OptionInfo(String name, String displayName, String description) {
201                this.name = name;
202                this.displayName = displayName;
203                this.description = description;
204            }
205    
206            public String getName() {
207                return name;
208            }
209    
210            public String getDisplayName() {
211                return displayName;
212            }
213    
214            public String getDescription() {
215                return description;
216            }
217    
218            public boolean isPassword() {
219                return password;
220            }
221    
222            public void setPassword(boolean password) {
223                this.password = password;
224            }
225    
226            public int getLength() {
227                return length;
228            }
229    
230            public void setLength(int length) {
231                this.length = length;
232            }
233    
234            public int getDisplayOrder() {
235                return displayOrder;
236            }
237    
238            public void setDisplayOrder(int displayOrder) {
239                this.displayOrder = displayOrder;
240            }
241    
242            public int compareTo(Object o) {
243                return displayOrder - ((OptionInfo)o).displayOrder;
244            }
245            
246            public boolean isBlankAllowed() {
247                return this.blankAllowed;
248            }
249            
250            public void setBlankAllowed(boolean blankAllowed) {
251                this.blankAllowed = blankAllowed;
252            }
253        }
254    }