Repository: gravitee-io/graviteeio-access-management
Pull request #804 (2020-05-13 11:52:19)

feat(security): improve inputs validation
Closes gravitee-io/issues#3755


Patch:
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/register/RegisterSubmissionEndpoint.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/register/RegisterSubmissionEndpoint.java
index edae051674..debe273bbd 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/register/RegisterSubmissionEndpoint.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/register/RegisterSubmissionEndpoint.java
@@ -24,7 +24,8 @@ import io.gravitee.am.identityprovider.api.DefaultUser;
 import io.gravitee.am.model.Domain;
 import io.gravitee.am.model.User;
 import io.gravitee.am.model.oidc.Client;
-import io.gravitee.am.service.exception.UserAlreadyExistsException;
+import io.gravitee.am.service.exception.EmailFormatInvalidException;
+import io.gravitee.am.service.exception.InvalidUserException;
 import io.gravitee.common.http.HttpHeaders;
 import io.vertx.core.AsyncResult;
 import io.vertx.core.Future;
@@ -75,8 +76,10 @@ public class RegisterSubmissionEndpoint extends UserRequestHandler {
 
             // if failure, return to the register page with an error
             if (h.failed()) {
-                if (h.cause() instanceof UserAlreadyExistsException) {
-                    queryParams.put(WARNING_PARAM, "user_already_exists");
+                if (h.cause() instanceof InvalidUserException) {
+                    queryParams.put(WARNING_PARAM, "invalid_user_information");
+                } else if (h.cause() instanceof EmailFormatInvalidException) {
+                    queryParams.put(WARNING_PARAM, "invalid_email");
                 } else {
                     LOGGER.error("An error occurs while ending user registration", h.cause());
                     queryParams.put(ERROR_PARAM, "registration_failed");
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/service/user/impl/UserServiceImpl.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/service/user/impl/UserServiceImpl.java
index 841b811be3..8d0239c5df 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/service/user/impl/UserServiceImpl.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/service/user/impl/UserServiceImpl.java
@@ -43,11 +43,14 @@ import io.gravitee.am.model.oidc.Client;
 import io.gravitee.am.repository.management.api.search.LoginAttemptCriteria;
 import io.gravitee.am.service.AuditService;
 import io.gravitee.am.service.LoginAttemptService;
+import io.gravitee.am.service.exception.EmailFormatInvalidException;
 import io.gravitee.am.service.exception.UserAlreadyExistsException;
 import io.gravitee.am.service.exception.UserNotFoundException;
 import io.gravitee.am.service.exception.UserProviderNotFoundException;
 import io.gravitee.am.service.reporter.builder.AuditBuilder;
 import io.gravitee.am.service.reporter.builder.management.UserAuditBuilder;
+import io.gravitee.am.service.validators.EmailValidator;
+import io.gravitee.am.service.validators.UserValidator;
 import io.reactivex.Completable;
 import io.reactivex.Maybe;
 import io.reactivex.MaybeSource;
@@ -115,8 +118,8 @@ public class UserServiceImpl implements UserService {
         // set user idp source
         final String source = user.getSource() == null ? DEFAULT_IDP_PREFIX + domain.getId() : user.getSource();
 
-        // check user uniqueness
-        return userService.findByDomainAndUsernameAndSource(domain.getId(), user.getUsername(), source)
+        // validate user and then check user uniqueness
+        return UserValidator.validate(user).andThen(userService.findByDomainAndUsernameAndSource(domain.getId(), user.getUsername(), source)
                 .isEmpty()
                 .map(isEmpty -> {
                     if (!isEmpty) {
@@ -171,7 +174,7 @@ public class UserServiceImpl implements UserService {
                             auditService.report(AuditBuilder.builder(UserAuditBuilder.class).domain(domain.getId()).client(user.getClient()).principal(principal1).type(EventType.USER_REGISTERED));
                         })
                         .doOnError(throwable -> auditService.report(AuditBuilder.builder(UserAuditBuilder.class).domain(domain.getId()).client(user.getClient()).principal(principal).type(EventType.USER_REGISTERED).throwable(throwable)))
-                );
+                ));
     }
 
     @Override
@@ -286,6 +289,11 @@ public class UserServiceImpl implements UserService {
 
     @Override
     public Completable forgotPassword(String email, Client client, io.gravitee.am.identityprovider.api.User principal) {
+
+        if (!EmailValidator.isValid(email)) {
+            return Completable.error(new EmailFormatInvalidException(email));
+        }
+
         return userService.findByDomainAndEmail(domain.getId(), email, false)
                 .map(users -> users.stream().filter(user -> user.isInternal() && email.toLowerCase().equals(user.getEmail().toLowerCase())).findFirst())
                 .map(optionalUser -> {
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/views/registration.html b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/views/registration.html
index 7d1ed4cfcd..2ee7fda238 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/views/registration.html
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/views/registration.html
@@ -25,9 +25,14 @@
                 <label>Sign up</label>
                 <span>Please fill in this form to create your account</span>
             </div>
-            <div class="register-error-info" th:if="${warning}">
-                <p style="margin: 0;" th:text="${warning == 'invalid_password_value'} ? 'Invalid password value. It does not comply with the password policy.' : 'An account already exists with this username.'"></p>
+
+            <div class="register-error-info" th:switch="${warning}" th:if="${warning}">
+                <p style="margin: 0;" th:case="invalid_password_value">Invalid password value. It does not comply with the password policy.</p>
+                <p style="margin: 0;" th:case="invalid_user_information">Invalid first name, last name or username.</p>
+                <p style="margin: 0;" th:case="invalid_email">Invalid email address.</p>
+                <p style="margin: 0;" th:case="*">Some information are missing or invalid.</p>
             </div>
+
             <form role="form" th:action="@{register}" method="post">
                 <div class="register-form-content">
                     <div style="display: flex; flex-direction: row">
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/exception/UniquenessException.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/exception/UniquenessException.java
index fff8e47b02..4ab6724711 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/exception/UniquenessException.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/exception/UniquenessException.java
@@ -34,6 +34,11 @@ public class UniquenessException extends SCIMException {
         super(message, cause);
     }
 
+    @Override
+    public int getHttpStatusCode() {
+        return 409;
+    }
+
     @Override
     public ScimType getScimType() {
         return ScimType.UNIQUENESS;
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/resources/ErrorHandler.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/resources/ErrorHandler.java
index 39479ca5b9..2b8b4687c6 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/resources/ErrorHandler.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/resources/ErrorHandler.java
@@ -107,6 +107,8 @@ public class ErrorHandler implements Handler<RoutingContext> {
         error.setDetail(errorDetail);
         if (scimType != null) {
             error.setScimType(scimType.value());
+        } else if(httpStatusCode == HttpStatusCode.BAD_REQUEST_400) {
+            error.setScimType(ScimType.INVALID_VALUE.value());
         }
         routingContext
                 .response()
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/service/impl/UserServiceImpl.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/service/impl/UserServiceImpl.java
index acd19a62af..8933977df7 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/service/impl/UserServiceImpl.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/main/java/io/gravitee/am/gateway/handler/scim/service/impl/UserServiceImpl.java
@@ -31,6 +31,7 @@ import io.gravitee.am.model.ReferenceType;
 import io.gravitee.am.repository.management.api.UserRepository;
 import io.gravitee.am.service.RoleService;
 import io.gravitee.am.service.exception.*;
+import io.gravitee.am.service.validators.UserValidator;
 import io.reactivex.Completable;
 import io.reactivex.Maybe;
 import io.reactivex.Observable;
@@ -98,7 +99,7 @@ public class UserServiceImpl implements UserService {
                 .map(user1 -> convert(user1, baseUrl, false))
                 .flatMap(scimUser -> setGroups(scimUser).toMaybe())
                 .onErrorResumeNext(ex -> {
-                    LOGGER.error("An error occurs while trying to find a user using its ID", userId, ex);
+                    LOGGER.error("An error occurs while trying to find a user using its ID {}", userId, ex);
                     return Maybe.error(new TechnicalManagementException(
                             String.format("An error occurs while trying to find a user using its ID: %s", userId), ex));
                 });
@@ -116,7 +117,7 @@ public class UserServiceImpl implements UserService {
                 .isEmpty()
                 .map(isEmpty -> {
                     if (!isEmpty) {
-                        throw new UniquenessException("User with username [" + user.getUserName()+ "] already exists");
+                        throw new UniquenessException("User with username [" + user.getUserName() + "] already exists");
                     }
                     return true;
                 })
@@ -138,7 +139,7 @@ public class UserServiceImpl implements UserService {
                     userModel.setEnabled(userModel.getPassword() != null);
 
                     // store user in its identity provider
-                    return userProvider.create(convert(userModel))
+                    return UserValidator.validate(userModel).andThen(userProvider.create(convert(userModel))
                             .flatMap(idpUser -> {
                                 // AM 'users' collection is not made for authentication (but only management stuff)
                                 // clear password
@@ -149,10 +150,10 @@ public class UserServiceImpl implements UserService {
                             })
                             .onErrorResumeNext(ex -> {
                                 if (ex instanceof UserAlreadyExistsException) {
-                                    return Single.error(new UniquenessException("User with username [" + user.getUserName()+ "] already exists"));
+                                    return Single.error(new UniquenessException("User with username [" + user.getUserName() + "] already exists"));
                                 }
                                 return Single.error(ex);
-                            });
+                            }));
                 })
                 .map(user1 -> convert(user1, baseUrl, true))
                 .onErrorResumeNext(ex -> {
@@ -160,7 +161,7 @@ public class UserServiceImpl implements UserService {
                         return Single.error(new InvalidValueException(ex.getMessage()));
                     }
 
-                    if (ex instanceof SCIMException) {
+                    if (ex instanceof SCIMException || ex instanceof AbstractManagementException) {
                         return Single.error(ex);
                     }
 
@@ -190,7 +191,7 @@ public class UserServiceImpl implements UserService {
                                 userToUpdate.setCreatedAt(existingUser.getCreatedAt());
                                 userToUpdate.setUpdatedAt(new Date());
 
-                                return identityProviderManager.getUserProvider(userToUpdate.getSource())
+                                return UserValidator.validate(userToUpdate).andThen(identityProviderManager.getUserProvider(userToUpdate.getSource())
                                         .switchIfEmpty(Maybe.error(new UserProviderNotFoundException(userToUpdate.getSource())))
                                         .flatMapSingle(userProvider -> {
                                             // no idp user check if we need to create it
@@ -221,7 +222,7 @@ public class UserServiceImpl implements UserService {
                                                 return userRepository.update(userToUpdate);
                                             }
                                             return Single.error(ex);
-                                        });
+                                        }));
                             }));
                 })
                 .map(user1 -> convert(user1, baseUrl, false))
@@ -236,6 +237,10 @@ public class UserServiceImpl implements UserService {
                         return Single.error(new InvalidValueException(ex.getMessage()));
                     }
 
+                    if (ex instanceof AbstractManagementException) {
+                        return Single.error(ex);
+                    }
+
                     LOGGER.error("An error occurs while trying to update a user", ex);
                     return Single.error(new TechnicalManagementException("An error occurs while trying to update a user", ex));
                 });
@@ -303,7 +308,7 @@ public class UserServiceImpl implements UserService {
                         throw new RoleNotFoundException(String.join(",", roles));
                     }
                     return roles1;
-                }).toCompletable();
+                }).ignoreElement();
     }
 
     private User convert(io.gravitee.am.model.User user, String baseUrl, boolean listing) {
@@ -362,7 +367,7 @@ public class UserServiceImpl implements UserService {
             meta.setLastModified(user.getUpdatedAt().toInstant().toString());
         }
         meta.setResourceType(User.RESOURCE_TYPE);
-        meta.setLocation(baseUrl + (listing ?  "/" + scimUser.getId() : ""));
+        meta.setLocation(baseUrl + (listing ? "/" + scimUser.getId() : ""));
         scimUser.setMeta(meta);
         return scimUser;
     }
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/authentication/crypto/password/PasswordValidator.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/authentication/crypto/password/PasswordValidator.java
index 7e2d8faca3..2243906649 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/authentication/crypto/password/PasswordValidator.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/authentication/crypto/password/PasswordValidator.java
@@ -21,5 +21,7 @@ package io.gravitee.am.service.authentication.crypto.password;
  */
 public interface PasswordValidator {
 
+    int PASSWORD_MAX_LENGTH = 72;
+
     boolean validate(final String password);
 }
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/authentication/crypto/password/RegexPasswordValidator.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/authentication/crypto/password/RegexPasswordValidator.java
index a1a556cd95..5edf60e0a0 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/authentication/crypto/password/RegexPasswordValidator.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/authentication/crypto/password/RegexPasswordValidator.java
@@ -15,6 +15,7 @@
  */
 package io.gravitee.am.service.authentication.crypto.password;
 
+import io.gravitee.am.service.authentication.crypto.password.bcrypt.BCryptPasswordEncoder;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Value;
 
