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