001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/security/owsrequestvalidator/csw/TransactionValidator.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.csw;
037
038 import java.io.IOException;
039 import java.net.URI;
040 import java.net.URISyntaxException;
041 import java.util.ArrayList;
042 import java.util.HashMap;
043 import java.util.List;
044 import java.util.Map;
045
046 import org.deegree.datatypes.QualifiedName;
047 import org.deegree.datatypes.Types;
048 import org.deegree.framework.log.ILogger;
049 import org.deegree.framework.log.LoggerFactory;
050 import org.deegree.framework.util.StringTools;
051 import org.deegree.framework.xml.NamespaceContext;
052 import org.deegree.framework.xml.XMLParsingException;
053 import org.deegree.framework.xml.XMLTools;
054 import org.deegree.model.feature.Feature;
055 import org.deegree.model.feature.FeatureFactory;
056 import org.deegree.model.feature.FeatureProperty;
057 import org.deegree.model.feature.schema.FeatureType;
058 import org.deegree.model.feature.schema.PropertyType;
059 import org.deegree.model.filterencoding.ComplexFilter;
060 import org.deegree.model.filterencoding.Expression;
061 import org.deegree.model.filterencoding.FeatureFilter;
062 import org.deegree.model.filterencoding.Filter;
063 import org.deegree.model.filterencoding.FilterConstructionException;
064 import org.deegree.model.filterencoding.Literal;
065 import org.deegree.model.filterencoding.LogicalOperation;
066 import org.deegree.model.filterencoding.OperationDefines;
067 import org.deegree.model.filterencoding.PropertyIsBetweenOperation;
068 import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
069 import org.deegree.model.filterencoding.PropertyIsLikeOperation;
070 import org.deegree.model.filterencoding.PropertyIsNullOperation;
071 import org.deegree.model.filterencoding.PropertyName;
072 import org.deegree.ogcbase.CommonNamespaces;
073 import org.deegree.ogcwebservices.InvalidParameterValueException;
074 import org.deegree.ogcwebservices.OGCWebServiceRequest;
075 import org.deegree.ogcwebservices.csw.manager.Delete;
076 import org.deegree.ogcwebservices.csw.manager.Insert;
077 import org.deegree.ogcwebservices.csw.manager.Operation;
078 import org.deegree.ogcwebservices.csw.manager.Transaction;
079 import org.deegree.ogcwebservices.csw.manager.Update;
080 import org.deegree.ogcwebservices.wfs.operation.Query;
081 import org.deegree.portal.standard.security.control.ClientHelper;
082 import org.deegree.security.GeneralSecurityException;
083 import org.deegree.security.UnauthorizedException;
084 import org.deegree.security.drm.SecurityAccess;
085 import org.deegree.security.drm.SecurityAccessManager;
086 import org.deegree.security.drm.model.Right;
087 import org.deegree.security.drm.model.RightSet;
088 import org.deegree.security.drm.model.RightType;
089 import org.deegree.security.drm.model.SecuredObject;
090 import org.deegree.security.drm.model.User;
091 import org.deegree.security.owsproxy.Condition;
092 import org.deegree.security.owsproxy.OperationParameter;
093 import org.deegree.security.owsproxy.Request;
094 import org.deegree.security.owsrequestvalidator.Messages;
095 import org.deegree.security.owsrequestvalidator.Policy;
096 import org.w3c.dom.Element;
097 import org.xml.sax.SAXException;
098
099 /**
100 * Validator for OGC CSW Transaction requests. It will validated values of:<br>
101 * <ul>
102 * <li>service version</li>
103 * <li>operation</li>
104 * <li>type names</li>
105 * <li>metadata standard</li>
106 * </ul>
107 *
108 * @version $Revision: 18195 $
109 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
110 * @author last edited by: $Author: mschneider $
111 *
112 * @version 1.0. $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $
113 *
114 * @since 2.0
115 */
116 public class TransactionValidator extends AbstractCSWRequestValidator {
117
118 private static final ILogger LOG = LoggerFactory.getLogger( TransactionValidator.class );
119
120 private final static String METADATAFORMAT = "metadataFormat";
121
122 private final static String TYPENAME = "typeName";
123
124 private static Map<QualifiedName, Filter> filterMap = new HashMap<QualifiedName, Filter>();
125
126 private static FeatureType insertFT = null;
127
128 private static FeatureType updateFT = null;
129
130 private static FeatureType deleteFT = null;
131
132 private static NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
133
134 static {
135 if ( insertFT == null ) {
136 insertFT = TransactionValidator.createInsertFeatureType();
137 }
138 if ( updateFT == null ) {
139 updateFT = TransactionValidator.createUpdateFeatureType();
140 }
141 if ( deleteFT == null ) {
142 deleteFT = TransactionValidator.createDeleteFeatureType();
143 }
144 }
145
146 /**
147 *
148 * @param policy
149 */
150 public TransactionValidator( Policy policy ) {
151 super( policy );
152 }
153
154 @Override
155 public void validateRequest( OGCWebServiceRequest request, User user )
156 throws InvalidParameterValueException, UnauthorizedException {
157
158 userCoupled = false;
159
160 Transaction cswreq = (Transaction) request;
161
162 List<Operation> ops = cswreq.getOperations();
163 for ( int i = 0; i < ops.size(); i++ ) {
164 userCoupled = false;
165 if ( ops.get( i ) instanceof Insert ) {
166 Request req = policy.getRequest( "CSW", "CSW_Insert" );
167 if ( req != null ) {
168 if ( !req.isAny() && !req.getPreConditions().isAny() ) {
169 Condition condition = req.getPreConditions();
170 validateOperation( condition, (Insert) ops.get( i ) );
171 }
172 if ( userCoupled ) {
173 validateAgainstRightsDB( (Insert) ops.get( i ), user );
174 }
175 if ( req.getPostConditions() != null ) {
176 evaluateFilter( ops.get( i ), req.getPostConditions(), user );
177 }
178 } else {
179 throw new UnauthorizedException( "You are not allowed to Insert items from the repository." );
180 }
181 } else if ( ops.get( i ) instanceof Update ) {
182 Request req = policy.getRequest( "CSW", "CSW_Update" );
183 if ( req != null ) {
184 if ( !req.isAny() && !req.getPreConditions().isAny() ) {
185 Condition condition = req.getPreConditions();
186 validateOperation( condition, (Update) ops.get( i ) );
187 }
188 if ( userCoupled ) {
189 validateAgainstRightsDB( (Update) ops.get( i ), user );
190 }
191 if ( req.getPostConditions() != null ) {
192 evaluateFilter( ops.get( i ), req.getPostConditions(), user );
193 }
194 } else {
195 throw new UnauthorizedException( "You are not allowed to update items from the repository." );
196 }
197 } else if ( ops.get( i ) instanceof Delete ) {
198 Request req = policy.getRequest( "CSW", "CSW_Delete" );
199 if ( req != null ) {
200 if ( !req.isAny() && !req.getPreConditions().isAny() ) {
201 Condition condition = req.getPreConditions();
202 validateOperation( condition, (Delete) ops.get( i ) );
203 }
204 if ( userCoupled ) {
205 validateAgainstRightsDB( (Delete) ops.get( i ), user );
206 }
207 if ( req.getPostConditions() != null ) {
208 evaluateFilter( ops.get( i ), req.getPostConditions(), user );
209 }
210 } else {
211 throw new UnauthorizedException( "You are not allowed to delete items from the repository." );
212 }
213 }
214 }
215
216 }
217
218 /**
219 * adds a filter to the passed opertaion. If the condition is userCoupled the filter will be read from the DRM
220 * otherwise it is read from the current WFS policy file
221 *
222 * @param operation
223 * @param postConditions
224 * @param user
225 * @throws InvalidParameterValueException
226 * @throws UnauthorizedException
227 */
228 private void evaluateFilter( Operation operation, Condition postConditions, User user )
229 throws InvalidParameterValueException, UnauthorizedException {
230 if ( postConditions.getOperationParameter( "instanceFilter" ) != null ) {
231 if ( postConditions.getOperationParameter( "instanceFilter" ).isAny() ) {
232 return;
233 }
234
235 List<QualifiedName> qns = getMetadataTypes( operation );
236 Map<QualifiedName, Filter> filter = null;
237 if ( postConditions.getOperationParameter( "instanceFilter" ).isUserCoupled() ) {
238 // read filterMap from constraints defined in deegree DRM
239 filter = readFilterFromDRM( qns, operation, user );
240 } else {
241 fillFilterMap( postConditions );
242 filter = filterMap;
243 }
244
245 if ( operation instanceof Update || operation instanceof Delete ) {
246 handleUpdateDelete( operation, filter );
247 } else {
248 handleInsert( (Insert) operation, filter );
249 }
250 } else if ( operation instanceof Insert ) {
251 // because of its pessimistic security concept deegree assumed
252 // that there is a security validation if no filter is available
253 // for a metadata type
254 String msg = org.deegree.i18n.Messages.getMessage( "OWSPROXY_CSW_INSERT_NOT_ALLOWED" );
255 throw new UnauthorizedException( msg );
256 }
257 }
258
259 /**
260 * validates if the content of an Insert operation matches the defined security conditions
261 *
262 * @param operation
263 * @param filterMap
264 * @throws InvalidParameterValueException
265 * @throws UnauthorizedException
266 */
267 private void handleInsert( Insert operation, Map<QualifiedName, Filter> filterMap )
268 throws InvalidParameterValueException, UnauthorizedException {
269
270 List<Element> records = operation.getRecords();
271
272 for ( int i = 0; i < records.size(); i++ ) {
273 Element rec = records.get( i );
274 String name = rec.getLocalName();
275 URI uri;
276 try {
277 uri = new URI( rec.getNamespaceURI() );
278 } catch ( URISyntaxException e ) {
279 LOG.logError( e.getMessage(), e );
280 throw new InvalidParameterValueException( e.getMessage(), e );
281 }
282 QualifiedName qn = new QualifiedName( "a", name, uri );
283
284 ComplexFilter filter = (ComplexFilter) filterMap.get( qn );
285 if ( filter != null ) {
286 boolean match = false;
287 // just if a constraint is defined on combination of insert
288 // operation and the current metadata type it can be evaluated
289 LogicalOperation lo = (LogicalOperation) filter.getOperation();
290 if ( lo.getOperatorId() == OperationDefines.AND ) {
291 // handle conditions connected by logical AND
292 List<org.deegree.model.filterencoding.Operation> args = lo.getArguments();
293 match = evaluateLogicalAnd( rec, args );
294 } else if ( lo.getOperatorId() == OperationDefines.OR ) {
295 // handle conditions connected by logical OR
296 List<org.deegree.model.filterencoding.Operation> args = lo.getArguments();
297 match = evaluateLogicalOr( rec, args );
298 } else {
299 // NOT
300 }
301 if ( !match ) {
302 // if loop has been left and 'match' is still false
303 // no condition has matched
304 String msg = org.deegree.i18n.Messages.getMessage( "OWSPROXY_CSW_INSERT_NOT_ALLOWED" );
305 throw new UnauthorizedException( msg );
306 }
307 } else {
308 // because of its pessimistic security concept deegree assumed
309 // that there is a security validation if no filter is available
310 // for a metadata type
311 String msg = org.deegree.i18n.Messages.getMessage( "OWSPROXY_CSW_INSERT_NOT_ALLOWED" );
312 throw new UnauthorizedException( msg );
313 }
314 }
315
316 }
317
318 /**
319 * evaluates if operations surrounded by a logical OR. If none of the contained conditions are fullfilled an
320 * {@link UnauthorizedException} will be thrown
321 *
322 * @param rec
323 * @param args
324 * @return the boolean result
325 * @throws InvalidParameterValueException
326 */
327 private boolean evaluateLogicalOr( Element rec, List<org.deegree.model.filterencoding.Operation> args )
328 throws InvalidParameterValueException {
329 boolean match = false;
330 for ( org.deegree.model.filterencoding.Operation op : args ) {
331 try {
332 match = evaluate( rec, op );
333 if ( match ) {
334 // loop can be breaked if at least one condition
335 // matches
336 return true;
337 }
338 } catch ( XMLParsingException e ) {
339 LOG.logError( e.getMessage(), e );
340 throw new InvalidParameterValueException( e.getMessage(), e );
341 }
342 }
343 return match;
344 }
345
346 /**
347 * evaluates if operations surrounded by a logical AND. If at least one of the contained conditions is not
348 * fullfilled an {@link UnauthorizedException} will be thrown
349 *
350 * @param rec
351 * @param args
352 * @return the truth
353 * @throws InvalidParameterValueException
354 */
355 private boolean evaluateLogicalAnd( Element rec, List<org.deegree.model.filterencoding.Operation> args )
356 throws InvalidParameterValueException {
357 boolean match = false;
358 for ( org.deegree.model.filterencoding.Operation op : args ) {
359 try {
360 match = evaluate( rec, op );
361 if ( !match ) {
362 break;
363 }
364 } catch ( XMLParsingException e ) {
365 LOG.logError( e.getMessage(), e );
366 throw new InvalidParameterValueException( e.getMessage(), e );
367 }
368 }
369 return match;
370 }
371
372 /**
373 * evaluates if the passed record matches the passed filter operation
374 *
375 * @param element
376 * @param op
377 * @return the truth
378 * @throws XMLParsingException
379 * @throws InvalidParameterValueException
380 */
381 private boolean evaluate( Element record, org.deegree.model.filterencoding.Operation op )
382 throws XMLParsingException, InvalidParameterValueException {
383 if( op == null ){
384 throw new InvalidParameterValueException( "The operation cannot be null" );
385 }
386 boolean matches = false;
387 Expression exp = null;
388 if ( op.getOperatorId() == OperationDefines.PROPERTYISEQUALTO
389 || op.getOperatorId() == OperationDefines.PROPERTYISGREATERTHAN
390 || op.getOperatorId() == OperationDefines.PROPERTYISGREATERTHANOREQUALTO
391 || op.getOperatorId() == OperationDefines.PROPERTYISLESSTHAN
392 || op.getOperatorId() == OperationDefines.PROPERTYISLESSTHANOREQUALTO ) {
393 matches = evaluateCOMP( record, (PropertyIsCOMPOperation) op );
394 } else if ( op.getOperatorId() == OperationDefines.PROPERTYISNULL ) {
395 PropertyName pn = ( (PropertyIsNullOperation) op ).getPropertyName();
396 String xpath = pn.getValue().getAsString();
397 nsc.addAll( pn.getValue().getNamespaceContext() );
398 matches = XMLTools.getNode( record, xpath, nsc ) == null;
399 } else if ( op.getOperatorId() == OperationDefines.PROPERTYISBETWEEN ) {
400 PropertyName pn = ( (PropertyIsBetweenOperation) op ).getPropertyName();
401 String xpath = pn.getValue().getAsString();
402 nsc.addAll( pn.getValue().getNamespaceContext() );
403 exp = ( (PropertyIsBetweenOperation) op ).getLowerBoundary();
404 String lower = ( (Literal) exp ).getValue();
405 exp = ( (PropertyIsBetweenOperation) op ).getUpperBoundary();
406 String upper = ( (Literal) exp ).getValue();
407 String value = XMLTools.getNodeAsString( record, xpath, nsc, null );
408 matches = lower.compareTo( value ) < 0 && upper.compareTo( value ) > 0;
409 } else if ( op.getOperatorId() == OperationDefines.PROPERTYISLIKE ) {
410 PropertyName pn = ( (PropertyIsLikeOperation) op ).getPropertyName();
411 String xpath = pn.getValue().getAsString();
412 nsc.addAll( pn.getValue().getNamespaceContext() );
413 String value = XMLTools.getNodeAsString( record, xpath, nsc, null );
414 String literal = ( (PropertyIsLikeOperation) op ).getLiteral().getValue();
415 if( literal == null ){
416 throw new InvalidParameterValueException( "No literal found resulting from the xpath: " + xpath + " therefore you're not authorized." );
417 }
418 matches = ( (PropertyIsLikeOperation) op ).matches( literal, value );
419 } else if ( op.getOperatorId() == OperationDefines.AND ) {
420 List<org.deegree.model.filterencoding.Operation> ops = ( (LogicalOperation) op ).getArguments();
421 return evaluateLogicalAnd( record, ops );
422 } else if ( op.getOperatorId() == OperationDefines.OR ) {
423 List<org.deegree.model.filterencoding.Operation> ops = ( (LogicalOperation) op ).getArguments();
424 return evaluateLogicalOr( record, ops );
425 }
426 return matches;
427 }
428
429 private boolean evaluateCOMP( Element record, PropertyIsCOMPOperation op )
430 throws XMLParsingException {
431 boolean matches = false;
432 Expression exp = op.getFirstExpression();
433 PropertyName pn = (PropertyName) exp;
434 String xpath = pn.getValue().getAsString();
435 nsc.addAll( pn.getValue().getNamespaceContext() );
436 String value = XMLTools.getNodeAsString( record, xpath, nsc, null );
437 exp = op.getSecondExpression();
438 Literal literal = (Literal) exp;
439 if ( op.getOperatorId() == OperationDefines.PROPERTYISEQUALTO ) {
440 matches = literal.getValue().equals( value );
441 } else if ( op.getOperatorId() == OperationDefines.PROPERTYISGREATERTHAN ) {
442 matches = value != null && literal.getValue().compareTo( value ) < 0;
443 } else if ( op.getOperatorId() == OperationDefines.PROPERTYISGREATERTHANOREQUALTO ) {
444 matches = value != null && literal.getValue().compareTo( value ) <= 0;
445 } else if ( op.getOperatorId() == OperationDefines.PROPERTYISLESSTHAN ) {
446 matches = value != null && literal.getValue().compareTo( value ) > 0;
447 } else if ( op.getOperatorId() == OperationDefines.PROPERTYISLESSTHANOREQUALTO ) {
448 matches = value != null && literal.getValue().compareTo( value ) >= 0;
449 }
450 return matches;
451 }
452
453 /**
454 * redefines the constraints of the passed operation if necessary
455 *
456 * @param operation
457 * @param filter
458 * @return the constrained operation
459 */
460 private Operation handleUpdateDelete( Operation operation, Map<QualifiedName, Filter> filter ) {
461 Filter tmpFilter = null;
462 Filter opFilter = null;
463 if ( operation instanceof Update ) {
464 opFilter = ( (Update) operation ).getConstraint();
465 } else {
466 opFilter = ( (Delete) operation ).getConstraint();
467 }
468 if ( opFilter instanceof ComplexFilter ) {
469 // create a new Filter that is a combination of the
470 // original filter and the one defined in the GetFeatures
471 // PostConditions coupled by a logical 'And'
472 ComplexFilter qFilter = (ComplexFilter) opFilter;
473 if ( filter == null ) {
474 // not filter defined in security managment
475 tmpFilter = qFilter;
476 } else {
477 // merger filter of update/delete operation and filter
478 // defined in security managment
479 tmpFilter = filter.values().iterator().next();
480 tmpFilter = new ComplexFilter( qFilter, (ComplexFilter) tmpFilter, OperationDefines.AND );
481 }
482 } else if ( opFilter instanceof FeatureFilter ) {
483 // just take original filter if it is as feature filter
484 // because feature filter and complex filters can not
485 // be combined
486 tmpFilter = opFilter;
487 }
488 if ( operation instanceof Update ) {
489 ( (Update) operation ).setConstraint( tmpFilter );
490 } else {
491 ( (Delete) operation ).setConstraint( tmpFilter );
492 }
493 return operation;
494 }
495
496 /**
497 * reads a filter m
498 *
499 * @param operation
500 * @param user
501 * @return the filter map
502 * @throws UnauthorizedException
503 * @throws InvalidParameterValueException
504 */
505 private Map<QualifiedName, Filter> readFilterFromDRM( List<QualifiedName> qns, Operation operation, User user )
506 throws UnauthorizedException, InvalidParameterValueException {
507 Map<QualifiedName, Filter> f = new HashMap<QualifiedName, Filter>();
508 try {
509 SecurityAccessManager sam = SecurityAccessManager.getInstance();
510 SecurityAccess access = sam.acquireAccess( user );
511
512 for ( int i = 0; i < qns.size(); i++ ) {
513 List<ComplexFilter> foundFilters = new ArrayList<ComplexFilter>();
514 SecuredObject secObj = access.getSecuredObjectByName( qns.get( i ).getFormattedString(),
515 ClientHelper.TYPE_METADATASCHEMA );
516 RightSet rs = user.getRights( access, secObj );
517 Right right = null;
518 if ( operation instanceof Update ) {
519 right = rs.getRight( secObj, RightType.UPDATE_RESPONSE );
520 } else if ( operation instanceof Delete ) {
521 right = rs.getRight( secObj, RightType.DELETE_RESPONSE );
522 } else {
523 right = rs.getRight( secObj, RightType.INSERT_RESPONSE );
524 }
525 // a constraint - if available - is constructed as a OGC Filter
526 // one of the filter operations may is 'PropertyIsEqualTo' and
527 // defines a ProperyName == 'instanceFilter'. The Literal of this
528 // operation itself is a complete and valid Filter expression.
529 if ( right != null ) {
530 ComplexFilter filter = (ComplexFilter) right.getConstraints();
531 if ( filter != null ) {
532 // extract filter expression to be used as additional
533 // filter for a GetFeature request
534 extractInstanceFilter( filter.getOperation(), foundFilters );
535 if ( foundFilters.size() == 1 ) {
536 filter = foundFilters.get( 0 );
537 } else if ( foundFilters.size() > 1 ) {
538 List<org.deegree.model.filterencoding.Operation> list = new ArrayList<org.deegree.model.filterencoding.Operation>();
539 for ( ComplexFilter cf : foundFilters ) {
540 list.add( cf.getOperation() );
541 }
542 LogicalOperation lo = new LogicalOperation( OperationDefines.OR, list );
543 filter = new ComplexFilter( lo );
544 }
545 f.put( qns.get( i ), filter );
546 }
547 }
548 }
549
550 } catch ( GeneralSecurityException e ) {
551 LOG.logError( e.getMessage(), e );
552 throw new UnauthorizedException( e.getMessage(), e );
553 } catch ( FilterConstructionException e ) {
554 LOG.logError( e.getMessage(), e );
555 throw new InvalidParameterValueException( e.getMessage(), e );
556 } catch ( SAXException e ) {
557 LOG.logError( e.getMessage(), e );
558 throw new InvalidParameterValueException( e.getMessage(), e );
559 } catch ( IOException e ) {
560 LOG.logError( e.getMessage(), e );
561 throw new InvalidParameterValueException( e.getMessage(), e );
562 }
563 return f;
564 }
565
566 /**
567 * @return the list a metadata types targeted by an operation
568 *
569 * @param operation
570 * @throws InvalidParameterValueException
571 */
572 private List<QualifiedName> getMetadataTypes( Operation operation )
573 throws InvalidParameterValueException {
574 List<QualifiedName> qns = new ArrayList<QualifiedName>();
575 if ( operation instanceof Update ) {
576
577 } else if ( operation instanceof Delete ) {
578
579 } else {
580 // get list of all record types to be inserted
581 List<Element> recs = ( (Insert) operation ).getRecords();
582 for ( int i = 0; i < recs.size(); i++ ) {
583 String name = recs.get( i ).getLocalName();
584 URI uri;
585 try {
586 uri = new URI( recs.get( i ).getNamespaceURI() );
587 } catch ( URISyntaxException e ) {
588 LOG.logError( e.getMessage(), e );
589 throw new InvalidParameterValueException( e.getMessage(), e );
590 }
591 QualifiedName qn = new QualifiedName( "a", name, uri );
592 if ( !qns.contains( qn ) ) {
593 qns.add( qn );
594 }
595 }
596 }
597 return qns;
598 }
599
600 private void fillFilterMap( Condition postConditions )
601 throws InvalidParameterValueException {
602 List<Element> complexValues = postConditions.getOperationParameter( "instanceFilter" ).getComplexValues();
603 try {
604 if ( filterMap.size() == 0 ) {
605 for ( int i = 0; i < complexValues.size(); i++ ) {
606 Query q = Query.create( complexValues.get( 0 ) );
607 Filter f = q.getFilter();
608 QualifiedName qn = q.getTypeNames()[0];
609 filterMap.put( qn, f );
610 }
611 }
612 } catch ( XMLParsingException e ) {
613 LOG.logError( e.getMessage(), e );
614 throw new InvalidParameterValueException( this.getClass().getName(), e.getMessage() );
615 }
616 }
617
618 /**
619 *
620 * @param condition
621 * @param insert
622 * @throws InvalidParameterValueException
623 */
624 private void validateOperation( Condition condition, Insert insert )
625 throws InvalidParameterValueException {
626
627 OperationParameter op = condition.getOperationParameter( METADATAFORMAT );
628
629 // version is valid because no restrictions are made
630 if ( op.isAny() ) {
631 return;
632 }
633
634 List<?> vals = op.getValues();
635
636 List<Element> records = insert.getRecords();
637 for ( int i = 0; i < records.size(); i++ ) {
638 String name = records.get( i ).getLocalName();
639 String ns = records.get( i ).getNamespaceURI();
640 String qn = StringTools.concat( 200, '{', ns, "}:", name );
641
642 if ( !vals.contains( qn ) ) {
643 if ( !op.isUserCoupled() ) {
644 String s = Messages.format( "CSWTransactionValidator.INVALIDMETADATAFORMAT", qn );
645 throw new InvalidParameterValueException( s );
646 }
647 userCoupled = true;
648 break;
649 }
650 }
651
652 }
653
654 /**
655 *
656 * @param condition
657 * @param delete
658 * @throws InvalidParameterValueException
659 */
660 private void validateOperation( Condition condition, Delete delete )
661 throws InvalidParameterValueException {
662 OperationParameter op = condition.getOperationParameter( TYPENAME );
663
664 // version is valid because no restrictions are made
665 if ( op.isAny() )
666 return;
667
668 URI typeName = delete.getTypeName();
669
670 if ( typeName == null ) {
671 String s = Messages.getString( "CSWTransactionValidator.INVALIDDELETETYPENAME1" );
672 throw new InvalidParameterValueException( s );
673 }
674
675 List<?> vals = op.getValues();
676 if ( !vals.contains( typeName.toASCIIString() ) ) {
677 if ( !op.isUserCoupled() ) {
678 String s = Messages.format( "CSWTransactionValidator.INVALIDDELETETYPENAME2", typeName );
679 throw new InvalidParameterValueException( s );
680 }
681 userCoupled = true;
682 }
683
684 }
685
686 /**
687 *
688 * @param condition
689 * @param update
690 * @throws InvalidParameterValueException
691 */
692 private void validateOperation( Condition condition, Update update )
693 throws InvalidParameterValueException {
694
695 URI typeName = update.getTypeName();
696 Element record = update.getRecord();
697
698 if ( typeName == null && record == null ) {
699 String s = Messages.getString( "CSWTransactionValidator.INVALIDUPDATETYPENAME1" );
700 throw new InvalidParameterValueException( s );
701 }
702
703 OperationParameter op = condition.getOperationParameter( TYPENAME );
704 List<?> vals = op.getValues();
705
706 if ( typeName != null && !vals.contains( typeName.toASCIIString() ) ) {
707 // version is valid because no restrictions are made
708 if ( op.isAny() ) {
709 return;
710 }
711 if ( !op.isUserCoupled() ) {
712 String s = Messages.format( "CSWTransactionValidator.INVALIDUPDATETYPENAME2", typeName );
713 throw new InvalidParameterValueException( s );
714 }
715 userCoupled = true;
716 } else {
717 op = condition.getOperationParameter( METADATAFORMAT );
718 // version is valid because no restrictions are made
719 if ( op.isAny() ) {
720 return;
721 }
722 vals = op.getValues();
723 String name = record.getLocalName();
724 String ns = record.getNamespaceURI();
725 String qn = StringTools.concat( 200, '{', ns, "}:", name );
726 if ( !vals.contains( qn ) ) {
727 if ( !op.isUserCoupled() ) {
728 String s = Messages.format( "CSWTransactionValidator.INVALIDMETADATAFORMAT", qn );
729 throw new InvalidParameterValueException( s );
730 }
731 userCoupled = true;
732 }
733 }
734 }
735
736 /**
737 * validates a Transcation.Delete request against the underlying users and rights management system
738 *
739 * @param delete
740 * @param version
741 * @param user
742 * @throws InvalidParameterValueException
743 * @throws UnauthorizedException
744 */
745 private void validateAgainstRightsDB( Delete delete, User user )
746 throws InvalidParameterValueException, UnauthorizedException {
747 if ( user == null ) {
748 throw new UnauthorizedException( Messages.getString( "RequestValidator.NOACCESS" ) );
749 }
750
751 // create a feature instance from the parameters of the GetRecords request
752 // to enable comparsion with a filter encoding expression stored in the
753 // assigned rights management system
754 List<FeatureProperty> fps = new ArrayList<FeatureProperty>();
755
756 URI typeName = delete.getTypeName();
757 String tn = null;
758 if ( typeName != null ) {
759 tn = typeName.toASCIIString();
760 }
761 FeatureProperty fp = FeatureFactory.createFeatureProperty( new QualifiedName( "typeName" ), tn );
762 fps.add( fp );
763 Feature feature = FeatureFactory.createFeature( "id", insertFT, fps );
764
765 handleUserCoupledRules( user, // the user who posted the request
766 feature, // This is the Database feature
767 // the name the metadataFormat to be deleted
768 "{http://www.opengis.net/cat/csw}:profil", ClientHelper.TYPE_METADATASCHEMA, // a
769 // primary
770 // key
771 // in
772 // the
773 // db.
774 RightType.DELETE );// We're requesting a featuretype.
775
776 }
777
778 /**
779 * validates a Transcation.Update request against the underlying users and rights management system
780 *
781 * @param update
782 * @param user
783 */
784 private void validateAgainstRightsDB( Update update, User user ) {
785 throw new NoSuchMethodError( getClass().getName() + ".validateAgainstRightsDB not implemented yet" );
786 }
787
788 /**
789 * validates the passed insert operation against the deegree user/rights management system
790 *
791 * @param insert
792 * @param version
793 * @param user
794 * @throws InvalidParameterValueException
795 * @throws UnauthorizedException
796 */
797 private void validateAgainstRightsDB( Insert insert, User user )
798 throws InvalidParameterValueException, UnauthorizedException {
799
800 if ( user == null ) {
801 throw new UnauthorizedException( Messages.getString( "RequestValidator.NOACCESS" ) );
802 }
803
804 // create a feature instance from the parameters of the GetRecords request
805 // to enable comparsion with a filter encoding expression stored in the
806 // assigned rights management system
807 List<FeatureProperty> fps = new ArrayList<FeatureProperty>();
808 FeatureProperty fp = null;
809 fps.add( fp );
810
811 Feature feature = FeatureFactory.createFeature( "id", insertFT, fps );
812
813 List<Element> records = insert.getRecords();
814 for ( int i = 0; i < records.size(); i++ ) {
815 String name = records.get( i ).getLocalName();
816 String ns = records.get( i ).getNamespaceURI();
817 String qn = StringTools.concat( 200, '{', ns, "}:", name );
818
819 handleUserCoupledRules( user, // the user who posted the request
820 feature, // This is the Database feature
821 qn, // the Qualified name of the users Featurerequest
822 ClientHelper.TYPE_METADATASCHEMA, // a primary key in the db.
823 RightType.INSERT );// We're requesting a featuretype.
824 }
825
826 }
827
828 /**
829 * creates a feature type that matches the parameters of a Insert operation
830 *
831 * @return created <tt>FeatureType</tt>
832 */
833 private static FeatureType createInsertFeatureType() {
834 PropertyType[] ftps = new PropertyType[1];
835 ftps[0] = FeatureFactory.createSimplePropertyType( new QualifiedName( "metadataFormat" ), Types.VARCHAR, false );
836
837 return FeatureFactory.createFeatureType( "CSW_Insert", false, ftps );
838 }
839
840 /**
841 * creates a feature type that matches the parameters of a Update operation
842 *
843 * @return created <tt>FeatureType</tt>
844 */
845 private static FeatureType createUpdateFeatureType() {
846 PropertyType[] ftps = new PropertyType[2];
847 ftps[0] = FeatureFactory.createSimplePropertyType( new QualifiedName( "metadataFormat" ), Types.VARCHAR, false );
848 ftps[1] = FeatureFactory.createSimplePropertyType( new QualifiedName( "typeName" ), Types.VARCHAR, false );
849
850 return FeatureFactory.createFeatureType( "CSW_Update", false, ftps );
851 }
852
853 /**
854 * creates a feature type that matches the parameters of a Delete operation
855 *
856 * @return created <tt>FeatureType</tt>
857 */
858 private static FeatureType createDeleteFeatureType() {
859 PropertyType[] ftps = new PropertyType[1];
860 ftps[0] = FeatureFactory.createSimplePropertyType( new QualifiedName( "typeName" ), Types.VARCHAR, false );
861
862 return FeatureFactory.createFeatureType( "CSW_Delete", false, ftps );
863 }
864
865 }