@@ -41,6 +42,11 @@ public class RegexPasswordValidator implements PasswordValidator, InitializingBe
 
     @Override
     public boolean validate(final String password) {
+
+        if(password.length() > PASSWORD_MAX_LENGTH) {
+            return false;
+        }
+
         matcher = pattern.matcher(password);
         return matcher.matches();
     }
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/exception/EmailFormatInvalidException.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/exception/EmailFormatInvalidException.java
new file mode 100644
index 0000000000..a19cbbb817
--- /dev/null
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/exception/EmailFormatInvalidException.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed 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 io.gravitee.am.service.exception;
+
+import static io.gravitee.common.http.HttpStatusCode.BAD_REQUEST_400;
+
+/**
+ * @author Jeoffrey HAEYAERT (jeoffrey.haeyaert at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public class EmailFormatInvalidException extends AbstractManagementException {
+
+    private final String value;
+
+    public EmailFormatInvalidException(String value) {
+        this.value = value;
+    }
+
+    @Override
+    public int getHttpStatusCode() {
+        return BAD_REQUEST_400;
+    }
+
+    @Override
+    public String getMessage() {
+        return "Value [" + value + "] is not a valid email.";
+    }
+}
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/UserServiceImpl.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/UserServiceImpl.java
index cc5d2b298c..e09a8d3d37 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/UserServiceImpl.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/UserServiceImpl.java
@@ -24,18 +24,15 @@ import io.gravitee.am.model.analytics.AnalyticsQuery;
 import io.gravitee.am.model.common.Page;
 import io.gravitee.am.model.common.event.Event;
 import io.gravitee.am.model.common.event.Payload;
-import io.gravitee.am.model.permissions.RoleScope;
 import io.gravitee.am.repository.management.api.UserRepository;
 import io.gravitee.am.service.EventService;
 import io.gravitee.am.service.GroupService;
 import io.gravitee.am.service.RoleService;
 import io.gravitee.am.service.UserService;
-import io.gravitee.am.service.exception.AbstractManagementException;
-import io.gravitee.am.service.exception.TechnicalManagementException;
-import io.gravitee.am.service.exception.UserAlreadyExistsException;
-import io.gravitee.am.service.exception.UserNotFoundException;
+import io.gravitee.am.service.exception.*;
 import io.gravitee.am.service.model.NewUser;
 import io.gravitee.am.service.model.UpdateUser;
+import io.gravitee.am.service.validators.UserValidator;
 import io.reactivex.Completable;
 import io.reactivex.Maybe;
 import io.reactivex.Single;
@@ -188,7 +185,7 @@ public class UserServiceImpl implements UserService {
         LOGGER.debug("Find user by {} {}, externalId and source: {} {}", referenceType, referenceId, externalId, source);
         return userRepository.findByExternalIdAndSource(referenceType, referenceId, externalId, source)
                 .onErrorResumeNext(ex -> {
-                    LOGGER.error("An error occurs while trying to find a user using its externalId: {} for the {} and source {}", externalId, referenceType, referenceId, source, ex);
+                    LOGGER.error("An error occurs while trying to find a user using its externalId: {} for the {} {} and source {}", externalId, referenceType, referenceId, source, ex);
                     return Maybe.error(new TechnicalManagementException(
                             String.format("An error occurs while trying to find a user using its externalId: %s for the %s %s and source %s", externalId, referenceType, referenceId, source), ex));
                 });
@@ -232,14 +229,9 @@ public class UserServiceImpl implements UserService {
                         user.setAdditionalInformation(newUser.getAdditionalInformation());
                         user.setCreatedAt(new Date());
                         user.setUpdatedAt(user.getCreatedAt());
-                        return userRepository.create(user);
+                        return create(user);
                     }
                 })
-                .flatMap(user -> {
-                    // create event for sync process
-                    Event event = new Event(Type.USER, new Payload(user.getId(), user.getReferenceType(), user.getReferenceId(), Action.CREATE));
-                    return eventService.create(event).flatMap(__ -> Single.just(user));
-                })
                 .onErrorResumeNext(ex -> {
                     if (ex instanceof AbstractManagementException) {
                         return Single.error(ex);
@@ -252,10 +244,12 @@ public class UserServiceImpl implements UserService {
 
     @Override
     public Single<User> create(User user) {
+
         LOGGER.debug("Create a user {}", user);
         user.setCreatedAt(new Date());
         user.setUpdatedAt(user.getCreatedAt());
-        return userRepository.create(user)
+
+        return UserValidator.validate(user).andThen(userRepository.create(user)
                 .flatMap(user1 -> {
                     // create event for sync process
                     Event event = new Event(Type.USER, new Payload(user1.getId(), user1.getReferenceType(), user1.getReferenceId(), Action.CREATE));
@@ -267,7 +261,7 @@ public class UserServiceImpl implements UserService {
                     }
                     LOGGER.error("An error occurs while trying to create a user", ex);
                     return Single.error(new TechnicalManagementException("An error occurs while trying to create a user", ex));
-                });
+                }));
     }
 
     @Override
@@ -287,12 +281,7 @@ public class UserServiceImpl implements UserService {
                     oldUser.setLoginsCount(updateUser.getLoginsCount());
                     oldUser.setUpdatedAt(new Date());
                     oldUser.setAdditionalInformation(updateUser.getAdditionalInformation());
-                    return userRepository.update(oldUser);
-                })
-                .flatMap(user -> {
-                    // create event for sync process
-                    Event event = new Event(Type.USER, new Payload(user.getId(), user.getReferenceType(), user.getReferenceId(), Action.UPDATE));
-                    return eventService.create(event).flatMap(__ -> Single.just(user));
+                    return update(oldUser);
                 })
                 .onErrorResumeNext(ex -> {
                     if (ex instanceof AbstractManagementException) {
@@ -315,7 +304,7 @@ public class UserServiceImpl implements UserService {
         LOGGER.debug("Update a user {}", user);
         // updated date
         user.setUpdatedAt(new Date());
-        return userRepository.update(user)
+        return UserValidator.validate(user).andThen(userRepository.update(user)
                 .flatMap(user1 -> {
                     // create event for sync process
                     Event event = new Event(Type.USER, new Payload(user1.getId(), user1.getReferenceType(), user1.getReferenceId(), Action.UPDATE));
@@ -327,7 +316,7 @@ public class UserServiceImpl implements UserService {
                     }
                     LOGGER.error("An error occurs while trying to update a user", ex);
                     return Single.error(new TechnicalManagementException("An error occurs while trying to update a user", ex));
-                });
+                }));
     }
 
     @Override
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/model/NewUser.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/model/NewUser.java
index 0df5303397..59ebc14ea8 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/model/NewUser.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/model/NewUser.java
@@ -15,30 +15,43 @@
  */
 package io.gravitee.am.service.model;
 
-import javax.validation.constraints.NotNull;
+import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
 import java.util.Date;
 import java.util.Map;
 
