001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/portal/standard/security/control/InitUserEditorListener.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036 package org.deegree.portal.standard.security.control;
037
038 import java.io.BufferedReader;
039 import java.io.BufferedWriter;
040 import java.io.File;
041 import java.io.FileReader;
042 import java.io.FileWriter;
043 import java.io.IOException;
044 import java.text.ParseException;
045 import java.util.Collection;
046 import java.util.HashMap;
047 import java.util.Hashtable;
048 import java.util.Iterator;
049 import java.util.List;
050 import java.util.Map;
051
052 import org.deegree.enterprise.control.AbstractListener;
053 import org.deegree.enterprise.control.FormEvent;
054 import org.deegree.framework.log.ILogger;
055 import org.deegree.framework.log.LoggerFactory;
056 import org.deegree.framework.util.StringTools;
057 import org.deegree.framework.xml.NamespaceContext;
058 import org.deegree.framework.xml.XMLFragment;
059 import org.deegree.framework.xml.XMLParsingException;
060 import org.deegree.framework.xml.XMLTools;
061 import org.deegree.i18n.Messages;
062 import org.deegree.ogcbase.CommonNamespaces;
063 import org.deegree.security.GeneralSecurityException;
064 import org.deegree.security.drm.SecurityAccess;
065 import org.deegree.security.drm.model.User;
066 import org.w3c.dom.DOMException;
067 import org.w3c.dom.Element;
068 import org.w3c.dom.Node;
069
070 /**
071 * This <code>Listener</code> reacts on 'initUserEditor' events, queries the <code>SecurityManager</code> and passes the
072 * group data on to be displayed by the JSP.
073 * <p>
074 * The internal "SEC_ADMIN" user is sorted out from the USERS parameter.
075 * </p>
076 * <p>
077 * Access constraints:
078 * <ul>
079 * <li>only users that have the 'SEC_ADMIN'-role are allowed</li>
080 * </ul>
081 * </p>
082 *
083 * @author <a href="mschneider@lat-lon.de">Markus Schneider </a>
084 * @author last edited by: $Author: mschneider $
085 *
086 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
087 */
088 public class InitUserEditorListener extends AbstractListener {
089
090 private static final ILogger LOG = LoggerFactory.getLogger( InitUserEditorListener.class );
091
092 private NamespaceContext cn = CommonNamespaces.getNamespaceContext();
093
094 private File usersDirectory = null;
095
096 private final String STARTCONTEXT = "STARTCONTEXT";
097
098 private final String CONTEXTNAME = "CONTEXT_NAME";
099
100 private String confPath = null;
101
102 @Override
103 public void actionPerformed( FormEvent event ) {
104
105 try {
106 // perform access check
107 SecurityAccess access = SecurityHelper.acquireAccess( this );
108 SecurityHelper.checkForAdminRole( access );
109
110 getRequest().setAttribute( "ACCESS", access );
111 User[] users = access.getAllUsers();
112 User[] noAdminUsers = new User[users.length - 1];
113 int j = 0;
114 for ( int i = 0; i < users.length; i++ ) {
115 if ( users[i].getID() != User.ID_SEC_ADMIN ) {
116 noAdminUsers[j++] = users[i];
117 }
118 }
119
120 // read the file name which contains a list of our startContexts
121 String configStartContexts = getInitParameter( "configFile" );
122 // now we know there is a file path in that string
123
124 // Start sending data to the jsp
125 if ( configStartContexts != null && configStartContexts.length() != 0 ) {
126 confPath = configStartContexts.substring( 0, configStartContexts.lastIndexOf( "/" ) + 1 );
127 String confFilePath = getHomePath() + "/" + configStartContexts;
128 /*
129 * String confFilePath = null; if ( getHomePath().endsWith( "/" ) ) { confFilePath = getHomePath() +
130 * configStartContexts; } else { confFilePath = getHomePath() + '/' + configStartContexts; }
131 */
132
133 File absFilePath = new File( confFilePath );
134 if ( absFilePath.exists() ) {
135 XMLFragment fragment = new XMLFragment( absFilePath.toURI().toURL() );
136 Map<String, StartContext> contextsList = parseContextsXml( fragment.getRootElement() );
137 Map<String, StartContext> usersList = parseUsersXml( fragment.getRootElement(), contextsList );
138
139 // sending the data to the jsp page
140 if ( contextsList == null ) {
141 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_CNXT_LIST_NULL" ) );
142 }
143 if ( usersList == null ) {
144 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_USERS_LIST_NULL" ) );
145 }
146
147 String usersDirectory = getHomePath() + confPath
148 + getUsersDirectory( fragment.getRootElement() ).toString();
149 getRequest().setAttribute( "STARTCONTEXTSLIST", contextsList );
150 getRequest().setAttribute( "USERSCONTEXTLIST", usersList );
151 getRequest().setAttribute( "USERSDIRECTORY", usersDirectory );
152 } else {
153 LOG.logDebug( "The configuration file could not be found: " + absFilePath.getCanonicalFile() );
154 }
155 } else {
156 LOG.logInfo( Messages.getMessage( "IGEO_STD_SEC_MISSING_CNTXT_FILE_PATH", "configFile" ) );
157 }
158
159 getRequest().setAttribute( "USERS", noAdminUsers );
160 } catch ( GeneralSecurityException e ) {
161 getRequest().setAttribute( "SOURCE", this.getClass().getName() );
162 getRequest().setAttribute( "MESSAGE",
163 Messages.getMessage( "IGEO_STD_SEC_FAIL_INIT_USER_EDITOR", e.getMessage() ) );
164 setNextPage( "error.jsp" );
165 LOG.logError( e.getMessage(), e );
166 } catch ( Exception e ) {
167 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_UNKNOWN", StringTools.stackTraceToString( e ) ) );
168 }
169 }
170
171 /**
172 * method used for context chooser
173 *
174 * @param rootElem
175 * @return a [2] map Array that contains a list of the read contexts as a first element and a list of the user
176 * contexts as a second element.the array length should always be 2
177 * @throws XMLParsingException
178 * @throws ClientConfigurationException
179 * @throws IOException
180 * @throws DOMException
181 */
182 private Map<String, StartContext> parseContextsXml( Element rootElem )
183 throws XMLParsingException, ClientConfigurationException, DOMException, IOException {
184
185 Hashtable<String, StartContext> contextsListHTable = new Hashtable<String, StartContext>();
186
187 String xPath = "dgsec:availableWMC/dgsec:WMC";
188
189 List<Node> list = XMLTools.getRequiredNodes( rootElem, xPath, cn );
190
191 if ( list.isEmpty() ) {
192 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_MISSING_XML_NO_CONTEXTS" ) );
193 throw new ClientConfigurationException( Messages.getMessage( "IGEO_STD_SEC_MISSING_XML_NO_CONTEXTS" ) );
194 }
195 contextsListHTable = new Hashtable<String, StartContext>( list.size() );
196
197 Iterator<Node> it = list.iterator();
198 // iterating through the context nodes
199 while ( it.hasNext() ) {
200 Node node = it.next();
201 boolean isDefault = false;
202 if ( node.hasAttributes() ) {
203 Node defaultSelection = node.getAttributes().getNamedItem( "isDefault" );
204 // if there exists the attribute "isDefault"
205 if ( defaultSelection != null && defaultSelection.getNodeValue().compareTo( "1" ) == 0 ) {
206 isDefault = true;
207 }
208 }
209
210 // extracting the name and path of the context
211 Node nameNode = XMLTools.getNode( node, "dgsec:Name", cn );
212 Node pathNode = XMLTools.getNode( node, "dgsec:URL", cn );
213 if ( isDefault ) {
214 updateDefaultContext( nameNode.getTextContent(), pathNode.getTextContent(), rootElem );
215 }
216 if ( nameNode == null ) {
217 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_MISSING_XML_ELEMENT", "name" ) );
218 throw new ClientConfigurationException(
219 Messages.getMessage( "IGEO_STD_SEC_MISSING_XML_ELEMENT", "name" ) );
220 }
221 if ( pathNode == null ) {
222 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_MISSING_XML_ELEMENT", "path" ) );
223 throw new ClientConfigurationException(
224 Messages.getMessage( "IGEO_STD_SEC_MISSING_XML_ELEMENT", "path" ) );
225 }
226 File contextPath = new File( getHomePath() + confPath + pathNode.getTextContent() );
227 StartContext context = new StartContext( nameNode.getTextContent(), contextPath.getCanonicalPath(),
228 isDefault );
229 contextsListHTable.put( context.getContextName(), context );
230 }
231
232 return contextsListHTable;
233 }
234
235 /**
236 * Used for context chooser
237 *
238 * @param rootElem
239 * @param contextsHT
240 * its the hashtable containing all the context read from the start_config.xml They will be useful to
241 * determine the context name
242 * @return list of users contexts
243 * @throws XMLParsingException
244 * @throws ClientConfigurationException
245 */
246 private Map<String, StartContext> parseUsersXml( Element rootElem, Map<String, StartContext> contextsHT )
247 throws XMLParsingException, ClientConfigurationException {
248
249 if ( usersDirectory == null ) {
250 usersDirectory = getUsersDirectory( rootElem );
251 }
252 // Will be used to find context names, for these contexts with no names
253 Collection<StartContext> contextsList = contextsHT.values();
254
255 Map<String, StartContext> usersListHTable = new HashMap<String, StartContext>( 20 );
256
257 // FileReader reader = null;
258 String[] tempParts = null;
259
260 // checking for the default context.properties
261 File absUsersDirectory = new File( getHomePath() + confPath + usersDirectory );
262
263 // the list of folders under the folder "users"
264 String[] usersList = absUsersDirectory.list();
265
266 try {
267 // iterating through the users folders
268 for ( int i = 0; i < usersList.length; i++ ) {
269 File userFolder = new File( absUsersDirectory.getAbsoluteFile() + "/" + usersList[i] );
270 if ( userFolder.isDirectory() ) {
271 // read the context properties of the user
272 File contextProps = new File( userFolder.getAbsoluteFile() + "/context.properties" );
273 if ( contextProps.exists() ) {
274 // reader = new FileReader( contextProps );
275 String line = getFirstLineMatch( contextProps.getCanonicalPath(), STARTCONTEXT );
276 if ( line != null && line.length() != 0 ) {
277 tempParts = line.split( "=" );
278 if ( tempParts.length < 2 ) {
279 throw new ClientConfigurationException( "the context.properties file in user '"
280 + userFolder.getName() + "' is bad formatted" );
281 }
282 File contextPath = new File( userFolder.getCanonicalPath() + "/" + tempParts[1] );
283 line = getFirstLineMatch( contextProps.getCanonicalPath(), CONTEXTNAME );
284
285 String[] tempParts2 = null;
286 String contextName = null;
287 if ( line != null && line.length() > 0 ) {
288 tempParts2 = line.split( "=" );
289 } else {
290 contextName = findContextName( usersList[i], tempParts[1], contextsList );
291 }
292
293 if ( tempParts2 != null && tempParts2.length == 2 ) {
294 contextName = tempParts2[1];
295 }
296 usersListHTable.put( userFolder.getName(),
297 new StartContext( contextName, contextPath.getCanonicalPath(),
298 new Boolean( false ) ) );
299 // reader.close();
300 }
301 }
302 }
303 }
304
305 } catch ( Exception e ) {
306 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_UNKNOWN", StringTools.stackTraceToString( e ) ) );
307 }
308 return usersListHTable;
309
310 }
311
312 /**
313 * method used for context chooser
314 *
315 * @param rootElem
316 * @return usserDirectory
317 * @throws XMLParsingException
318 * @throws ClientConfigurationException
319 */
320 private File getUsersDirectory( Element rootElem )
321 throws XMLParsingException, ClientConfigurationException {
322
323 if ( usersDirectory != null ) {
324 return usersDirectory;
325 }
326
327 Node userDirectoryNode = XMLTools.getNode( rootElem, "dgsec:UserDirectory", cn );
328 if ( userDirectoryNode == null ) {
329 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_MISSING_XML_ELEMENT", "userdirectory" ) );
330 throw new ClientConfigurationException( Messages.getMessage( "IGEO_STD_SEC_MISSING_XML_ELEMENT",
331 "userdirectory" ) );
332 }
333
334 return new File( userDirectoryNode.getTextContent() );
335 }
336
337 /**
338 * @param contextPath
339 * The path to search for in the contexts
340 * @param contexts
341 * The list of contexts to look into
342 * @return The found context name if nothing is found, the file name.xml will be used
343 */
344 private String findContextName( String user, String contextPath, Collection<StartContext> contexts ) {
345
346 Iterator<StartContext> it = contexts.iterator();
347 String[] delimiters = { "\\", "/" };
348
349 File absUserDirectory = new File( getHomePath() + confPath + usersDirectory + "/" + user );
350
351 while ( it.hasNext() ) {
352 StartContext context = it.next();
353 File absContextPath = new File( getHomePath() + confPath + context.getPath() );
354
355 try {
356 String mappedPath = RelativePath.mapRelativePath( absUserDirectory.getCanonicalPath(),
357 absContextPath.getCanonicalPath(), delimiters );
358
359 // We return the context name in which its path matches the path written in
360 // context.properties
361 if ( mappedPath.compareTo( contextPath ) == 0 ) {
362 return context.getContextName();
363 }
364 } catch ( Exception e ) {
365 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_PATH_MAPPING",
366 absUserDirectory.getAbsolutePath(), absContextPath.getAbsolutePath() ) );
367 }
368 }
369
370 int index = contextPath.lastIndexOf( "/" );
371 String contextName = null;
372 if ( index != -1 ) {
373 contextName = contextPath.substring( index + 1 );
374 }
375 return contextName;
376 }
377
378 /**
379 * @param target
380 * The string we are looking for
381 * @return The whole line where our string exists
382 */
383 private String getFirstLineMatch( String filePath, String target ) {
384
385 try {
386 String line = null;
387 BufferedReader buffer = new BufferedReader( new FileReader( filePath ) );
388 while ( ( line = buffer.readLine() ) != null ) {
389 if ( line.indexOf( target ) > -1 ) {
390 return line;
391 }
392 }
393 } catch ( Exception e ) {
394 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_READING_FILE", filePath ) );
395 }
396 return null;
397 }
398
399 /**
400 * @param contextName
401 * @param contextPath
402 */
403 private void updateDefaultContext( String contextName, String contextPath, Element rootElem ) {
404
405 File usersFolder = null;
406 File contextFile = null;
407 try {
408 usersFolder = new File( getHomePath() + confPath + getUsersDirectory( rootElem ) );
409 File defaultContextFile = new File( getHomePath() + confPath + getUsersDirectory( rootElem )
410 + "/context.properties" );
411 contextFile = new File( getHomePath() + confPath + contextPath );
412
413 String[] delimiters = { "\\", "/" };
414 String mappedPath = RelativePath.mapRelativePath( usersFolder.getCanonicalPath(),
415 contextFile.getCanonicalPath(), delimiters );
416 boolean pathChanged = false;
417 if ( !defaultContextFile.exists() ) {
418 defaultContextFile.createNewFile();
419 pathChanged = true;
420 }
421 String line = getFirstLineMatch( defaultContextFile.getCanonicalPath(), "STARTCONTEXT" );
422 if ( line != null && line.length() > 0 ) {
423 String[] parts = line.split( "=" );
424 if ( parts.length == 2 ) {
425 if ( parts[1].compareTo( mappedPath ) != 0 ) {
426 pathChanged = true;
427 }
428 }
429 }
430
431 if ( pathChanged ) {
432 BufferedWriter bufferedWriter = new BufferedWriter(
433 new FileWriter(
434 defaultContextFile.getCanonicalPath() ) );
435 bufferedWriter.flush();
436 StringBuffer buffer = new StringBuffer();
437 buffer.append( STARTCONTEXT + "=" + mappedPath + System.getProperty( "line.separator" ) );
438 buffer.append( CONTEXTNAME + "=" + contextName + System.getProperty( "line.separator" ) );
439 bufferedWriter.write( buffer.toString() );
440 bufferedWriter.close();
441 getRequest().setAttribute(
442 "DEFAULTCHANGED",
443 contextFile.getCanonicalPath().substring(
444 contextFile.getCanonicalPath().indexOf(
445 "WEB-INF" ) ) );
446 }
447
448 } catch ( ParseException e ) {
449 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_PATH_MAPPING", usersFolder, contextFile ) );
450 } catch ( IOException e ) {
451 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_IO", StringTools.stackTraceToString( e ) ) );
452 } catch ( ClientConfigurationException e ) {
453 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_CLIENT_CONFIG", e.getMessage() ) );
454 } catch ( Exception e ) {
455 LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_UNKNOWN", StringTools.stackTraceToString( e ) ) );
456 }
457 }
458 }