001/* 002 * Copyright 2015-2016 UnboundID Corp. 003 * 004 * This program is free software; you can redistribute it and/or modify 005 * it under the terms of the GNU General Public License (GPLv2 only) 006 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 007 * as published by the Free Software Foundation. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 * 014 * You should have received a copy of the GNU General Public License 015 * along with this program; if not, see <http://www.gnu.org/licenses>. 016 */ 017 018package com.unboundid.scim2.server.utils; 019 020import com.unboundid.scim2.common.Path; 021import com.unboundid.scim2.common.types.AttributeDefinition; 022 023import java.util.Set; 024 025 026 027/** 028 * A resource trimmer implementing the SCIM standard for returning attributes. 029 */ 030public class ScimResourceTrimmer extends ResourceTrimmer 031{ 032 private final ResourceTypeDefinition resourceType; 033 private final Set<Path> requestAttributes; 034 private final Set<Path> queryAttributes; 035 private final boolean excluded; 036 037 038 039 /** 040 * Create a new SCIMResourceTrimmer. 041 * @param resourceType The resource type definition for resources to 042 * trim. 043 * @param requestAttributes The attributes in the request object or null for 044 * other requests. 045 * @param queryAttributes The attributes from the 'attributes' or 046 * 'excludedAttributes' query parameter. 047 * @param excluded {@code true} if the queryAttributes came from 048 * the excludedAttributes query parameter. 049 */ 050 public ScimResourceTrimmer(final ResourceTypeDefinition resourceType, 051 final Set<Path> requestAttributes, 052 final Set<Path> queryAttributes, 053 final boolean excluded) 054 { 055 this.resourceType = resourceType; 056 this.requestAttributes = requestAttributes; 057 this.queryAttributes = queryAttributes; 058 this.excluded = excluded; 059 } 060 061 062 063 /** 064 * {@inheritDoc} 065 */ 066 @Override 067 public boolean shouldReturn(final Path path) 068 { 069 AttributeDefinition attributeDefinition = 070 resourceType.getAttributeDefinition(path); 071 AttributeDefinition.Returned returned = attributeDefinition == null ? 072 AttributeDefinition.Returned.DEFAULT : 073 attributeDefinition.getReturned(); 074 075 switch(returned) 076 { 077 case ALWAYS: 078 return true; 079 case NEVER: 080 return false; 081 case REQUEST: 082 // Return only if it was one of the request attributes or if there are 083 // no request attributes, then only if it was one of the override query 084 // attributes. 085 return pathContains(requestAttributes, path) || 086 (requestAttributes.isEmpty() && !excluded && 087 pathContains(queryAttributes, path)); 088 default: 089 // Return if it is not one of the excluded query attributes and no 090 // override query attributes are provided. If override query attributes 091 // are provided, only return if it is one of them. 092 if(excluded) 093 { 094 return !pathContains(queryAttributes, path); 095 } 096 else 097 { 098 return queryAttributes.isEmpty() || 099 pathContains(queryAttributes, path); 100 } 101 } 102 } 103 104 private boolean pathContains(final Set<Path> paths, final Path path) 105 { 106 // Exact path match 107 if (paths.contains(path)) 108 { 109 return true; 110 } 111 112 // See if a sub-attribute of the given path is included in the list 113 // ie. include name if name.givenName is in the list. 114 for (Path p : paths) 115 { 116 if(p.size() > path.size() && path.equals(p.subPath(path.size()))) 117 { 118 return true; 119 } 120 } 121 122 // See if the parent attribute of the given path is included in the list 123 // ie. include name.{anything} if name is in the list. 124 for (Path p = path; p.size() > 0; p = p.subPath(p.size() - 1)) 125 { 126 if (paths.contains(p)) 127 { 128 return true; 129 } 130 } 131 132 return false; 133 } 134}