001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/portal/standard/context/control/AbstractContextListener.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.context.control; 037 038 import java.io.File; 039 import java.io.IOException; 040 import java.io.InputStream; 041 import java.io.StringWriter; 042 import java.net.MalformedURLException; 043 import java.net.URL; 044 import java.util.ArrayList; 045 import java.util.Arrays; 046 import java.util.List; 047 import java.util.Properties; 048 049 import javax.servlet.http.HttpServletRequest; 050 import javax.servlet.http.HttpSession; 051 import javax.xml.transform.TransformerException; 052 053 import org.apache.commons.httpclient.HttpClient; 054 import org.apache.commons.httpclient.methods.GetMethod; 055 import org.deegree.enterprise.WebUtils; 056 import org.deegree.enterprise.control.AbstractListener; 057 import org.deegree.enterprise.control.RPCMember; 058 import org.deegree.enterprise.control.RPCMethodCall; 059 import org.deegree.enterprise.control.RPCParameter; 060 import org.deegree.enterprise.control.RPCStruct; 061 import org.deegree.enterprise.control.RPCUtils; 062 import org.deegree.enterprise.control.RPCWebEvent; 063 import org.deegree.framework.log.ILogger; 064 import org.deegree.framework.log.LoggerFactory; 065 import org.deegree.framework.util.StringTools; 066 import org.deegree.framework.xml.NamespaceContext; 067 import org.deegree.framework.xml.XMLFragment; 068 import org.deegree.framework.xml.XMLParsingException; 069 import org.deegree.framework.xml.XMLTools; 070 import org.deegree.framework.xml.XSLTDocument; 071 import org.deegree.i18n.Messages; 072 import org.deegree.model.crs.CoordinateSystem; 073 import org.deegree.model.spatialschema.Envelope; 074 import org.deegree.model.spatialschema.GeometryFactory; 075 import org.deegree.model.spatialschema.Point; 076 import org.deegree.ogcbase.BaseURL; 077 import org.deegree.ogcbase.CommonNamespaces; 078 import org.deegree.ogcwebservices.OWSUtils; 079 import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities; 080 import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument; 081 import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory; 082 import org.deegree.portal.Constants; 083 import org.deegree.portal.PortalException; 084 import org.deegree.portal.context.ContextException; 085 import org.deegree.portal.context.General; 086 import org.deegree.portal.context.GeneralExtension; 087 import org.deegree.portal.context.Layer; 088 import org.deegree.portal.context.LayerList; 089 import org.deegree.portal.context.Server; 090 import org.deegree.portal.context.ViewContext; 091 import org.xml.sax.SAXException; 092 093 /** 094 * This exception shall be thrown when a session(ID) will be used that has been expired. 095 * 096 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a> 097 * @author last edited by: $Author: jmays $ 098 * 099 * @version $Revision: 24549 $, $Date: 2010-05-25 14:29:38 +0200 (Di, 25 Mai 2010) $ 100 */ 101 abstract public class AbstractContextListener extends AbstractListener { 102 103 private static ILogger LOG = LoggerFactory.getLogger( AbstractContextListener.class ); 104 105 private static final NamespaceContext nsContext = CommonNamespaces.getNamespaceContext(); 106 107 /** 108 * WEB-INF/conf/igeoportal/users/ 109 */ 110 protected static final String userDir = "WEB-INF/conf/igeoportal/users/"; 111 112 /** 113 * gets the user name assigned to the passed session ID from an authentication service. If no user is assigned to 114 * the session ID <tt>null</tt> will be returned. If the session is closed or expired an exception will be thrown 115 * 116 * @param sessionId 117 * @return name of the user assigned to the passed session ID 118 * @throws XMLParsingException 119 * @throws SAXException 120 * @throws IOException 121 */ 122 protected String getUserName( String sessionId ) 123 throws XMLParsingException, IOException, SAXException { 124 125 HttpSession session = ( (HttpServletRequest) getRequest() ).getSession( true ); 126 ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT ); 127 if ( vc == null ) { 128 return null; 129 } 130 GeneralExtension ge = vc.getGeneral().getExtension(); 131 String userName = null; 132 if ( sessionId != null && ge.getAuthentificationSettings() != null ) { 133 LOG.logDebug( "try getting user from WAS/sessionID" ); 134 BaseURL baseUrl = ge.getAuthentificationSettings().getAuthentificationURL(); 135 String url = OWSUtils.validateHTTPGetBaseURL( baseUrl.getOnlineResource().toExternalForm() ); 136 StringBuffer sb = new StringBuffer( url ); 137 sb.append( "request=DescribeUser&SESSIONID=" ).append( sessionId ); 138 139 XMLFragment xml = new XMLFragment(); 140 xml.load( new URL( sb.toString() ) ); 141 142 userName = XMLTools.getRequiredNodeAsString( xml.getRootElement(), "/User/UserName", nsContext ); 143 } else { 144 LOG.logDebug( "try getting user from getUserPrincipal()" ); 145 if ( ( (HttpServletRequest) getRequest() ).getUserPrincipal() != null ) { 146 userName = ( (HttpServletRequest) getRequest() ).getUserPrincipal().getName(); 147 if ( userName.indexOf( "\\" ) > 1 ) { 148 String[] us = StringTools.toArray( userName, "\\", false ); 149 userName = us[us.length - 1]; 150 } 151 } 152 } 153 LOG.logDebug( "userName: " + userName ); 154 return userName; 155 } 156 157 /** 158 * gets the user password assigned to the passed session ID from a authentification service. If no user is assigned 159 * to the session ID <tt>null</tt> will be returned. If the session is closed or expired an exception will be thrown 160 * 161 * @param sessionId 162 * @return password of the user assigned to the passed session ID 163 */ 164 protected String getUserPassword( String sessionId ) 165 throws XMLParsingException, IOException, SAXException, PortalException { 166 167 HttpSession session = ( (HttpServletRequest) getRequest() ).getSession( true ); 168 ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT ); 169 if ( vc == null ) { 170 return null; 171 } 172 GeneralExtension ge = vc.getGeneral().getExtension(); 173 String userPassword = null; 174 if ( sessionId != null && ge.getAuthentificationSettings() != null ) { 175 LOG.logDebug( "try getting user from WAS/sessionID" ); 176 BaseURL baseUrl = ge.getAuthentificationSettings().getAuthentificationURL(); 177 String url = OWSUtils.validateHTTPGetBaseURL( baseUrl.getOnlineResource().toExternalForm() ); 178 StringBuffer sb = new StringBuffer( url ); 179 sb.append( "request=DescribeUser&SESSIONID=" ).append( sessionId ); 180 181 XMLFragment xml = new XMLFragment(); 182 xml.load( new URL( sb.toString() ) ); 183 184 LOG.logDebug( xml.getAsPrettyString() ); 185 userPassword = XMLTools.getRequiredNodeAsString( xml.getRootElement(), "/User/Password", nsContext ); 186 } else { 187 throw new PortalException( "The session ID is null and thus the user password can not be extracted" ); 188 } 189 LOG.logDebug( "Password: " + userPassword ); 190 return userPassword; 191 } 192 193 /** 194 * reads the users session ID.<br> 195 * first the PRC will be parsed for a 'sessionID' element. If not present the sessionID will be read from the users 196 * session. If even the user's HTTP session does not contain a sessionID, it will be tried to get it from the WAS 197 * registered to the current context. If no WAS available <code>null</code> will be returned. 198 * 199 * @param struct 200 * @return the users session id 201 * @throws IOException 202 * @throws SAXException 203 * @throws XMLParsingException 204 */ 205 protected String readSessionID( RPCStruct struct ) 206 throws XMLParsingException, SAXException, IOException { 207 String sid = RPCUtils.getRpcPropertyAsString( struct, "sessionID" ); 208 if ( sid == null ) { 209 LOG.logDebug( "try getting sessionID from HTTP session" ); 210 HttpSession session = ( (HttpServletRequest) getRequest() ).getSession(); 211 sid = (String) session.getAttribute( "SESSIONID" ); 212 } 213 if ( sid == null ) { 214 // try get SessionID from WAS if user name is available 215 // in this case it is assumed that a user's name can be determined 216 // evaluating the requests userPrincipal that will be available if 217 // the user has been logged in to the the server (or network) 218 String userName = getUserName( null ); 219 if ( userName != null ) { 220 LOG.logDebug( "try getting sessionID by authorizing current user: " + userName ); 221 HttpSession session = ( (HttpServletRequest) getRequest() ).getSession( true ); 222 ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT ); 223 GeneralExtension ge = vc.getGeneral().getExtension(); 224 if ( ge.getAuthentificationSettings() != null ) { 225 BaseURL baseUrl = ge.getAuthentificationSettings().getAuthentificationURL(); 226 StringBuffer sb = new StringBuffer( 500 ); 227 String addr = baseUrl.getOnlineResource().toExternalForm(); 228 sb.append( OWSUtils.validateHTTPGetBaseURL( addr ) ); 229 sb.append( "SERVICE=WAS&VERSION=1.0.0&REQUEST=GetSession&" ); 230 sb.append( "AUTHMETHOD=urn:x-gdi-nrw:authnMethod:1.0:password&CREDENTIALS=" ); 231 sb.append( userName ); 232 LOG.logDebug( "authenticat user: ", sb.toString() ); 233 try { 234 HttpClient client = new HttpClient(); 235 client = WebUtils.enableProxyUsage( client, baseUrl.getOnlineResource() ); 236 GetMethod meth = new GetMethod( sb.toString() ); 237 client.executeMethod( meth ); 238 if ( meth.getStatusCode() == 200 ) { 239 sid = meth.getResponseBodyAsString(); 240 session.setAttribute( "SESSIONID", sid ); 241 } else { 242 LOG.logWarning( "Web application at " + addr + " does not exist." ); 243 } 244 } catch ( Exception e ) { 245 LOG.logWarning( "WAS at " + addr + " does not exist." ); 246 } 247 } 248 } 249 } 250 LOG.logDebug( "sessionID: " + sid ); 251 return sid; 252 } 253 254 /** 255 * Convenience method to extract the boundig box from an rpc fragment. 256 * 257 * @param bboxStruct 258 * the <code>RPCStruct</code> containing the bounding box. For example, 259 * <code><member><name>boundingBox</name>etc...</code>. 260 * @param crs 261 * a coordinate system value, may be null. 262 * @return an envelope with the boundaries defined in the rpc structure 263 */ 264 protected Envelope extractBBox( RPCStruct bboxStruct, CoordinateSystem crs ) { 265 266 Double minx = (Double) bboxStruct.getMember( Constants.RPC_BBOXMINX ).getValue(); 267 Double miny = (Double) bboxStruct.getMember( Constants.RPC_BBOXMINY ).getValue(); 268 Double maxx = (Double) bboxStruct.getMember( Constants.RPC_BBOXMAXX ).getValue(); 269 Double maxy = (Double) bboxStruct.getMember( Constants.RPC_BBOXMAXY ).getValue(); 270 271 Envelope bbox = GeometryFactory.createEnvelope( minx.doubleValue(), miny.doubleValue(), maxx.doubleValue(), 272 maxy.doubleValue(), crs ); 273 return bbox; 274 } 275 276 /** 277 * This method is kept for downward compatibility of the API. Do not use it any more! 278 * 279 * @deprecated use extractBBox( RPCStruct, CoordinateSystem ) instead. 280 * @param bboxStruct 281 * the <code>RPCStruct</code> containing the bounding box. For example, 282 * <code><member><name>boundingBox</name>etc...</code>. 283 * @return an envelope with the boundaries defined in the rpc structure 284 */ 285 @Deprecated 286 protected Envelope extractBBox( RPCStruct bboxStruct ) { 287 return extractBBox( bboxStruct, null ); 288 } 289 290 /** 291 * changes the bounding box of a given view context 292 * 293 * @param vc 294 * the view context to be changed 295 * @param bbox 296 * the new bounding box 297 * @throws PortalException 298 */ 299 public static final void changeBBox( ViewContext vc, Envelope bbox ) 300 throws PortalException { 301 General gen = vc.getGeneral(); 302 303 CoordinateSystem cs = gen.getBoundingBox()[0].getCoordinateSystem(); 304 Point[] p = new Point[] { GeometryFactory.createPoint( bbox.getMin(), cs ), 305 GeometryFactory.createPoint( bbox.getMax(), cs ) }; 306 try { 307 gen.setBoundingBox( p ); 308 } catch ( ContextException e ) { 309 LOG.logError( e.getMessage(), e ); 310 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_SET_BBOX" ) ); 311 } 312 } 313 314 /** 315 * changes the layer list of the ViewContext vc according to the information contained in the rpcLayerList 316 * 317 * @param vc 318 * The original ViewContext where the changes will be applied to 319 * @param rpcLayerList 320 * the current layerlist 321 * @throws PortalException 322 */ 323 protected void changeLayerList( ViewContext vc, RPCMember[] rpcLayerList ) 324 throws PortalException { 325 LayerList layerList = vc.getLayerList(); 326 ArrayList<Layer> nLayers = new ArrayList<Layer>( rpcLayerList.length ); 327 328 // this is needed to keep layer order 329 // order is correct in rpc call JavaScript) but get lost in translation... 330 for ( int i = 0; i < rpcLayerList.length; i++ ) { 331 String[] v = StringTools.toArray( (String) rpcLayerList[i].getValue(), "|", false ); 332 String n = rpcLayerList[i].getName(); 333 334 String title = n; 335 if ( v.length > 5 ) { 336 // this check is necessary, in order to not break running iGeoPortal instances 337 title = v[5]; 338 } 339 boolean isQueryable = false; 340 if ( v.length > 6 ) { 341 // JM: this check is necessary, in order to not break running iGeoPortal instances 342 isQueryable = v[6].equalsIgnoreCase( "true" ); 343 } 344 345 boolean isVisible = Boolean.valueOf( v[0] ).booleanValue(); 346 Layer l = layerList.getLayer( n, null ); 347 if ( l != null ) { 348 // needed to reconstruct new layer order 349 // otherwise layer order is still from original context 350 l.setHidden( !isVisible ); 351 } else { 352 353 if ( layerList.getLayers().length == 0 ) { 354 // FIXME is this Exception Correct 355 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_EMPTY_LAYERLIST" ) ); 356 } 357 358 Layer p = layerList.getLayers()[0]; 359 // a new layer must be created because it is not prsent 360 // in the current context. This is the case if the client 361 // has loaded an additional WMS 362 String[] tmp = StringTools.toArray( v[2], " ", false ); 363 try { 364 v[4] = OWSUtils.validateHTTPGetBaseURL( v[4] ); 365 String s = v[4] + "request=GetCapabilities&service=WMS"; 366 WMSCapabilitiesDocument doc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( new URL( s ) ); 367 OGCCapabilities capa = doc.parseCapabilities(); 368 Server server = new Server( v[3], tmp[1], tmp[0], new URL( v[4] ), capa ); 369 // l = new Layer( server, n, title, "", p.getSrs(), null, null, p.getFormatList(), p.getStyleList(), 370 // isQueryable, !isVisible, null ); 371 l = new Layer( server, n, title, "", p.getSrs(), p.getDataURL(), p.getMetadataURL(), 372 p.getFormatList(), p.getStyleList(), isQueryable, !isVisible, p.getExtension() ); 373 } catch ( Exception e ) { 374 throw new PortalException( StringTools.stackTraceToString( e ) ); 375 } 376 } 377 nLayers.add( l ); 378 } 379 try { 380 nLayers.trimToSize(); 381 Layer[] ls = new Layer[nLayers.size()]; 382 ls = nLayers.toArray( ls ); 383 vc.setLayerList( new LayerList( ls ) ); 384 } catch ( ContextException e ) { 385 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_SET_LAYERLIST", 386 StringTools.stackTraceToString( e.getStackTrace() ) ) ); 387 } 388 } 389 390 /** 391 * This function takes in a XmlFragment and transforms it to a html map context 392 * 393 * @param xml 394 * xmlFragment to transform 395 * @param xsl 396 * xsl file used to transform 397 * @return html representing the mapContext 398 * @throws TransformerException 399 * @throws SAXException 400 * @throws IOException 401 * @throws MalformedURLException 402 */ 403 protected String transformToHtmlMapContext( XMLFragment xml, String xsl ) 404 throws TransformerException, MalformedURLException, IOException, SAXException { 405 406 XSLTDocument xslt = new XSLTDocument(); 407 StringWriter sw = new StringWriter( 30000 ); 408 409 xslt.load( new URL( xsl ) ); 410 xml = xslt.transform( xml ); 411 xml.write( sw ); 412 413 return sw.toString(); 414 } 415 416 /** 417 * Extracts the parameters from the method call element within the passed rpcEvent. 418 * 419 * @param rpcEvent 420 * @return Returns the parameters as array of <code>RPCParameter</code>. 421 * @throws PortalException 422 */ 423 protected RPCParameter[] extractRPCParameters( RPCWebEvent rpcEvent ) 424 throws PortalException { 425 RPCParameter[] params; 426 try { 427 RPCMethodCall mc = rpcEvent.getRPCMethodCall(); 428 params = mc.getParameters(); 429 } catch ( Exception e ) { 430 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_EXTRACT_PARAM_RPC", e.getMessage() ) ); 431 } 432 return params; 433 } 434 435 /** 436 * Extracts the <code>RPCStruct</code> from the indicated parameter in the params element of the passed 437 * <code>RPCWebEvent</code>. 438 * 439 * @param rpcEvent 440 * The RPCWebEvent, that contains the RPCStruct to extract. 441 * @param index 442 * The index of the parameter from which to extract the RPCStruct (starting with 0). 443 * @return Returns the <code>RPCStruct</code> from the indicated params element. 444 * @throws PortalException 445 */ 446 protected RPCStruct extractRPCStruct( RPCWebEvent rpcEvent, int index ) 447 throws PortalException { 448 RPCStruct rpcStruct; 449 try { 450 RPCParameter[] params = extractRPCParameters( rpcEvent ); 451 rpcStruct = (RPCStruct) params[index].getValue(); 452 } catch ( Exception e ) { 453 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_EXTRACT_STRUCT_RPC", e.getMessage() ) ); 454 } 455 return rpcStruct; 456 } 457 458 /** 459 * returns a list of all available context documents assigned to the passed user 460 * 461 * @param userName 462 * @return the list of available context documents 463 */ 464 protected List<String> getContextList( String userName ) { 465 466 String path2Dir = getHomePath() + userDir + userName; 467 File dir = new File( path2Dir ); 468 File[] files = dir.listFiles(); 469 List<String> contextList = new ArrayList<String>(); 470 if ( files != null ) { 471 for ( int i = 0; i < files.length; i++ ) { 472 String s = files[i].getName(); 473 if ( files[i].isFile() && s.endsWith( ".xml" ) ) { 474 contextList.add( files[i].getName() ); 475 } 476 } 477 } 478 String[] list = contextList.toArray( new String[contextList.size()] ); 479 Arrays.sort( list ); 480 return new ArrayList<String>( Arrays.asList( list ) ); 481 } 482 483 /** 484 * returns the name of the users start context. If the user does not own an individual start context the name of the 485 * default start context for all users will be returned. 486 * 487 * (copied and adapted from org.deegree.portal.standard.security.control.GetSessionIDListener) 488 * 489 * @param userName 490 * @return String 491 * @throws IOException 492 */ 493 protected String getUsersStartContext( String userName ) 494 throws IOException { 495 StringBuffer dir = new StringBuffer( "users/" ); 496 StringBuffer sb = new StringBuffer( 300 ); 497 sb.append( getHomePath() ).append( userDir ).append( userName ); 498 sb.append( "/context.properties" ); 499 500 File file = new File( sb.toString() ); 501 if ( !file.exists() ) { 502 sb.delete( 0, sb.length() ); 503 sb.append( getHomePath() ).append( userDir ).append( "context.properties" ); 504 file = new File( sb.toString() ); 505 } else { 506 dir.append( userName ).append( '/' ); 507 } 508 509 Properties prop = new Properties(); 510 InputStream is = file.toURL().openStream(); 511 prop.load( is ); 512 is.close(); 513 514 return dir.append( prop.getProperty( "STARTCONTEXT" ) ).toString(); 515 } 516 517 }