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 }