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(),