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 }