001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/security/owsrequestvalidator/GetCapabilitiesResponseValidator.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.security.owsrequestvalidator;
037    
038    import static org.deegree.framework.util.CharsetUtils.getSystemCharset;
039    import static org.deegree.security.drm.model.RightType.GETFEATURE;
040    import static org.deegree.security.drm.model.RightType.GETMAP;
041    
042    import java.io.ByteArrayInputStream;
043    import java.io.ByteArrayOutputStream;
044    import java.io.IOException;
045    import java.io.InputStreamReader;
046    import java.io.PrintWriter;
047    import java.io.StringReader;
048    import java.net.MalformedURLException;
049    import java.net.URL;
050    import java.util.List;
051    import java.util.Properties;
052    
053    import javax.xml.transform.OutputKeys;
054    
055    import org.deegree.framework.log.ILogger;
056    import org.deegree.framework.log.LoggerFactory;
057    import org.deegree.framework.util.MimeTypeMapper;
058    import org.deegree.framework.util.StringTools;
059    import org.deegree.framework.xml.XMLFragment;
060    import org.deegree.framework.xml.XMLParsingException;
061    import org.deegree.model.metadata.iso19115.Linkage;
062    import org.deegree.model.metadata.iso19115.OnlineResource;
063    import org.deegree.ogcwebservices.InvalidParameterValueException;
064    import org.deegree.ogcwebservices.OGCWebServiceRequest;
065    import org.deegree.ogcwebservices.csw.capabilities.CatalogueCapabilities;
066    import org.deegree.ogcwebservices.csw.capabilities.CatalogueCapabilitiesDocument;
067    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
068    import org.deegree.ogcwebservices.wfs.capabilities.FeatureTypeList;
069    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
070    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument;
071    import org.deegree.ogcwebservices.wfs.capabilities.WFSFeatureType;
072    import org.deegree.ogcwebservices.wms.XMLFactory;
073    import org.deegree.ogcwebservices.wms.capabilities.Layer;
074    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
075    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
076    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
077    import org.deegree.owscommon_new.DCP;
078    import org.deegree.owscommon_new.HTTP;
079    import org.deegree.owscommon_new.Operation;
080    import org.deegree.security.GeneralSecurityException;
081    import org.deegree.security.UnauthorizedException;
082    import org.deegree.security.drm.SecurityAccess;
083    import org.deegree.security.drm.SecurityAccessManager;
084    import org.deegree.security.drm.model.SecuredObject;
085    import org.deegree.security.drm.model.User;
086    import org.deegree.security.owsproxy.Condition;
087    import org.deegree.security.owsproxy.OperationParameter;
088    import org.deegree.security.owsproxy.Request;
089    import org.deegree.security.owsrequestvalidator.wms.GetMapRequestValidator;
090    import org.w3c.dom.Document;
091    
092    /**
093     *
094     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
095     * @author last edited by: $Author: mschneider $
096     *
097     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
098     */
099    public class GetCapabilitiesResponseValidator extends ResponseValidator {
100    
101        private static final ILogger LOG = LoggerFactory.getLogger( GetCapabilitiesResponseValidator.class );
102    
103        private static final String INVALIDSERVICE = Messages.getString( "GetCapabilitiesResponseValidator.INVALIDSERVICE" );
104    
105        private String proxyURL = null;
106    
107        /**
108         * @param policy
109         * @param proxyURL
110         */
111        public GetCapabilitiesResponseValidator( Policy policy, String proxyURL ) {
112            super( policy );
113            this.proxyURL = proxyURL;
114        }
115    
116        /**
117         * validates the passed object as a response to a OWS request. The validity of the response may is assigned to
118         * specific user rights. If the passed user is <>null this will be evaluated. <br>
119         * the reponse may contain three valid kinds of objects:
120         * <ul>
121         * <li>a serialized image
122         * <li>a xml encoded exception
123         * <li>a svg-encoded vector image
124         * </ul>
125         * Each of these types can be identified by the mime-type of the response that is also passed to the method. <br>
126         * If something basic went wrong it is possible that not further specified kind of object is passed as response. In
127         * this case the method will throw an <tt>InvalidParameterValueException</tt> to avoid sending bad responses to the
128         * client.
129         *
130         * @param service
131         *            service which produced the response (WMS, WFS ...)
132         * @param response
133         * @param mime
134         *            mime-type of the response
135         * @param user
136         * @return the new response array
137         * @throws InvalidParameterValueException
138         * @throws UnauthorizedException
139         * @see GetMapRequestValidator#validateRequest(OGCWebServiceRequest, User)
140         */
141        @Override
142        public byte[] validateResponse( String service, byte[] response, String mime, User user )
143                                throws InvalidParameterValueException, UnauthorizedException {
144    
145            Request req = policy.getRequest( service, "GetCapabilities" );
146            if ( req == null ) {
147                throw new InvalidParameterValueException( INVALIDSERVICE + service );
148            }
149            // request is valid because no restrictions are made
150            if ( req.isAny() || req.getPostConditions().isAny() ) {
151                return response;
152            }
153    
154            if ( MimeTypeMapper.isKnownOGCType( mime ) ) {
155                // if the mime-type is a known OGC mime-type it must be an XML
156                // document. probably it is a capabilities document but it also
157                // could be an
158                response = validateXML( service, response, user );
159            } else if ( mime.equals( "text/xml" ) ) {
160                // if the mime-type isn't an image type but 'text/xml'
161                // it could be an exception
162                response = validateXML( service, response, user );
163            } else {
164                throw new InvalidParameterValueException( UNKNOWNMIMETYPE + mime );
165            }
166    
167            return response;
168        }
169    
170        /**
171         * splits document string into 'core' capabilities document and xml header
172         *
173         * @param xml
174         * @return the splitted document
175         * @throws InvalidParameterValueException
176         */
177        private String[] clearCapabilities( byte[] xml )
178                                throws InvalidParameterValueException {
179            InputStreamReader isr = new InputStreamReader( new ByteArrayInputStream( xml ) );
180            StringBuffer sb = new StringBuffer( 50000 );
181            int c = 0;
182            try {
183                while ( ( c = isr.read() ) > -1 ) {
184                    sb.append( (char) c );
185                }
186                isr.close();
187            } catch ( IOException e ) {
188                String s = Messages.format( "GetCapabilitiesResponseValidator.CAPAREAD", e.getMessage() );
189                throw new InvalidParameterValueException( s );
190            }
191            // WMS <= 1.1.1
192            int pos = sb.indexOf( "<WMT_MS_Capabilities" );
193            // WMS 1.3
194            if ( pos < 0 ) {
195                pos = sb.indexOf( "WMS_Capabilities" );
196            }
197            // WFS 1.1.0
198            if ( pos < 0 ) {
199                pos = sb.indexOf( "WFS_Capabilities" );
200            }
201            // CSW 2.0.0
202            if ( pos < 0 ) {
203                pos = sb.indexOf( "Capabilities" );
204            }
205            // WCS 1.0.0
206            if ( pos < 0 ) {
207                pos = sb.indexOf( "WCS_Capabilities" );
208            }
209    
210            // just if pos is > -1 it makes sense to find the starting
211            // index of the root element
212            if ( pos > -1 ) {
213                pos = pos + 4;
214                char ch = '$';
215                // find starting index of the root element
216                while ( ch != '<' && pos > 0 ) {
217                    pos--;
218                    ch = sb.charAt( pos );
219                }
220                // if the least char read does not equal '<' the parsed document
221                // is not an XML document
222                if ( ch != '<' ) {
223                    pos = -1;
224                }
225            }
226            String[] o = new String[2];
227            if ( pos > 0 ) {
228                // XML header / doctype
229                o[0] = sb.substring( 0, pos );
230            } else {
231                o[0] = "";
232            }
233            if ( pos > -1 ) {
234                // xml document starting at the root element
235                o[1] = sb.substring( pos );
236            } else {
237                // no XML document
238                o[0] = "ERROR";
239                o[1] = sb.toString();
240            }
241    
242            return o;
243        }
244    
245        /**
246         * validates the passed xml to be valid against the policy
247         *
248         * @param service
249         *            service which produced the response (WMS, WFS ...)
250         * @param xml
251         * @param user
252         * @throws InvalidParameterValueException
253         */
254        private byte[] validateXML( String service, byte[] xml, User user )
255                                throws InvalidParameterValueException, UnauthorizedException {
256    
257            String[] st = clearCapabilities( xml );
258            if ( st[0].equals( "ERROR" ) ) {
259                LOG.logError( st[1] );
260                String s = Messages.format( "GetCapabilitiesResponseValidator.NOCAPADOC", st[1] );
261                throw new InvalidParameterValueException( s );
262            }
263            Document doc = null;
264            try {
265                XMLFragment frag = new XMLFragment();
266                frag.load( new StringReader( st[1] ), XMLFragment.DEFAULT_URL );
267                doc = frag.getRootElement().getOwnerDocument();
268            } catch ( Exception e ) {
269                LOG.logError( e.getMessage(), e );
270                String s = Messages.getString( "GetCapabilitiesResponseValidator.ALLCAPAPARSE" );
271                throw new InvalidParameterValueException( s );
272            }
273            String root = doc.getDocumentElement().getNodeName();
274            if ( root.equalsIgnoreCase( "Exception" ) ) {
275                // if the xml contains a exception the reponse is valid!
276            } else if ( "WMS".equals( service ) ) {
277                try {
278                    xml = validateWMSCapabilities( doc, user );
279                } catch ( XMLParsingException e ) {
280                    LOG.logError( e.getMessage(), e );
281                    throw new InvalidParameterValueException( "invalid WMS capabilities" );
282                }
283            } else if ( "WFS".equals( service ) ) {
284                xml = validateWFSCapabilities( doc, user );
285            } else if ( "WCS".equals( service ) ) {
286                xml = validateWCSCapabilities( doc, user );
287            } else if ( "CSW".equals( service ) ) {
288                xml = validateCSWCapabilities( doc );
289            }
290    
291            StringBuffer sb = new StringBuffer( xml.length + st[0].length() );
292            sb.append( st[0] );
293            String s = new String( xml );
294            int p = s.indexOf( "?>" );
295            if ( p > -1 ) {
296                sb.append( s.substring( p + 2, s.length() ) );
297            } else {
298                sb.append( s );
299            }
300            s = sb.toString();
301            if ( s.indexOf( "<?xml version" ) > 1 ) {
302                s = StringTools.replace( s, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>", "", false );
303                s = StringTools.replace( s, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "", false );
304            }
305    
306            // TODO
307            // regular expression
308            // s = sb.toString().replaceAll( "<?...?>", "" );
309    
310            return s.getBytes();
311        }
312    
313        /**
314         *
315         * @param doc
316         * @param user
317         * @return nothing, an exception is thrown
318         */
319        private byte[] validateWCSCapabilities( Document doc, User user ) {
320            // TODO
321            // implement support for WCS
322            throw new UnsupportedOperationException();
323        }
324    
325        /**
326         * validates the passed xml to be valid against the policy
327         *
328         * @param user
329         * @throws InvalidParameterValueException
330         * @throws XMLParsingException
331         */
332        private byte[] validateWMSCapabilities( Document doc, User user )
333                                throws InvalidParameterValueException, UnauthorizedException, XMLParsingException {
334    
335            WMSCapabilitiesDocument cdoc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( doc.getDocumentElement() );
336            WMSCapabilities capa = null;
337            try {
338                capa = (WMSCapabilities) cdoc.parseCapabilities();
339            } catch ( InvalidCapabilitiesException e ) {
340                LOG.logError( e.getMessage(), e );
341                String s = Messages.format( "GetCapabilitiesResponseValidator.WMSCAPAPARSE", e.getMessage() );
342                throw new InvalidParameterValueException( s );
343            }
344            capa = filterWMSLayers( capa, user );
345    
346            List<Operation> ops = capa.getOperationMetadata().getOperations();
347            for ( Operation operation : ops ) {
348                setNewOnlineResource( operation );
349            }
350    
351            ByteArrayOutputStream bos = new ByteArrayOutputStream( 50000 );
352            byte[] b;
353            try {
354                cdoc = XMLFactory.export( capa );
355                Properties properties = new Properties();
356                // setting this to system charset is no problem, as later on it will be converted to a different encoding
357                // again anyway
358                // not using byte arrays might solve the problems here...
359                properties.setProperty( OutputKeys.ENCODING, getSystemCharset() );
360                cdoc.write( bos, properties );
361                b = bos.toByteArray();
362                bos.close();
363            } catch ( Exception e ) {
364                LOG.logError( e.getMessage(), e );
365                String s = Messages.format( "GetCapabilitiesResponseValidator.WMSCAPAEXPORT", e.getMessage() );
366                throw new InvalidParameterValueException( s );
367            }
368    
369            return b;
370    
371        }
372    
373        /**
374         *
375         * @param op
376         */
377        private void setNewOnlineResource( Operation op ) {
378            if ( op.getDCP() != null ) {
379                List<DCP> dcps = op.getDCP();
380                for ( DCP dcp : dcps ) {
381                    HTTP http = (HTTP) dcp;
382                    List<OnlineResource> links = http.getLinks();
383                    try {
384                        int size = links.size();
385                        links.clear();
386                        OnlineResource proxy = new OnlineResource( new Linkage( new URL( proxyURL ) ) );
387                        for ( int i = 0; i < size; ++i )
388                            links.add( proxy );
389                    } catch ( MalformedURLException e1 ) {
390                        LOG.logError( e1.getLocalizedMessage(), e1 );
391                    }
392                }
393            }
394        }
395    
396        /**
397         * Sets the proxy online resource in the old owscommon Operation class. To be removed soon!
398         *
399         * @param op
400         */
401        private void setNewOnlineResourceInOldOperation( org.deegree.ogcwebservices.getcapabilities.Operation op ) {
402            if ( op.getDCPs() != null ) {
403                for ( int i = 0; i < op.getDCPs().length; i++ ) {
404                    org.deegree.ogcwebservices.getcapabilities.HTTP http = (org.deegree.ogcwebservices.getcapabilities.HTTP) op.getDCPs()[i].getProtocol();
405                    try {
406                        if ( http.getGetOnlineResources().length > 0 ) {
407                            URL urls[] = new URL[http.getGetOnlineResources().length];
408                            for ( int k = 0; k < http.getGetOnlineResources().length; ++k )
409                                urls[k] = new URL( proxyURL );
410                            http.setGetOnlineResources( urls );
411                        }
412                        if ( http.getPostOnlineResources().length > 0 ) {
413                            URL urls[] = new URL[http.getPostOnlineResources().length];
414                            for ( int k = 0; k < http.getPostOnlineResources().length; ++k )
415                                urls[k] = new URL( proxyURL );
416                            http.setPostOnlineResources( urls );
417                        }
418                    } catch ( MalformedURLException e1 ) {
419                        e1.printStackTrace();
420                    }
421                }
422            }
423        }
424    
425        /**
426         * validates the passed xml to be valid against the policy
427         *
428         * @param user
429         * @throws InvalidParameterValueException
430         * @throws UnauthorizedException
431         */
432        private byte[] validateWFSCapabilities( Document doc, User user )
433                                throws InvalidParameterValueException, UnauthorizedException {
434    
435            WFSCapabilities capa = null;
436            try {
437                WFSCapabilitiesDocument capaDoc = new WFSCapabilitiesDocument();
438                capaDoc.setRootElement( doc.getDocumentElement() );
439                capa = (WFSCapabilities) capaDoc.parseCapabilities();
440            } catch ( Exception e ) {
441                LOG.logError( e.getMessage(), e );
442                String s = Messages.format( "GetCapabilitiesResponseValidator.INVALIDWFSCAPA", e.getMessage() );
443                throw new InvalidParameterValueException( s );
444            }
445    
446            capa = filterWFSFeatureType( capa, user );
447    
448            org.deegree.ogcwebservices.getcapabilities.Operation[] ops = capa.getOperationsMetadata().getOperations();
449            for ( int i = 0; i < ops.length; i++ ) {
450                setNewOnlineResourceInOldOperation( ops[i] );
451            }
452    
453            WFSCapabilitiesDocument capaDoc = null;
454            try {
455                capaDoc = org.deegree.ogcwebservices.wfs.XMLFactory.export( capa );
456            } catch ( Exception e ) {
457                throw new InvalidParameterValueException( e );
458            }
459            ByteArrayOutputStream bos = new ByteArrayOutputStream( 20000 );
460            PrintWriter pr = new PrintWriter( bos );
461            capaDoc.write( pr );
462            return bos.toByteArray();
463    
464        }
465    
466        /**
467         * validates the passed xml to be valid against the policy
468         *
469         * @param doc
470         * @return the new response
471         * @throws InvalidParameterValueException
472         */
473        private byte[] validateCSWCapabilities( Document doc )
474                                throws InvalidParameterValueException {
475            CatalogueCapabilities capa = null;
476            try {
477                CatalogueCapabilitiesDocument capaDoc = new CatalogueCapabilitiesDocument();
478                capaDoc.setRootElement( doc.getDocumentElement() );
479                capa = (CatalogueCapabilities) capaDoc.parseCapabilities();
480            } catch ( Exception e ) {
481                LOG.logError( e.getMessage(), e );
482                throw new InvalidParameterValueException(
483                                                          Messages.format(
484                                                                           "GetCapabilitiesResponseValidator.INVALIDWFSCAPA",
485                                                                           e.getMessage() ) );
486            }
487    
488            org.deegree.ogcwebservices.getcapabilities.Operation[] ops = capa.getOperationsMetadata().getOperations();
489            for ( int i = 0; i < ops.length; i++ ) {
490                setNewOnlineResourceInOldOperation( ops[i] );
491            }
492    
493            CatalogueCapabilitiesDocument capaDoc = null;
494            try {
495                capaDoc = org.deegree.ogcwebservices.csw.XMLFactory_2_0_0.export( capa, null );
496            } catch ( Exception e ) {
497                throw new InvalidParameterValueException( e );
498            }
499            ByteArrayOutputStream bos = new ByteArrayOutputStream( 20000 );
500            PrintWriter pr = new PrintWriter( bos );
501            capaDoc.write( pr );
502            return bos.toByteArray();
503        }
504    
505        /**
506         * filters the wms capabilities to rturn just the valid layers
507         *
508         * @param capa
509         * @param user
510         */
511        private WMSCapabilities filterWMSLayers( WMSCapabilities capa, User user )
512                                throws UnauthorizedException {
513    
514            Request req = policy.getRequest( "WMS", "GetCapabilities" );
515            Condition con = req.getPostConditions();
516            OperationParameter op = con.getOperationParameter( "layers" );
517            if ( op.isAny() )
518                return capa;
519    
520            Layer layer = capa.getLayer();
521            if ( op.isUserCoupled() && user != null ) {
522                try {
523                    SecurityAccessManager sam = SecurityAccessManager.getInstance();
524                    SecurityAccess access = sam.acquireAccess( user );
525                    // call recursive method to remove all 'named' layers not
526                    // included in the list from the capabilities
527                    layer = removeWMSLayer( layer, user, access );
528                } catch ( Exception e ) {
529                    LOG.logError( e.getMessage(), e );
530                    throw new UnauthorizedException( Messages.format( "GetCapabilitiesResponseValidator.INVALIDUSER", user ) );
531                }
532            } else {
533                // get list of valid wms layers
534                List<?> list = op.getValues();
535                // call recursive method to remove all 'named' layers not
536                // included in the list from the capabilities
537                layer = removeWMSLayer( layer, list );
538            }
539            capa.setLayer( layer );
540            return capa;
541    
542        }
543    
544        /**
545         * recursive method that removes all 'named' layers (layers that has a name in addtion to a title) from the layer
546         * tree thats root node (layer) is passed to the method and that not present in the passed <tt>List</tt>
547         *
548         * @param layer
549         * @param validLayers
550         */
551        private Layer removeWMSLayer( Layer layer, List<?> validLayers ) {
552            Layer[] layers = layer.getLayer();
553            for ( int i = 0; i < layers.length; i++ ) {
554                if ( layers[i].getName() != null && !validLayers.contains( layers[i].getName() ) ) {
555                    layer.removeLayer( layers[i].getName() );
556                } else {
557                    removeWMSLayer( layers[i], validLayers );
558                    if ( layers[i].getLayer().length == 0 && layers[i].getName() == null ) {
559                        layer.removeLayerByTitle( layers[i].getTitle() );
560                    }
561                }
562            }
563            return layer;
564        }
565    
566        /**
567         * recursive method that removes all 'named' layers (layers that has a name in addition to a title) from the layer
568         * tree thats root node (layer) is passed to the method and the passed user doesn't have a GetMap right on.
569         *
570         * @param layer
571         *            layer to validate
572         * @param user
573         *            user whose rights are considered
574         * @param access
575         *            object to access DRM registry
576         *
577         */
578        private Layer removeWMSLayer( Layer layer, User user, SecurityAccess access )
579                                throws GeneralSecurityException {
580            Layer[] layers = layer.getLayer();
581            for ( int i = 0; i < layers.length; i++ ) {
582                if ( layers[i].getName() != null ) {
583                    SecuredObject secObj = null;
584                    try {
585                        // must be in try-catch block because an exception will be thrown
586                        // if no SecuredObject with the passed layer exists
587                        if ( policy.getSecurityConfig().getProxiedUrl() == null ) {
588                            secObj = access.getSecuredObjectByName( layers[i].getName(), "Layer" );
589                        } else {
590                            secObj = access.getSecuredObjectByName( "[" + policy.getSecurityConfig().getProxiedUrl() + "]:"
591                                                                    + layers[i].getName(), "Layer" );
592                        }
593                    } catch ( Exception e ) {
594                        LOG.logDebug( "Lookup failed? ", e.getLocalizedMessage() );
595                    }
596                    if ( secObj == null || user.getRights( access, secObj ).getRight( secObj, GETMAP ) == null ) {
597                        // remove the layer from the capabilities if it's not known
598                        // by the DRM registry or if the user doesn't have a GetMap
599                        // right on it
600                        layer.removeLayer( layers[i].getName() );
601                    }
602                } else {
603                    removeWMSLayer( layers[i], user, access );
604                    if ( layers[i].getLayer().length == 0 && layers[i].getName() == null ) {
605                        layer.removeLayerByTitle( layers[i].getTitle() );
606                    }
607                }
608            }
609            return layer;
610        }
611    
612        /**
613         * @param capa
614         * @param user
615         * @return the new capabilities
616         * @throws UnauthorizedException
617         */
618        private WFSCapabilities filterWFSFeatureType( WFSCapabilities capa, User user )
619                                throws UnauthorizedException {
620    
621            Request req = policy.getRequest( "WFS", "GetCapabilities" );
622            Condition con = req.getPostConditions();
623            OperationParameter op = con.getOperationParameter( "featureTypes" );
624            if ( op.isAny() )
625                return capa;
626    
627            if ( op.isUserCoupled() && user != null ) {
628                try {
629                    SecurityAccessManager sam = SecurityAccessManager.getInstance();
630                    SecurityAccess access = sam.acquireAccess( user );
631                    FeatureTypeList ftl = capa.getFeatureTypeList();
632                    WFSFeatureType[] ft = ftl.getFeatureTypes();
633                    StringBuffer sb = new StringBuffer( 200 );
634                    for ( int i = 0; i < ft.length; i++ ) {
635                        SecuredObject secObj = null;
636                        try {
637                            // must be in try-catch block because an exception will be thrown
638                            // if no SecuredObject with the passed layer exists
639                            sb.delete( 0, sb.length() );
640                            sb.append( '{' ).append( ft[i].getName().getNamespace().toASCIIString() );
641                            sb.append( "}:" ).append( ft[i].getName().getLocalName() );
642                            if ( policy.getSecurityConfig().getProxiedUrl() == null ) {
643                                secObj = access.getSecuredObjectByName( sb.toString(), "Featuretype" );
644                            } else {
645                                secObj = access.getSecuredObjectByName( "[" + policy.getSecurityConfig().getProxiedUrl()
646                                                                        + "]:" + sb, "Featuretype" );
647                            }
648                        } catch ( Exception e ) {
649                            LOG.logDebug( "Lookup failed? ", e.getLocalizedMessage() );
650                        }
651                        if ( secObj == null || user.getRights( access, secObj ).getRight( secObj, GETFEATURE ) == null ) {
652                            ftl.removeFeatureType( ft[i] );
653                        }
654                    }
655                } catch ( Exception e ) {
656                    LOG.logError( e.getMessage(), e );
657                    throw new UnauthorizedException( Messages.format( "GetCapabilitiesResponseValidator.INVALIDUSER", user ) );
658                }
659            } else {
660                // get list of valid wms layers
661                List<String> list = op.getValues();
662                FeatureTypeList ftl = capa.getFeatureTypeList();
663                WFSFeatureType[] ft = ftl.getFeatureTypes();
664                StringBuffer sb = new StringBuffer( 200 );
665                for ( int i = 0; i < ft.length; i++ ) {
666                    sb.delete( 0, sb.length() );
667                    sb.append( '{' ).append( ft[i].getName().getNamespace().toASCIIString() );
668                    sb.append( "}:" ).append( ft[i].getName().getLocalName() );
669                    if ( !list.contains( sb.toString() ) ) {
670                        ftl.removeFeatureType( ft[i] );
671                    }
672                }
673            }
674    
675            return capa;
676        }
677    }