You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/03/09 14:46:25 UTC
[1/2] syncope git commit: Ensuring secure XSLT processing everywhere
Repository: syncope
Updated Branches:
refs/heads/1_2_X 222a486e1 -> 44a5ca0fb
Ensuring secure XSLT processing everywhere
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/726231fb
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/726231fb
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/726231fb
Branch: refs/heads/1_2_X
Commit: 726231fbf7b817bd2a9467171dcb1c0087c75bc6
Parents: 222a486
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Mar 8 17:26:01 2018 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Mar 9 14:40:45 2018 +0100
----------------------------------------------------------------------
.../syncope/console/commons/XMLRolesReader.java | 8 +-
.../apache/syncope/core/report/ReportJob.java | 21 +-
.../core/rest/controller/ReportController.java | 14 +-
.../core/rest/controller/XSLTTransformer.java | 201 +++++++++++++++++++
.../syncope/core/util/ContentExporter.java | 3 +
.../syncope/core/util/VoidURIResolver.java | 35 ++++
6 files changed, 268 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/726231fb/console/src/main/java/org/apache/syncope/console/commons/XMLRolesReader.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/commons/XMLRolesReader.java b/console/src/main/java/org/apache/syncope/console/commons/XMLRolesReader.java
index 69cf4ec..fb4c0ec 100644
--- a/console/src/main/java/org/apache/syncope/console/commons/XMLRolesReader.java
+++ b/console/src/main/java/org/apache/syncope/console/commons/XMLRolesReader.java
@@ -20,11 +20,10 @@ package org.apache.syncope.console.commons;
import java.util.HashMap;
import java.util.Map;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
+import org.apache.cxf.staxutils.StaxUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
@@ -52,11 +51,8 @@ public class XMLRolesReader {
private void init() {
authMap = new HashMap<Pair<String, String>, String>();
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(true);
try {
- DocumentBuilder db = dbf.newDocumentBuilder();
- Document doc = db.parse(getClass().getResource("/" + authorizations).openStream());
+ Document doc = StaxUtils.read(getClass().getResource("/" + authorizations).openStream());
doc.getDocumentElement().normalize();
Node authNode = null;
http://git-wip-us.apache.org/repos/asf/syncope/blob/726231fb/core/src/main/java/org/apache/syncope/core/report/ReportJob.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/report/ReportJob.java b/core/src/main/java/org/apache/syncope/core/report/ReportJob.java
index 3caf414..5ed703f 100644
--- a/core/src/main/java/org/apache/syncope/core/report/ReportJob.java
+++ b/core/src/main/java/org/apache/syncope/core/report/ReportJob.java
@@ -24,8 +24,11 @@ import java.util.Date;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
+import javax.xml.XMLConstants;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
@@ -40,6 +43,7 @@ import org.apache.syncope.core.persistence.dao.ReportExecDAO;
import org.apache.syncope.core.rest.data.ReportDataBinder;
import org.apache.syncope.core.util.ApplicationContextProvider;
import org.apache.syncope.core.util.ExceptionUtil;
+import org.apache.syncope.core.util.VoidURIResolver;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
@@ -62,6 +66,18 @@ public class ReportJob implements Job {
*/
private static final Logger LOG = LoggerFactory.getLogger(ReportJob.class);
+ private static final SAXTransformerFactory TRANSFORMER_FACTORY;
+
+ static {
+ TRANSFORMER_FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
+ TRANSFORMER_FACTORY.setURIResolver(new VoidURIResolver());
+ try {
+ TRANSFORMER_FACTORY.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ } catch (TransformerConfigurationException e) {
+ LOG.error("Could not enable secure XML processing", e);
+ }
+ }
+
/**
* Report DAO.
*/
@@ -119,8 +135,7 @@ public class ReportJob implements Job {
ZipOutputStream zos = new ZipOutputStream(baos);
zos.setLevel(Deflater.BEST_COMPRESSION);
try {
- SAXTransformerFactory tFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
- handler = tFactory.newTransformerHandler();
+ handler = TRANSFORMER_FACTORY.newTransformerHandler();
Transformer serializer = handler.getTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, SyncopeConstants.DEFAULT_ENCODING);
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
@@ -153,7 +168,7 @@ public class ReportJob implements Job {
if (reportletClass != null) {
Reportlet<ReportletConf> autowired =
(Reportlet<ReportletConf>) ApplicationContextProvider.getBeanFactory().
- createBean(reportletClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ createBean(reportletClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
autowired.setConf(reportletConf);
// invoke reportlet
http://git-wip-us.apache.org/repos/asf/syncope/blob/726231fb/core/src/main/java/org/apache/syncope/core/rest/controller/ReportController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/rest/controller/ReportController.java b/core/src/main/java/org/apache/syncope/core/rest/controller/ReportController.java
index baeb06f..e84e97a 100644
--- a/core/src/main/java/org/apache/syncope/core/rest/controller/ReportController.java
+++ b/core/src/main/java/org/apache/syncope/core/rest/controller/ReportController.java
@@ -29,13 +29,13 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipInputStream;
+import javax.xml.transform.stream.StreamSource;
import org.apache.cocoon.optional.pipeline.components.sax.fop.FopSerializer;
import org.apache.cocoon.pipeline.NonCachingPipeline;
import org.apache.cocoon.pipeline.Pipeline;
import org.apache.cocoon.sax.SAXPipelineComponent;
import org.apache.cocoon.sax.component.XMLGenerator;
import org.apache.cocoon.sax.component.XMLSerializer;
-import org.apache.cocoon.sax.component.XSLTTransformer;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.syncope.common.report.ReportletConf;
@@ -195,28 +195,32 @@ public class ReportController extends AbstractJobController<ReportTO> {
switch (format) {
case HTML:
- XSLTTransformer xsl2html = new XSLTTransformer(getClass().getResource("/report/report2html.xsl"));
+ XSLTTransformer xsl2html = new XSLTTransformer(
+ new StreamSource(getClass().getResourceAsStream("/report/report2html.xsl")));
xsl2html.setParameters(parameters);
pipeline.addComponent(xsl2html);
pipeline.addComponent(XMLSerializer.createXHTMLSerializer());
break;
case PDF:
- XSLTTransformer xsl2pdf = new XSLTTransformer(getClass().getResource("/report/report2fo.xsl"));
+ XSLTTransformer xsl2pdf = new XSLTTransformer(
+ new StreamSource(getClass().getResourceAsStream("/report/report2fo.xsl")));
xsl2pdf.setParameters(parameters);
pipeline.addComponent(xsl2pdf);
pipeline.addComponent(new FopSerializer(MimeConstants.MIME_PDF));
break;
case RTF:
- XSLTTransformer xsl2rtf = new XSLTTransformer(getClass().getResource("/report/report2fo.xsl"));
+ XSLTTransformer xsl2rtf = new XSLTTransformer(
+ new StreamSource(getClass().getResourceAsStream("/report/report2fo.xsl")));
xsl2rtf.setParameters(parameters);
pipeline.addComponent(xsl2rtf);
pipeline.addComponent(new FopSerializer(MimeConstants.MIME_RTF));
break;
case CSV:
- XSLTTransformer xsl2csv = new XSLTTransformer(getClass().getResource("/report/report2csv.xsl"));
+ XSLTTransformer xsl2csv = new XSLTTransformer(
+ new StreamSource(getClass().getResourceAsStream("/report/report2csv.xsl")));
xsl2csv.setParameters(parameters);
pipeline.addComponent(xsl2csv);
pipeline.addComponent(new TextSerializer());
http://git-wip-us.apache.org/repos/asf/syncope/blob/726231fb/core/src/main/java/org/apache/syncope/core/rest/controller/XSLTTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/rest/controller/XSLTTransformer.java b/core/src/main/java/org/apache/syncope/core/rest/controller/XSLTTransformer.java
new file mode 100644
index 0000000..d4ad75d
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/rest/controller/XSLTTransformer.java
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.syncope.core.rest.controller;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+import javax.xml.XMLConstants;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import org.apache.cocoon.pipeline.SetupException;
+import org.apache.cocoon.pipeline.caching.CacheKey;
+import org.apache.cocoon.pipeline.component.CachingPipelineComponent;
+import org.apache.cocoon.pipeline.util.StringRepresentation;
+import org.apache.cocoon.sax.AbstractSAXTransformer;
+import org.apache.cocoon.sax.SAXConsumer;
+import org.apache.cocoon.sax.util.SAXConsumerAdapter;
+import org.apache.syncope.core.util.VoidURIResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class XSLTTransformer extends AbstractSAXTransformer implements CachingPipelineComponent {
+
+ private static final Logger LOG = LoggerFactory.getLogger(XSLTTransformer.class);
+
+ /**
+ * A generic transformer factory to parse XSLTs.
+ */
+ private static final SAXTransformerFactory TRAX_FACTORY = createNewSAXTransformerFactory();
+
+ /**
+ * The XSLT parameters name pattern.
+ */
+ private static final Pattern XSLT_PARAMETER_NAME_PATTERN = Pattern.compile("[a-zA-Z_][\\w\\-\\.]*");
+
+ /**
+ * The XSLT parameters reference.
+ */
+ private Map<String, Object> parameters;
+
+ /**
+ * The XSLT Template reference.
+ */
+ private Templates templates;
+
+ private Source source;
+
+ public XSLTTransformer(final Source source) {
+ super();
+ this.load(source, null);
+ }
+
+ /**
+ * Creates a new transformer reading the XSLT from the Source source and setting the TransformerFactory attributes.
+ *
+ * This constructor is useful when users want to perform XSLT transformation using <a
+ * href="http://xml.apache.org/xalan-j/xsltc_usage.html">xsltc</a>.
+ *
+ * @param source the XSLT source
+ * @param attributes the Transformer Factory attributes
+ */
+ public XSLTTransformer(final Source source, final Map<String, Object> attributes) {
+ super();
+ this.load(source, attributes);
+ }
+
+ /**
+ * Method useful to create a new transformer reading the XSLT from the URL source and setting the Transformer
+ * Factory attributes.
+ *
+ * This method is useful when users want to perform XSLT transformation using <a
+ * href="http://xml.apache.org/xalan-j/xsltc_usage.html">xsltc</a>.
+ *
+ * @param source the XSLT source
+ * @param attributes the Transformer Factory attributes
+ */
+ private void load(final Source source, final Map<String, Object> attributes) {
+ if (source == null) {
+ throw new IllegalArgumentException("The parameter 'source' mustn't be null.");
+ }
+
+ this.source = source;
+
+ this.load(this.source, this.source.toString(), attributes);
+ }
+
+ private void load(final Source source, final String localCacheKey, final Map<String, Object> attributes) {
+ LOG.debug("{} local cache miss: {}", getClass().getSimpleName(), localCacheKey);
+
+ // XSLT has to be parsed
+ final SAXTransformerFactory transformerFactory;
+ if (attributes == null || attributes.isEmpty()) {
+ transformerFactory = TRAX_FACTORY;
+ } else {
+ transformerFactory = createNewSAXTransformerFactory();
+ for (Map.Entry<String, Object> attribute : attributes.entrySet()) {
+ transformerFactory.setAttribute(attribute.getKey(), attribute.getValue());
+ }
+ }
+
+ try {
+ this.templates = transformerFactory.newTemplates(source);
+ } catch (TransformerConfigurationException e) {
+ throw new SetupException("Impossible to read XSLT from '" + source + "', see nested exception", e);
+ }
+ }
+
+ /**
+ * Sets the XSLT parameters to be applied to XSLT stylesheet.
+ *
+ * @param parameters the XSLT parameters to be applied to XSLT stylesheet
+ */
+ public void setParameters(final Map<String, ? extends Object> parameters) {
+ if (parameters == null) {
+ this.parameters = null;
+ } else {
+ this.parameters = new HashMap<String, Object>(parameters);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setSAXConsumer(final SAXConsumer consumer) {
+ TransformerHandler transformerHandler;
+ try {
+ transformerHandler = TRAX_FACTORY.newTransformerHandler(this.templates);
+ } catch (Exception e) {
+ throw new SetupException("Could not initialize transformer handler.", e);
+ }
+
+ if (this.parameters != null) {
+ final Transformer transformer = transformerHandler.getTransformer();
+
+ for (Map.Entry<String, Object> entry : this.parameters.entrySet()) {
+ final String name = entry.getKey();
+
+ // is valid XSLT parameter name
+ if (XSLT_PARAMETER_NAME_PATTERN.matcher(name).matches()) {
+ transformer.setParameter(name, entry.getValue());
+ }
+ }
+ }
+
+ final SAXResult result = new SAXResult();
+ result.setHandler(consumer);
+ // According to TrAX specs, all TransformerHandlers are LexicalHandlers
+ result.setLexicalHandler(consumer);
+ transformerHandler.setResult(result);
+
+ final SAXConsumerAdapter saxConsumerAdapter = new SAXConsumerAdapter();
+ saxConsumerAdapter.setContentHandler(transformerHandler);
+ super.setSAXConsumer(saxConsumerAdapter);
+ }
+
+ @Override
+ public CacheKey constructCacheKey() {
+ return null;
+ }
+
+ /**
+ * Utility method to create a new transformer factory.
+ *
+ * @return a new transformer factory
+ */
+ private static SAXTransformerFactory createNewSAXTransformerFactory() {
+ SAXTransformerFactory transformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+ transformerFactory.setURIResolver(new VoidURIResolver());
+ try {
+ transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ } catch (TransformerConfigurationException e) {
+ LOG.error("Could not enable secure XML processing", e);
+ }
+ return transformerFactory;
+ }
+
+ @Override
+ public String toString() {
+ return StringRepresentation.buildString(this, "src=<" + this.source + ">");
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/726231fb/core/src/main/java/org/apache/syncope/core/util/ContentExporter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/util/ContentExporter.java b/core/src/main/java/org/apache/syncope/core/util/ContentExporter.java
index 0af230b..5ca706f 100644
--- a/core/src/main/java/org/apache/syncope/core/util/ContentExporter.java
+++ b/core/src/main/java/org/apache/syncope/core/util/ContentExporter.java
@@ -40,6 +40,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import javax.xml.XMLConstants;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
@@ -346,6 +347,8 @@ public class ContentExporter extends AbstractContentDealer {
StreamResult streamResult = new StreamResult(os);
final SAXTransformerFactory transformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+ transformerFactory.setURIResolver(new VoidURIResolver());
+ transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
TransformerHandler handler = transformerFactory.newTransformerHandler();
Transformer serializer = handler.getTransformer();
http://git-wip-us.apache.org/repos/asf/syncope/blob/726231fb/core/src/main/java/org/apache/syncope/core/util/VoidURIResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/util/VoidURIResolver.java b/core/src/main/java/org/apache/syncope/core/util/VoidURIResolver.java
new file mode 100644
index 0000000..0d38fbd
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/util/VoidURIResolver.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.util;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+
+/**
+ * This implementation disallows any XSLT include, for security reasons.
+ */
+public class VoidURIResolver implements URIResolver {
+
+ @Override
+ public Source resolve(final String href, final String base) throws TransformerException {
+ return null;
+ }
+
+}
[2/2] syncope git commit: Review fields usable for search and orderBy
Posted by il...@apache.org.
Review fields usable for search and orderBy
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/44a5ca0f
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/44a5ca0f
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/44a5ca0f
Branch: refs/heads/1_2_X
Commit: 44a5ca0fbd357b8b5d81aa9313fb01cca30d8ad3
Parents: 726231f
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Mar 8 17:25:37 2018 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Mar 9 14:49:52 2018 +0100
----------------------------------------------------------------------
.../syncope/common/search/SearchableFields.java | 2 +-
.../dao/impl/SubjectSearchDAOImpl.java | 20 ++++++++++++++++++--
.../syncope/core/rest/SearchTestITCase.java | 17 +++++++++++++++++
3 files changed, 36 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/44a5ca0f/common/src/main/java/org/apache/syncope/common/search/SearchableFields.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/syncope/common/search/SearchableFields.java b/common/src/main/java/org/apache/syncope/common/search/SearchableFields.java
index ce06934..b61dfc8 100644
--- a/common/src/main/java/org/apache/syncope/common/search/SearchableFields.java
+++ b/common/src/main/java/org/apache/syncope/common/search/SearchableFields.java
@@ -33,7 +33,7 @@ public class SearchableFields {
protected static final String[] ATTRIBUTES_NOTINCLUDED = {
"attrs", "derAttrs", "virAttrs",
"serialVersionUID", "memberships", "entitlements", "resources", "password",
- "propagationTOs", "propagationStatusMap"
+ "propagationTOs", "propagationStatusMap", "securityAnswer", "token", "tokenExpireTime"
};
public static final List<String> get(final SubjectType subjectType) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/44a5ca0f/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SubjectSearchDAOImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SubjectSearchDAOImpl.java b/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SubjectSearchDAOImpl.java
index d901bdf..7b03b83 100644
--- a/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SubjectSearchDAOImpl.java
+++ b/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SubjectSearchDAOImpl.java
@@ -63,6 +63,10 @@ public class SubjectSearchDAOImpl extends AbstractDAOImpl implements SubjectSear
private static final String[] SUBJECT_FIELDS = new String[] { "parent", "userOwner", "roleOwner" };
+ private static final String[] ORDER_BY_NOT_ALLOWED = {
+ "serialVersionUID", "password", "securityQuestion", "securityAnswer", "token", "tokenExpireTime"
+ };
+
@Autowired
private UserDAO userDAO;
@@ -285,12 +289,24 @@ public class SubjectSearchDAOImpl extends AbstractDAOImpl implements SubjectSear
return orderBy;
}
- private OrderBySupport parseOrderBy(final SearchSupport svs, final List<OrderByClause> orderByClauses) {
+ protected List<OrderByClause> filterOrderBy(final List<OrderByClause> orderBy) {
+ List<OrderByClause> result = new ArrayList<OrderByClause>();
+
+ for (OrderByClause clause : orderBy) {
+ if (!ArrayUtils.contains(ORDER_BY_NOT_ALLOWED, clause.getField())) {
+ result.add(clause);
+ }
+ }
+
+ return result;
+ }
+
+ private OrderBySupport parseOrderBy(final SearchSupport svs, final List<OrderByClause> orderBy) {
final AttributableUtil attrUtil = AttributableUtil.getInstance(svs.type.asAttributableType());
OrderBySupport obs = new OrderBySupport();
- for (OrderByClause clause : orderByClauses) {
+ for (OrderByClause clause : filterOrderBy(orderBy)) {
OrderBySupport.Item item = new OrderBySupport.Item();
Field subjectField = ReflectionUtils.findField(attrUtil.attributableClass(), clause.getField());
http://git-wip-us.apache.org/repos/asf/syncope/blob/44a5ca0f/core/src/test/java/org/apache/syncope/core/rest/SearchTestITCase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/syncope/core/rest/SearchTestITCase.java b/core/src/test/java/org/apache/syncope/core/rest/SearchTestITCase.java
index e1626b4..974edd8 100644
--- a/core/src/test/java/org/apache/syncope/core/rest/SearchTestITCase.java
+++ b/core/src/test/java/org/apache/syncope/core/rest/SearchTestITCase.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import org.apache.commons.lang3.RandomStringUtils;
import org.apache.syncope.client.SyncopeClient;
import org.apache.syncope.common.reqres.PagedResult;
import org.apache.syncope.common.services.UserSelfService;
@@ -200,6 +201,22 @@ public class SearchTestITCase extends AbstractTest {
}
@Test
+ public void searchBySecurityAnswer() {
+ String securityAnswer = RandomStringUtils.randomAlphanumeric(10);
+ UserTO userTO = UserTestITCase.getUniqueSampleTO("securityAnswer@syncope.apache.org");
+ userTO.setSecurityQuestion(1L);
+ userTO.setSecurityAnswer(securityAnswer);
+
+ userTO = createUser(userTO);
+ assertNotNull(userTO.getSecurityQuestion());
+
+ PagedResult<UserTO> matchingUsers = userService.search(SyncopeClient.getUserSearchConditionBuilder().
+ is("securityAnswer").equalTo(securityAnswer).query());
+ assertNotNull(matchingUsers);
+ assertTrue(matchingUsers.getResult().isEmpty());
+ }
+
+ @Test
public void orderBy() {
PagedResult<UserTO> users = userService.search(
SyncopeClient.getUserSearchConditionBuilder().is("userId").equalTo("*@apache.org").query(),