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