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 }