001/* 002 * Copyright 2015-2018 Ping Identity Corporation 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 044 * {@code null} for 045 * other requests. 046 * @param queryAttributes The attributes from the 'attributes' or 047 * 'excludedAttributes' query parameter. 048 * @param excluded {@code true} if the queryAttributes came from 049 * the excludedAttributes query parameter. 050 */ 051 public ScimResourceTrimmer(final ResourceTypeDefinition resourceType, 052 final Set<Path> requestAttributes, 053 final Set<Path> queryAttributes, 054 final boolean excluded) 055 { 056 this.resourceType = resourceType; 057 this.requestAttributes = requestAttributes; 058 this.queryAttributes = queryAttributes; 059 this.excluded = excluded; 060 } 061 062 063 064 /** 065 * {@inheritDoc} 066 */ 067 @Override 068 public boolean shouldReturn(final Path path) 069 { 070 AttributeDefinition attributeDefinition = 071 resourceType.getAttributeDefinition(path); 072 AttributeDefinition.Returned returned = attributeDefinition == null ? 073 AttributeDefinition.Returned.DEFAULT : 074 attributeDefinition.getReturned(); 075 076 switch(returned) 077 { 078 case ALWAYS: 079 return true; 080 case NEVER: 081 return false; 082 case REQUEST: 083 // Return only if it was one of the request attributes or if there are 084 // no request attributes, then only if it was one of the override query 085 // attributes. 086 return pathContains(requestAttributes, path) || 087 (requestAttributes.isEmpty() && !excluded && 088 pathContains(queryAttributes, path)); 089 default: 090 // Return if it is not one of the excluded query attributes and no 091 // override query attributes are provided. If override query attributes 092 // are provided, only return if it is one of them. 093 if(excluded) 094 { 095 return !pathContains(queryAttributes, path); 096 } 097 else 098 { 099 return queryAttributes.isEmpty() || 100 pathContains(queryAttributes, path); 101 } 102 } 103 } 104 105 private boolean pathContains(final Set<Path> paths, final Path path) 106 { 107 // Exact path match 108 if (paths.contains(path)) 109 { 110 return true; 111 } 112 113 if (!excluded) 114 { 115 // See if a sub-attribute of the given path is included in the list 116 // ie. include name if name.givenName is in the list. 117 for (Path p : paths) 118 { 119 if (p.size() > path.size() && path.equals(p.subPath(path.size()))) 120 { 121 return true; 122 } 123 } 124 } 125 126 // See if the parent attribute of the given path is included in the list 127 // ie. include name.{anything} if name is in the list. 128 for (Path p = path; p.size() > 0; p = p.subPath(p.size() - 1)) 129 { 130 if (paths.contains(p)) 131 { 132 return true; 133 } 134 } 135 136 return false; 137 } 138}