+import static io.gravitee.am.service.authentication.crypto.password.PasswordValidator.PASSWORD_MAX_LENGTH;
+import static io.gravitee.am.service.validators.EmailValidator.EMAIL_MAX_LENGTH;
+import static io.gravitee.am.service.validators.EmailValidator.EMAIL_PATTERN;
+import static io.gravitee.am.service.validators.UserValidator.*;
+
 /**
  * @author Titouan COMPIEGNE (titouan.compiegne at graviteesource.com)
  * @author GraviteeSource Team
  */
 public class NewUser {
 
-    @NotNull
+    @NotBlank
+    @Size(max = DEFAULT_MAX_LENGTH)
+    @Pattern(regexp = USERNAME_PATTERN, message = "invalid username")
     private String username;
 
+    @Size(max = PASSWORD_MAX_LENGTH, message = "must not be greater than "+ PASSWORD_MAX_LENGTH)
     private String password;
 
-    @NotNull
-    @Pattern(regexp = "^[\\w!#$%&’*+/=?`{|}~^-]+(?:\\.[\\w!#$%&’*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$", message = "must be a well-formed email address")
+    @NotBlank
+    @Pattern(regexp = EMAIL_PATTERN, message = "must be a well-formed email address")
     private String email;
 
+    @Pattern(regexp = NAME_STRICT_PATTERN, message = "invalid first name")
     private String firstName;
 
+    @Size(max = DEFAULT_MAX_LENGTH,  message = "must not be greater than "+ DEFAULT_MAX_LENGTH)
+    @Pattern(regexp = NAME_STRICT_PATTERN, message = "invalid last name")
     private String lastName;
 
+    @Size(max = DEFAULT_MAX_LENGTH,  message = "must not be greater than "+ DEFAULT_MAX_LENGTH)
     private String externalId;
 
     private boolean accountNonExpired = true;
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/model/UpdateUser.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/model/UpdateUser.java
index f7dd92a804..55dbb671a2 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/model/UpdateUser.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/model/UpdateUser.java
@@ -15,25 +15,35 @@
  */
 package io.gravitee.am.service.model;
 
+import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
 import java.util.Date;
 import java.util.Map;
 
+import static io.gravitee.am.service.validators.EmailValidator.EMAIL_MAX_LENGTH;
+import static io.gravitee.am.service.validators.EmailValidator.EMAIL_PATTERN;
+import static io.gravitee.am.service.validators.UserValidator.*;
+
 /**
  * @author Titouan COMPIEGNE (titouan.compiegne at graviteesource.com)
  * @author GraviteeSource Team
  */
 public class UpdateUser {
 
-    @NotNull
-    @Pattern(regexp = "^[\\w!#$%&’*+/=?`{|}~^-]+(?:\\.[\\w!#$%&’*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$", message = "must be a well-formed email address")
+    @NotBlank
+    @Size(max = EMAIL_MAX_LENGTH,  message = "must not be greater than "+ EMAIL_MAX_LENGTH)
+    @Pattern(regexp = EMAIL_PATTERN, message = "must be a well-formed email address")
     private String email;
 
+    @Pattern(regexp = NAME_STRICT_PATTERN, message = "invalid first name")
     private String firstName;
 
+    @Pattern(regexp = NAME_STRICT_PATTERN, message = "invalid last name")
     private String lastName;
 
+    @Size(max = DEFAULT_MAX_LENGTH,  message = "must not be greater than "+ DEFAULT_MAX_LENGTH)
     private String externalId;
 
     private boolean accountNonExpired = true;
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/validators/EmailValidator.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/validators/EmailValidator.java
new file mode 100644
index 0000000000..8e647cb88b
--- /dev/null
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/validators/EmailValidator.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed 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 io.gravitee.am.service.validators;
+
+import java.util.regex.Pattern;
+
+/**
+ * An email validator based on the rules defined by OWASP and excluding '*' and '&' characters.
+ * <a href=https://owasp.org/www-community/OWASP_Validation_Regex_Repository>OWASP_Validation_Regex_Repository</a>.
+ *
+ * @author Jeoffrey HAEYAERT (jeoffrey.haeyaert at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public class EmailValidator {
+
+    public static final int EMAIL_MAX_LENGTH = 320;
+    public static final String EMAIL_PATTERN = "^[a-zA-Z0-9_+-]+(?:\\.[a-zA-Z0-9_+-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
+
+    private static final Pattern PATTERN = Pattern.compile(EMAIL_PATTERN);
+
+    /**
+     * Validate the email against owasp pattern.
+     * Note: <code>null</code> is considered as valid to allow validation of optional email.
+     *
+     * @param email the email to validate
+     * @return <code>true</code> if email is valid, <code>false</code> else.
+     */
+    public static boolean isValid(String email) {
+        return email == null || (email.length() <= EMAIL_MAX_LENGTH && PATTERN.matcher(email).matches());
+    }
+}
\ No newline at end of file
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/validators/UserValidator.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/validators/UserValidator.java
new file mode 100644
index 0000000000..1ffb040bba
--- /dev/null
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/validators/UserValidator.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed 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 io.gravitee.am.service.validators;
+
+import io.gravitee.am.model.User;
+import io.gravitee.am.service.exception.EmailFormatInvalidException;
+import io.gravitee.am.service.exception.InvalidUserException;
+import io.reactivex.Completable;
+
+import java.util.regex.Pattern;
+
+/**
+ * A validator which can be used to validate user information. It simply allows to validate that a string does not contains prohibited characters such as '$', '£', ... and has a max size of 100 characters.
+ * This validator is mainly used to validate first name or last name.
+ *
+ * Note: a <code>null</code> value is considered valid.
+ *
+ * @author Jeoffrey HAEYAERT (jeoffrey.haeyaert at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public class UserValidator {
+
+    public static final int DEFAULT_MAX_LENGTH = 100;
+    public static final String NAME_STRICT_PATTERN = "^[^±!@£$%^&*_+§¡€#¢¶•ªº«»\\\\/<>?:;|=.,]{1," + DEFAULT_MAX_LENGTH + "}$";
+    public static final String NAME_LAX_PATTERN = "^[^±!@£$%^&*_+§¡€#¢¶•ªº«»\\\\/<>?|=]{1," + DEFAULT_MAX_LENGTH + "}$";
+    public static final String USERNAME_PATTERN = "^[^±!£$%^&*+§¡€#¢¶•ªº«»\\\\/<>?:;|=,]{1," + DEFAULT_MAX_LENGTH + "}$";
+
+    private static final Pattern NAME_STRICT_PATTERN_COMPILED = Pattern.compile(NAME_STRICT_PATTERN);
+    private static final Pattern NAME_LAX_PATTERN_COMPILED = Pattern.compile(NAME_LAX_PATTERN);
+    private static final Pattern USERNAME_PATTERN_COMPILED = Pattern.compile(USERNAME_PATTERN);
+
+    public static Completable validate(User user) {
+
+        if (!isValid(user.getUsername(), USERNAME_PATTERN_COMPILED)) {
+            return Completable.error(new InvalidUserException(String.format("Username [%s] is not a valid value", user.getUsername())));
+        }
+
+        if (!EmailValidator.isValid(user.getEmail())) {
+            return Completable.error(new EmailFormatInvalidException(user.getEmail()));
+        }
+
+        if (!isValid(user.getFirstName(), NAME_STRICT_PATTERN_COMPILED)) {
+            return Completable.error(new InvalidUserException(String.format("First name [%s] is not a valid value", user.getFirstName())));
+        }
+
+        if (!isValid(user.getLastName(), NAME_STRICT_PATTERN_COMPILED)) {
+            return Completable.error(new InvalidUserException(String.format("Last name [%s] is not a valid value", user.getLastName())));
+        }
+
+        if (!isValid(user.getDisplayName(), NAME_LAX_PATTERN_COMPILED)) {
+            return Completable.error(new InvalidUserException(String.format("Display name [%s] is not a valid value", user.getDisplayName())));
+        }
+
+        if (!isValid(user.getNickName(), NAME_LAX_PATTERN_COMPILED)) {
+            return Completable.error(new InvalidUserException(String.format("Nick name [%s] is not a valid value", user.getNickName())));
+        }
+
+        if (user.getExternalId() != null && user.getExternalId().length() > DEFAULT_MAX_LENGTH) {
+            return Completable.error(new InvalidUserException(String.format("External id [%s] is not a valid value", user.getExternalId())));
+        }
+
+        return Completable.complete();
+    }
+
+    private static boolean isValid(String userInfo, Pattern pattern) {
+        return userInfo == null || pattern.matcher(userInfo).matches();
+    }
+}
\ No newline at end of file
diff --git a/postman/collections/graviteeio-am-scim-collection-app-version.json b/postman/collections/graviteeio-am-scim-collection-app-version.json
index 323d7c96bb..6ca90cd184 100644
--- a/postman/collections/graviteeio-am-scim-collection-app-version.json
+++ b/postman/collections/graviteeio-am-scim-collection-app-version.json
@@ -1500,6 +1500,234 @@
                   },
                   "response": []
                 },
+                {
+                  "name": "Invalid request - userName invalid",
+                  "event": [
+                    {
+                      "listen": "test",
+                      "script": {
+                        "id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+                        "exec": [
+                          "pm.test(\"Status code is 400\", function () {",
+                          "    pm.response.to.have.status(400);",
+                          "});",
+                          "",
+                          "pm.test(\"SCIM create userName field invalid\", function () {",
+                          "    var jsonData = pm.response.json();",
+                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.scimType).to.eql(\"invalidValue\");",
+                          "    pm.expect(jsonData.detail).to.eql(\"Username [#Invalid] is not a valid value\");",
+                          "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
+                          "});"
+                        ],
+                        "type": "text/javascript"
+                      }
+                    }
+                  ],
+                  "request": {
+                    "method": "POST",
+                    "header": [
+                      {
+                        "key": "Authorization",
+                        "type": "text",
+                        "value": "Bearer {{access_token}}"
+                      },
+                      {
+                        "key": "Content-Type",
+                        "name": "Content-Type",
+                        "type": "text",
+                        "value": "application/json"
+                      }
+                    ],
+                    "body": {
+                      "mode": "raw",
+                      "raw": "{\n     \"schemas\":[\"urn:ietf:params:scim:schemas:core:2.0:User\"],\n     \"externalId\":\"bjensen\",\n     \"userName\": \"#Invalid\",\n     \"name\":{\n       \"formatted\":\"Ms. Barbara J Jensen III\",\n       \"familyName\":\"Jensen\",\n       \"givenName\":\"Barbara\"\n     }\n   }"
+                    },
+                    "url": {
+                      "raw": "{{gateway_url}}/{{domain}}/scim/Users",
+                      "host": [
+                        "{{gateway_url}}"
+                      ],
+                      "path": [
+                        "{{domain}}",
+                        "scim",
+                        "Users"
+                      ]
+                    }
+                  },
+                  "response": []
+                },
+                {
+                  "name": "Invalid request - familyName invalid",
+                  "event": [
+                    {
+                      "listen": "test",
+                      "script": {
+                        "id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+                        "exec": [
+                          "pm.test(\"Status code is 400\", function () {",
+                          "    pm.response.to.have.status(400);",
+                          "});",
+                          "",
+                          "pm.test(\"SCIM create familyName field invalid\", function () {",
+                          "    var jsonData = pm.response.json();",
+                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.scimType).to.eql(\"invalidValue\");",
+                          "    pm.expect(jsonData.detail).to.eql(\"Last name [#Invalid] is not a valid value\");",
+                          "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
+                          "});"
+                        ],
+                        "type": "text/javascript"
+                      }
+                    }
+                  ],
+                  "request": {
+                    "method": "POST",
+                    "header": [
+                      {
+                        "key": "Authorization",
+                        "type": "text",
+                        "value": "Bearer {{access_token}}"
+                      },
+                      {
+                        "key": "Content-Type",
+                        "name": "Content-Type",
+                        "type": "text",
+                        "value": "application/json"
+                      }
+                    ],
+                    "body": {
+                      "mode": "raw",
+                      "raw": "{\n     \"schemas\":[\"urn:ietf:params:scim:schemas:core:2.0:User\"],\n     \"externalId\":\"bjensen\",\n     \"userName\": \"bjensen@example.com\",\n     \"name\":{\n       \"formatted\":\"Ms. Barbara J Jensen III\",\n       \"familyName\":\"#Invalid\",\n       \"givenName\":\"Barbara\"\n     }\n   }"
+                    },
+                    "url": {
+                      "raw": "{{gateway_url}}/{{domain}}/scim/Users",
+                      "host": [
+                        "{{gateway_url}}"
+                      ],
+                      "path": [
+                        "{{domain}}",
+                        "scim",
+                        "Users"
+                      ]
+                    }
+                  },
+                  "response": []
+                },
+                {
+                  "name": "Invalid request - givenName invalid",
+                  "event": [
+                    {
+                      "listen": "test",
+                      "script": {
+                        "id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+                        "exec": [
+                          "pm.test(\"Status code is 400\", function () {",
+                          "    pm.response.to.have.status(400);",
+                          "});",
+                          "",
+                          "pm.test(\"SCIM create givenName field invalid\", function () {",
+                          "    var jsonData = pm.response.json();",
+                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.scimType).to.eql(\"invalidValue\");",
+                          "    pm.expect(jsonData.detail).to.eql(\"First name [#Invalid] is not a valid value\");",
+                          "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
+                          "});"
+                        ],
+                        "type": "text/javascript"
+                      }
+                    }
+                  ],
+                  "request": {
+                    "method": "POST",
+                    "header": [
+                      {
+                        "key": "Authorization",
+                        "type": "text",
+                        "value": "Bearer {{access_token}}"
+                      },
+                      {
+                        "key": "Content-Type",
+                        "name": "Content-Type",
+                        "type": "text",
+                        "value": "application/json"
+                      }
+                    ],
+                    "body": {
+                      "mode": "raw",
+                      "raw": "{\n     \"schemas\":[\"urn:ietf:params:scim:schemas:core:2.0:User\"],\n     \"externalId\":\"bjensen\",\n     \"userName\": \"bjensen@example.com\",\n     \"name\":{\n       \"formatted\":\"Ms. Barbara J Jensen III\",\n       \"familyName\": \"Jensen\",\n       \"givenName\":\"#Invalid\"\n     }\n   }"
+                    },
+                    "url": {
+                      "raw": "{{gateway_url}}/{{domain}}/scim/Users",
+                      "host": [
+                        "{{gateway_url}}"
+                      ],
+                      "path": [
+                        "{{domain}}",
+                        "scim",
+                        "Users"
+                      ]
+                    }
+                  },
+                  "response": []
+                },
+                {
+                  "name": "Invalid request - email invalid",
+                  "event": [
+                    {
+                      "listen": "test",
+                      "script": {
+                        "id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+                        "exec": [
+                          "pm.test(\"Status code is 400\", function () {",
+                          "    pm.response.to.have.status(400);",
+                          "});",
+                          "",
+                          "pm.test(\"SCIM create givenName field invalid\", function () {",
+                          "    var jsonData = pm.response.json();",
+                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.scimType).to.eql(\"invalidValue\");",
+                          "    pm.expect(jsonData.detail).to.eql(\"Value [#Invalid] is not a valid email.\");",
+                          "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
+                          "});"
+                        ],
+                        "type": "text/javascript"
+                      }
+                    }
+                  ],
+                  "request": {
+                    "method": "POST",
+                    "header": [
+                      {
+                        "key": "Authorization",
+                        "type": "text",
+                        "value": "Bearer {{access_token}}"
+                      },
+                      {
+                        "key": "Content-Type",
+                        "name": "Content-Type",
+                        "type": "text",
+                        "value": "application/json"
+                      }
+                    ],
+                    "body": {
+                      "mode": "raw",
+                      "raw": "{\n     \"schemas\":[\"urn:ietf:params:scim:schemas:core:2.0:User\"],\n     \"externalId\":\"bjensen\",\n     \"userName\": \"bjensen@example.com\",\n     \"name\":{\n       \"formatted\":\"Ms. Barbara J Jensen III\",\n       \"familyName\": \"Jensen\",\n       \"givenName\": \"Barbara\"\n     },\n     \"emails\": [\n\t    {\n\t      \"value\": \"#Invalid\",\n\t      \"type\": \"work\",\n\t      \"primary\": true\n\t    }\n\t  ]\n   }"
+                    },
+                    "url": {
+                      "raw": "{{gateway_url}}/{{domain}}/scim/Users",
+                      "host": [
+                        "{{gateway_url}}"
+                      ],
+                      "path": [
+                        "{{domain}}",
+                        "scim",
+                        "Users"
+                      ]
+                    }
+                  },
+                  "response": []
+                },
                 {
                   "name": "Create user",
                   "event": [
@@ -1564,13 +1792,13 @@
                       "script": {
                         "id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
                         "exec": [
-                          "pm.test(\"Status code is 400\", function () {",
-                          "    pm.response.to.have.status(400);",
+                          "pm.test(\"Status code is 409\", function () {",
+                          "    pm.response.to.have.status(409);",
                           "});",
                           "",
                           "pm.test(\"SCIM create user uniqueness\", function () {",
                           "    var jsonData = pm.response.json();",
-                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.status).to.eql(\"409\");",
                           "    pm.expect(jsonData.scimType).to.eql(\"uniqueness\");",
                           "    pm.expect(jsonData.detail).to.eql(\"User with username [bjensen@example.com] already exists\");",
                           "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
@@ -2178,13 +2406,13 @@
                       "script": {
                         "id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
                         "exec": [
-                          "pm.test(\"Status code is 400\", function () {",
-                          "    pm.response.to.have.status(400);",
+                          "pm.test(\"Status code is 409\", function () {",
+                          "    pm.response.to.have.status(409);",
                           "});",
                           "",
                           "pm.test(\"SCIM create group uniqueness\", function () {",
                           "    var jsonData = pm.response.json();",
-                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.status).to.eql(\"409\");",
                           "    pm.expect(jsonData.scimType).to.eql(\"uniqueness\");",
                           "    pm.expect(jsonData.detail).to.eql(\"Group with display name [Tour Guides] already exists\");",
                           "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
diff --git a/postman/collections/graviteeio-am-scim-collection.json b/postman/collections/graviteeio-am-scim-collection.json
index 9b23606c98..64b4c7e57f 100644
--- a/postman/collections/graviteeio-am-scim-collection.json
+++ b/postman/collections/graviteeio-am-scim-collection.json
@@ -1518,6 +1518,234 @@
                   },
                   "response": []
                 },
+                {
+                  "name": "Invalid request - userName invalid",
+                  "event": [
+                    {
+                      "listen": "test",
+                      "script": {
+                        "id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+                        "exec": [
+                          "pm.test(\"Status code is 400\", function () {",
+                          "    pm.response.to.have.status(400);",
+                          "});",
+                          "",
+                          "pm.test(\"SCIM create userName field invalid\", function () {",
+                          "    var jsonData = pm.response.json();",
+                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.scimType).to.eql(\"invalidValue\");",
+                          "    pm.expect(jsonData.detail).to.eql(\"Username [#Invalid] is not a valid value\");",
+                          "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
+                          "});"
+                        ],
+                        "type": "text/javascript"
+                      }
+                    }
+                  ],
+                  "request": {
+                    "method": "POST",
+                    "header": [
+                      {
+                        "key": "Authorization",
+                        "type": "text",
+                        "value": "Bearer {{access_token}}"
+                      },
+                      {
+                        "key": "Content-Type",
+                        "name": "Content-Type",
+                        "type": "text",
+                        "value": "application/json"
+                      }
+                    ],
+                    "body": {
+                      "mode": "raw",
+                      "raw": "{\n     \"schemas\":[\"urn:ietf:params:scim:schemas:core:2.0:User\"],\n     \"externalId\":\"bjensen\",\n     \"userName\": \"#Invalid\",\n     \"name\":{\n       \"formatted\":\"Ms. Barbara J Jensen III\",\n       \"familyName\":\"Jensen\",\n       \"givenName\":\"Barbara\"\n     }\n   }"
+                    },
+                    "url": {
+                      "raw": "{{gateway_url}}/{{domain}}/scim/Users",
+                      "host": [
+                        "{{gateway_url}}"
+                      ],
+                      "path": [
+                        "{{domain}}",
+                        "scim",
+                        "Users"
+                      ]
+                    }
+                  },
+                  "response": []
+                },
+                {
+                  "name": "Invalid request - familyName invalid",
+                  "event": [
+                    {
+                      "listen": "test",
+                      "script": {
+                        "id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+                        "exec": [
+                          "pm.test(\"Status code is 400\", function () {",
+                          "    pm.response.to.have.status(400);",
+                          "});",
+                          "",
+                          "pm.test(\"SCIM create familyName field invalid\", function () {",
+                          "    var jsonData = pm.response.json();",
+                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.scimType).to.eql(\"invalidValue\");",
+                          "    pm.expect(jsonData.detail).to.eql(\"Last name [#Invalid] is not a valid value\");",
+                          "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
+                          "});"
+                        ],
+                        "type": "text/javascript"
+                      }
+                    }
+                  ],
+                  "request": {
+                    "method": "POST",
+                    "header": [
+                      {
+                        "key": "Authorization",
+                        "type": "text",
+                        "value": "Bearer {{access_token}}"
+                      },
+                      {
+                        "key": "Content-Type",
+                        "name": "Content-Type",
+                        "type": "text",
+                        "value": "application/json"
+                      }
+                    ],
+                    "body": {
+                      "mode": "raw",
+                      "raw": "{\n     \"schemas\":[\"urn:ietf:params:scim:schemas:core:2.0:User\"],\n     \"externalId\":\"bjensen\",\n     \"userName\": \"bjensen@example.com\",\n     \"name\":{\n       \"formatted\":\"Ms. Barbara J Jensen III\",\n       \"familyName\":\"#Invalid\",\n       \"givenName\":\"Barbara\"\n     }\n   }"
+                    },
+                    "url": {
+                      "raw": "{{gateway_url}}/{{domain}}/scim/Users",
+                      "host": [
+                        "{{gateway_url}}"
+                      ],
+                      "path": [
+                        "{{domain}}",
+                        "scim",
+                        "Users"
+                      ]
+                    }
+                  },
+                  "response": []
+                },
+                {
+                  "name": "Invalid request - givenName invalid",
+                  "event": [
+                    {
+                      "listen": "test",
+                      "script": {
+                        "id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+                        "exec": [
+                          "pm.test(\"Status code is 400\", function () {",
+                          "    pm.response.to.have.status(400);",
+                          "});",
+                          "",
+                          "pm.test(\"SCIM create givenName field invalid\", function () {",
+                          "    var jsonData = pm.response.json();",
+                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.scimType).to.eql(\"invalidValue\");",
+                          "    pm.expect(jsonData.detail).to.eql(\"First name [#Invalid] is not a valid value\");",
+                          "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
+                          "});"
+                        ],
+                        "type": "text/javascript"
+                      }
+                    }
+                  ],
+                  "request": {
+                    "method": "POST",
+                    "header": [
+                      {
+                        "key": "Authorization",
+                        "type": "text",
+                        "value": "Bearer {{access_token}}"
+                      },
+                      {
+                        "key": "Content-Type",
+                        "name": "Content-Type",
+                        "type": "text",
+                        "value": "application/json"
+                      }
+                    ],
+                    "body": {
+                      "mode": "raw",
+                      "raw": "{\n     \"schemas\":[\"urn:ietf:params:scim:schemas:core:2.0:User\"],\n     \"externalId\":\"bjensen\",\n     \"userName\": \"bjensen@example.com\",\n     \"name\":{\n       \"formatted\":\"Ms. Barbara J Jensen III\",\n       \"familyName\": \"Jensen\",\n       \"givenName\":\"#Invalid\"\n     }\n   }"
+                    },
+                    "url": {
+                      "raw": "{{gateway_url}}/{{domain}}/scim/Users",
+                      "host": [
+                        "{{gateway_url}}"
+                      ],
+                      "path": [
+                        "{{domain}}",
+                        "scim",
+                        "Users"
+                      ]
+                    }
+                  },
+                  "response": []
+                },
+                {
+                  "name": "Invalid request - email invalid",
+                  "event": [
+                    {
+                      "listen": "test",
+                      "script": {
+                        "id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+                        "exec": [
+                          "pm.test(\"Status code is 400\", function () {",
+                          "    pm.response.to.have.status(400);",
+                          "});",
+                          "",
+                          "pm.test(\"SCIM create givenName field invalid\", function () {",
+                          "    var jsonData = pm.response.json();",
+                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.scimType).to.eql(\"invalidValue\");",
+                          "    pm.expect(jsonData.detail).to.eql(\"Value [#Invalid] is not a valid email.\");",
+                          "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
+                          "});"
+                        ],
+                        "type": "text/javascript"
+                      }
+                    }
+                  ],
+                  "request": {
+                    "method": "POST",
+                    "header": [
+                      {
+                        "key": "Authorization",
+                        "type": "text",
+                        "value": "Bearer {{access_token}}"
+                      },
+                      {
+                        "key": "Content-Type",
+                        "name": "Content-Type",
+                        "type": "text",
+                        "value": "application/json"
+                      }
+                    ],
+                    "body": {
+                      "mode": "raw",
+                      "raw": "{\n     \"schemas\":[\"urn:ietf:params:scim:schemas:core:2.0:User\"],\n     \"externalId\":\"bjensen\",\n     \"userName\": \"bjensen@example.com\",\n     \"name\":{\n       \"formatted\":\"Ms. Barbara J Jensen III\",\n       \"familyName\": \"Jensen\",\n       \"givenName\": \"Barbara\"\n     },\n     \"emails\": [\n\t    {\n\t      \"value\": \"#Invalid\",\n\t      \"type\": \"work\",\n\t      \"primary\": true\n\t    }\n\t  ]\n   }"
+                    },
+                    "url": {
+                      "raw": "{{gateway_url}}/{{domain}}/scim/Users",
+                      "host": [
+                        "{{gateway_url}}"
+                      ],
+                      "path": [
+                        "{{domain}}",
+                        "scim",
+                        "Users"
+                      ]
+                    }
+                  },
+                  "response": []
+                },
                 {
                   "name": "Create user",
                   "event": [
@@ -1582,13 +1810,13 @@
                       "script": {
                         "id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
                         "exec": [
-                          "pm.test(\"Status code is 400\", function () {",
-                          "    pm.response.to.have.status(400);",
+                          "pm.test(\"Status code is 409\", function () {",
+                          "    pm.response.to.have.status(409);",
                           "});",
                           "",
                           "pm.test(\"SCIM create user uniqueness\", function () {",
                           "    var jsonData = pm.response.json();",
-                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.status).to.eql(\"409\");",
                           "    pm.expect(jsonData.scimType).to.eql(\"uniqueness\");",
                           "    pm.expect(jsonData.detail).to.eql(\"User with username [bjensen@example.com] already exists\");",
                           "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
@@ -2199,13 +2427,13 @@
                       "script": {
                         "id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
                         "exec": [
-                          "pm.test(\"Status code is 400\", function () {",
-                          "    pm.response.to.have.status(400);",
+                          "pm.test(\"Status code is 409\", function () {",
+                          "    pm.response.to.have.status(409);",
                           "});",
                           "",
                           "pm.test(\"SCIM create group uniqueness\", function () {",
                           "    var jsonData = pm.response.json();",
-                          "    pm.expect(jsonData.status).to.eql(\"400\");",
+                          "    pm.expect(jsonData.status).to.eql(\"409\");",
                           "    pm.expect(jsonData.scimType).to.eql(\"uniqueness\");",
                           "    pm.expect(jsonData.detail).to.eql(\"Group with display name [Tour Guides] already exists\");",
                           "    pm.expect(jsonData.schemas).to.eql(['urn:ietf:params:scim:api:messages:2.0:Error']);",
diff --git a/postman/collections/graviteeio-am-user-management-collection-app-version.json b/postman/collections/graviteeio-am-user-management-collection-app-version.json
index 0f5cce48be..8fd80f9f53 100644
--- a/postman/collections/graviteeio-am-user-management-collection-app-version.json
+++ b/postman/collections/graviteeio-am-user-management-collection-app-version.json
@@ -902,7 +902,7 @@
 													"",
 													"pm.test(\"UM - create user - username field required\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"[username: must not be null]\");",
+													"    pm.expect(jsonData.message).to.eql(\"[username: must not be blank]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -961,7 +961,7 @@
 													"",
 													"pm.test(\"UM - create user - email field required\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"[email: must not be null]\");",
+													"    pm.expect(jsonData.message).to.eql(\"[email: must not be blank]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1066,7 +1066,7 @@
 									"response": []
 								},
 								{
-									"name": "Invalid request - email malformed",
+									"name": "Invalid request - username invalid",
 									"event": [
 										{
 											"listen": "test",
@@ -1077,9 +1077,9 @@
 													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - create user - email malformed\", function () {",
+													"pm.test(\"UM - create user - username invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"[jensen.barba: must be a well-formed email address]\");",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid username]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1103,7 +1103,7 @@
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barba\",\n\t\"password\": \"password\"\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"#Invalid\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1125,28 +1125,20 @@
 									"response": []
 								},
 								{
-									"name": "Create user",
+									"name": "Invalid request - email invalid",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
-													"pm.test(\"Status code is 201\", function () {",
-													"    pm.response.to.have.status(201);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - create user\", function () {",
+													"pm.test(\"UM - create user - email invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    let domain = pm.environment.get(\"domain\");",
-													"    ",
-													"    pm.expect(jsonData).to.have.property('id');",
-													"    pm.expect(jsonData.internal).to.eql(true);",
-													"    pm.expect(jsonData.enabled).to.eql(true);",
-													"    pm.expect(jsonData.preRegistration).to.eql(false);",
-													"    pm.expect(jsonData.registrationCompleted).to.eql(true);",
-													"    pm.expect(jsonData.source).to.eql('default-idp-'+domain)",
-													"    pm.environment.set('userUM', jsonData.id);",
+													"    pm.expect(jsonData.message).to.eql(\"[jensen.barba: must be a well-formed email address]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1158,19 +1150,19 @@
 										"header": [
 											{
 												"key": "Authorization",
-												"value": "Bearer {{token}}",
-												"type": "text"
+												"type": "text",
+												"value": "Bearer {{token}}"
 											},
 											{
 												"key": "Content-Type",
 												"name": "Content-Type",
-												"value": "application/json",
-												"type": "text"
+												"type": "text",
+												"value": "application/json"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barba\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1192,20 +1184,20 @@
 									"response": []
 								},
 								{
-									"name": "Invalid request - username already exists",
+									"name": "Invalid request - first name invalid",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
 													"pm.test(\"Status code is 400\", function () {",
 													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - create user - uniqueness\", function () {",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"A user [jensen.barbara] already exists.\");",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid first name]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1229,7 +1221,7 @@
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
+											"raw": "{\n\t\"firstName\": \"#Invalid\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1251,20 +1243,20 @@
 									"response": []
 								},
 								{
-									"name": "Invalid request - username already exists - case insensitive",
+									"name": "Invalid request - last name invalid",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
 													"pm.test(\"Status code is 400\", function () {",
 													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - create user - uniqueness\", function () {",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"A user [jensen.BarBara] already exists.\");",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid last name]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1288,7 +1280,7 @@
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.BarBara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"#Invalid\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1308,24 +1300,22 @@
 										}
 									},
 									"response": []
-								}
-							],
-							"protocolProfileBehavior": {},
-							"_postman_isSubFolder": true
-						},
-						{
-							"name": "Pre-Register",
-							"item": [
+								},
 								{
-									"name": "Patch domain - dynamic user registration",
+									"name": "Invalid request - password too long",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "29adabbe-3199-4e82-afb7-851bdd50b1bb",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
-													"pm.test(\"Status code is 200\", function () {",
-													"    pm.response.to.have.status(200);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: must not be greater than 72]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1333,30 +1323,26 @@
 										}
 									],
 									"request": {
-										"method": "PATCH",
+										"method": "POST",
 										"header": [
 											{
 												"key": "Authorization",
-												"value": "Bearer {{token}}",
-												"type": "text"
+												"type": "text",
+												"value": "Bearer {{token}}"
 											},
 											{
 												"key": "Content-Type",
-												"value": "application/json",
-												"type": "text"
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n  \"accountSettings\": {\n    \"dynamicUserRegistration\": true\n  }\n}",
-											"options": {
-												"raw": {
-													"language": "json"
-												}
-											}
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n}"
 										},
 										"url": {
-											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}",
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
 											"host": [
 												"{{management_url}}"
 											],
@@ -1367,39 +1353,28 @@
 												"environments",
 												"{{defaultEnvironmentId}}",
 												"domains",
-												"{{domain}}"
+												"{{domain}}",
+												"users"
 											]
 										}
 									},
 									"response": []
 								},
 								{
-									"name": "Create user",
+									"name": "Invalid request - email too long",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
-													"pm.test(\"Status code is 201\", function () {",
-													"    pm.response.to.have.status(201);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - pre-register user\", function () {",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    let domain = pm.environment.get(\"domain\");",
-													"    ",
-													"    pm.expect(jsonData).to.have.property('id');",
-													"    pm.expect(jsonData).to.have.property('registrationUserUri');",
-													"    pm.expect(jsonData).to.have.property('registrationAccessToken');",
-													"    pm.expect(jsonData.internal).to.eql(true);",
-													"    pm.expect(jsonData.enabled).to.eql(false);",
-													"    pm.expect(jsonData.preRegistration).to.eql(true);",
-													"    pm.expect(jsonData.registrationCompleted).to.eql(false);",
-													"    pm.expect(jsonData.source).to.eql('default-idp-'+domain)",
-													"    pm.environment.set('userTemp', jsonData.id);",
-													"    pm.environment.set('userRegistrationURI', jsonData.registrationUserUri);",
-													"    pm.environment.set('userRegistrationToken', jsonData.registrationAccessToken);",
+													"    pm.expect(jsonData.message).to.eql(\"[jensen.barbara@maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaail.com: must not be greater than 320]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1411,19 +1386,19 @@
 										"header": [
 											{
 												"key": "Authorization",
-												"value": "Bearer {{token}}",
-												"type": "text"
+												"type": "text",
+												"value": "Bearer {{token}}"
 											},
 											{
 												"key": "Content-Type",
 												"name": "Content-Type",
-												"value": "application/json",
-												"type": "text"
+												"type": "text",
+												"value": "application/json"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"John\",\n\t\"lastName\": \"Doe\",\n\t\"username\": \"john.doe\",\n\t\"email\": \"john.doe@mail.com\",\n\t\"preRegistration\": true\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1445,65 +1420,87 @@
 									"response": []
 								},
 								{
-									"name": "Initiate post registration flow",
+									"name": "Invalid request - external id too long",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "fb56a849-b090-4e80-9c8c-eca9f4d72e85",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
-													"pm.test(\"Status code is 200\", function () {",
-													"    pm.response.to.have.status(200);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"Should be a redirection to confirm registration page\", function() {",
-													"    pm.response.to.be.ok;",
-													"    var responseHTML = cheerio(pm.response.text());",
-													"    tests['Redirect to confirm registration page'] = responseHTML.find('span').text().includes('Thanks for signing up, please complete the form to activate your account');",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[Tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long: must not be greater than 100]\");",
 													"});"
 												],
 												"type": "text/javascript"
 											}
-										},
-										{
-											"listen": "prerequest",
-											"script": {
-												"id": "904f0113-b2b9-4645-9511-48bb10791506",
-												"exec": [
-													""
-												],
-												"type": "text/javascript"
-											}
 										}
 									],
 									"request": {
-										"method": "GET",
-										"header": [],
+										"method": "POST",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\",\n\t\"externalId\": \"Tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long\"\n}"
+										},
 										"url": {
-											"raw": "{{userRegistrationURI}}?token={{userRegistrationToken}}",
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
 											"host": [
-												"{{userRegistrationURI}}"
+												"{{management_url}}"
 											],
-											"query": [
-												{
-													"key": "token",
-													"value": "{{userRegistrationToken}}"
-												}
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users"
 											]
 										}
 									},
 									"response": []
 								},
 								{
-									"name": "Delete user",
+									"name": "Create user",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
 												"exec": [
-													"pm.test(\"Status code is 204\", function () {",
-													"    pm.response.to.have.status(204);",
+													"pm.test(\"Status code is 201\", function () {",
+													"    pm.response.to.have.status(201);",
+													"});",
+													"",
+													"pm.test(\"UM - create user\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    let domain = pm.environment.get(\"domain\");",
+													"    ",
+													"    pm.expect(jsonData).to.have.property('id');",
+													"    pm.expect(jsonData.internal).to.eql(true);",
+													"    pm.expect(jsonData.enabled).to.eql(true);",
+													"    pm.expect(jsonData.preRegistration).to.eql(false);",
+													"    pm.expect(jsonData.registrationCompleted).to.eql(true);",
+													"    pm.expect(jsonData.source).to.eql('default-idp-'+domain)",
+													"    pm.environment.set('userUM', jsonData.id);",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1511,20 +1508,26 @@
 										}
 									],
 									"request": {
-										"method": "DELETE",
+										"method": "POST",
 										"header": [
 											{
 												"key": "Authorization",
-												"type": "text",
-												"value": "Bearer {{token}}"
+												"value": "Bearer {{token}}",
+												"type": "text"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"value": "application/json",
+												"type": "text"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": ""
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
-											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userTemp}}",
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
 											"host": [
 												"{{management_url}}"
 											],
@@ -1536,35 +1539,27 @@
 												"{{defaultEnvironmentId}}",
 												"domains",
 												"{{domain}}",
-												"users",
-												"{{userTemp}}"
+												"users"
 											]
 										}
 									},
 									"response": []
-								}
-							],
-							"protocolProfileBehavior": {},
-							"_postman_isSubFolder": true
-						},
-						{
-							"name": "Update",
-							"item": [
+								},
 								{
-									"name": "Invalid request - user not found",
+									"name": "Invalid request - username already exists",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
 												"exec": [
-													"pm.test(\"Status code is 404\", function () {",
-													"    pm.response.to.have.status(404);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - update user - unknown user\", function () {",
+													"pm.test(\"UM - create user - uniqueness\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"User [wrong-id] can not be found.\");",
+													"    pm.expect(jsonData.message).to.eql(\"A user [jensen.barbara] already exists.\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1572,7 +1567,7 @@
 										}
 									],
 									"request": {
-										"method": "PUT",
+										"method": "POST",
 										"header": [
 											{
 												"key": "Authorization",
@@ -1582,16 +1577,16 @@
 											{
 												"key": "Content-Type",
 												"name": "Content-Type",
-												"value": "application/json",
-												"type": "text"
+												"type": "text",
+												"value": "application/json"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@mail.com\"\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
-											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/wrong-id",
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
 											"host": [
 												"{{management_url}}"
 											],
@@ -1603,23 +1598,27 @@
 												"{{defaultEnvironmentId}}",
 												"domains",
 												"{{domain}}",
-												"users",
-												"wrong-id"
+												"users"
 											]
 										}
 									},
 									"response": []
 								},
 								{
-									"name": "Invalid request - malformed json",
+									"name": "Invalid request - username already exists - case insensitive",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
 												"exec": [
 													"pm.test(\"Status code is 400\", function () {",
 													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - uniqueness\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"A user [jensen.BarBara] already exists.\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1627,18 +1626,673 @@
 										}
 									],
 									"request": {
-										"method": "PUT",
+										"method": "POST",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.BarBara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users"
+											]
+										}
+									},
+									"response": []
+								}
+							],
+							"protocolProfileBehavior": {},
+							"_postman_isSubFolder": true
+						},
+						{
+							"name": "Pre-Register",
+							"item": [
+								{
+									"name": "Patch domain - dynamic user registration",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "29adabbe-3199-4e82-afb7-851bdd50b1bb",
+												"exec": [
+													"pm.test(\"Status code is 200\", function () {",
+													"    pm.response.to.have.status(200);",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PATCH",
+										"header": [
+											{
+												"key": "Authorization",
+												"value": "Bearer {{token}}",
+												"type": "text"
+											},
+											{
+												"key": "Content-Type",
+												"value": "application/json",
+												"type": "text"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n  \"accountSettings\": {\n    \"dynamicUserRegistration\": true\n  }\n}",
+											"options": {
+												"raw": {
+													"language": "json"
+												}
+											}
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Create user",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"exec": [
+													"pm.test(\"Status code is 201\", function () {",
+													"    pm.response.to.have.status(201);",
+													"});",
+													"",
+													"pm.test(\"UM - pre-register user\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    let domain = pm.environment.get(\"domain\");",
+													"    ",
+													"    pm.expect(jsonData).to.have.property('id');",
+													"    pm.expect(jsonData).to.have.property('registrationUserUri');",
+													"    pm.expect(jsonData).to.have.property('registrationAccessToken');",
+													"    pm.expect(jsonData.internal).to.eql(true);",
+													"    pm.expect(jsonData.enabled).to.eql(false);",
+													"    pm.expect(jsonData.preRegistration).to.eql(true);",
+													"    pm.expect(jsonData.registrationCompleted).to.eql(false);",
+													"    pm.expect(jsonData.source).to.eql('default-idp-'+domain)",
+													"    pm.environment.set('userTemp', jsonData.id);",
+													"    pm.environment.set('userRegistrationURI', jsonData.registrationUserUri);",
+													"    pm.environment.set('userRegistrationToken', jsonData.registrationAccessToken);",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "POST",
 										"header": [
 											{
 												"key": "Authorization",
 												"value": "Bearer {{token}}",
 												"type": "text"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"value": "application/json",
+												"type": "text"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"John\",\n\t\"lastName\": \"Doe\",\n\t\"username\": \"john.doe\",\n\t\"email\": \"john.doe@mail.com\",\n\t\"preRegistration\": true\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Initiate post registration flow",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "fb56a849-b090-4e80-9c8c-eca9f4d72e85",
+												"exec": [
+													"pm.test(\"Status code is 200\", function () {",
+													"    pm.response.to.have.status(200);",
+													"});",
+													"",
+													"pm.test(\"Should be a redirection to confirm registration page\", function() {",
+													"    pm.response.to.be.ok;",
+													"    var responseHTML = cheerio(pm.response.text());",
+													"    tests['Redirect to confirm registration page'] = responseHTML.find('span').text().includes('Thanks for signing up, please complete the form to activate your account');",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										},
+										{
+											"listen": "prerequest",
+											"script": {
+												"id": "904f0113-b2b9-4645-9511-48bb10791506",
+												"exec": [
+													""
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "GET",
+										"header": [],
+										"url": {
+											"raw": "{{userRegistrationURI}}?token={{userRegistrationToken}}",
+											"host": [
+												"{{userRegistrationURI}}"
+											],
+											"query": [
+												{
+													"key": "token",
+													"value": "{{userRegistrationToken}}"
+												}
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Delete user",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 204\", function () {",
+													"    pm.response.to.have.status(204);",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "DELETE",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
 											}
 										],
 										"body": {
 											"mode": "raw",
 											"raw": ""
 										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userTemp}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userTemp}}"
+											]
+										}
+									},
+									"response": []
+								}
+							],
+							"protocolProfileBehavior": {},
+							"_postman_isSubFolder": true
+						},
+						{
+							"name": "Update",
+							"item": [
+								{
+									"name": "Invalid request - user not found",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 404\", function () {",
+													"    pm.response.to.have.status(404);",
+													"});",
+													"",
+													"pm.test(\"UM - update user - unknown user\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"User [wrong-id] can not be found.\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"value": "application/json",
+												"type": "text"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@mail.com\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/wrong-id",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"wrong-id"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - malformed json",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"value": "Bearer {{token}}",
+												"type": "text"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": ""
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - email invalid",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - email invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[jensen.barba: must be a well-formed email address]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barba\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - first name invalid",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid first name]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"#Invalid\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@mail.com\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - last name invalid",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid last name]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"#Invalid\",\n\t\"email\": \"jensen.barbara@mail.com\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - email too long",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[jensen.barbara@maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaail.com: must not be greater than 320]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaail.com\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - external id too long",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[Tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long: must not be greater than 100]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"externalId\": \"Tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long\"\n}"
+										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
 											"host": [
diff --git a/postman/collections/graviteeio-am-user-management-collection.json b/postman/collections/graviteeio-am-user-management-collection.json
index 0a29ec711b..8e89f0daa3 100644
--- a/postman/collections/graviteeio-am-user-management-collection.json
+++ b/postman/collections/graviteeio-am-user-management-collection.json
@@ -902,7 +902,7 @@
 													"",
 													"pm.test(\"UM - create user - username field required\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"[username: must not be null]\");",
+													"    pm.expect(jsonData.message).to.eql(\"[username: must not be blank]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -961,7 +961,7 @@
 													"",
 													"pm.test(\"UM - create user - email field required\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"[email: must not be null]\");",
+													"    pm.expect(jsonData.message).to.eql(\"[email: must not be blank]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1066,7 +1066,7 @@
 									"response": []
 								},
 								{
-									"name": "Invalid request - email malformed",
+									"name": "Invalid request - username invalid",
 									"event": [
 										{
 											"listen": "test",
@@ -1077,9 +1077,9 @@
 													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - create user - email malformed\", function () {",
+													"pm.test(\"UM - create user - username invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"[jensen.barba: must be a well-formed email address]\");",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid username]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1103,7 +1103,7 @@
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barba\",\n\t\"password\": \"password\"\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"#Invalid\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1125,30 +1125,20 @@
 									"response": []
 								},
 								{
-									"name": "Create user",
+									"name": "Invalid request - email invalid",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
-													"pm.test(\"Status code is 201\", function () {",
-													"    pm.response.to.have.status(201);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - create user\", function () {",
+													"pm.test(\"UM - create user - email invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    let domain = pm.environment.get(\"domain\");",
-													"    ",
-													"    pm.expect(jsonData).to.have.property('id');",
-													"    pm.expect(jsonData).to.not.have.property('registrationUserUri');",
-													"    pm.expect(jsonData).to.not.have.property('registrationAccessToken');",
-													"    pm.expect(jsonData.internal).to.eql(true);",
-													"    pm.expect(jsonData.enabled).to.eql(true);",
-													"    pm.expect(jsonData.preRegistration).to.eql(false);",
-													"    pm.expect(jsonData.registrationCompleted).to.eql(true);",
-													"    pm.expect(jsonData.source).to.eql('default-idp-'+domain)",
-													"    pm.environment.set('userUM', jsonData.id);",
+													"    pm.expect(jsonData.message).to.eql(\"[jensen.barba: must be a well-formed email address]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1160,19 +1150,19 @@
 										"header": [
 											{
 												"key": "Authorization",
-												"value": "Bearer {{token}}",
-												"type": "text"
+												"type": "text",
+												"value": "Bearer {{token}}"
 											},
 											{
 												"key": "Content-Type",
 												"name": "Content-Type",
-												"value": "application/json",
-												"type": "text"
+												"type": "text",
+												"value": "application/json"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barba\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1194,20 +1184,20 @@
 									"response": []
 								},
 								{
-									"name": "Invalid request - username already exists",
+									"name": "Invalid request - first name invalid",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
 													"pm.test(\"Status code is 400\", function () {",
 													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - create user - uniqueness\", function () {",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"A user [jensen.barbara] already exists.\");",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid first name]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1231,7 +1221,7 @@
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
+											"raw": "{\n\t\"firstName\": \"#Invalid\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1253,20 +1243,20 @@
 									"response": []
 								},
 								{
-									"name": "Invalid request - username already exists - case insensitive",
+									"name": "Invalid request - last name invalid",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
 													"pm.test(\"Status code is 400\", function () {",
 													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - create user - uniqueness\", function () {",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"A user [jensen.BarBara] already exists.\");",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid last name]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1290,7 +1280,7 @@
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.BarBara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"#Invalid\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1310,24 +1300,22 @@
 										}
 									},
 									"response": []
-								}
-							],
-							"protocolProfileBehavior": {},
-							"_postman_isSubFolder": true
-						},
-						{
-							"name": "Pre-Register",
-							"item": [
+								},
 								{
-									"name": "Patch domain - dynamic user registration",
+									"name": "Invalid request - password too long",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "29adabbe-3199-4e82-afb7-851bdd50b1bb",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
-													"pm.test(\"Status code is 200\", function () {",
-													"    pm.response.to.have.status(200);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: must not be greater than 72]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1335,30 +1323,26 @@
 										}
 									],
 									"request": {
-										"method": "PATCH",
+										"method": "POST",
 										"header": [
 											{
 												"key": "Authorization",
-												"value": "Bearer {{token}}",
-												"type": "text"
+												"type": "text",
+												"value": "Bearer {{token}}"
 											},
 											{
 												"key": "Content-Type",
-												"value": "application/json",
-												"type": "text"
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n  \"accountSettings\": {\n    \"dynamicUserRegistration\": true\n  }\n}",
-											"options": {
-												"raw": {
-													"language": "json"
-												}
-											}
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n}"
 										},
 										"url": {
-											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}",
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
 											"host": [
 												"{{management_url}}"
 											],
@@ -1369,39 +1353,28 @@
 												"environments",
 												"{{defaultEnvironmentId}}",
 												"domains",
-												"{{domain}}"
+												"{{domain}}",
+												"users"
 											]
 										}
 									},
 									"response": []
 								},
 								{
-									"name": "Create user",
+									"name": "Invalid request - email too long",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
-													"pm.test(\"Status code is 201\", function () {",
-													"    pm.response.to.have.status(201);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - pre-register user\", function () {",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    let domain = pm.environment.get(\"domain\");",
-													"    ",
-													"    pm.expect(jsonData).to.have.property('id');",
-													"    pm.expect(jsonData).to.have.property('registrationUserUri');",
-													"    pm.expect(jsonData).to.have.property('registrationAccessToken');",
-													"    pm.expect(jsonData.internal).to.eql(true);",
-													"    pm.expect(jsonData.enabled).to.eql(false);",
-													"    pm.expect(jsonData.preRegistration).to.eql(true);",
-													"    pm.expect(jsonData.registrationCompleted).to.eql(false);",
-													"    pm.expect(jsonData.source).to.eql('default-idp-'+domain)",
-													"    pm.environment.set('userTemp', jsonData.id);",
-													"    pm.environment.set('userRegistrationURI', jsonData.registrationUserUri);",
-													"    pm.environment.set('userRegistrationToken', jsonData.registrationAccessToken);",
+													"    pm.expect(jsonData.message).to.eql(\"[jensen.barbara@maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaail.com: must not be greater than 320]\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1413,19 +1386,19 @@
 										"header": [
 											{
 												"key": "Authorization",
-												"value": "Bearer {{token}}",
-												"type": "text"
+												"type": "text",
+												"value": "Bearer {{token}}"
 											},
 											{
 												"key": "Content-Type",
 												"name": "Content-Type",
-												"value": "application/json",
-												"type": "text"
+												"type": "text",
+												"value": "application/json"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"John\",\n\t\"lastName\": \"Doe\",\n\t\"username\": \"john.doe\",\n\t\"email\": \"john.doe@mail.com\",\n\t\"preRegistration\": true\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
@@ -1447,65 +1420,89 @@
 									"response": []
 								},
 								{
-									"name": "Initiate post registration flow",
+									"name": "Invalid request - external id too long",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "fb56a849-b090-4e80-9c8c-eca9f4d72e85",
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
 												"exec": [
-													"pm.test(\"Status code is 200\", function () {",
-													"    pm.response.to.have.status(200);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"Should be a redirection to confirm registration page\", function() {",
-													"    pm.response.to.be.ok;",
-													"    var responseHTML = cheerio(pm.response.text());",
-													"    tests['Redirect to confirm registration page'] = responseHTML.find('span').text().includes('Thanks for signing up, please complete the form to activate your account');",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[Tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long: must not be greater than 100]\");",
 													"});"
 												],
 												"type": "text/javascript"
 											}
-										},
-										{
-											"listen": "prerequest",
-											"script": {
-												"id": "904f0113-b2b9-4645-9511-48bb10791506",
-												"exec": [
-													""
-												],
-												"type": "text/javascript"
-											}
 										}
 									],
 									"request": {
-										"method": "GET",
-										"header": [],
+										"method": "POST",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\",\n\t\"externalId\": \"Tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long\"\n}"
+										},
 										"url": {
-											"raw": "{{userRegistrationURI}}?token={{userRegistrationToken}}",
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
 											"host": [
-												"{{userRegistrationURI}}"
+												"{{management_url}}"
 											],
-											"query": [
-												{
-													"key": "token",
-													"value": "{{userRegistrationToken}}"
-												}
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users"
 											]
 										}
 									},
 									"response": []
 								},
 								{
-									"name": "Delete user",
+									"name": "Create user",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
 												"exec": [
-													"pm.test(\"Status code is 204\", function () {",
-													"    pm.response.to.have.status(204);",
+													"pm.test(\"Status code is 201\", function () {",
+													"    pm.response.to.have.status(201);",
+													"});",
+													"",
+													"pm.test(\"UM - create user\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    let domain = pm.environment.get(\"domain\");",
+													"    ",
+													"    pm.expect(jsonData).to.have.property('id');",
+													"    pm.expect(jsonData).to.not.have.property('registrationUserUri');",
+													"    pm.expect(jsonData).to.not.have.property('registrationAccessToken');",
+													"    pm.expect(jsonData.internal).to.eql(true);",
+													"    pm.expect(jsonData.enabled).to.eql(true);",
+													"    pm.expect(jsonData.preRegistration).to.eql(false);",
+													"    pm.expect(jsonData.registrationCompleted).to.eql(true);",
+													"    pm.expect(jsonData.source).to.eql('default-idp-'+domain)",
+													"    pm.environment.set('userUM', jsonData.id);",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1513,20 +1510,26 @@
 										}
 									],
 									"request": {
-										"method": "DELETE",
+										"method": "POST",
 										"header": [
 											{
 												"key": "Authorization",
-												"type": "text",
-												"value": "Bearer {{token}}"
+												"value": "Bearer {{token}}",
+												"type": "text"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"value": "application/json",
+												"type": "text"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": ""
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
-											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userTemp}}",
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
 											"host": [
 												"{{management_url}}"
 											],
@@ -1538,35 +1541,27 @@
 												"{{defaultEnvironmentId}}",
 												"domains",
 												"{{domain}}",
-												"users",
-												"{{userTemp}}"
+												"users"
 											]
 										}
 									},
 									"response": []
-								}
-							],
-							"protocolProfileBehavior": {},
-							"_postman_isSubFolder": true
-						},
-						{
-							"name": "Update",
-							"item": [
+								},
 								{
-									"name": "Invalid request - user not found",
+									"name": "Invalid request - username already exists",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
 												"exec": [
-													"pm.test(\"Status code is 404\", function () {",
-													"    pm.response.to.have.status(404);",
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
 													"});",
 													"",
-													"pm.test(\"UM - update user - unknown user\", function () {",
+													"pm.test(\"UM - create user - uniqueness\", function () {",
 													"    var jsonData = pm.response.json();",
-													"    pm.expect(jsonData.message).to.eql(\"User [wrong-id] can not be found.\");",
+													"    pm.expect(jsonData.message).to.eql(\"A user [jensen.barbara] already exists.\");",
 													"});"
 												],
 												"type": "text/javascript"
@@ -1574,7 +1569,7 @@
 										}
 									],
 									"request": {
-										"method": "PUT",
+										"method": "POST",
 										"header": [
 											{
 												"key": "Authorization",
@@ -1584,16 +1579,16 @@
 											{
 												"key": "Content-Type",
 												"name": "Content-Type",
-												"value": "application/json",
-												"type": "text"
+												"type": "text",
+												"value": "application/json"
 											}
 										],
 										"body": {
 											"mode": "raw",
-											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@mail.com\"\n}"
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
 										},
 										"url": {
-											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/wrong-id",
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
 											"host": [
 												"{{management_url}}"
 											],
@@ -1605,42 +1600,701 @@
 												"{{defaultEnvironmentId}}",
 												"domains",
 												"{{domain}}",
-												"users",
-												"wrong-id"
+												"users"
 											]
 										}
 									},
 									"response": []
 								},
 								{
-									"name": "Invalid request - malformed json",
+									"name": "Invalid request - username already exists - case insensitive",
 									"event": [
 										{
 											"listen": "test",
 											"script": {
-												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
 												"exec": [
 													"pm.test(\"Status code is 400\", function () {",
 													"    pm.response.to.have.status(400);",
-													"});"
-												],
+													"});",
+													"",
+													"pm.test(\"UM - create user - uniqueness\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"A user [jensen.BarBara] already exists.\");",
+													"});"
+												],
 												"type": "text/javascript"
 											}
 										}
 									],
 									"request": {
-										"method": "PUT",
+										"method": "POST",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"username\": \"jensen.BarBara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"password\": \"password\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users"
+											]
+										}
+									},
+									"response": []
+								}
+							],
+							"protocolProfileBehavior": {},
+							"_postman_isSubFolder": true
+						},
+						{
+							"name": "Pre-Register",
+							"item": [
+								{
+									"name": "Patch domain - dynamic user registration",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "29adabbe-3199-4e82-afb7-851bdd50b1bb",
+												"exec": [
+													"pm.test(\"Status code is 200\", function () {",
+													"    pm.response.to.have.status(200);",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PATCH",
+										"header": [
+											{
+												"key": "Authorization",
+												"value": "Bearer {{token}}",
+												"type": "text"
+											},
+											{
+												"key": "Content-Type",
+												"value": "application/json",
+												"type": "text"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n  \"accountSettings\": {\n    \"dynamicUserRegistration\": true\n  }\n}",
+											"options": {
+												"raw": {
+													"language": "json"
+												}
+											}
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Create user",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "ac86c3c9-c0a7-4616-b7cf-6847a7f48801",
+												"exec": [
+													"pm.test(\"Status code is 201\", function () {",
+													"    pm.response.to.have.status(201);",
+													"});",
+													"",
+													"pm.test(\"UM - pre-register user\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    let domain = pm.environment.get(\"domain\");",
+													"    ",
+													"    pm.expect(jsonData).to.have.property('id');",
+													"    pm.expect(jsonData).to.have.property('registrationUserUri');",
+													"    pm.expect(jsonData).to.have.property('registrationAccessToken');",
+													"    pm.expect(jsonData.internal).to.eql(true);",
+													"    pm.expect(jsonData.enabled).to.eql(false);",
+													"    pm.expect(jsonData.preRegistration).to.eql(true);",
+													"    pm.expect(jsonData.registrationCompleted).to.eql(false);",
+													"    pm.expect(jsonData.source).to.eql('default-idp-'+domain)",
+													"    pm.environment.set('userTemp', jsonData.id);",
+													"    pm.environment.set('userRegistrationURI', jsonData.registrationUserUri);",
+													"    pm.environment.set('userRegistrationToken', jsonData.registrationAccessToken);",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "POST",
 										"header": [
 											{
 												"key": "Authorization",
 												"value": "Bearer {{token}}",
 												"type": "text"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"value": "application/json",
+												"type": "text"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"John\",\n\t\"lastName\": \"Doe\",\n\t\"username\": \"john.doe\",\n\t\"email\": \"john.doe@mail.com\",\n\t\"preRegistration\": true\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Initiate post registration flow",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "fb56a849-b090-4e80-9c8c-eca9f4d72e85",
+												"exec": [
+													"pm.test(\"Status code is 200\", function () {",
+													"    pm.response.to.have.status(200);",
+													"});",
+													"",
+													"pm.test(\"Should be a redirection to confirm registration page\", function() {",
+													"    pm.response.to.be.ok;",
+													"    var responseHTML = cheerio(pm.response.text());",
+													"    tests['Redirect to confirm registration page'] = responseHTML.find('span').text().includes('Thanks for signing up, please complete the form to activate your account');",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										},
+										{
+											"listen": "prerequest",
+											"script": {
+												"id": "904f0113-b2b9-4645-9511-48bb10791506",
+												"exec": [
+													""
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "GET",
+										"header": [],
+										"url": {
+											"raw": "{{userRegistrationURI}}?token={{userRegistrationToken}}",
+											"host": [
+												"{{userRegistrationURI}}"
+											],
+											"query": [
+												{
+													"key": "token",
+													"value": "{{userRegistrationToken}}"
+												}
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Delete user",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 204\", function () {",
+													"    pm.response.to.have.status(204);",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "DELETE",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
 											}
 										],
 										"body": {
 											"mode": "raw",
 											"raw": ""
 										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userTemp}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userTemp}}"
+											]
+										}
+									},
+									"response": []
+								}
+							],
+							"protocolProfileBehavior": {},
+							"_postman_isSubFolder": true
+						},
+						{
+							"name": "Update",
+							"item": [
+								{
+									"name": "Invalid request - user not found",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 404\", function () {",
+													"    pm.response.to.have.status(404);",
+													"});",
+													"",
+													"pm.test(\"UM - update user - unknown user\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"User [wrong-id] can not be found.\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"value": "application/json",
+												"type": "text"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@mail.com\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/wrong-id",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"wrong-id"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - malformed json",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"value": "Bearer {{token}}",
+												"type": "text"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": ""
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - email invalid",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - email invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[jensen.barba: must be a well-formed email address]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barba\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - first name invalid",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid first name]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"#Invalid\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@mail.com\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - last name invalid",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[#Invalid: invalid last name]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"#Invalid\",\n\t\"email\": \"jensen.barbara@mail.com\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - email too long",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[jensen.barbara@maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaail.com: must not be greater than 320]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaail.com\"\n}"
+										},
+										"url": {
+											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
+											"host": [
+												"{{management_url}}"
+											],
+											"path": [
+												"management",
+												"organizations",
+												"{{defaultOrganizationId}}",
+												"environments",
+												"{{defaultEnvironmentId}}",
+												"domains",
+												"{{domain}}",
+												"users",
+												"{{userUM}}"
+											]
+										}
+									},
+									"response": []
+								},
+								{
+									"name": "Invalid request - external id too long",
+									"event": [
+										{
+											"listen": "test",
+											"script": {
+												"id": "56ffba4f-b70a-452d-a063-8c3865594fd4",
+												"exec": [
+													"pm.test(\"Status code is 400\", function () {",
+													"    pm.response.to.have.status(400);",
+													"});",
+													"",
+													"pm.test(\"UM - create user - first name invalid\", function () {",
+													"    var jsonData = pm.response.json();",
+													"    pm.expect(jsonData.message).to.eql(\"[Tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long: must not be greater than 100]\");",
+													"});"
+												],
+												"type": "text/javascript"
+											}
+										}
+									],
+									"request": {
+										"method": "PUT",
+										"header": [
+											{
+												"key": "Authorization",
+												"type": "text",
+												"value": "Bearer {{token}}"
+											},
+											{
+												"key": "Content-Type",
+												"name": "Content-Type",
+												"type": "text",
+												"value": "application/json"
+											}
+										],
+										"body": {
+											"mode": "raw",
+											"raw": "{\n\t\"firstName\": \"Jensen\",\n\t\"lastName\": \"Barbara\",\n\t\"email\": \"jensen.barbara@mail.com\",\n\t\"externalId\": \"Tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long\"\n}"
+										},
 										"url": {
 											"raw": "{{management_url}}/management/organizations/{{defaultOrganizationId}}/environments/{{defaultEnvironmentId}}/domains/{{domain}}/users/{{userUM}}",
 											"host": [


Test patch:
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/password/ForgotPasswordSubmissionEndpointTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/password/ForgotPasswordSubmissionEndpointTest.java
new file mode 100644
index 0000000000..3d7c128fe5
--- /dev/null
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/password/ForgotPasswordSubmissionEndpointTest.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed 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 io.gravitee.am.gateway.handler.root.resources.endpoint.user.password;
+
+import io.gravitee.am.gateway.handler.common.vertx.RxWebTestBase;
+import io.gravitee.am.gateway.handler.common.vertx.web.handler.ErrorHandler;
+import io.gravitee.am.gateway.handler.root.service.user.UserService;
+import io.gravitee.am.identityprovider.api.DefaultUser;
+import io.gravitee.am.identityprovider.api.User;
+import io.gravitee.am.model.Domain;
+import io.gravitee.am.model.oidc.Client;
+import io.gravitee.am.service.exception.EmailFormatInvalidException;
+import io.gravitee.am.service.exception.UserNotFoundException;
+import io.gravitee.common.http.HttpHeader;
+import io.gravitee.common.http.HttpStatusCode;
+import io.netty.handler.codec.Headers;
+import io.reactivex.Completable;
+import io.reactivex.Single;
+import io.vertx.core.http.HttpHeaders;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.json.Json;
+import io.vertx.reactivex.ext.web.multipart.FormDataPart;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Collections;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author Titouan COMPIEGNE (titouan.compiegne at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ForgotPasswordSubmissionEndpointTest extends RxWebTestBase {
+
+    @Mock
+    private UserService userService;
+
+    @Mock
+    private Domain domain;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        ForgotPasswordSubmissionEndpoint forgotPasswordSubmissionEndpoint = new ForgotPasswordSubmissionEndpoint(userService, domain);
+        router.route(HttpMethod.POST, "/forgotPassword")
+                .handler(forgotPasswordSubmissionEndpoint)
+                .failureHandler(new ErrorHandler());
+    }
+
+    @Test
+    public void shouldInvokeForgotPasswordEndpoint() throws Exception {
+        Client client = new Client();
+        client.setId("client-id");
+        client.setClientId("client-id");
+
+        router.route().order(-1).handler(routingContext -> {
+            routingContext.put("client", client);
+            routingContext.next();
+        });
+
+        when(userService.forgotPassword(eq("email@test.com"), eq(client), any(User.class))).thenReturn(Completable.complete());
+
+        testRequest(
+                HttpMethod.POST, "/forgotPassword?email=email@test.com",
+                null,
+                resp -> {
+                    String location = resp.headers().get("location");
+                    assertNotNull(location);
+                    assertTrue(location.endsWith("/forgotPassword?success=forgot_password_completed&client_id=client-id"));
+                },
+                HttpStatusCode.FOUND_302, "Found", null);
+    }
+
+
+    @Test
+    public void shouldCompleteWhenUserNotFoundException() throws Exception {
+        Client client = new Client();
+        client.setId("client-id");
+        client.setClientId("client-id");
+
+        router.route().order(-1).handler(routingContext -> {
+            routingContext.put("client", client);
+            routingContext.next();
+        });
+
+        when(userService.forgotPassword(eq("email@test.com"), eq(client), any(User.class))).thenReturn(Completable.error(new UserNotFoundException("email@test.com")));
+
+        testRequest(
+                HttpMethod.POST, "/forgotPassword?email=email@test.com",
+                null,
+                resp -> {
+                    String location = resp.headers().get("location");
+                    assertNotNull(location);
+                    assertTrue(location.endsWith("/forgotPassword?success=forgot_password_completed&client_id=client-id"));
+                },
+                HttpStatusCode.FOUND_302, "Found", null);
+    }
+
+    @Test
+    public void shouldFailWhenEmailFormatInvalidException() throws Exception {
+        Client client = new Client();
+        client.setId("client-id");
+        client.setClientId("client-id");
+
+        router.route().order(-1).handler(routingContext -> {
+            routingContext.put("client", client);
+            routingContext.next();
+        });
+
+        when(userService.forgotPassword(eq("email.test.com"), eq(client), any(User.class))).thenReturn(Completable.error(new EmailFormatInvalidException("email.test.com")));
+
+        testRequest(
+                HttpMethod.POST, "/forgotPassword?email=email.test.com",
+                null,
+                resp -> {
+                    String location = resp.headers().get("location");
+                    assertNotNull(location);
+                    assertTrue(location.endsWith("/forgotPassword?error=forgot_password_failed&client_id=client-id"));
+                },
+                HttpStatusCode.FOUND_302, "Found", null);
+    }
+}
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/register/RegisterSubmissionEndpointTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/register/RegisterSubmissionEndpointTest.java
index f1201eedca..a70e9f082e 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/register/RegisterSubmissionEndpointTest.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/user/register/RegisterSubmissionEndpointTest.java
@@ -21,6 +21,9 @@ import io.gravitee.am.gateway.handler.root.service.response.RegistrationResponse
 import io.gravitee.am.gateway.handler.root.service.user.UserService;
 import io.gravitee.am.model.Domain;
 import io.gravitee.am.model.oidc.Client;
+import io.gravitee.am.service.exception.EmailFormatInvalidException;
+import io.gravitee.am.service.exception.InvalidUserException;
+import io.gravitee.am.service.exception.UserAlreadyExistsException;
 import io.gravitee.common.http.HttpStatusCode;
 import io.reactivex.Single;
 import io.vertx.core.http.HttpMethod;
@@ -111,4 +114,79 @@ public class RegisterSubmissionEndpointTest extends RxWebTestBase {
                 },
                 HttpStatusCode.FOUND_302, "Found", null);
     }
+
+    @Test
+    public void shouldFail_UserAlreadyExistsException() throws Exception {
+        Client client = new Client();
+        client.setId("client-id");
+        client.setClientId("client-id");
+        client.setRedirectUris(Collections.singletonList("http://localhost:9999/callback"));
+
+        router.route().order(-1).handler(routingContext -> {
+            routingContext.put("client", client);
+            routingContext.next();
+        });
+
+        when(userService.register(eq(client), any(), any())).thenReturn(Single.error(new UserAlreadyExistsException("test")));
+
+        testRequest(
+                HttpMethod.POST, "/register",
+                null,
+                resp -> {
+                    String location = resp.headers().get("location");
+                    assertNotNull(location);
+                    assertTrue(location.endsWith("/register?error=registration_failed&client_id=client-id"));
+                },
+                HttpStatusCode.FOUND_302, "Found", null);
+    }
+
+    @Test
+    public void shouldFail_invalidUserException() throws Exception {
+        Client client = new Client();
+        client.setId("client-id");
+        client.setClientId("client-id");
+        client.setRedirectUris(Collections.singletonList("http://localhost:9999/callback"));
+
+        router.route().order(-1).handler(routingContext -> {
+            routingContext.put("client", client);
+            routingContext.next();
+        });
+
+        when(userService.register(eq(client), any(), any())).thenReturn(Single.error(new InvalidUserException("Username invalid")));
+
+        testRequest(
+                HttpMethod.POST, "/register",
+                null,
+                resp -> {
+                    String location = resp.headers().get("location");
+                    assertNotNull(location);
+                    assertTrue(location.endsWith("/register?warning=invalid_user_information&client_id=client-id"));
+                },
+                HttpStatusCode.FOUND_302, "Found", null);
+    }
+
+    @Test
+    public void shouldFail_emailFormatInvalidException() throws Exception {
+        Client client = new Client();
+        client.setId("client-id");
+        client.setClientId("client-id");
+        client.setRedirectUris(Collections.singletonList("http://localhost:9999/callback"));
+
+        router.route().order(-1).handler(routingContext -> {
+            routingContext.put("client", client);
+            routingContext.next();
+        });
+
+        when(userService.register(eq(client), any(), any())).thenReturn(Single.error(new EmailFormatInvalidException("test")));
+
+        testRequest(
+                HttpMethod.POST, "/register",
+                null,
+                resp -> {
+                    String location = resp.headers().get("location");
+                    assertNotNull(location);
+                    assertTrue(location.endsWith("/register?warning=invalid_email&client_id=client-id"));
+                },
+                HttpStatusCode.FOUND_302, "Found", null);
+    }
 }
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/test/java/io/gravitee/am/gateway/handler/scim/resources/users/CreateUserEndpointHandlerTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/test/java/io/gravitee/am/gateway/handler/scim/resources/users/CreateUserEndpointHandlerTest.java
index 42475bf8e3..1a29aa129f 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/test/java/io/gravitee/am/gateway/handler/scim/resources/users/CreateUserEndpointHandlerTest.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/test/java/io/gravitee/am/gateway/handler/scim/resources/users/CreateUserEndpointHandlerTest.java
@@ -19,11 +19,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectWriter;
 import io.gravitee.am.gateway.handler.common.vertx.RxWebTestBase;
 import io.gravitee.am.gateway.handler.scim.exception.InvalidValueException;
+import io.gravitee.am.gateway.handler.scim.exception.UniquenessException;
 import io.gravitee.am.gateway.handler.scim.model.Meta;
 import io.gravitee.am.gateway.handler.scim.model.User;
 import io.gravitee.am.gateway.handler.scim.resources.ErrorHandler;
 import io.gravitee.am.gateway.handler.scim.service.UserService;
 import io.gravitee.am.service.authentication.crypto.password.PasswordValidator;
+import io.gravitee.am.service.exception.EmailFormatInvalidException;
+import io.gravitee.am.service.exception.InvalidUserException;
 import io.gravitee.am.service.exception.RoleNotFoundException;
 import io.gravitee.am.service.exception.UserProviderNotFoundException;
 import io.reactivex.Single;
@@ -163,6 +166,75 @@ public class CreateUserEndpointHandlerTest extends RxWebTestBase {
                         "}");
     }
 
+    @Test
+    public void shouldReturn409WhenUsernameAlreadyExists() throws Exception {
+        router.route("/Users").handler(usersEndpoint::create);
+        when(passwordValidator.validate(anyString())).thenReturn(true);
+        when(userService.create(any(), any())).thenReturn(Single.error(new UniquenessException("Username already exists")));
+
+        testRequest(
+                HttpMethod.POST,
+                "/Users",
+                req -> {
+                    req.setChunked(true);
+                    req.write(Json.encode(getUser()));
+                },
+                409,
+                "Conflict",
+                "{\n" +
+                        "  \"status\" : \"409\",\n" +
+                        "  \"scimType\" : \"uniqueness\",\n" +
+                        "  \"detail\" : \"Username already exists\",\n" +
+                        "  \"schemas\" : [ \"urn:ietf:params:scim:api:messages:2.0:Error\" ]\n" +
+                        "}");
+    }
+
+    @Test
+    public void shouldReturn400WhenInvalidUserException() throws Exception {
+        router.route("/Users").handler(usersEndpoint::create);
+        when(passwordValidator.validate(anyString())).thenReturn(true);
+        when(userService.create(any(), any())).thenReturn(Single.error(new InvalidUserException("Invalid user infos")));
+
+        testRequest(
+                HttpMethod.POST,
+                "/Users",
+                req -> {
+                    req.setChunked(true);
+                    req.write(Json.encode(getUser()));
+                },
+                400,
+                "Bad Request",
+                "{\n" +
+                        "  \"status\" : \"400\",\n" +
+                        "  \"scimType\" : \"invalidValue\",\n" +
+                        "  \"detail\" : \"Invalid user infos\",\n" +
+                        "  \"schemas\" : [ \"urn:ietf:params:scim:api:messages:2.0:Error\" ]\n" +
+                        "}");
+    }
+
+    @Test
+    public void shouldReturn400WhenEmailFormatInvalidException() throws Exception {
+        router.route("/Users").handler(usersEndpoint::create);
+        when(passwordValidator.validate(anyString())).thenReturn(true);
+        when(userService.create(any(), any())).thenReturn(Single.error(new EmailFormatInvalidException("Invalid email")));
+
+        testRequest(
+                HttpMethod.POST,
+                "/Users",
+                req -> {
+                    req.setChunked(true);
+                    req.write(Json.encode(getUser()));
+                },
+                400,
+                "Bad Request",
+                "{\n" +
+                        "  \"status\" : \"400\",\n" +
+                        "  \"scimType\" : \"invalidValue\",\n" +
+                        "  \"detail\" : \"Value [Invalid email] is not a valid email.\",\n" +
+                        "  \"schemas\" : [ \"urn:ietf:params:scim:api:messages:2.0:Error\" ]\n" +
+                        "}");
+    }
+
     private User getUser() {
         User user = new User();
         user.setUserName("username");
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/test/java/io/gravitee/am/gateway/handler/scim/resources/users/UpdateUserEndpointHandlerTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/test/java/io/gravitee/am/gateway/handler/scim/resources/users/UpdateUserEndpointHandlerTest.java
index fc7eeee2b4..4a651ddf03 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/test/java/io/gravitee/am/gateway/handler/scim/resources/users/UpdateUserEndpointHandlerTest.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-scim/src/test/java/io/gravitee/am/gateway/handler/scim/resources/users/UpdateUserEndpointHandlerTest.java
@@ -24,6 +24,8 @@ import io.gravitee.am.gateway.handler.scim.model.User;
 import io.gravitee.am.gateway.handler.scim.resources.ErrorHandler;
 import io.gravitee.am.gateway.handler.scim.service.UserService;
 import io.gravitee.am.service.authentication.crypto.password.PasswordValidator;
+import io.gravitee.am.service.exception.EmailFormatInvalidException;
+import io.gravitee.am.service.exception.InvalidUserException;
 import io.gravitee.am.service.exception.RoleNotFoundException;
 import io.reactivex.Single;
 import io.vertx.core.http.HttpMethod;
@@ -137,6 +139,52 @@ public class UpdateUserEndpointHandlerTest extends RxWebTestBase {
                         "}");
     }
 
+    @Test
+    public void shouldReturn400WhenInvalidUserException() throws Exception {
+        router.route("/Users").handler(userEndpoint::update);
+        when(passwordValidator.validate(anyString())).thenReturn(true);
+        when(userService.update(any(), any(), anyString())).thenReturn(Single.error(new InvalidUserException("Invalid user infos")));
+
+        testRequest(
+                HttpMethod.PUT,
+                "/Users",
+                req -> {
+                    req.setChunked(true);
+                    req.write(Json.encode(getUser()));
+                },
+                400,
+                "Bad Request",
+                "{\n" +
+                        "  \"status\" : \"400\",\n" +
+                        "  \"scimType\" : \"invalidValue\",\n" +
+                        "  \"detail\" : \"Invalid user infos\",\n" +
+                        "  \"schemas\" : [ \"urn:ietf:params:scim:api:messages:2.0:Error\" ]\n" +
+                        "}");
+    }
+
+    @Test
+    public void shouldReturn400WhenEmailFormatInvalidException() throws Exception {
+        router.route("/Users").handler(userEndpoint::update);
+        when(passwordValidator.validate(anyString())).thenReturn(true);
+        when(userService.update(any(), any(), anyString())).thenReturn(Single.error(new EmailFormatInvalidException("Invalid email")));
+
+        testRequest(
+                HttpMethod.PUT,
+                "/Users",
+                req -> {
+                    req.setChunked(true);
+                    req.write(Json.encode(getUser()));
+                },
+                400,
+                "Bad Request",
+                "{\n" +
+                        "  \"status\" : \"400\",\n" +
+                        "  \"scimType\" : \"invalidValue\",\n" +
+                        "  \"detail\" : \"Value [Invalid email] is not a valid email.\",\n" +
+                        "  \"schemas\" : [ \"urn:ietf:params:scim:api:messages:2.0:Error\" ]\n" +
+                        "}");
+    }
+
     private User getUser() {
         User user = new User();
         user.setUserName("username");
diff --git a/gravitee-am-service/src/test/java/io/gravitee/am/service/UserServiceTest.java b/gravitee-am-service/src/test/java/io/gravitee/am/service/UserServiceTest.java
index 3d74e0da71..6b32638ff9 100644
--- a/gravitee-am-service/src/test/java/io/gravitee/am/service/UserServiceTest.java
+++ b/gravitee-am-service/src/test/java/io/gravitee/am/service/UserServiceTest.java
@@ -21,9 +21,7 @@ import io.gravitee.am.model.common.event.Event;
 import io.gravitee.am.model.ReferenceType;
 import io.gravitee.am.repository.exceptions.TechnicalException;
 import io.gravitee.am.repository.management.api.UserRepository;
-import io.gravitee.am.service.exception.TechnicalManagementException;
-import io.gravitee.am.service.exception.UserAlreadyExistsException;
-import io.gravitee.am.service.exception.UserNotFoundException;
+import io.gravitee.am.service.exception.*;
 import io.gravitee.am.service.impl.UserServiceImpl;
 import io.gravitee.am.service.model.NewUser;
 import io.gravitee.am.service.model.UpdateUser;
@@ -191,6 +189,44 @@ public class UserServiceTest {
         verify(eventService, times(1)).create(any());
     }
 
+    @Test
+    public void shouldNotCreate_emailFormatInvalidException() {
+        User user = new User();
+        user.setReferenceType(ReferenceType.DOMAIN);
+        user.setReferenceId(DOMAIN);
+
+        NewUser newUser = new NewUser();
+        newUser.setEmail("invalid");
+        when(userRepository.findByUsernameAndSource(ReferenceType.DOMAIN, DOMAIN, newUser.getUsername(), newUser.getSource())).thenReturn(Maybe.empty());
+        when(userRepository.create(any(User.class))).thenReturn(Single.just(user));
+
+        TestObserver<User> testObserver = userService.create(DOMAIN, newUser).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertError(EmailFormatInvalidException.class);
+
+        verifyZeroInteractions(eventService);
+    }
+
+    @Test
+    public void shouldNotCreate_invalidUserException() {
+        User user = new User();
+        user.setReferenceType(ReferenceType.DOMAIN);
+        user.setReferenceId(DOMAIN);
+
+        NewUser newUser = new NewUser();
+        newUser.setUsername("#####");
+        when(userRepository.findByUsernameAndSource(ReferenceType.DOMAIN, DOMAIN, newUser.getUsername(), newUser.getSource())).thenReturn(Maybe.empty());
+        when(userRepository.create(any(User.class))).thenReturn(Single.just(user));
+
+        TestObserver<User> testObserver = userService.create(DOMAIN, newUser).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertError(InvalidUserException.class);
+
+        verifyZeroInteractions(eventService);
+    }
+
     @Test
     public void shouldCreate_technicalException() {
         NewUser newUser = Mockito.mock(NewUser.class);
@@ -242,6 +278,44 @@ public class UserServiceTest {
         verify(eventService, times(1)).create(any());
     }
 
+    @Test
+    public void shouldNotUpdate_emailFormatInvalidException() {
+        User user = new User();
+        user.setReferenceType(ReferenceType.DOMAIN);
+        user.setReferenceId(DOMAIN);
+
+        UpdateUser updateUser = new UpdateUser();
+        updateUser.setEmail("invalid");
+        when(userRepository.findById(eq(ReferenceType.DOMAIN), eq(DOMAIN), eq("my-user"))).thenReturn(Maybe.just(user));
+        when(userRepository.update(any(User.class))).thenReturn(Single.just(user));
+
+        TestObserver<User> testObserver = userService.update(DOMAIN, "my-user", updateUser).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertError(EmailFormatInvalidException.class);
+
+        verifyZeroInteractions(eventService);
+    }
+
+    @Test
+    public void shouldNotUpdate_invalidUserException() {
+        User user = new User();
+        user.setReferenceType(ReferenceType.DOMAIN);
+        user.setReferenceId(DOMAIN);
+
+        UpdateUser updateUser = new UpdateUser();
+        updateUser.setFirstName("$$^^^^¨¨¨)");
+        when(userRepository.findById(eq(ReferenceType.DOMAIN), eq(DOMAIN), eq("my-user"))).thenReturn(Maybe.just(user));
+        when(userRepository.update(any(User.class))).thenReturn(Single.just(user));
+
+        TestObserver<User> testObserver = userService.update(DOMAIN, "my-user", updateUser).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertError(InvalidUserException.class);
+
+        verifyZeroInteractions(eventService);
+    }
+
     @Test
     public void shouldUpdate_technicalException() {
         UpdateUser updateUser = Mockito.mock(UpdateUser.class);
diff --git a/gravitee-am-service/src/test/java/io/gravitee/am/service/validators/UserValidatorTest.java b/gravitee-am-service/src/test/java/io/gravitee/am/service/validators/UserValidatorTest.java
new file mode 100644
index 0000000000..6454b4171a
--- /dev/null
+++ b/gravitee-am-service/src/test/java/io/gravitee/am/service/validators/UserValidatorTest.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed 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 io.gravitee.am.service.validators;
+
+import io.gravitee.am.model.User;
+import io.gravitee.am.service.exception.EmailFormatInvalidException;
+import io.gravitee.am.service.exception.InvalidUserException;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author Jeoffrey HAEYAERT (jeoffrey.haeyaert at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public class UserValidatorTest {
+
+    @Test
+    public void validate() {
+
+        User user = getValidUser();
+
+        Throwable throwable = UserValidator.validate(user).blockingGet();
+
+        assertNull(throwable);
+    }
+
+    @Test
+    public void validate_invalidEmail() {
+
+        User user = getValidUser();
+        user.setEmail("invalid");
+
+        Throwable throwable = UserValidator.validate(user).blockingGet();
+
+        assertNotNull(throwable);
+        assertTrue(throwable instanceof EmailFormatInvalidException);
+    }
+
+    @Test
+    public void validate_invalidFirstName() {
+
+        User user = getValidUser();
+        user.setFirstName("$¨¨^invalid");
+
+        Throwable throwable = UserValidator.validate(user).blockingGet();
+
+        assertNotNull(throwable);
+        assertTrue(throwable instanceof InvalidUserException);
+    }
+
+    @Test
+    public void validate_invalidLastName() {
+
+        User user = getValidUser();
+        user.setLastName("$¨¨^invalid");
+
+        Throwable throwable = UserValidator.validate(user).blockingGet();
+
+        assertNotNull(throwable);
+        assertTrue(throwable instanceof InvalidUserException);
+    }
+
+    @Test
+    public void validate_invalidNickName() {
+
+        User user = getValidUser();
+        user.setNickName("$¨¨^invalid");
+
+        Throwable throwable = UserValidator.validate(user).blockingGet();
+
+        assertNotNull(throwable);
+        assertTrue(throwable instanceof InvalidUserException);
+    }
+
+    @Test
+    public void validate_invalidDisplayName() {
+
+        User user = getValidUser();
+        user.setNickName("$¨¨^invalid");
+
+        Throwable throwable = UserValidator.validate(user).blockingGet();
+
+        assertNotNull(throwable);
+        assertTrue(throwable instanceof InvalidUserException);
+    }
+
+    @Test
+    public void validate_invalidUsername() {
+
+        User user = getValidUser();
+        user.setUsername("$¨¨^invalid");
+
+        Throwable throwable = UserValidator.validate(user).blockingGet();
+
+        assertNotNull(throwable);
+        assertTrue(throwable instanceof InvalidUserException);
+    }
+
+    private User getValidUser() {
+        User user = new User();
+        user.setEmail("valid.email@gravitee.io");
+        user.setFirstName("valid first name");
+        user.setLastName("valid last name");
+        user.setNickName("Valid, nick name;");
+        user.setDisplayName("Valid, display-name;");
+        user.setUsername("valid-@username");
+
+        return user;
+    }
+}
\ No newline at end of file