From 21dee620011210eda0202f7a15ec3ba04293758f Mon Sep 17 00:00:00 2001 From: Filip Hanik Date: Thu, 20 Apr 2017 12:24:09 -0700 Subject: [PATCH 1/3] bump for next release --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6047e4994eb..7d6e81a7e19 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=3.15.0 +version=3.16.0-SNAPSHOT From 74b9b270787aa602196d59d58893c3a6e09816f9 Mon Sep 17 00:00:00 2001 From: Filip Hanik Date: Wed, 19 Apr 2017 12:54:17 -0700 Subject: [PATCH 2/3] better parsing of attributes --- .../jdbc/SimpleSearchQueryConverter.java | 111 ++++++++++++++++-- .../jdbc/SimpleSearchQueryConverterTests.java | 95 +++++++++++++++ .../jdbc/ScimSearchQueryConverterTests.java | 8 +- 3 files changed, 201 insertions(+), 13 deletions(-) create mode 100644 server/src/test/java/org/cloudfoundry/identity/uaa/resources/jdbc/SimpleSearchQueryConverterTests.java diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/SimpleSearchQueryConverter.java b/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/SimpleSearchQueryConverter.java index 1d129e3c18c..9a9f04f91d0 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/SimpleSearchQueryConverter.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/resources/jdbc/SimpleSearchQueryConverter.java @@ -13,13 +13,7 @@ package org.cloudfoundry.identity.uaa.resources.jdbc; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - +import com.unboundid.scim.sdk.InvalidResourceException; import com.unboundid.scim.sdk.SCIMException; import com.unboundid.scim.sdk.SCIMFilter; import org.apache.commons.logging.Log; @@ -29,15 +23,85 @@ import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import org.springframework.util.StringUtils; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import static java.util.Collections.emptyList; +import static java.util.Optional.ofNullable; import static org.cloudfoundry.identity.uaa.resources.jdbc.SearchQueryConverter.ProcessedFilter.ORDER_BY; public class SimpleSearchQueryConverter implements SearchQueryConverter { + //LOWER + public static final List VALID_ATTRIBUTE_NAMES = Collections.unmodifiableList( + Arrays.asList( + "id", + "created", + "lastmodified", + "version", + "username", + "password", + "email", + "givenname", + "familyname", + "name.familyname", + "name.givenname", + "active", + "phonenumber", + "verified", + "origin", + "identity_zone_id", + "passwd_lastmodified", + "passwd_change_required", + "last_logon_success_time", + "previous_logon_success_time", + "displayname", + "scope", + "group_id", + "member_id", + "member_type", + "description", + "client_id", + "authorized_grant_types", + "web_server_redirect_uri", + "redirect_uri", + "access_token_validity", + "refresh_token_validity", + "autoapprove", + "show_on_home_page", + "created_by", + "required_user_groups", + "user_id", + "meta.lastmodified", + "meta.created", + "meta.location", + "meta.resourcetype", + "meta.version", + "emails.value", + "groups.display", + "phonenumbers.value", + "gm.external_group", + "gm.origin", + "g.displayname", + "g.id" + ) + ); + private static Log logger = LogFactory.getLog(SimpleSearchQueryConverter.class); private AttributeNameMapper mapper = new SimpleAttributeNameMapper(Collections. emptyMap()); private boolean dbCaseInsensitive = false; + public SimpleSearchQueryConverter() { + } + public boolean isDbCaseInsensitive() { return dbCaseInsensitive; } @@ -92,7 +156,7 @@ private String getWhereClause(String filter, String sortBy, boolean ascending, M } } - private SCIMFilter scimFilter(String filter) throws SCIMException { + protected SCIMFilter scimFilter(String filter) throws SCIMException { SCIMFilter scimFilter; try { scimFilter = SCIMFilter.parse(filter); @@ -101,9 +165,33 @@ private SCIMFilter scimFilter(String filter) throws SCIMException { filter = filter.replaceAll("'","\""); scimFilter = SCIMFilter.parse(filter); } + validateFilterAttributes(scimFilter); return scimFilter; } + private void validateFilterAttributes(SCIMFilter filter) throws SCIMException { + List invalidAttributes = new LinkedList<>(); + validateFilterAttributes(filter, invalidAttributes); + if (!invalidAttributes.isEmpty()) { + throw new InvalidResourceException("Invalid filter attributes:"+StringUtils.collectionToCommaDelimitedString(invalidAttributes)); + } + } + + private void validateFilterAttributes(SCIMFilter filter, List invalidAttribues) { + if (filter.getFilterAttribute()!=null && filter.getFilterAttribute().getAttributeName()!=null) { + String name = filter.getFilterAttribute().getAttributeName(); + if (filter.getFilterAttribute().getSubAttributeName()!=null) { + name = name + "." + filter.getFilterAttribute().getSubAttributeName(); + } + if (!VALID_ATTRIBUTE_NAMES.contains(name.toLowerCase())) { + invalidAttribues.add(name); + } + } + for (SCIMFilter subfilter : ofNullable(filter.getFilterComponents()).orElse(emptyList())) { + validateFilterAttributes(subfilter, invalidAttribues); + } + } + private String createFilter(SCIMFilter filter, Map values, AttributeNameMapper mapper, String paramPrefix) { switch (filter.getFilterType()) { case AND: @@ -130,7 +218,12 @@ private String createFilter(SCIMFilter filter, Map values, Attrib return null; } - protected String comparisonClause(SCIMFilter filter, String comparator, Map values, String valuePrefix, String valueSuffix, String paramPrefix) { + protected String comparisonClause(SCIMFilter filter, + String comparator, + Map values, + String valuePrefix, + String valueSuffix, + String paramPrefix) { String pName = getParamName(values, paramPrefix); String paramName = ":"+pName; if (filter.getFilterValue() == null) { diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/resources/jdbc/SimpleSearchQueryConverterTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/resources/jdbc/SimpleSearchQueryConverterTests.java new file mode 100644 index 00000000000..beadf2e45ac --- /dev/null +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/resources/jdbc/SimpleSearchQueryConverterTests.java @@ -0,0 +1,95 @@ +/* + * **************************************************************************** + * Cloud Foundry + * Copyright (c) [2009-2017] Pivotal Software, Inc. All Rights Reserved. + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product includes a number of subcomponents with + * separate copyright notices and license terms. Your use of these + * subcomponents is subject to the terms and conditions of the + * subcomponent's license, as noted in the LICENSE file. + * **************************************************************************** + */ + +package org.cloudfoundry.identity.uaa.resources.jdbc; + +import com.unboundid.scim.sdk.InvalidResourceException; +import com.unboundid.scim.sdk.SCIMFilter; +import org.cloudfoundry.identity.uaa.scim.jdbc.ScimSearchQueryConverter; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.concurrent.atomic.AtomicInteger; + +import static java.util.Collections.emptyList; +import static java.util.Optional.ofNullable; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.startsWith; + +public class SimpleSearchQueryConverterTests { + + SimpleSearchQueryConverter converter; + + String query = "user_id eq \"7e2345e8-8bbf-4eaa-9bc3-ae1ba610f890\"" + + "and " + + "client_id eq \"app\"" + + "and " + + "meta.lastmodified gt \"some-value\"" + + "and " + + "(an/**/invalid/**/attribute/**/and/**/1" + //invalid attribute name + " pr " + //operator (present) + "and " + + "1 eq 1)" + //invalid attribute name 1 + " and " + + "\"1\" eq \"1\""; + + String validQuery = "user_id eq \"7e2345e8-8bbf-4eaa-9bc3-ae1ba610f890\"" + + "and " + + "client_id eq \"app\"" + + "and " + + "meta.lastmodified gt \"some-value\"" + + "and " + + "meta.created pr"; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Before + public void setup() { + converter = new ScimSearchQueryConverter(); + } + + @Test + public void test_query() throws Exception { + exception.expect(InvalidResourceException.class); + exception.expectMessage(startsWith("Invalid filter attributes")); + exception.expectMessage(containsString("an/**/invalid/**/attribute/**/and/**/1")); + exception.expectMessage(containsString("1")); + exception.expectMessage(containsString("\"1\"")); + SCIMFilter filter = converter.scimFilter(query); + } + + @Test + public void print_query() throws Exception { + SCIMFilter filter = converter.scimFilter(validQuery); + printFilterAttributes(filter, new AtomicInteger(0)); + } + + public void printFilterAttributes(SCIMFilter filter, AtomicInteger pos) { + if (filter.getFilterAttribute() != null) { + String name = filter.getFilterAttribute().getAttributeName(); + if (filter.getFilterAttribute().getSubAttributeName() != null) { + name = name + "." + filter.getFilterAttribute().getSubAttributeName(); + } + System.out.println((pos.incrementAndGet()) + ". Attribute name:" + name); + } + for (SCIMFilter subfilter : ofNullable(filter.getFilterComponents()).orElse(emptyList())) { + printFilterAttributes(subfilter, pos); + } + } + +} \ No newline at end of file diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/ScimSearchQueryConverterTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/ScimSearchQueryConverterTests.java index f4a7074bd57..22095768b7d 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/ScimSearchQueryConverterTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/scim/jdbc/ScimSearchQueryConverterTests.java @@ -58,8 +58,8 @@ public void canConvertValidFilters() throws Exception { validate(filterProcessor.convert("username pr and emails.value co \".com\"", null, false),"(username IS NOT NULL AND LOWER(email) LIKE LOWER(:__value_0))", 1); validate(filterProcessor.convert("username eq \"joe\" or emails.value co \".com\"", null, false),"(LOWER(username) = LOWER(:__value_0) OR LOWER(email) LIKE LOWER(:__value_1))", 2); validate(filterProcessor.convert("active eq true", null, false),"active = :__value_0", 1, Boolean.class); - validate(filterProcessor.convert("test eq 1000000.45", null, false),"test = :__value_0", 1, Double.class); - validate(filterProcessor.convert("test eq 1000000", null, false),"test = :__value_0", 1, Double.class); + validate(filterProcessor.convert("Version eq 1000000.45", null, false),"Version = :__value_0", 1, Double.class); + validate(filterProcessor.convert("meta.VerSion eq 1000000", null, false),"VerSion = :__value_0", 1, Double.class); } @Test @@ -84,8 +84,8 @@ public void caseInsensitiveDbDoesNotInjectLower() throws Exception { validate(filterProcessor.convert("username pr and emails.value co \".com\"", null, false),"(username IS NOT NULL AND email LIKE :__value_0)", 1); validate(filterProcessor.convert("username eq \"joe\" or emails.value co \".com\"", null, false),"(username = :__value_0 OR email LIKE :__value_1)", 2); validate(filterProcessor.convert("active eq true", null, false),"active = :__value_0", 1, Boolean.class); - validate(filterProcessor.convert("test eq 1000000.45", null, false),"test = :__value_0", 1, Double.class); - validate(filterProcessor.convert("test eq 1000000", null, false),"test = :__value_0", 1, Double.class); + validate(filterProcessor.convert("Version eq 1000000.45", null, false),"Version = :__value_0", 1, Double.class); + validate(filterProcessor.convert("meta.VerSion eq 1000000", null, false),"VerSion = :__value_0", 1, Double.class); } @Test From 74e0744c774d1b0c0a1cc873b3b112083e89ba63 Mon Sep 17 00:00:00 2001 From: Filip Hanik Date: Thu, 20 Apr 2017 18:57:45 -0700 Subject: [PATCH 3/3] Bump release version to 3.16.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7d6e81a7e19..b8a72f8b7ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=3.16.0-SNAPSHOT +version=3.16.0