001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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 }