You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by an...@apache.org on 2017/04/12 10:15:57 UTC
syncope git commit: [SYNCOPE-1064] improved security to avoid JS
hacking and exploitation,
added relative tests and moved form customization server side
Repository: syncope
Updated Branches:
refs/heads/master 7a08dc65a -> f1329b799
[SYNCOPE-1064] improved security to avoid JS hacking and exploitation, added relative tests and moved form customization server side
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/f1329b79
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/f1329b79
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/f1329b79
Branch: refs/heads/master
Commit: f1329b79966d1986bbbfe031e46d61469468abd1
Parents: 7a08dc6
Author: Andrea Patricelli <an...@apache.org>
Authored: Wed Apr 12 11:21:56 2017 +0200
Committer: Andrea Patricelli <an...@apache.org>
Committed: Wed Apr 12 12:14:20 2017 +0200
----------------------------------------------------------------------
archetype/pom.xml | 2 +
.../archetype-resources/enduser/pom.xml | 4 +
client/enduser/pom.xml | 8 +
.../enduser/SyncopeEnduserApplication.java | 101 ++++++++++
.../client/enduser/SyncopeEnduserConstants.java | 2 +
.../client/enduser/SyncopeEnduserSession.java | 15 ++
.../enduser/adapters/PlatformInfoAdapter.java | 6 +-
.../client/enduser/model/CustomAttribute.java | 62 ++++++
.../enduser/model/CustomAttributesInfo.java | 8 +-
.../enduser/model/PlatformInfoRequest.java | 11 +
.../enduser/resources/BaseUserSelfResource.java | 14 ++
.../client/enduser/resources/InfoResource.java | 12 +-
.../enduser/resources/SchemaResource.java | 14 +-
.../resources/UserSelfCreateResource.java | 200 ++++++++++---------
.../enduser/resources/UserSelfReadResource.java | 40 +++-
.../resources/UserSelfUpdateResource.java | 188 +++++++++--------
.../enduser/util/UserRequestValidator.java | 86 ++++++++
.../resources/app/configuration/customForm.json | 1 -
.../resources/META-INF/resources/app/js/app.js | 15 +-
.../app/js/controllers/UserController.js | 2 +-
.../app/js/services/configurationService.js | 41 ----
.../resources/app/js/services/schemaService.js | 12 +-
.../enduser/src/main/resources/customForm.json | 1 +
.../enduser/util/UserRequestValidatorTest.java | 85 ++++++++
.../enduser/src/test/resources/customForm.json | 47 +++++
deb/enduser/pom.xml | 1 +
deb/enduser/src/deb/control/conffiles | 1 +
.../src/main/resources/customForm.json | 1 +
.../src/test/resources/customForm.json | 1 +
29 files changed, 711 insertions(+), 270 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/archetype/pom.xml
----------------------------------------------------------------------
diff --git a/archetype/pom.xml b/archetype/pom.xml
index f996dcc..1db4417 100644
--- a/archetype/pom.xml
+++ b/archetype/pom.xml
@@ -257,6 +257,7 @@ under the License.
<targetPath>${project.build.outputDirectory}/archetype-resources/enduser/src/main/resources</targetPath>
<includes>
<include>enduser.properties</include>
+ <include>customForm.json</include>
</includes>
</resource>
<resource>
@@ -283,6 +284,7 @@ under the License.
<includes>
<include>enduser.properties</include>
<include>saml2sp-agent.properties</include>
+ <include>customForm.json</include>
</includes>
</resource>
<resource>
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/archetype/src/main/resources/archetype-resources/enduser/pom.xml
----------------------------------------------------------------------
diff --git a/archetype/src/main/resources/archetype-resources/enduser/pom.xml b/archetype/src/main/resources/archetype-resources/enduser/pom.xml
index 36bbf0a..06f77d4 100644
--- a/archetype/src/main/resources/archetype-resources/enduser/pom.xml
+++ b/archetype/src/main/resources/archetype-resources/enduser/pom.xml
@@ -246,6 +246,10 @@ under the License.
<copy file="${project.build.directory}/test-classes/enduser.properties"
todir="${project.build.directory}/${project.build.finalName}/WEB-INF/classes"
overwrite="true"/>
+
+ <copy file="${project.build.directory}/test-classes/customForm"
+ todir="${project.build.directory}/${project.build.finalName}/WEB-INF/classes"
+ overwrite="true"/>
</target>
</configuration>
<goals>
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/pom.xml
----------------------------------------------------------------------
diff --git a/client/enduser/pom.xml b/client/enduser/pom.xml
index 99d4c0b..52fe436 100644
--- a/client/enduser/pom.xml
+++ b/client/enduser/pom.xml
@@ -182,6 +182,14 @@ under the License.
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
+
+ <!-- TEST -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
index cfed2c5..fc0d730 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
@@ -18,16 +18,28 @@
*/
package org.apache.syncope.client.enduser;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.syncope.client.enduser.pages.HomePage;
import java.util.Properties;
import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.monitor.FileAlterationListener;
+import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
+import org.apache.commons.io.monitor.FileAlterationMonitor;
+import org.apache.commons.io.monitor.FileAlterationObserver;
import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.enduser.annotations.Resource;
import org.apache.syncope.client.enduser.init.ClassPathScanImplementationLookup;
import org.apache.syncope.client.enduser.init.EnduserInitializer;
+import org.apache.syncope.client.enduser.model.CustomAttributesInfo;
import org.apache.syncope.client.enduser.resources.CaptchaResource;
import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
import org.apache.syncope.common.lib.SyncopeConstants;
@@ -52,6 +64,8 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali
private static final String ENDUSER_PROPERTIES = "enduser.properties";
+ private static final String CUSTOM_FORM_FILE = "customForm.json";
+
public static SyncopeEnduserApplication get() {
return (SyncopeEnduserApplication) WebApplication.get();
}
@@ -76,6 +90,10 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali
private SyncopeClientFactoryBean clientFactory;
+ private Map<String, CustomAttributesInfo> customForm;
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
@Override
protected void init() {
super.init();
@@ -131,6 +149,80 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali
setContentType(SyncopeClientFactoryBean.ContentType.JSON).
setUseCompression(BooleanUtils.toBoolean(useGZIPCompression));
+ // read customForm.json
+ try (InputStream is = getClass().getResourceAsStream("/" + CUSTOM_FORM_FILE)) {
+ customForm = MAPPER.readValue(is,
+ new TypeReference<HashMap<String, CustomAttributesInfo>>() {
+ });
+ File enduserDir = new File(props.getProperty("enduser.directory"));
+ boolean existsEnduserDir = enduserDir.exists() && enduserDir.canRead() && enduserDir.isDirectory();
+ if (existsEnduserDir) {
+ File customFormFile = FileUtils.getFile(enduserDir, CUSTOM_FORM_FILE);
+ if (customFormFile.exists() && customFormFile.canRead() && customFormFile.isFile()) {
+ customForm = MAPPER.readValue(FileUtils.openInputStream(customFormFile),
+ new TypeReference<HashMap<String, CustomAttributesInfo>>() {
+ });
+ }
+ }
+ FileAlterationObserver observer = existsEnduserDir
+ ? new FileAlterationObserver(enduserDir, new FileFilter() {
+
+ @Override
+ public boolean accept(final File pathname) {
+ return StringUtils.contains(pathname.getPath(), CUSTOM_FORM_FILE);
+ }
+ })
+ : new FileAlterationObserver(getClass().getResource("/" + CUSTOM_FORM_FILE).getFile(),
+ new FileFilter() {
+
+ @Override
+ public boolean accept(final File pathname) {
+ return StringUtils.contains(pathname.getPath(), CUSTOM_FORM_FILE);
+ }
+ });
+
+ FileAlterationMonitor monitor = new FileAlterationMonitor(5000);
+
+ FileAlterationListener listener = new FileAlterationListenerAdaptor() {
+
+ @Override
+ public void onFileChange(final File file) {
+ try {
+ LOG.trace("{} has changed. Reloading form customization configuration.", CUSTOM_FORM_FILE);
+ customForm = MAPPER.readValue(FileUtils.openInputStream(file),
+ new TypeReference<HashMap<String, CustomAttributesInfo>>() {
+ });
+ } catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+
+ @Override
+ public void onFileCreate(final File file) {
+ try {
+ LOG.trace("{} has been created. Loading form customization configuration.", CUSTOM_FORM_FILE);
+ customForm = MAPPER.readValue(FileUtils.openInputStream(file),
+ new TypeReference<HashMap<String, CustomAttributesInfo>>() {
+ });
+ } catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+
+ @Override
+ public void onFileDelete(final File file) {
+ LOG.trace("{} has been deleted. Resetting form customization configuration.", CUSTOM_FORM_FILE);
+ customForm = null;
+ }
+ };
+
+ observer.addListener(listener);
+ monitor.addObserver(observer);
+ monitor.start();
+ } catch (Exception e) {
+ throw new WicketRuntimeException("Could not read " + CUSTOM_FORM_FILE, e);
+ }
+
// mount resources
ClassPathScanImplementationLookup classPathScanImplementationLookup =
(ClassPathScanImplementationLookup) getServletContext().
@@ -221,4 +313,13 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali
return xsrfEnabled;
}
+ public Map<String, CustomAttributesInfo> getCustomForm() {
+ return customForm;
+ }
+
+ public void setCustomForm(final Map<String, CustomAttributesInfo> customForm) {
+ this.customForm.clear();
+ this.customForm.putAll(customForm);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java
index 4600166..0a683a9 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java
@@ -26,6 +26,8 @@ public final class SyncopeEnduserConstants {
public static final String XSRF_HEADER_NAME = "X-XSRF-TOKEN";
+ public static final String MEMBERSHIP_ATTR_SEPARATOR = "#";
+
private SyncopeEnduserConstants() {
// private constructor for utility class
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
index 168656c..8268ef5 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
@@ -19,6 +19,7 @@
package org.apache.syncope.client.enduser;
import java.security.AccessControlException;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -28,6 +29,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.client.enduser.model.CustomAttributesInfo;
import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.common.lib.info.PlatformInfo;
@@ -66,6 +68,8 @@ public class SyncopeEnduserSession extends WebSession {
private final CookieUtils cookieUtils;
+ private final Map<String, CustomAttributesInfo> customForm;
+
private boolean xsrfTokenGenerated = false;
public static SyncopeEnduserSession get() {
@@ -92,6 +96,7 @@ public class SyncopeEnduserSession extends WebSession {
return object.getType() == AttrSchemaType.Date;
}
});
+ customForm = new HashMap<>();
}
private void afterAuthentication() {
@@ -197,4 +202,14 @@ public class SyncopeEnduserSession extends WebSession {
public void setXsrfTokenGenerated(final boolean xsrfTokenGenerated) {
this.xsrfTokenGenerated = xsrfTokenGenerated;
}
+
+ public Map<String, CustomAttributesInfo> getCustomForm() {
+ return customForm;
+ }
+
+ public void setCustomForm(final Map<String, CustomAttributesInfo> customForm) {
+ this.customForm.clear();
+ this.customForm.putAll(customForm);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java
index 5ed11be..a961576 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java
@@ -18,19 +18,23 @@
*/
package org.apache.syncope.client.enduser.adapters;
+import java.util.Map;
import org.apache.syncope.client.enduser.SyncopeEnduserApplication;
+import org.apache.syncope.client.enduser.model.CustomAttributesInfo;
import org.apache.syncope.client.enduser.model.PlatformInfoRequest;
import org.apache.syncope.common.lib.info.PlatformInfo;
public final class PlatformInfoAdapter {
- public static PlatformInfoRequest toPlatformInfoRequest(final PlatformInfo platformInfo) {
+ public static PlatformInfoRequest toPlatformInfoRequest(final PlatformInfo platformInfo,
+ final Map<String, CustomAttributesInfo> customForm) {
PlatformInfoRequest request = new PlatformInfoRequest();
request.setPwdResetAllowed(platformInfo.isPwdResetAllowed());
request.setSelfRegAllowed(platformInfo.isSelfRegAllowed());
request.setPwdResetRequiringSecurityQuestions(platformInfo.isPwdResetRequiringSecurityQuestions());
request.setVersion(platformInfo.getVersion());
request.setCaptchaEnabled(SyncopeEnduserApplication.get().isCaptchaEnabled());
+ request.setCustomForm(customForm);
return request;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttribute.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttribute.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttribute.java
new file mode 100644
index 0000000..80d65f6
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttribute.java
@@ -0,0 +1,62 @@
+/*
+ * 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.client.enduser.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CustomAttribute implements Serializable {
+
+ private static final long serialVersionUID = 4910266842123376686L;
+
+ private Boolean readonly;
+
+ private List<String> defaultValues = new ArrayList<>();
+
+ public CustomAttribute() {
+ }
+
+ public Boolean getReadonly() {
+ return readonly;
+ }
+
+ public void setReadonly(final Boolean readonly) {
+ this.readonly = readonly;
+ }
+
+ public List<String> getDefaultValues() {
+ return defaultValues;
+ }
+
+ public void setDefaultValues(final List<String> defaultValues) {
+ this.defaultValues = defaultValues;
+ }
+
+ public CustomAttribute readonly(final Boolean value) {
+ this.readonly = value;
+ return this;
+ }
+
+ public CustomAttribute defaultValues(final List<String> value) {
+ this.defaultValues = value;
+ return this;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java
index 61d08f1..a62a6bb 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java
@@ -28,7 +28,7 @@ public class CustomAttributesInfo implements Serializable {
private Boolean show = Boolean.TRUE;
- private Map<String, ?> attributes = new LinkedHashMap<>();
+ private Map<String, CustomAttribute> attributes = new LinkedHashMap<>();
public CustomAttributesInfo() {
}
@@ -41,11 +41,11 @@ public class CustomAttributesInfo implements Serializable {
this.show = show;
}
- public Map<String, ?> getAttributes() {
+ public Map<String, CustomAttribute> getAttributes() {
return attributes;
}
- public void setAttributes(final Map<String, ?> attributes) {
+ public void setAttributes(final Map<String, CustomAttribute> attributes) {
this.attributes = attributes;
}
@@ -54,7 +54,7 @@ public class CustomAttributesInfo implements Serializable {
return this;
}
- public CustomAttributesInfo attributes(final Map<String, ?> value) {
+ public CustomAttributesInfo attributes(final Map<String, CustomAttribute> value) {
this.attributes = value;
return this;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java
index b95706c..a75ae53 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java
@@ -19,6 +19,7 @@
package org.apache.syncope.client.enduser.model;
import java.io.Serializable;
+import java.util.Map;
public class PlatformInfoRequest implements Serializable {
@@ -34,6 +35,8 @@ public class PlatformInfoRequest implements Serializable {
private boolean captchaEnabled;
+ private Map<String, CustomAttributesInfo> customForm;
+
public PlatformInfoRequest() {
}
@@ -77,4 +80,12 @@ public class PlatformInfoRequest implements Serializable {
this.captchaEnabled = captchaEnabled;
}
+ public Map<String, CustomAttributesInfo> getCustomForm() {
+ return customForm;
+ }
+
+ public void setCustomForm(final Map<String, CustomAttributesInfo> customForm) {
+ this.customForm = customForm;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/BaseUserSelfResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/BaseUserSelfResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/BaseUserSelfResource.java
index 6071642..a3e73e8 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/BaseUserSelfResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/BaseUserSelfResource.java
@@ -18,6 +18,8 @@
*/
package org.apache.syncope.client.enduser.resources;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
@@ -63,5 +65,17 @@ public abstract class BaseUserSelfResource extends BaseResource {
dateAttr.getValues().addAll(formattedValues);
}
}
+
+ protected void buildResponse(final ResourceResponse response, final int statusCode, final String message) {
+ response.setTextEncoding(StandardCharsets.UTF_8.name());
+ response.setStatusCode(statusCode);
+ response.setWriteCallback(new WriteCallback() {
+
+ @Override
+ public void writeData(final Attributes attributes) throws IOException {
+ attributes.getResponse().write(message);
+ }
+ });
+ }
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java
index bd4d30f..c96fa2a 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java
@@ -18,15 +18,21 @@
*/
package org.apache.syncope.client.enduser.resources;
+import static org.apache.syncope.client.enduser.resources.BaseResource.MAPPER;
+
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.enduser.SyncopeEnduserApplication;
import org.apache.syncope.client.enduser.SyncopeEnduserConstants;
import org.apache.syncope.client.enduser.SyncopeEnduserSession;
import org.apache.syncope.client.enduser.adapters.PlatformInfoAdapter;
import org.apache.syncope.client.enduser.annotations.Resource;
+import org.apache.syncope.client.enduser.model.CustomAttributesInfo;
import org.apache.syncope.client.enduser.util.SaltGenerator;
import org.apache.wicket.request.resource.IResource;
import org.apache.wicket.util.cookies.CookieUtils;
@@ -57,10 +63,14 @@ public class InfoResource extends BaseResource {
@Override
public void writeData(final IResource.Attributes attributes) throws IOException {
+ Map<String, CustomAttributesInfo> customForm = SyncopeEnduserApplication.get().getCustomForm();
attributes.getResponse().write(
MAPPER.writeValueAsString(
PlatformInfoAdapter.toPlatformInfoRequest(
- SyncopeEnduserSession.get().getPlatformInfo())));
+ SyncopeEnduserSession.get().getPlatformInfo(),
+ customForm == null
+ ? new HashMap<String, CustomAttributesInfo>()
+ : customForm)));
}
});
response.setStatusCode(Response.Status.OK.getStatusCode());
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java
index 169d1b4..5edd4b0 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java
@@ -20,13 +20,11 @@ package org.apache.syncope.client.enduser.resources;
import static org.apache.syncope.client.enduser.resources.BaseResource.MAPPER;
-import com.fasterxml.jackson.core.type.TypeReference;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
@@ -36,8 +34,11 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.enduser.SyncopeEnduserApplication;
+import org.apache.syncope.client.enduser.SyncopeEnduserConstants;
import org.apache.syncope.client.enduser.SyncopeEnduserSession;
import org.apache.syncope.client.enduser.annotations.Resource;
+import org.apache.syncope.client.enduser.model.CustomAttribute;
import org.apache.syncope.client.enduser.model.CustomAttributesInfo;
import org.apache.syncope.client.enduser.model.SchemaResponse;
import org.apache.syncope.common.lib.to.AbstractSchemaTO;
@@ -103,9 +104,8 @@ public class SchemaResource extends BaseResource {
}
}
- Map<String, CustomAttributesInfo> customForm = MAPPER.readValue(request.getReader().readLine(),
- new TypeReference<HashMap<String, CustomAttributesInfo>>() {
- });
+ // USER from customization, if empty or null ignore it, use it to filter attributes otherwise
+ Map<String, CustomAttributesInfo> customForm = SyncopeEnduserApplication.get().getCustomForm();
SchemaService schemaService = SyncopeEnduserSession.get().getService(SchemaService.class);
final List<AbstractSchemaTO> plainSchemas = classes.isEmpty()
@@ -176,7 +176,7 @@ public class SchemaResource extends BaseResource {
}
private List<AbstractSchemaTO> customizeSchemas(final List<AbstractSchemaTO> schemaTOs, final String groupParam,
- final Map<String, ?> customForm) {
+ final Map<String, CustomAttribute> customForm) {
if (customForm.isEmpty()) {
return schemaTOs;
@@ -211,7 +211,7 @@ public class SchemaResource extends BaseResource {
}
private String compositeSchemaKey(final String prefix, final String schemaKey) {
- return prefix + "#" + schemaKey;
+ return prefix + SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR + schemaKey;
}
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
index fbb2e33..b7775b1 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
@@ -20,8 +20,6 @@ package org.apache.syncope.client.enduser.resources;
import static org.apache.syncope.client.enduser.resources.BaseResource.LOG;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -34,6 +32,7 @@ import org.apache.commons.lang3.SerializationUtils;
import org.apache.syncope.client.enduser.SyncopeEnduserConstants;
import org.apache.syncope.client.enduser.SyncopeEnduserSession;
import org.apache.syncope.client.enduser.annotations.Resource;
+import org.apache.syncope.client.enduser.util.UserRequestValidator;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.to.AttrTO;
import org.apache.syncope.common.lib.to.MembershipTO;
@@ -83,113 +82,118 @@ public class UserSelfCreateResource extends BaseUserSelfResource {
}
if (isSelfRegistrationAllowed() && userTO != null) {
-
- // 1. membership attributes management
- Set<AttrTO> membAttrs = new HashSet<>();
- for (AttrTO attr : userTO.getPlainAttrs()) {
- if (attr.getSchema().contains("#")) {
- final String[] simpleAttrs = attr.getSchema().split("#");
- MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
- new Predicate<MembershipTO>() {
-
- @Override
- public boolean evaluate(final MembershipTO item) {
- return simpleAttrs[0].equals(item.getGroupName());
+ LOG.debug("User self registration request for [{}]", userTO.getUsername());
+ LOG.trace("Request is [{}]", userTO);
+
+ // check if request is compliant with customization form rules
+ if (UserRequestValidator.compliant(userTO, SyncopeEnduserSession.get().getCustomForm(), true)) {
+
+ // 1. membership attributes management
+ Set<AttrTO> membAttrs = new HashSet<>();
+ for (AttrTO attr : userTO.getPlainAttrs()) {
+ if (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR)) {
+ final String[] simpleAttrs = attr.getSchema().split(
+ SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
+ MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
+ new Predicate<MembershipTO>() {
+
+ @Override
+ public boolean evaluate(final MembershipTO item) {
+ return simpleAttrs[0].equals(item.getGroupName());
+ }
+ });
+ if (membership == null) {
+ membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+ userTO.getMemberships().add(membership);
}
- });
- if (membership == null) {
- membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
- userTO.getMemberships().add(membership);
- }
- AttrTO clone = SerializationUtils.clone(attr);
- clone.setSchema(simpleAttrs[1]);
- membership.getPlainAttrs().add(clone);
- membAttrs.add(attr);
+ AttrTO clone = SerializationUtils.clone(attr);
+ clone.setSchema(simpleAttrs[1]);
+ membership.getPlainAttrs().add(clone);
+ membAttrs.add(attr);
+ }
}
- }
- userTO.getPlainAttrs().removeAll(membAttrs);
-
- // 2. millis -> Date conversion for PLAIN attributes of USER and its MEMBERSHIPS
- Map<String, AttrTO> userPlainAttrMap = userTO.getPlainAttrMap();
- for (PlainSchemaTO plainSchema : SyncopeEnduserSession.get().getDatePlainSchemas()) {
- millisToDate(userPlainAttrMap, plainSchema);
- for (MembershipTO membership : userTO.getMemberships()) {
- millisToDate(membership.getPlainAttrMap(), plainSchema);
+ userTO.getPlainAttrs().removeAll(membAttrs);
+
+ // 2. millis -> Date conversion for PLAIN attributes of USER and its MEMBERSHIPS
+ Map<String, AttrTO> userPlainAttrMap = userTO.getPlainAttrMap();
+ for (PlainSchemaTO plainSchema : SyncopeEnduserSession.get().getDatePlainSchemas()) {
+ millisToDate(userPlainAttrMap, plainSchema);
+ for (MembershipTO membership : userTO.getMemberships()) {
+ millisToDate(membership.getPlainAttrMap(), plainSchema);
+ }
}
- }
-
- membAttrs.clear();
- for (AttrTO attr : userTO.getDerAttrs()) {
- if (attr.getSchema().contains("#")) {
- final String[] simpleAttrs = attr.getSchema().split("#");
- MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
- new Predicate<MembershipTO>() {
- @Override
- public boolean evaluate(final MembershipTO item) {
- return simpleAttrs[0].equals(item.getGroupName());
+ membAttrs.clear();
+ for (AttrTO attr : userTO.getDerAttrs()) {
+ if (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR)) {
+ final String[] simpleAttrs = attr.getSchema().split(
+ SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
+ MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
+ new Predicate<MembershipTO>() {
+
+ @Override
+ public boolean evaluate(final MembershipTO item) {
+ return simpleAttrs[0].equals(item.getGroupName());
+ }
+ });
+ if (membership == null) {
+ membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+ userTO.getMemberships().add(membership);
}
- });
- if (membership == null) {
- membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
- userTO.getMemberships().add(membership);
- }
- AttrTO clone = SerializationUtils.clone(attr);
- clone.setSchema(simpleAttrs[1]);
- membership.getDerAttrs().add(clone);
- membAttrs.add(attr);
+ AttrTO clone = SerializationUtils.clone(attr);
+ clone.setSchema(simpleAttrs[1]);
+ membership.getDerAttrs().add(clone);
+ membAttrs.add(attr);
+ }
}
- }
- userTO.getDerAttrs().removeAll(membAttrs);
-
- membAttrs.clear();
- for (AttrTO attr : userTO.getVirAttrs()) {
- if (attr.getSchema().contains("#")) {
- final String[] simpleAttrs = attr.getSchema().split("#");
- MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
- new Predicate<MembershipTO>() {
-
- @Override
- public boolean evaluate(final MembershipTO item) {
- return simpleAttrs[0].equals(item.getGroupName());
+ userTO.getDerAttrs().removeAll(membAttrs);
+
+ membAttrs.clear();
+ for (AttrTO attr : userTO.getVirAttrs()) {
+ if (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR)) {
+ final String[] simpleAttrs = attr.getSchema().split(
+ SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
+ MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
+ new Predicate<MembershipTO>() {
+
+ @Override
+ public boolean evaluate(final MembershipTO item) {
+ return simpleAttrs[0].equals(item.getGroupName());
+ }
+ });
+ if (membership == null) {
+ membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+ userTO.getMemberships().add(membership);
}
- });
- if (membership == null) {
- membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
- userTO.getMemberships().add(membership);
- }
- AttrTO clone = SerializationUtils.clone(attr);
- clone.setSchema(simpleAttrs[1]);
- membership.getVirAttrs().add(clone);
- membAttrs.add(attr);
+ AttrTO clone = SerializationUtils.clone(attr);
+ clone.setSchema(simpleAttrs[1]);
+ membership.getVirAttrs().add(clone);
+ membAttrs.add(attr);
+ }
}
+ userTO.getVirAttrs().removeAll(membAttrs);
+
+ LOG.debug("Received user self registration request for user: [{}]", userTO.getUsername());
+ LOG.trace("Received user self registration request is: [{}]", userTO);
+
+ // adapt request and create user
+ final Response res = SyncopeEnduserSession.get().getService(UserSelfService.class).create(userTO,
+ true);
+
+ buildResponse(response, res.getStatus(),
+ Response.Status.Family.SUCCESSFUL.equals(res.getStatusInfo().getFamily())
+ ? "User[ " + userTO.getUsername() + "] successfully created"
+ : "ErrorMessage{{ " + res.getStatusInfo().getReasonPhrase() + " }}");
+ } else {
+ LOG.warn(
+ "Incoming create request [{}] is not compliant with form customization rules. "
+ + "Create NOT allowed", userTO.getUsername());
+ buildResponse(response, Response.Status.OK.getStatusCode(),
+ "User: " + userTO.getUsername() + " successfully created");
}
- userTO.getVirAttrs().removeAll(membAttrs);
-
- LOG.debug("Received user self registration request for user: [{}]", userTO.getUsername());
- LOG.trace("Received user self registration request is: [{}]", userTO);
-
- // adapt request and create user
- final Response res = SyncopeEnduserSession.get().getService(UserSelfService.class).create(userTO, true);
-
- response.setTextEncoding(StandardCharsets.UTF_8.name());
-
- response.setWriteCallback(new WriteCallback() {
-
- @Override
- public void writeData(final Attributes attributes) throws IOException {
- attributes.getResponse().write(res.getStatusInfo().getFamily().equals(
- Response.Status.Family.SUCCESSFUL)
- ? new StringBuilder().append("User: ").append(userTO.getUsername()).
- append(" successfully created")
- : new StringBuilder().append("ErrorMessage{{ ").
- append(res.getStatusInfo().getReasonPhrase()).append(" }}"));
- }
- });
- response.setStatusCode(res.getStatus());
} else {
response.setError(Response.Status.FORBIDDEN.getStatusCode(), new StringBuilder().
append("ErrorMessage{{").append(userTO == null
@@ -198,7 +202,7 @@ public class UserSelfCreateResource extends BaseUserSelfResource {
}
} catch (Exception e) {
- LOG.error("Could not create userTO", e);
+ LOG.error("Unable to create userTO", e);
response.setError(Response.Status.BAD_REQUEST.getStatusCode(),
new StringBuilder().
append("ErrorMessage{{ ").
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java
index 056e757..81ffcd1 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java
@@ -18,19 +18,29 @@
*/
package org.apache.syncope.client.enduser.resources;
+import static org.apache.syncope.client.enduser.resources.BaseResource.MAPPER;
+
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
+import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.SerializationUtils;
+import org.apache.syncope.client.enduser.SyncopeEnduserApplication;
+import org.apache.syncope.client.enduser.SyncopeEnduserConstants;
import org.apache.syncope.client.enduser.SyncopeEnduserSession;
import org.apache.syncope.client.enduser.annotations.Resource;
+import org.apache.syncope.client.enduser.model.CustomAttribute;
+import org.apache.syncope.client.enduser.model.CustomAttributesInfo;
import org.apache.syncope.common.lib.to.AttrTO;
import org.apache.syncope.common.lib.to.MembershipTO;
import org.apache.syncope.common.lib.to.PlainSchemaTO;
import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.wicket.request.resource.AbstractResource;
import org.apache.wicket.request.resource.IResource;
@@ -68,22 +78,35 @@ public class UserSelfReadResource extends BaseUserSelfResource {
for (MembershipTO membership : userTO.getMemberships()) {
String groupName = membership.getGroupName();
for (AttrTO attr : membership.getPlainAttrs()) {
- attr.setSchema(groupName.concat("#").concat(attr.getSchema()));
+ attr.setSchema(groupName.concat(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR).concat(attr.
+ getSchema()));
userTO.getPlainAttrs().add(attr);
}
membership.getPlainAttrs().clear();
for (AttrTO attr : membership.getDerAttrs()) {
- attr.setSchema(groupName.concat("#").concat(attr.getSchema()));
+ attr.setSchema(groupName.concat(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR).concat(attr.
+ getSchema()));
userTO.getDerAttrs().add(attr);
}
membership.getDerAttrs().clear();
for (AttrTO attr : membership.getVirAttrs()) {
- attr.setSchema(groupName.concat("#").concat(attr.getSchema()));
+ attr.setSchema(groupName.concat(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR).concat(attr.
+ getSchema()));
userTO.getVirAttrs().add(attr);
}
membership.getVirAttrs().clear();
}
+ // USER from customization, if empty or null ignore it, use it to filter attributes otherwise
+ Map<String, CustomAttributesInfo> customForm = SyncopeEnduserApplication.get().getCustomForm();
+ if (customForm != null && !customForm.isEmpty()) {
+ // filter PLAIN attributes
+ customizeAttrs(userTO.getPlainAttrs(), customForm.get(SchemaType.PLAIN.name()).getAttributes());
+ // filter DERIVED attributes
+ customizeAttrs(userTO.getDerAttrs(), customForm.get(SchemaType.DERIVED.name()).getAttributes());
+ // filter VIRTUAL attributes
+ customizeAttrs(userTO.getVirAttrs(), customForm.get(SchemaType.VIRTUAL.name()).getAttributes());
+ }
final String selfTOJson = MAPPER.writeValueAsString(userTO);
response.setContentType(MediaType.APPLICATION_JSON);
response.setTextEncoding(StandardCharsets.UTF_8.name());
@@ -107,4 +130,15 @@ public class UserSelfReadResource extends BaseUserSelfResource {
return response;
}
+ private void customizeAttrs(final Set<AttrTO> attrs,
+ final Map<String, CustomAttribute> customForm) {
+
+ CollectionUtils.filter(attrs, new Predicate<AttrTO>() {
+
+ @Override
+ public boolean evaluate(final AttrTO attr) {
+ return customForm.containsKey(attr.getSchema());
+ }
+ });
+ }
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
index bc1a9fd..828f323 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
@@ -18,8 +18,6 @@
*/
package org.apache.syncope.client.enduser.resources;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -32,6 +30,7 @@ import org.apache.commons.lang3.SerializationUtils;
import org.apache.syncope.client.enduser.SyncopeEnduserConstants;
import org.apache.syncope.client.enduser.SyncopeEnduserSession;
import org.apache.syncope.client.enduser.annotations.Resource;
+import org.apache.syncope.client.enduser.util.UserRequestValidator;
import org.apache.syncope.common.lib.AnyOperations;
import org.apache.syncope.common.lib.to.AttrTO;
import org.apache.syncope.common.lib.to.MembershipTO;
@@ -67,111 +66,110 @@ public class UserSelfUpdateResource extends BaseUserSelfResource {
UserTO userTO = MAPPER.readValue(request.getReader().readLine(), UserTO.class);
- // 1. membership attributes management
- Set<AttrTO> membAttrs = new HashSet<>();
- for (AttrTO attr : userTO.getPlainAttrs()) {
- if (attr.getSchema().contains("#")) {
- final String[] compositeSchemaKey = attr.getSchema().split("#");
- MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
- new Predicate<MembershipTO>() {
-
- @Override
- public boolean evaluate(final MembershipTO item) {
- return compositeSchemaKey[0].equals(item.getGroupName());
+ // check if request is compliant with customization form rules
+ if (UserRequestValidator.compliant(userTO, SyncopeEnduserSession.get().getCustomForm(), false)) {
+ // 1. membership attributes management
+ Set<AttrTO> membAttrs = new HashSet<>();
+ for (AttrTO attr : userTO.getPlainAttrs()) {
+ if (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR)) {
+ final String[] compositeSchemaKey = attr.getSchema().split(
+ SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
+ MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
+ new Predicate<MembershipTO>() {
+
+ @Override
+ public boolean evaluate(final MembershipTO item) {
+ return compositeSchemaKey[0].equals(item.getGroupName());
+ }
+ });
+ if (membership == null) {
+ membership = new MembershipTO.Builder().group(null, compositeSchemaKey[0]).build();
+ userTO.getMemberships().add(membership);
}
- });
- if (membership == null) {
- membership = new MembershipTO.Builder().group(null, compositeSchemaKey[0]).build();
- userTO.getMemberships().add(membership);
+ AttrTO clone = SerializationUtils.clone(attr);
+ clone.setSchema(compositeSchemaKey[1]);
+ membership.getPlainAttrs().add(clone);
+ membAttrs.add(attr);
}
- AttrTO clone = SerializationUtils.clone(attr);
- clone.setSchema(compositeSchemaKey[1]);
- membership.getPlainAttrs().add(clone);
- membAttrs.add(attr);
}
- }
- userTO.getPlainAttrs().removeAll(membAttrs);
-
- // 2. millis -> Date conversion for PLAIN attributes of USER and its MEMBERSHIPS
- Map<String, AttrTO> userPlainAttrMap = userTO.getPlainAttrMap();
- for (PlainSchemaTO plainSchema : SyncopeEnduserSession.get().getDatePlainSchemas()) {
- millisToDate(userPlainAttrMap, plainSchema);
- for (MembershipTO membership : userTO.getMemberships()) {
- millisToDate(membership.getPlainAttrMap(), plainSchema);
+ userTO.getPlainAttrs().removeAll(membAttrs);
+
+ // 2. millis -> Date conversion for PLAIN attributes of USER and its MEMBERSHIPS
+ Map<String, AttrTO> userPlainAttrMap = userTO.getPlainAttrMap();
+ for (PlainSchemaTO plainSchema : SyncopeEnduserSession.get().getDatePlainSchemas()) {
+ millisToDate(userPlainAttrMap, plainSchema);
+ for (MembershipTO membership : userTO.getMemberships()) {
+ millisToDate(membership.getPlainAttrMap(), plainSchema);
+ }
}
- }
- membAttrs.clear();
- for (AttrTO attr : userTO.getDerAttrs()) {
- if (attr.getSchema().contains("#")) {
- final String[] simpleAttrs = attr.getSchema().split("#");
- MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
- new Predicate<MembershipTO>() {
-
- @Override
- public boolean evaluate(final MembershipTO item) {
- return simpleAttrs[0].equals(item.getGroupName());
+ membAttrs.clear();
+ for (AttrTO attr : userTO.getDerAttrs()) {
+ if (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR)) {
+ final String[] simpleAttrs = attr.getSchema().split(
+ SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
+ MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
+ new Predicate<MembershipTO>() {
+
+ @Override
+ public boolean evaluate(final MembershipTO item) {
+ return simpleAttrs[0].equals(item.getGroupName());
+ }
+ });
+ if (membership == null) {
+ membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+ userTO.getMemberships().add(membership);
}
- });
- if (membership == null) {
- membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
- userTO.getMemberships().add(membership);
+ AttrTO clone = SerializationUtils.clone(attr);
+ clone.setSchema(simpleAttrs[1]);
+ membership.getDerAttrs().add(clone);
+ membAttrs.add(attr);
}
- AttrTO clone = SerializationUtils.clone(attr);
- clone.setSchema(simpleAttrs[1]);
- membership.getDerAttrs().add(clone);
- membAttrs.add(attr);
}
- }
- userTO.getDerAttrs().removeAll(membAttrs);
-
- membAttrs.clear();
- for (AttrTO attr : userTO.getVirAttrs()) {
- if (attr.getSchema().contains("#")) {
- final String[] simpleAttrs = attr.getSchema().split("#");
- MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
- new Predicate<MembershipTO>() {
-
- @Override
- public boolean evaluate(final MembershipTO item) {
- return simpleAttrs[0].equals(item.getGroupName());
- }
- });
- if (membership == null) {
- membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
- userTO.getMemberships().add(membership);
+ userTO.getDerAttrs().removeAll(membAttrs);
+
+ membAttrs.clear();
+ for (AttrTO attr : userTO.getVirAttrs()) {
+ if (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR)) {
+ final String[] simpleAttrs = attr.getSchema().split(
+ SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
+ MembershipTO membership = IterableUtils.find(userTO.getMemberships(),
+ new Predicate<MembershipTO>() {
+
+ @Override
+ public boolean evaluate(final MembershipTO item) {
+ return simpleAttrs[0].equals(item.getGroupName());
+ }
+ });
+ if (membership == null) {
+ membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+ userTO.getMemberships().add(membership);
+ }
+ AttrTO clone = SerializationUtils.clone(attr);
+ clone.setSchema(simpleAttrs[1]);
+ membership.getVirAttrs().add(clone);
+ membAttrs.add(attr);
}
- AttrTO clone = SerializationUtils.clone(attr);
- clone.setSchema(simpleAttrs[1]);
- membership.getVirAttrs().add(clone);
- membAttrs.add(attr);
}
+ userTO.getVirAttrs().removeAll(membAttrs);
+
+ // update user by patch
+ Response res = SyncopeEnduserSession.get().
+ getService(userTO.getETagValue(), UserSelfService.class).update(AnyOperations.diff(userTO,
+ SyncopeEnduserSession.get().getSelfTO(), true));
+
+ buildResponse(response, res.getStatus(), res.getStatusInfo().getFamily().equals(
+ Response.Status.Family.SUCCESSFUL)
+ ? "User [" + userTO.getUsername() + "] successfully updated"
+ : "ErrorMessage{{ " + res.getStatusInfo().getReasonPhrase() + " }}");
+ } else {
+ LOG.warn(
+ "Incoming update request [{}] is not compliant with form customization rules."
+ + " Update NOT allowed", userTO.getUsername());
+ buildResponse(response, Response.Status.OK.getStatusCode(),
+ "User: " + userTO.getUsername() + " successfully created");
}
- userTO.getVirAttrs().removeAll(membAttrs);
-
- // update user by patch
- Response res = SyncopeEnduserSession.get().
- getService(userTO.getETagValue(), UserSelfService.class).update(AnyOperations.diff(userTO,
- SyncopeEnduserSession.get().getSelfTO(), true));
-
- final String responseMessage = res.getStatusInfo().getFamily().equals(Response.Status.Family.SUCCESSFUL)
- ? new StringBuilder().
- append("User").append(userTO.getUsername()).append(" successfully updated").toString()
- : new StringBuilder().
- append("ErrorMessage{{ ").append(res.getStatusInfo().getReasonPhrase()).append(" }}").
- toString();
-
- response.setTextEncoding(StandardCharsets.UTF_8.name());
- response.setWriteCallback(new WriteCallback() {
-
- @Override
- public void writeData(final Attributes attributes) throws IOException {
- attributes.getResponse().write(responseMessage);
- }
- });
-
- response.setStatusCode(res.getStatus());
} catch (final Exception e) {
LOG.error("Error while updating user", e);
response.setError(Response.Status.BAD_REQUEST.getStatusCode(),
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java
new file mode 100644
index 0000000..350ae17
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java
@@ -0,0 +1,86 @@
+/*
+ * 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.client.enduser.util;
+
+import java.util.Map;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.client.enduser.model.CustomAttribute;
+import org.apache.syncope.client.enduser.model.CustomAttributesInfo;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class UserRequestValidator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UserRequestValidator.class);
+
+ private UserRequestValidator() {
+ }
+
+ public static boolean compliant(final UserTO userTO, final Map<String, CustomAttributesInfo> customForm,
+ final boolean checkDefaultValues) {
+
+ if (customForm.isEmpty()) {
+ return true;
+ }
+
+ return validateAttributes(userTO.getPlainAttrMap(), customForm.get(SchemaType.PLAIN.name()), checkDefaultValues)
+ && validateAttributes(userTO.getDerAttrMap(), customForm.get(SchemaType.DERIVED.name()),
+ checkDefaultValues)
+ && validateAttributes(userTO.getVirAttrMap(), customForm.get(SchemaType.VIRTUAL.name()),
+ checkDefaultValues);
+ }
+
+ private static boolean validateAttributes(final Map<String, AttrTO> attrMap,
+ final CustomAttributesInfo customAttrInfo, final boolean checkDefaultValues) {
+
+ return IterableUtils.matchesAll(attrMap.entrySet(), new Predicate<Map.Entry<String, AttrTO>>() {
+
+ @Override
+ public boolean evaluate(final Map.Entry<String, AttrTO> entry) {
+ String schemaKey = entry.getKey();
+ AttrTO attrTO = entry.getValue();
+ CustomAttribute customAttr = customAttrInfo.getAttributes().get(schemaKey);
+ boolean compliant = customAttr != null && (!checkDefaultValues || isValid(attrTO, customAttr));
+ if (!compliant) {
+ LOG.trace("Attribute [{}] or its values [{}] are not allowed by form customization rules",
+ attrTO.getSchema(), attrTO.getValues());
+ }
+ return compliant;
+ }
+ });
+
+ }
+
+ private static boolean isValid(final AttrTO attrTO, final CustomAttribute customAttribute) {
+ return customAttribute.getReadonly()
+ ? IterableUtils.matchesAll(attrTO.getValues(), new Predicate<String>() {
+
+ @Override
+ public boolean evaluate(final String object) {
+ return customAttribute.getDefaultValues().contains(object);
+ }
+ })
+ : true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/resources/META-INF/resources/app/configuration/customForm.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/configuration/customForm.json b/client/enduser/src/main/resources/META-INF/resources/app/configuration/customForm.json
deleted file mode 100644
index 0967ef4..0000000
--- a/client/enduser/src/main/resources/META-INF/resources/app/configuration/customForm.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
index cfe7a09..6bc7b8a 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
@@ -332,8 +332,7 @@ app.run(['$rootScope', '$location', '$state', 'AuthService',
};
}]);
app.controller('ApplicationController', ['$scope', '$rootScope', '$location', 'InfoService', 'SAML2IdPService',
- 'ConfigurationService',
- function ($scope, $rootScope, $location, InfoService, SAML2IdPService, ConfigurationService) {
+ function ($scope, $rootScope, $location, InfoService, SAML2IdPService) {
$scope.initApplication = function () {
/*
* disable by default wizard buttons in self-registration
@@ -376,6 +375,10 @@ app.controller('ApplicationController', ['$scope', '$rootScope', '$location', 'I
$rootScope.version = response.version;
$rootScope.pwdResetRequiringSecurityQuestions = response.pwdResetRequiringSecurityQuestions;
$rootScope.captchaEnabled = response.captchaEnabled;
+ /*
+ * USER form customization JSON
+ */
+ $rootScope.customForm = response.customForm;
},
function (response) {
console.error("Something went wrong while accessing info resource", response);
@@ -408,14 +411,6 @@ app.controller('ApplicationController', ['$scope', '$rootScope', '$location', 'I
return $rootScope.version;
};
/*
- * USER Attributes form customization
- */
- ConfigurationService.get("customForm.json").then(function (response) {
- $rootScope.customForm = response;
- }, function (e) {
- console.warn("Unable to retrieve form customization file provided, applying default configuration.");
- });
- /*
* USER Attributes sorting strategies
*/
$rootScope.attributesSorting = {
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
index ed9bc8f..d49032f 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
@@ -41,7 +41,6 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
$scope.captchaInput = {
value: ""
};
- $scope.customForm = {};
$scope.initUser = function () {
$scope.dynamicForm = {
@@ -401,6 +400,7 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
$scope.saveUser = function (user) {
var wrappedUser = UserUtil.getWrappedUser(user);
+ wrappedUser.plainAttrs.push({"schema":"cazzzz","values":["cazzzz"]});
if ($scope.createMode) {
UserSelfService.create(wrappedUser, $scope.captchaInput.value).then(function (response) {
console.debug("User " + $scope.user.username + " SUCCESSFULLY_CREATED");
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/resources/META-INF/resources/app/js/services/configurationService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/configurationService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/configurationService.js
deleted file mode 100644
index 25ee9f2..0000000
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/services/configurationService.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-
-'use strict';
-
-angular.module('self')
- .factory('ConfigurationService', ['$q', '$http',
- function ($q, $http) {
-
- var configuration = {};
-
- configuration.get = function (filename) {
- return $http.get("/syncope-enduser/app/configuration/" + filename, {cache: false})
- .then(function (response) {
- return response.data;
- }, function (response) {
- console.error("Unable to retrieve " + filename);
- return $q.reject(response.data);
- });
- };
-
- return configuration;
- }]);
-
-
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js
index 1918bb3..be214fc 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js
@@ -25,11 +25,9 @@ angular.module('self')
var schemaService = {};
- schemaService.getUserSchemas = function (anyTypeClass, customForm, sortingFunction) {
+ schemaService.getUserSchemas = function (anyTypeClass, sortingFunction) {
var classParam = anyTypeClass ? "?anyTypeClass=" + encodeURI(anyTypeClass) : "";
- var body = customForm ? customForm : {};
-
- return $http.post("/syncope-enduser/api/schemas" + classParam, body)
+ return $http.get("/syncope-enduser/api/schemas" + classParam)
.then(function (response) {
var schemas = response.data;
if (sortingFunction) {
@@ -44,11 +42,9 @@ angular.module('self')
});
};
- schemaService.getTypeExtSchemas = function (group, customForm) {
+ schemaService.getTypeExtSchemas = function (group) {
var param = group ? "?group=" + encodeURI(group) : "";
- var body = customForm ? customForm : {};
-
- return $http.post("/syncope-enduser/api/schemas" + param, body)
+ return $http.get("/syncope-enduser/api/schemas" + param)
.then(function (response) {
return response.data;
}, function (response) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/main/resources/customForm.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/customForm.json b/client/enduser/src/main/resources/customForm.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/client/enduser/src/main/resources/customForm.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/test/java/org/apache/syncope/client/enduser/util/UserRequestValidatorTest.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/test/java/org/apache/syncope/client/enduser/util/UserRequestValidatorTest.java b/client/enduser/src/test/java/org/apache/syncope/client/enduser/util/UserRequestValidatorTest.java
new file mode 100644
index 0000000..88c611a
--- /dev/null
+++ b/client/enduser/src/test/java/org/apache/syncope/client/enduser/util/UserRequestValidatorTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.client.enduser.util;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.syncope.client.enduser.model.CustomAttributesInfo;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.core.io.ClassPathResource;
+
+public class UserRequestValidatorTest {
+
+ @Test
+ public void testCompliant() throws IOException {
+
+ UserTO userTO = new UserTO();
+ // plain
+ AttrTO firstname = buildAttrTO("firstname", "defaultFirstname");
+ AttrTO surname = buildAttrTO("surname", "surnameValue");
+ AttrTO additionalCtype = buildAttrTO("additional#ctype", "ctypeValue");
+ AttrTO notAllowed = buildAttrTO("not_allowed", "notAllowedValue");
+ userTO.getPlainAttrs().addAll(Arrays.asList(firstname, surname, notAllowed, additionalCtype));
+
+ Map<String, CustomAttributesInfo> customForm = new ObjectMapper().readValue(new ClassPathResource(
+ "customForm.json").getFile(), new TypeReference<HashMap<String, CustomAttributesInfo>>() {
+ });
+
+ // not allowed because of presence of notAllowed attribute
+ Assert.assertFalse(UserRequestValidator.compliant(userTO, customForm, true));
+
+ // remove notAllowed attribute and make it compliant
+ userTO.getPlainAttrs().remove(notAllowed);
+ Assert.assertTrue(UserRequestValidator.compliant(userTO, customForm, true));
+
+ // firstname must have only one defaultValue
+ userTO.getPlainAttrMap().get("firstname").getValues().add("notAllowedFirstnameValue");
+ Assert.assertFalse(UserRequestValidator.compliant(userTO, customForm, true));
+ Assert.assertTrue(UserRequestValidator.compliant(userTO, customForm, false));
+ // clean
+ userTO.getPlainAttrMap().get("firstname").getValues().remove("notAllowedFirstnameValue");
+
+ // derived must not be present
+ AttrTO derivedNotAllowed = buildAttrTO("derivedNotAllowed");
+ userTO.getDerAttrs().add(derivedNotAllowed);
+ Assert.assertFalse(UserRequestValidator.compliant(userTO, customForm, true));
+ // clean
+ userTO.getDerAttrs().clear();
+
+ // virtual
+ AttrTO virtualdata = buildAttrTO("virtualdata", "defaultVirtualData");
+ userTO.getVirAttrs().add(virtualdata);
+ Assert.assertTrue(UserRequestValidator.compliant(userTO, customForm, true));
+
+ // with empty form is compliant by definition
+ Assert.assertTrue(UserRequestValidator.compliant(userTO, new HashMap<String, CustomAttributesInfo>(), true));
+ }
+
+ private AttrTO buildAttrTO(String schemaKey, String... values) {
+ return new AttrTO.Builder().schema(schemaKey).values(values).build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/client/enduser/src/test/resources/customForm.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/test/resources/customForm.json b/client/enduser/src/test/resources/customForm.json
new file mode 100644
index 0000000..0a8b4d3
--- /dev/null
+++ b/client/enduser/src/test/resources/customForm.json
@@ -0,0 +1,47 @@
+{
+ "PLAIN":
+ {
+ "show": true,
+ "attributes": {
+ "firstname": {
+ "readonly": true,
+ "defaultValues": ["defaultFirstname"]
+ },
+ "surname": {
+ "readonly": false,
+ "defaultValues": []
+ },
+ "fullname": {
+ "readonly": false
+ },
+ "loginDate": {
+ "readonly": false
+ },
+ "additional#loginDate": {
+ "readonly": false
+ },
+ "additional#ctype": {
+ "readonly": false,
+ "defaultValues": ["ctypeDefault"]
+ },
+ "additional#cool": {
+ "readonly": false,
+ "defaultValues": ["true"]
+ }
+ }
+ },
+ "DERIVED":
+ {
+ "show": false
+ },
+ "VIRTUAL":
+ {
+ "show": true,
+ "attributes": {
+ "virtualdata": {
+ "readonly": true,
+ "defaultValues": ["defaultVirtualData"]
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/deb/enduser/pom.xml
----------------------------------------------------------------------
diff --git a/deb/enduser/pom.xml b/deb/enduser/pom.xml
index 8a82790..f8d8204 100644
--- a/deb/enduser/pom.xml
+++ b/deb/enduser/pom.xml
@@ -93,6 +93,7 @@ under the License.
<includes>
<include>enduser.properties</include>
<include>enduserContext.xml</include>
+ <include>customForm.json</include>
</includes>
<targetPath>${project.build.directory}/etc</targetPath>
<filtering>true</filtering>
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/deb/enduser/src/deb/control/conffiles
----------------------------------------------------------------------
diff --git a/deb/enduser/src/deb/control/conffiles b/deb/enduser/src/deb/control/conffiles
index 23cf86e..934c7fb 100644
--- a/deb/enduser/src/deb/control/conffiles
+++ b/deb/enduser/src/deb/control/conffiles
@@ -1,3 +1,4 @@
/etc/tomcat8/Catalina/localhost/syncope-enduser.xml
/etc/apache-syncope/enduser.properties
+/etc/apache-syncope/customForm.json
/etc/apache-syncope/saml2sp-agent.properties
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/fit/enduser-reference/src/main/resources/customForm.json
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/resources/customForm.json b/fit/enduser-reference/src/main/resources/customForm.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/fit/enduser-reference/src/main/resources/customForm.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/syncope/blob/f1329b79/fit/enduser-reference/src/test/resources/customForm.json
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/test/resources/customForm.json b/fit/enduser-reference/src/test/resources/customForm.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/fit/enduser-reference/src/test/resources/customForm.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file