You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/05/11 13:02:38 UTC

[1/2] syncope git commit: [SYNCOPE-1018] self registration for OpenID Connect

Repository: syncope
Updated Branches:
  refs/heads/2_0_X c0a3d367d -> e7d679512
  refs/heads/master 3f0c52c46 -> 3b385e5c9


[SYNCOPE-1018] self registration for OpenID Connect


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/e7d67951
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/e7d67951
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/e7d67951

Branch: refs/heads/2_0_X
Commit: e7d679512650e091a01fba19374f2149b8b19439
Parents: c0a3d36
Author: dayash <di...@tirasa.net>
Authored: Fri May 11 12:28:52 2018 +0200
Committer: dayash <di...@tirasa.net>
Committed: Fri May 11 14:28:34 2018 +0200

----------------------------------------------------------------------
 .../syncope/client/enduser/pages/HomePage.java  |  2 +
 .../resources/META-INF/resources/app/index.html |  2 +
 .../resources/META-INF/resources/app/js/app.js  | 14 +++
 .../app/js/controllers/OIDCClientController.js  | 29 ++++++
 .../app/js/controllers/UserController.js        | 28 +++++-
 .../app/js/services/oidcClientService.js        | 42 +++++++++
 .../ext/oidcclient/agent/CodeConsumer.java      | 41 +++++++--
 .../syncope/ext/oidcclient/agent/Constants.java |  4 +
 .../client/console/pages/OIDCClientSelfReg.java | 38 ++++++++
 .../wizards/OIDCProviderWizardBuilder.java      |  5 +
 .../wizards/OIDCProviderWizardBuilder$OP.html   |  1 +
 .../OIDCProviderWizardBuilder$OP.properties     |  1 +
 .../OIDCProviderWizardBuilder$OP_it.properties  |  1 +
 ...IDCProviderWizardBuilder$OP_pt_BR.properties |  1 +
 .../OIDCProviderWizardBuilder$OP_ru.properties  |  1 +
 .../client/enduser/pages/OIDCClientSelfReg.java | 50 ++++++++++
 .../resources/OIDCClientUserAttrsResource.java  | 65 +++++++++++++
 .../common/lib/to/OIDCLoginResponseTO.java      | 10 ++
 .../syncope/common/lib/to/OIDCProviderTO.java   | 10 ++
 .../syncope/core/logic/OIDCClientLogic.java     | 16 ++++
 .../persistence/api/entity/OIDCProvider.java    |  8 +-
 .../persistence/jpa/entity/JPAOIDCProvider.java | 21 ++++-
 .../validation/entity/OIDCProviderCheck.java    | 41 +++++++++
 .../entity/OIDCProviderValidator.java           | 97 ++++++++++++++++++++
 .../java/data/OIDCProviderDataBinderImpl.java   |  2 +
 .../src/main/webapp/WEB-INF/web.xml             |  5 +
 .../src/main/webapp/WEB-INF/web.xml             |  6 +-
 27 files changed, 526 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
index 1e78222..3adec28 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
@@ -40,6 +40,8 @@ public class HomePage extends WebPage {
             appendMessage(redirectUrl, parameters.get("successMessage").toString());
         } else if (!parameters.get("saml2SPUserAttrs").isNull()) {
             redirectUrl.append("#!self-saml2sp");
+        } else if (!parameters.get("oidcClientUserAttrs").isNull()) {
+            redirectUrl.append("#!self-oidcclient");
         }
         throw new NonResettingRestartException(redirectUrl.toString());
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/client/enduser/src/main/resources/META-INF/resources/app/index.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/index.html b/client/enduser/src/main/resources/META-INF/resources/app/index.html
index 2613a6e..3aa57f5 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/index.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/index.html
@@ -102,10 +102,12 @@ under the License.
   <script src="js/services/saml2IdPService.js"></script>
   <script src="js/services/oidcProviderService.js"></script>
   <script src="js/services/saml2SPService.js"></script>
+  <script src="js/services/oidcClientService.js"></script>
   <!--controllers-->
   <script src="js/controllers/HomeController.js"></script>
   <script src="js/controllers/LoginController.js"></script>
   <script src="js/controllers/SAML2SPController.js"></script>
+  <script src="js/controllers/OIDCClientController.js"></script>
   <script src="js/controllers/UserController.js"></script>
   <!--directives-->
   <script src="js/directives/dynamicPlainAttribute.js"></script>

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
index 1019cad..475f74b 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
@@ -86,6 +86,20 @@ app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', '$translate
               }
             })
             /* </Extensions> */
+            
+            /* <Extensions> */
+            .state('self-oidcclient', {
+              url: '/self-oidcclient',
+              templateUrl: 'views/self.html',
+              controller: 'OIDCClientController',
+              resolve: {
+                'userAttrs': ['OIDCClientService',
+                  function (OIDCClientService) {
+                    return OIDCClientService.getOIDCClientUserAttrs();
+                  }]
+              }
+            })
+            /* </Extensions> */
             .state('user-self-update', {
               url: '/user-self-update',
               templateUrl: 'views/home.html',

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/OIDCClientController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/OIDCClientController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/OIDCClientController.js
new file mode 100644
index 0000000..f3eab68
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/OIDCClientController.js
@@ -0,0 +1,29 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+'use strict';
+angular.module("login").controller("OIDCClientController", function ($scope, $rootScope, $location, userAttrs) {
+  $scope.selfCreate = function () {
+    $location.path("/self/create");
+  };
+
+  $rootScope.oidcops.userAttrs = userAttrs;
+
+  $scope.selfCreate();
+});

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
index d2380f1..629c90d 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
@@ -45,6 +45,8 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
 
     /* <Extensions> */
     $scope.loadFromSAML2AuthSelfReg = $rootScope.saml2idps.userAttrs && $rootScope.saml2idps.userAttrs.length;
+
+    $scope.loadFromOIDCAuthSelfReg = $rootScope.oidcops.userAttrs && $rootScope.oidcops.userAttrs.length;
     /* </Extensions> */
 
     $scope.initUser = function () {
@@ -71,6 +73,12 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
                 ? found[0].values : [];
       };
 
+      var findLoadedOIDCAttrValue = function (schemaKey) {
+        var found = $filter('filter')($rootScope.oidcops.userAttrs, {"schema": schemaKey}, true);
+        return (found && found.length && found[0].values && found[0].values.length)
+                ? found[0].values : [];
+      };
+
       var initUserSchemas = function (anyTypeClass, group) {
         // initialization is done here synchronously to have all schema fields populated correctly
         var schemaService;
@@ -127,6 +135,10 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
             if ($scope.loadFromSAML2AuthSelfReg) {
               $scope.user.plainAttrs[plainSchemaKey].values = findLoadedSAML2AttrValue(plainSchemaKey);
             }
+            
+            if ($scope.loadFromOIDCAuthSelfReg) {
+              $scope.user.plainAttrs[plainSchemaKey].values = findLoadedOIDCAttrValue(plainSchemaKey);
+            }
 
             if (schemas.plainSchemas[i].multivalue) {
               // initialize multivalue schema and support table: create mode, default multivalues
@@ -181,6 +193,10 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
             if ($scope.loadFromSAML2AuthSelfReg) {
               $scope.user.virAttrs[virSchemaKey].values = findLoadedSAML2AttrValue(virSchemaKey);
             }
+            
+             if ($scope.loadFromOIDCAuthSelfReg) {
+              $scope.user.virAttrs[virSchemaKey].values = findLoadedOIDCAttrValue(virSchemaKey);
+            }
 
             // initialize multivalue attribute and support table: create mode, only first value
             $scope.dynamicForm.virtualAttributeTable[schemas.virSchemas[i].key] = {
@@ -205,6 +221,9 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
 
         //clean SAML Self Reg user attributes variable
         delete $rootScope.saml2idps.userAttrs;
+        
+        //clean OIDC Self Reg user attributes variable
+        delete $rootScope.oidcops.userAttrs;
       };
 
       var initSecurityQuestions = function () {
@@ -450,7 +469,14 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
           if (username.length) {
             $scope.user.username = username[0];
           }
-        }
+        } 
+        
+        if ($scope.loadFromOIDCAuthSelfReg) {
+          var username = findLoadedOIDCAttrValue("username");
+          if (username.length) {
+            $scope.user.username = username[0];
+          }
+        } 
       } else {
         // read user from syncope core
         readUser();

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/client/enduser/src/main/resources/META-INF/resources/app/js/services/oidcClientService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/oidcClientService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/oidcClientService.js
new file mode 100644
index 0000000..9e8cbc0
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/oidcClientService.js
@@ -0,0 +1,42 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+'use strict';
+
+angular.module('self')
+        .factory('OIDCClientService', ['$q', '$http',
+          function ($q, $http) {
+
+            var oidcClientService = {};
+
+            oidcClientService.getOIDCClientUserAttrs = function () {
+              return $http.get("../api/OIDCClients/userAttrs")
+                      .then(function (response) {
+                        return response.data;
+                      }, function (response) {
+                        console.error("Something went wrong while getting oidc user attributes, exit with status: ",
+                                response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+
+            return oidcClientService;
+          }]);
+
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
index 20c39c4..7bb26c1 100644
--- a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
+++ b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
@@ -18,6 +18,8 @@
  */
 package org.apache.syncope.ext.oidcclient.agent;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
@@ -29,6 +31,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.OIDCConstants;
+import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
 import org.apache.syncope.common.rest.api.service.OIDCClientService;
 import org.slf4j.Logger;
@@ -41,6 +44,9 @@ public class CodeConsumer extends HttpServlet {
 
     protected static final Logger LOG = LoggerFactory.getLogger(CodeConsumer.class);
 
+    private static final ObjectMapper MAPPER =
+            new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+
     @Override
     protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
             throws ServletException, IOException {
@@ -59,17 +65,34 @@ public class CodeConsumer extends HttpServlet {
                         request.getRequestURL().toString(),
                         authorizationCode,
                         request.getSession().getAttribute(OIDCConstants.OP).toString());
-                request.getSession().setAttribute(
-                        Constants.OIDCCLIENTJWT, responseTO.getAccessToken());
-                request.getSession().setAttribute(
-                        Constants.OIDCCLIENTJWT_EXPIRE, responseTO.getAccessTokenExpiryTime());
+                if (responseTO.isSelfReg()) {
+                    responseTO.getAttrs().add(
+                            new AttrTO.Builder().schema("username").values(responseTO.getUsername()).build());
+                    request.getSession(true).
+                            setAttribute(Constants.OIDCCLIENT_USER_ATTRS, MAPPER.writeValueAsString(responseTO.
+                                    getAttrs()));
 
-                String successURL = getServletContext().getInitParameter(Constants.CONTEXT_PARAM_LOGIN_SUCCESS_URL);
-                if (successURL == null) {
-                    request.setAttribute("responseTO", responseTO);
-                    request.getRequestDispatcher("loginSuccess.jsp").forward(request, response);
+                    String selfRegRedirectURL =
+                            getServletContext().getInitParameter(Constants.CONTEXT_PARAM_REDIRECT_SELFREG_URL);
+                    if (selfRegRedirectURL == null) {
+                        request.setAttribute("responseTO", responseTO);
+                        request.getRequestDispatcher("loginSuccess.jsp").forward(request, response);
+                    } else {
+                        response.sendRedirect(selfRegRedirectURL);
+                    }
                 } else {
-                    response.sendRedirect(successURL + "?logoutSupported=" + responseTO.isLogoutSupported());
+                    request.getSession().setAttribute(
+                            Constants.OIDCCLIENTJWT, responseTO.getAccessToken());
+                    request.getSession().setAttribute(
+                            Constants.OIDCCLIENTJWT_EXPIRE, responseTO.getAccessTokenExpiryTime());
+
+                    String successURL = getServletContext().getInitParameter(Constants.CONTEXT_PARAM_LOGIN_SUCCESS_URL);
+                    if (successURL == null) {
+                        request.setAttribute("responseTO", responseTO);
+                        request.getRequestDispatcher("loginSuccess.jsp").forward(request, response);
+                    } else {
+                        response.sendRedirect(successURL + "?logoutSupported=" + responseTO.isLogoutSupported());
+                    }
                 }
             } else {
                 throw new IllegalArgumentException("Invalid " + OIDCConstants.STATE + " provided");

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java
index 988b7cc..62e00c0 100644
--- a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java
+++ b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java
@@ -34,10 +34,14 @@ public final class Constants {
 
     public static final String CONTEXT_PARAM_LOGOUT_ERROR_URL = "oidcclient.logout.error.url";
 
+    public static final String CONTEXT_PARAM_REDIRECT_SELFREG_URL = "oidcclient.redirect.selfreg";
+
     public static final String OIDCCLIENTJWT = "oidcclient.jwt";
 
     public static final String OIDCCLIENTJWT_EXPIRE = "oidcclient.jwt.expire";
 
+    public static final String OIDCCLIENT_USER_ATTRS = "oidcclient.userattrs";
+
     private Constants() {
         // private constructor for static utility class
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCClientSelfReg.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCClientSelfReg.java b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCClientSelfReg.java
new file mode 100644
index 0000000..db29dce
--- /dev/null
+++ b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCClientSelfReg.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+public class OIDCClientSelfReg extends WebPage {
+
+    private static final long serialVersionUID = 864538706654644353L;
+
+    private static final String OIDC_ACCESS_ERROR =
+            "OpenID Connect error - Admin Console does not support Self Registration";
+
+    public OIDCClientSelfReg(final PageParameters parameters) {
+        super(parameters);
+
+        PageParameters params = new PageParameters();
+        params.add("errorMessage", OIDC_ACCESS_ERROR);
+        setResponsePage(Login.class, params);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java
index 9fec11b..680746d 100644
--- a/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java
+++ b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java
@@ -135,6 +135,11 @@ public class OIDCProviderWizardBuilder extends AjaxWizardBuilder<OIDCProviderTO>
                     false);
             add(createUnmatching);
 
+            AjaxCheckBoxPanel selfRegUnmatching = new AjaxCheckBoxPanel(
+                    "selfRegUnmatching", "selfRegUnmatching", new PropertyModel<Boolean>(opTO, "selfRegUnmatching"),
+                    false);
+            add(selfRegUnmatching);
+
             AjaxCheckBoxPanel updateMatching = new AjaxCheckBoxPanel(
                     "updateMatching", "updateMatching", new PropertyModel<Boolean>(opTO, "updateMatching"), false);
             add(updateMatching);

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html
index 4ad49d8..cfe5df7 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html
@@ -22,6 +22,7 @@ under the License.  actionsClassNames
     <div class="form-group"><span wicket:id="clientID">[clientID]</span></div>
     <div class="form-group"><span wicket:id="clientSecret">[clientSecret]</span></div>
     <div class="form-group"><span wicket:id="createUnmatching">[createUnmatching]</span></div>
+    <div class="form-group"><span wicket:id="selfRegUnmatching">[selfRegUnmatching]</span></div>
     <div class="form-group"><span wicket:id="updateMatching">[updateMatching]</span></div>
     <div class="form-group"><span wicket:id="actionsClassNames">[actionsClassNames]</span></div>
   </wicket:panel>

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties
index 5ed531a..123372f 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties
@@ -18,6 +18,7 @@ name=Name
 clientID=Client ID
 clientSecret=Client Secret
 createUnmatching=Create unmatching users
+selfRegUnmatching=OIDC-initiated self-registration
 updateMatching=Update matching users
 actionsClassNames=Actions
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties
index 5ed531a..123372f 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties
@@ -18,6 +18,7 @@ name=Name
 clientID=Client ID
 clientSecret=Client Secret
 createUnmatching=Create unmatching users
+selfRegUnmatching=OIDC-initiated self-registration
 updateMatching=Update matching users
 actionsClassNames=Actions
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties
index 5ed531a..123372f 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties
@@ -18,6 +18,7 @@ name=Name
 clientID=Client ID
 clientSecret=Client Secret
 createUnmatching=Create unmatching users
+selfRegUnmatching=OIDC-initiated self-registration
 updateMatching=Update matching users
 actionsClassNames=Actions
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties
index 5ed531a..123372f 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties
@@ -18,6 +18,7 @@ name=Name
 clientID=Client ID
 clientSecret=Client Secret
 createUnmatching=Create unmatching users
+selfRegUnmatching=OIDC-initiated self-registration
 updateMatching=Update matching users
 actionsClassNames=Actions
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/OIDCClientSelfReg.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/OIDCClientSelfReg.java b/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/OIDCClientSelfReg.java
new file mode 100644
index 0000000..68bbc7b
--- /dev/null
+++ b/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/OIDCClientSelfReg.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.enduser.pages;
+
+import org.apache.syncope.ext.oidcclient.agent.Constants;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OIDCClientSelfReg extends WebPage {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OIDCClientSelfReg.class);
+
+    private static final long serialVersionUID = -2533879075075645461L;
+
+    private static final String OIDC_ACCESS_ERROR = "OpenID Connect error - while getting user attributes";
+
+    public OIDCClientSelfReg(final PageParameters parameters) {
+        super(parameters);
+
+        PageParameters params = new PageParameters();
+        try {
+            params.add("oidcClientUserAttrs", ((ServletWebRequest) getRequest()).getContainerRequest().
+                    getSession().getAttribute(Constants.OIDCCLIENT_USER_ATTRS));
+        } catch (Exception e) {
+            LOG.error("While extracting user attributes", e);
+
+            params.add("errorMessage", OIDC_ACCESS_ERROR);
+        }
+        setResponsePage(getApplication().getHomePage(), params);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/resources/OIDCClientUserAttrsResource.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/resources/OIDCClientUserAttrsResource.java b/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/resources/OIDCClientUserAttrsResource.java
new file mode 100644
index 0000000..29dfa3c
--- /dev/null
+++ b/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/resources/OIDCClientUserAttrsResource.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.enduser.annotations.Resource;
+import org.apache.syncope.ext.oidcclient.agent.Constants;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.request.resource.IResource;
+
+@Resource(key = "OIDCClients", path = "/api/OIDCClients/userAttrs")
+public class OIDCClientUserAttrsResource extends BaseResource {
+
+    private static final long serialVersionUID = 7273151109078469253L;
+
+    @Override
+    protected ResourceResponse newResourceResponse(final IResource.Attributes attributes) {
+        ResourceResponse response = new ResourceResponse();
+        response.setContentType(MediaType.APPLICATION_JSON);
+
+        try {
+            response.setTextEncoding(StandardCharsets.UTF_8.name());
+            response.setWriteCallback(new AbstractResource.WriteCallback() {
+
+                @Override
+                public void writeData(final Attributes attributes) throws IOException {
+                    attributes.getResponse().write(
+                            (CharSequence) ((HttpServletRequest) RequestCycle.get().getRequest().
+                                    getContainerRequest()).getSession().getAttribute(Constants.OIDCCLIENT_USER_ATTRS));
+                }
+            });
+            response.setStatusCode(Response.Status.OK.getStatusCode());
+        } catch (Exception e) {
+            LOG.error("Error retrieving oidc user attributes", e);
+            response.setError(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), new StringBuilder()
+                    .append("ErrorMessage{{ ")
+                    .append(e.getMessage())
+                    .append(" }}")
+                    .toString());
+        }
+
+        return response;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java b/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java
index d5e0679..3147dd8 100644
--- a/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java
+++ b/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java
@@ -41,6 +41,8 @@ public class OIDCLoginResponseTO extends AbstractBaseBean {
 
     private boolean logoutSupported;
 
+    private boolean selfReg;
+
     private String accessToken;
 
     private Date accessTokenExpiryTime;
@@ -63,6 +65,14 @@ public class OIDCLoginResponseTO extends AbstractBaseBean {
         this.logoutSupported = logoutSupported;
     }
 
+    public boolean isSelfReg() {
+        return selfReg;
+    }
+
+    public void setSelfReg(final boolean selfReg) {
+        this.selfReg = selfReg;
+    }
+
     public String getAccessToken() {
         return accessToken;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java b/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java
index 699147e..6c1e284 100644
--- a/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java
+++ b/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java
@@ -66,6 +66,8 @@ public class OIDCProviderTO extends AbstractBaseBean implements EntityTO, ItemCo
 
     private boolean updateMatching;
 
+    private boolean selfRegUnmatching;
+
     private final List<ItemTO> items = new ArrayList<>();
 
     private final Set<String> actionsClassNames = new HashSet<>();
@@ -185,6 +187,14 @@ public class OIDCProviderTO extends AbstractBaseBean implements EntityTO, ItemCo
         this.updateMatching = updateMatching;
     }
 
+    public boolean isSelfRegUnmatching() {
+        return selfRegUnmatching;
+    }
+
+    public void setSelfRegUnmatching(final boolean selfRegUnmatching) {
+        this.selfRegUnmatching = selfRegUnmatching;
+    }
+
     @Override
     public ItemTO getConnObjectKeyItem() {
         return IterableUtils.find(getItems(), new Predicate<ItemTO>() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java b/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java
index c96f79f..5645ed9 100644
--- a/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java
+++ b/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java
@@ -52,6 +52,7 @@ import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.OIDCLoginRequestTO;
 import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
 import org.apache.syncope.common.lib.to.OIDCLogoutRequestTO;
+import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
@@ -320,6 +321,21 @@ public class OIDCClientLogic extends AbstractTransactionalLogic<AbstractBaseBean
                         return userManager.create(op, responseTO, emailValue);
                     }
                 });
+            } else if (op.isSelfRegUnmatching()) {
+                UserTO userTO = new UserTO();
+
+                userManager.fill(op, responseTO, userTO);
+
+                responseTO.getAttrs().clear();
+                responseTO.getAttrs().addAll(userTO.getPlainAttrs());
+                responseTO.getAttrs().addAll(userTO.getVirAttrs());
+                if (StringUtils.isNotBlank(userTO.getUsername())) {
+                    responseTO.setUsername(userTO.getUsername());
+                }
+
+                responseTO.setSelfReg(true);
+
+                return responseTO;
             } else {
                 throw new NotFoundException(keyValue == null
                         ? "User marching the provided claims"

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java b/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java
index 7759369..47a9bd8 100644
--- a/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java
+++ b/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java
@@ -54,7 +54,7 @@ public interface OIDCProvider extends Entity {
     String getUserinfoEndpoint();
 
     void setUserinfoEndpoint(String userinfoEndpoint);
-    
+
     String getEndSessionEndpoint();
 
     void setEndSessionEndpoint(String endSessionEndpoint);
@@ -62,11 +62,15 @@ public interface OIDCProvider extends Entity {
     boolean getHasDiscovery();
 
     void setHasDiscovery(boolean hasDiscovery);
-    
+
     boolean isCreateUnmatching();
 
     void setCreateUnmatching(boolean createUnmatching);
 
+    boolean isSelfRegUnmatching();
+
+    void setSelfRegUnmatching(boolean selfRegUnmatching);
+
     boolean isUpdateMatching();
 
     void setUpdateMatching(boolean updateMatching);

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java
index cfd8ccc..e42eb0e 100644
--- a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java
+++ b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java
@@ -40,10 +40,12 @@ import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
 import org.apache.syncope.core.persistence.api.entity.OIDCProviderItem;
 import org.apache.syncope.core.persistence.api.entity.OIDCUserTemplate;
+import org.apache.syncope.core.persistence.jpa.validation.entity.OIDCProviderCheck;
 
 @Entity
 @Table(name = JPAOIDCProvider.TABLE)
 @Cacheable
+@OIDCProviderCheck
 public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCProvider {
 
     public static final String TABLE = "OIDCProvider";
@@ -73,7 +75,7 @@ public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCP
 
     @Column(nullable = true)
     private String userinfoEndpoint;
-    
+
     @Column(nullable = true)
     private String endSessionEndpoint;
 
@@ -94,6 +96,11 @@ public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCP
     @Min(0)
     @Max(1)
     @Column(nullable = false)
+    private Integer selfRegUnmatching;
+
+    @Min(0)
+    @Max(1)
+    @Column(nullable = false)
     private Integer updateMatching;
 
     @ElementCollection(fetch = FetchType.EAGER)
@@ -182,7 +189,7 @@ public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCP
     public void setUserinfoEndpoint(final String userinfoEndpoint) {
         this.userinfoEndpoint = userinfoEndpoint;
     }
-    
+
     @Override
     public String getEndSessionEndpoint() {
         return endSessionEndpoint;
@@ -214,6 +221,16 @@ public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCP
     }
 
     @Override
+    public boolean isSelfRegUnmatching() {
+        return isBooleanAsInteger(selfRegUnmatching);
+    }
+
+    @Override
+    public void setSelfRegUnmatching(final boolean selfRegUnmatching) {
+        this.selfRegUnmatching = getBooleanAsInteger(selfRegUnmatching);
+    }
+
+    @Override
     public boolean isUpdateMatching() {
         return isBooleanAsInteger(updateMatching);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderCheck.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderCheck.java b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderCheck.java
new file mode 100644
index 0000000..2f96a33
--- /dev/null
+++ b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderCheck.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.validation.entity;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = OIDCProviderValidator.class)
+@Documented
+public @interface OIDCProviderCheck {
+
+    String message() default "{org.apache.syncope.core.persistence.validation.oidcprovider}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderValidator.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderValidator.java b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderValidator.java
new file mode 100644
index 0000000..87f7c52
--- /dev/null
+++ b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderValidator.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.validation.entity;
+
+import javax.validation.ConstraintValidatorContext;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
+import org.apache.syncope.core.persistence.api.entity.OIDCProviderItem;
+import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
+
+public class OIDCProviderValidator extends AbstractValidator<OIDCProviderCheck, OIDCProvider> {
+
+    @Override
+    public boolean isValid(final OIDCProvider value, final ConstraintValidatorContext context) {
+
+        if (value.isSelfRegUnmatching() && value.isCreateUnmatching()) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.Standard,
+                            "Either selfRegUnmatching or createUnmatching, not both")).
+                    addPropertyNode("selfRegUnmatching").
+                    addPropertyNode("createUnmatching").addConstraintViolation();
+            return false;
+        }
+
+        long connObjectKeys = IterableUtils.countMatches(value.getItems(), new Predicate<OIDCProviderItem>() {
+
+            @Override
+            public boolean evaluate(final OIDCProviderItem item) {
+                return item.isConnObjectKey();
+            }
+        });
+        if (!value.getItems().isEmpty() && connObjectKeys != 1) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, "Single ConnObjectKey mapping is required")).
+                    addPropertyNode("connObjectKey.size").addConstraintViolation();
+            return false;
+        }
+
+        boolean isValid = true;
+
+        long passwords = IterableUtils.countMatches(value.getItems(), new Predicate<OIDCProviderItem>() {
+
+            @Override
+            public boolean evaluate(final OIDCProviderItem item) {
+                return item.isPassword();
+            }
+        });
+        if (passwords > 0) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, "No password mapping is allowed")).
+                    addPropertyNode("password.size").addConstraintViolation();
+            isValid = false;
+        }
+
+        for (OIDCProviderItem item : value.getItems()) {
+            for (String className : item.getTransformerClassNames()) {
+                Class<?> actionsClass = null;
+                boolean isAssignable = false;
+                try {
+                    actionsClass = Class.forName(className);
+                    isAssignable = ItemTransformer.class.isAssignableFrom(actionsClass);
+                } catch (Exception e) {
+                    LOG.error("Invalid MappingItemTransformer specified: {}", className, e);
+                }
+
+                if (actionsClass == null || !isAssignable) {
+                    context.buildConstraintViolationWithTemplate(
+                            getTemplate(EntityViolationType.InvalidMapping,
+                                    "Invalid mapping item trasformer class name")).
+                            addPropertyNode("mappingItemTransformerClassName").addConstraintViolation();
+                    isValid = false;
+                }
+            }
+        }
+
+        return isValid;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
index 0f01eac..1849fe3 100644
--- a/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
+++ b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
@@ -185,6 +185,7 @@ public class OIDCProviderDataBinderImpl implements OIDCProviderDataBinder {
         op.setEndSessionEndpoint(opTO.getEndSessionEndpoint());
         op.setHasDiscovery(opTO.getHasDiscovery());
         op.setCreateUnmatching(opTO.isCreateUnmatching());
+        op.setSelfRegUnmatching(opTO.isSelfRegUnmatching());
         op.setUpdateMatching(opTO.isUpdateMatching());
 
         if (opTO.getUserTemplate() == null) {
@@ -252,6 +253,7 @@ public class OIDCProviderDataBinderImpl implements OIDCProviderDataBinder {
         opTO.setEndSessionEndpoint(op.getEndSessionEndpoint());
         opTO.setHasDiscovery(op.getHasDiscovery());
         opTO.setCreateUnmatching(op.isCreateUnmatching());
+        opTO.setSelfRegUnmatching(op.isSelfRegUnmatching());
         opTO.setUpdateMatching(op.isUpdateMatching());
 
         if (op.getUserTemplate() != null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/fit/console-reference/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/fit/console-reference/src/main/webapp/WEB-INF/web.xml b/fit/console-reference/src/main/webapp/WEB-INF/web.xml
index 4bfe198..7497b2e 100644
--- a/fit/console-reference/src/main/webapp/WEB-INF/web.xml
+++ b/fit/console-reference/src/main/webapp/WEB-INF/web.xml
@@ -71,6 +71,11 @@ under the License.
     <param-name>oidcclient.logout.error.url</param-name>
     <param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.Login</param-value>
   </context-param>
+  
+  <context-param>
+    <param-name>oidcclient.redirect.selfreg</param-name>
+    <param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.OIDCClientSelfReg</param-value>
+  </context-param>
 
   <!-- SESSION TIMEOUT (MINUTES)-->
   <session-config>

http://git-wip-us.apache.org/repos/asf/syncope/blob/e7d67951/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml b/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
index 03444d2..24b263a 100644
--- a/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
+++ b/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
@@ -71,7 +71,11 @@ under the License.
     <param-value>../wicket/bookmarkable/org.apache.syncope.client.enduser.pages.HomePage</param-value>
   </context-param>
 
-
+  <context-param>
+    <param-name>oidcclient.redirect.selfreg</param-name>
+    <param-value>../wicket/bookmarkable/org.apache.syncope.client.enduser.pages.OIDCClientSelfReg</param-value>
+  </context-param>
+  
   <!-- SESSION TIMEOUT (MINUTES)-->
   <session-config>
     <session-timeout>30</session-timeout>


[2/2] syncope git commit: [SYNCOPE-1018] self registration for OpenID Connect - This closes #76

Posted by il...@apache.org.
[SYNCOPE-1018] self registration for OpenID Connect - This closes #76


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/3b385e5c
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/3b385e5c
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/3b385e5c

Branch: refs/heads/master
Commit: 3b385e5c9c788f7e013b363e9c940f2544725644
Parents: 3f0c52c
Author: dayash <di...@tirasa.net>
Authored: Fri May 11 12:28:52 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri May 11 15:01:54 2018 +0200

----------------------------------------------------------------------
 .../syncope/client/enduser/pages/HomePage.java  |  2 +
 .../resources/META-INF/resources/app/index.html |  2 +
 .../resources/META-INF/resources/app/js/app.js  | 14 ++++
 .../app/js/controllers/OIDCClientController.js  | 29 +++++++
 .../app/js/controllers/UserController.js        | 28 ++++++-
 .../app/js/services/oidcClientService.js        | 42 ++++++++++
 .../ext/oidcclient/agent/CodeConsumer.java      | 41 +++++++--
 .../syncope/ext/oidcclient/agent/Constants.java |  4 +
 .../client/console/pages/OIDCClientSelfReg.java | 38 +++++++++
 .../wizards/OIDCProviderWizardBuilder.java      |  5 ++
 .../wizards/OIDCProviderWizardBuilder$OP.html   |  1 +
 .../OIDCProviderWizardBuilder$OP.properties     |  1 +
 .../OIDCProviderWizardBuilder$OP_it.properties  |  1 +
 ...IDCProviderWizardBuilder$OP_pt_BR.properties |  1 +
 .../OIDCProviderWizardBuilder$OP_ru.properties  |  1 +
 .../client/enduser/pages/OIDCClientSelfReg.java | 50 +++++++++++
 .../resources/OIDCClientUserAttrsResource.java  | 65 +++++++++++++++
 .../common/lib/to/OIDCLoginResponseTO.java      | 10 +++
 .../syncope/common/lib/to/OIDCProviderTO.java   | 10 +++
 .../syncope/core/logic/OIDCClientLogic.java     | 16 ++++
 .../persistence/api/entity/OIDCProvider.java    |  6 +-
 .../persistence/jpa/entity/JPAOIDCProvider.java | 21 ++++-
 .../validation/entity/OIDCProviderCheck.java    | 41 +++++++++
 .../entity/OIDCProviderValidator.java           | 88 ++++++++++++++++++++
 .../java/data/OIDCProviderDataBinderImpl.java   |  2 +
 .../src/main/webapp/WEB-INF/web.xml             |  5 ++
 .../src/main/webapp/WEB-INF/web.xml             |  6 +-
 27 files changed, 516 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
index 1e78222..3adec28 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
@@ -40,6 +40,8 @@ public class HomePage extends WebPage {
             appendMessage(redirectUrl, parameters.get("successMessage").toString());
         } else if (!parameters.get("saml2SPUserAttrs").isNull()) {
             redirectUrl.append("#!self-saml2sp");
+        } else if (!parameters.get("oidcClientUserAttrs").isNull()) {
+            redirectUrl.append("#!self-oidcclient");
         }
         throw new NonResettingRestartException(redirectUrl.toString());
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/client/enduser/src/main/resources/META-INF/resources/app/index.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/index.html b/client/enduser/src/main/resources/META-INF/resources/app/index.html
index 2613a6e..3aa57f5 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/index.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/index.html
@@ -102,10 +102,12 @@ under the License.
   <script src="js/services/saml2IdPService.js"></script>
   <script src="js/services/oidcProviderService.js"></script>
   <script src="js/services/saml2SPService.js"></script>
+  <script src="js/services/oidcClientService.js"></script>
   <!--controllers-->
   <script src="js/controllers/HomeController.js"></script>
   <script src="js/controllers/LoginController.js"></script>
   <script src="js/controllers/SAML2SPController.js"></script>
+  <script src="js/controllers/OIDCClientController.js"></script>
   <script src="js/controllers/UserController.js"></script>
   <!--directives-->
   <script src="js/directives/dynamicPlainAttribute.js"></script>

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
index 1019cad..475f74b 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
@@ -86,6 +86,20 @@ app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', '$translate
               }
             })
             /* </Extensions> */
+            
+            /* <Extensions> */
+            .state('self-oidcclient', {
+              url: '/self-oidcclient',
+              templateUrl: 'views/self.html',
+              controller: 'OIDCClientController',
+              resolve: {
+                'userAttrs': ['OIDCClientService',
+                  function (OIDCClientService) {
+                    return OIDCClientService.getOIDCClientUserAttrs();
+                  }]
+              }
+            })
+            /* </Extensions> */
             .state('user-self-update', {
               url: '/user-self-update',
               templateUrl: 'views/home.html',

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/OIDCClientController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/OIDCClientController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/OIDCClientController.js
new file mode 100644
index 0000000..f3eab68
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/OIDCClientController.js
@@ -0,0 +1,29 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+'use strict';
+angular.module("login").controller("OIDCClientController", function ($scope, $rootScope, $location, userAttrs) {
+  $scope.selfCreate = function () {
+    $location.path("/self/create");
+  };
+
+  $rootScope.oidcops.userAttrs = userAttrs;
+
+  $scope.selfCreate();
+});

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
index d2380f1..629c90d 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
@@ -45,6 +45,8 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
 
     /* <Extensions> */
     $scope.loadFromSAML2AuthSelfReg = $rootScope.saml2idps.userAttrs && $rootScope.saml2idps.userAttrs.length;
+
+    $scope.loadFromOIDCAuthSelfReg = $rootScope.oidcops.userAttrs && $rootScope.oidcops.userAttrs.length;
     /* </Extensions> */
 
     $scope.initUser = function () {
@@ -71,6 +73,12 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
                 ? found[0].values : [];
       };
 
+      var findLoadedOIDCAttrValue = function (schemaKey) {
+        var found = $filter('filter')($rootScope.oidcops.userAttrs, {"schema": schemaKey}, true);
+        return (found && found.length && found[0].values && found[0].values.length)
+                ? found[0].values : [];
+      };
+
       var initUserSchemas = function (anyTypeClass, group) {
         // initialization is done here synchronously to have all schema fields populated correctly
         var schemaService;
@@ -127,6 +135,10 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
             if ($scope.loadFromSAML2AuthSelfReg) {
               $scope.user.plainAttrs[plainSchemaKey].values = findLoadedSAML2AttrValue(plainSchemaKey);
             }
+            
+            if ($scope.loadFromOIDCAuthSelfReg) {
+              $scope.user.plainAttrs[plainSchemaKey].values = findLoadedOIDCAttrValue(plainSchemaKey);
+            }
 
             if (schemas.plainSchemas[i].multivalue) {
               // initialize multivalue schema and support table: create mode, default multivalues
@@ -181,6 +193,10 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
             if ($scope.loadFromSAML2AuthSelfReg) {
               $scope.user.virAttrs[virSchemaKey].values = findLoadedSAML2AttrValue(virSchemaKey);
             }
+            
+             if ($scope.loadFromOIDCAuthSelfReg) {
+              $scope.user.virAttrs[virSchemaKey].values = findLoadedOIDCAttrValue(virSchemaKey);
+            }
 
             // initialize multivalue attribute and support table: create mode, only first value
             $scope.dynamicForm.virtualAttributeTable[schemas.virSchemas[i].key] = {
@@ -205,6 +221,9 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
 
         //clean SAML Self Reg user attributes variable
         delete $rootScope.saml2idps.userAttrs;
+        
+        //clean OIDC Self Reg user attributes variable
+        delete $rootScope.oidcops.userAttrs;
       };
 
       var initSecurityQuestions = function () {
@@ -450,7 +469,14 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
           if (username.length) {
             $scope.user.username = username[0];
           }
-        }
+        } 
+        
+        if ($scope.loadFromOIDCAuthSelfReg) {
+          var username = findLoadedOIDCAttrValue("username");
+          if (username.length) {
+            $scope.user.username = username[0];
+          }
+        } 
       } else {
         // read user from syncope core
         readUser();

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/client/enduser/src/main/resources/META-INF/resources/app/js/services/oidcClientService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/oidcClientService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/oidcClientService.js
new file mode 100644
index 0000000..9e8cbc0
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/oidcClientService.js
@@ -0,0 +1,42 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+'use strict';
+
+angular.module('self')
+        .factory('OIDCClientService', ['$q', '$http',
+          function ($q, $http) {
+
+            var oidcClientService = {};
+
+            oidcClientService.getOIDCClientUserAttrs = function () {
+              return $http.get("../api/OIDCClients/userAttrs")
+                      .then(function (response) {
+                        return response.data;
+                      }, function (response) {
+                        console.error("Something went wrong while getting oidc user attributes, exit with status: ",
+                                response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+
+            return oidcClientService;
+          }]);
+
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
index 20c39c4..7bb26c1 100644
--- a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
+++ b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
@@ -18,6 +18,8 @@
  */
 package org.apache.syncope.ext.oidcclient.agent;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
@@ -29,6 +31,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.OIDCConstants;
+import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
 import org.apache.syncope.common.rest.api.service.OIDCClientService;
 import org.slf4j.Logger;
@@ -41,6 +44,9 @@ public class CodeConsumer extends HttpServlet {
 
     protected static final Logger LOG = LoggerFactory.getLogger(CodeConsumer.class);
 
+    private static final ObjectMapper MAPPER =
+            new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+
     @Override
     protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
             throws ServletException, IOException {
@@ -59,17 +65,34 @@ public class CodeConsumer extends HttpServlet {
                         request.getRequestURL().toString(),
                         authorizationCode,
                         request.getSession().getAttribute(OIDCConstants.OP).toString());
-                request.getSession().setAttribute(
-                        Constants.OIDCCLIENTJWT, responseTO.getAccessToken());
-                request.getSession().setAttribute(
-                        Constants.OIDCCLIENTJWT_EXPIRE, responseTO.getAccessTokenExpiryTime());
+                if (responseTO.isSelfReg()) {
+                    responseTO.getAttrs().add(
+                            new AttrTO.Builder().schema("username").values(responseTO.getUsername()).build());
+                    request.getSession(true).
+                            setAttribute(Constants.OIDCCLIENT_USER_ATTRS, MAPPER.writeValueAsString(responseTO.
+                                    getAttrs()));
 
-                String successURL = getServletContext().getInitParameter(Constants.CONTEXT_PARAM_LOGIN_SUCCESS_URL);
-                if (successURL == null) {
-                    request.setAttribute("responseTO", responseTO);
-                    request.getRequestDispatcher("loginSuccess.jsp").forward(request, response);
+                    String selfRegRedirectURL =
+                            getServletContext().getInitParameter(Constants.CONTEXT_PARAM_REDIRECT_SELFREG_URL);
+                    if (selfRegRedirectURL == null) {
+                        request.setAttribute("responseTO", responseTO);
+                        request.getRequestDispatcher("loginSuccess.jsp").forward(request, response);
+                    } else {
+                        response.sendRedirect(selfRegRedirectURL);
+                    }
                 } else {
-                    response.sendRedirect(successURL + "?logoutSupported=" + responseTO.isLogoutSupported());
+                    request.getSession().setAttribute(
+                            Constants.OIDCCLIENTJWT, responseTO.getAccessToken());
+                    request.getSession().setAttribute(
+                            Constants.OIDCCLIENTJWT_EXPIRE, responseTO.getAccessTokenExpiryTime());
+
+                    String successURL = getServletContext().getInitParameter(Constants.CONTEXT_PARAM_LOGIN_SUCCESS_URL);
+                    if (successURL == null) {
+                        request.setAttribute("responseTO", responseTO);
+                        request.getRequestDispatcher("loginSuccess.jsp").forward(request, response);
+                    } else {
+                        response.sendRedirect(successURL + "?logoutSupported=" + responseTO.isLogoutSupported());
+                    }
                 }
             } else {
                 throw new IllegalArgumentException("Invalid " + OIDCConstants.STATE + " provided");

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java
index 988b7cc..62e00c0 100644
--- a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java
+++ b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/Constants.java
@@ -34,10 +34,14 @@ public final class Constants {
 
     public static final String CONTEXT_PARAM_LOGOUT_ERROR_URL = "oidcclient.logout.error.url";
 
+    public static final String CONTEXT_PARAM_REDIRECT_SELFREG_URL = "oidcclient.redirect.selfreg";
+
     public static final String OIDCCLIENTJWT = "oidcclient.jwt";
 
     public static final String OIDCCLIENTJWT_EXPIRE = "oidcclient.jwt.expire";
 
+    public static final String OIDCCLIENT_USER_ATTRS = "oidcclient.userattrs";
+
     private Constants() {
         // private constructor for static utility class
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCClientSelfReg.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCClientSelfReg.java b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCClientSelfReg.java
new file mode 100644
index 0000000..db29dce
--- /dev/null
+++ b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCClientSelfReg.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+public class OIDCClientSelfReg extends WebPage {
+
+    private static final long serialVersionUID = 864538706654644353L;
+
+    private static final String OIDC_ACCESS_ERROR =
+            "OpenID Connect error - Admin Console does not support Self Registration";
+
+    public OIDCClientSelfReg(final PageParameters parameters) {
+        super(parameters);
+
+        PageParameters params = new PageParameters();
+        params.add("errorMessage", OIDC_ACCESS_ERROR);
+        setResponsePage(Login.class, params);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java
index 9fec11b..680746d 100644
--- a/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java
+++ b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java
@@ -135,6 +135,11 @@ public class OIDCProviderWizardBuilder extends AjaxWizardBuilder<OIDCProviderTO>
                     false);
             add(createUnmatching);
 
+            AjaxCheckBoxPanel selfRegUnmatching = new AjaxCheckBoxPanel(
+                    "selfRegUnmatching", "selfRegUnmatching", new PropertyModel<Boolean>(opTO, "selfRegUnmatching"),
+                    false);
+            add(selfRegUnmatching);
+
             AjaxCheckBoxPanel updateMatching = new AjaxCheckBoxPanel(
                     "updateMatching", "updateMatching", new PropertyModel<Boolean>(opTO, "updateMatching"), false);
             add(updateMatching);

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html
index 4ad49d8..cfe5df7 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.html
@@ -22,6 +22,7 @@ under the License.  actionsClassNames
     <div class="form-group"><span wicket:id="clientID">[clientID]</span></div>
     <div class="form-group"><span wicket:id="clientSecret">[clientSecret]</span></div>
     <div class="form-group"><span wicket:id="createUnmatching">[createUnmatching]</span></div>
+    <div class="form-group"><span wicket:id="selfRegUnmatching">[selfRegUnmatching]</span></div>
     <div class="form-group"><span wicket:id="updateMatching">[updateMatching]</span></div>
     <div class="form-group"><span wicket:id="actionsClassNames">[actionsClassNames]</span></div>
   </wicket:panel>

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties
index 5ed531a..123372f 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP.properties
@@ -18,6 +18,7 @@ name=Name
 clientID=Client ID
 clientSecret=Client Secret
 createUnmatching=Create unmatching users
+selfRegUnmatching=OIDC-initiated self-registration
 updateMatching=Update matching users
 actionsClassNames=Actions
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties
index 5ed531a..123372f 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_it.properties
@@ -18,6 +18,7 @@ name=Name
 clientID=Client ID
 clientSecret=Client Secret
 createUnmatching=Create unmatching users
+selfRegUnmatching=OIDC-initiated self-registration
 updateMatching=Update matching users
 actionsClassNames=Actions
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties
index 5ed531a..123372f 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_pt_BR.properties
@@ -18,6 +18,7 @@ name=Name
 clientID=Client ID
 clientSecret=Client Secret
 createUnmatching=Create unmatching users
+selfRegUnmatching=OIDC-initiated self-registration
 updateMatching=Update matching users
 actionsClassNames=Actions
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties
index 5ed531a..123372f 100644
--- a/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties
+++ b/ext/oidcclient/client-console/src/main/resources/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder$OP_ru.properties
@@ -18,6 +18,7 @@ name=Name
 clientID=Client ID
 clientSecret=Client Secret
 createUnmatching=Create unmatching users
+selfRegUnmatching=OIDC-initiated self-registration
 updateMatching=Update matching users
 actionsClassNames=Actions
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/OIDCClientSelfReg.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/OIDCClientSelfReg.java b/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/OIDCClientSelfReg.java
new file mode 100644
index 0000000..68bbc7b
--- /dev/null
+++ b/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/OIDCClientSelfReg.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.enduser.pages;
+
+import org.apache.syncope.ext.oidcclient.agent.Constants;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OIDCClientSelfReg extends WebPage {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OIDCClientSelfReg.class);
+
+    private static final long serialVersionUID = -2533879075075645461L;
+
+    private static final String OIDC_ACCESS_ERROR = "OpenID Connect error - while getting user attributes";
+
+    public OIDCClientSelfReg(final PageParameters parameters) {
+        super(parameters);
+
+        PageParameters params = new PageParameters();
+        try {
+            params.add("oidcClientUserAttrs", ((ServletWebRequest) getRequest()).getContainerRequest().
+                    getSession().getAttribute(Constants.OIDCCLIENT_USER_ATTRS));
+        } catch (Exception e) {
+            LOG.error("While extracting user attributes", e);
+
+            params.add("errorMessage", OIDC_ACCESS_ERROR);
+        }
+        setResponsePage(getApplication().getHomePage(), params);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/resources/OIDCClientUserAttrsResource.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/resources/OIDCClientUserAttrsResource.java b/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/resources/OIDCClientUserAttrsResource.java
new file mode 100644
index 0000000..29dfa3c
--- /dev/null
+++ b/ext/oidcclient/client-enduser/src/main/java/org/apache/syncope/client/enduser/resources/OIDCClientUserAttrsResource.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.enduser.annotations.Resource;
+import org.apache.syncope.ext.oidcclient.agent.Constants;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.request.resource.IResource;
+
+@Resource(key = "OIDCClients", path = "/api/OIDCClients/userAttrs")
+public class OIDCClientUserAttrsResource extends BaseResource {
+
+    private static final long serialVersionUID = 7273151109078469253L;
+
+    @Override
+    protected ResourceResponse newResourceResponse(final IResource.Attributes attributes) {
+        ResourceResponse response = new ResourceResponse();
+        response.setContentType(MediaType.APPLICATION_JSON);
+
+        try {
+            response.setTextEncoding(StandardCharsets.UTF_8.name());
+            response.setWriteCallback(new AbstractResource.WriteCallback() {
+
+                @Override
+                public void writeData(final Attributes attributes) throws IOException {
+                    attributes.getResponse().write(
+                            (CharSequence) ((HttpServletRequest) RequestCycle.get().getRequest().
+                                    getContainerRequest()).getSession().getAttribute(Constants.OIDCCLIENT_USER_ATTRS));
+                }
+            });
+            response.setStatusCode(Response.Status.OK.getStatusCode());
+        } catch (Exception e) {
+            LOG.error("Error retrieving oidc user attributes", e);
+            response.setError(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), new StringBuilder()
+                    .append("ErrorMessage{{ ")
+                    .append(e.getMessage())
+                    .append(" }}")
+                    .toString());
+        }
+
+        return response;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java b/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java
index 7b670c4..78e4dd6 100644
--- a/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java
+++ b/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCLoginResponseTO.java
@@ -40,6 +40,8 @@ public class OIDCLoginResponseTO extends AbstractBaseBean {
 
     private boolean logoutSupported;
 
+    private boolean selfReg;
+
     private String accessToken;
 
     private Date accessTokenExpiryTime;
@@ -62,6 +64,14 @@ public class OIDCLoginResponseTO extends AbstractBaseBean {
         this.logoutSupported = logoutSupported;
     }
 
+    public boolean isSelfReg() {
+        return selfReg;
+    }
+
+    public void setSelfReg(final boolean selfReg) {
+        this.selfReg = selfReg;
+    }
+
     public String getAccessToken() {
         return accessToken;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java b/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java
index 86f5535..7669d22 100644
--- a/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java
+++ b/ext/oidcclient/common-lib/src/main/java/org/apache/syncope/common/lib/to/OIDCProviderTO.java
@@ -64,6 +64,8 @@ public class OIDCProviderTO extends AbstractBaseBean implements EntityTO, ItemCo
 
     private boolean updateMatching;
 
+    private boolean selfRegUnmatching;
+
     private final List<ItemTO> items = new ArrayList<>();
 
     private final Set<String> actionsClassNames = new HashSet<>();
@@ -183,6 +185,14 @@ public class OIDCProviderTO extends AbstractBaseBean implements EntityTO, ItemCo
         this.updateMatching = updateMatching;
     }
 
+    public boolean isSelfRegUnmatching() {
+        return selfRegUnmatching;
+    }
+
+    public void setSelfRegUnmatching(final boolean selfRegUnmatching) {
+        this.selfRegUnmatching = selfRegUnmatching;
+    }
+
     @Override
     public ItemTO getConnObjectKeyItem() {
         return getItems().stream().filter(ItemTO::isConnObjectKey).findFirst().get();

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java b/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java
index 8a98585..12ca5fa 100644
--- a/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java
+++ b/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/OIDCClientLogic.java
@@ -52,6 +52,7 @@ import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.OIDCLoginRequestTO;
 import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
 import org.apache.syncope.common.lib.to.OIDCLogoutRequestTO;
+import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
@@ -314,6 +315,21 @@ public class OIDCClientLogic extends AbstractTransactionalLogic<AbstractBaseBean
                 final String emailValue = userInfo.getEmail();
                 username = AuthContextUtils.execWithAuthContext(AuthContextUtils.getDomain(),
                         () -> userManager.create(op, responseTO, emailValue));
+            } else if (op.isSelfRegUnmatching()) {
+                UserTO userTO = new UserTO();
+
+                userManager.fill(op, responseTO, userTO);
+
+                responseTO.getAttrs().clear();
+                responseTO.getAttrs().addAll(userTO.getPlainAttrs());
+                responseTO.getAttrs().addAll(userTO.getVirAttrs());
+                if (StringUtils.isNotBlank(userTO.getUsername())) {
+                    responseTO.setUsername(userTO.getUsername());
+                }
+
+                responseTO.setSelfReg(true);
+
+                return responseTO;
             } else {
                 throw new NotFoundException(keyValue == null
                         ? "User marching the provided claims"

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java b/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java
index 585ba9a..ad96052 100644
--- a/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java
+++ b/ext/oidcclient/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/OIDCProvider.java
@@ -55,7 +55,7 @@ public interface OIDCProvider extends Entity {
     String getUserinfoEndpoint();
 
     void setUserinfoEndpoint(String userinfoEndpoint);
-    
+
     String getEndSessionEndpoint();
 
     void setEndSessionEndpoint(String endSessionEndpoint);
@@ -68,6 +68,10 @@ public interface OIDCProvider extends Entity {
 
     void setCreateUnmatching(boolean createUnmatching);
 
+    boolean isSelfRegUnmatching();
+
+    void setSelfRegUnmatching(boolean selfRegUnmatching);
+
     boolean isUpdateMatching();
 
     void setUpdateMatching(boolean updateMatching);

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java
index 9a7224f..b161241 100644
--- a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java
+++ b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProvider.java
@@ -39,10 +39,12 @@ import javax.validation.constraints.Min;
 import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
 import org.apache.syncope.core.persistence.api.entity.OIDCProviderItem;
 import org.apache.syncope.core.persistence.api.entity.OIDCUserTemplate;
+import org.apache.syncope.core.persistence.jpa.validation.entity.OIDCProviderCheck;
 
 @Entity
 @Table(name = JPAOIDCProvider.TABLE)
 @Cacheable
+@OIDCProviderCheck
 public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCProvider {
 
     public static final String TABLE = "OIDCProvider";
@@ -72,7 +74,7 @@ public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCP
 
     @Column(nullable = true)
     private String userinfoEndpoint;
-    
+
     @Column(nullable = true)
     private String endSessionEndpoint;
 
@@ -93,6 +95,11 @@ public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCP
     @Min(0)
     @Max(1)
     @Column(nullable = false)
+    private Integer selfRegUnmatching;
+
+    @Min(0)
+    @Max(1)
+    @Column(nullable = false)
     private Integer updateMatching;
 
     @ElementCollection(fetch = FetchType.EAGER)
@@ -181,7 +188,7 @@ public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCP
     public void setUserinfoEndpoint(final String userinfoEndpoint) {
         this.userinfoEndpoint = userinfoEndpoint;
     }
-    
+
     @Override
     public String getEndSessionEndpoint() {
         return endSessionEndpoint;
@@ -213,6 +220,16 @@ public class JPAOIDCProvider extends AbstractGeneratedKeyEntity implements OIDCP
     }
 
     @Override
+    public boolean isSelfRegUnmatching() {
+        return isBooleanAsInteger(selfRegUnmatching);
+    }
+
+    @Override
+    public void setSelfRegUnmatching(final boolean selfRegUnmatching) {
+        this.selfRegUnmatching = getBooleanAsInteger(selfRegUnmatching);
+    }
+
+    @Override
     public boolean isUpdateMatching() {
         return isBooleanAsInteger(updateMatching);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderCheck.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderCheck.java b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderCheck.java
new file mode 100644
index 0000000..2f96a33
--- /dev/null
+++ b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderCheck.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.validation.entity;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = OIDCProviderValidator.class)
+@Documented
+public @interface OIDCProviderCheck {
+
+    String message() default "{org.apache.syncope.core.persistence.validation.oidcprovider}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderValidator.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderValidator.java b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderValidator.java
new file mode 100644
index 0000000..730f5e1
--- /dev/null
+++ b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/OIDCProviderValidator.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.validation.entity;
+
+import static org.apache.syncope.core.persistence.jpa.validation.entity.AbstractValidator.LOG;
+
+import javax.validation.ConstraintValidatorContext;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.common.lib.types.ImplementationEngine;
+import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
+import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
+
+public class OIDCProviderValidator extends AbstractValidator<OIDCProviderCheck, OIDCProvider> {
+
+    @Override
+    public boolean isValid(final OIDCProvider value, final ConstraintValidatorContext context) {
+
+        if (value.isSelfRegUnmatching() && value.isCreateUnmatching()) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.Standard,
+                            "Either selfRegUnmatching or createUnmatching, not both")).
+                    addPropertyNode("selfRegUnmatching").
+                    addPropertyNode("createUnmatching").addConstraintViolation();
+            return false;
+        }
+
+        long connObjectKeys = value.getItems().stream().filter(item -> item.isConnObjectKey()).count();
+        if (!value.getItems().isEmpty() && connObjectKeys != 1) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, "Single ConnObjectKey mapping is required")).
+                    addPropertyNode("connObjectKey.size").addConstraintViolation();
+            return false;
+        }
+
+        final boolean[] isValid = new boolean[] { true };
+
+        long passwords = value.getItems().stream().filter(item -> item.isPassword()).count();
+        if (passwords > 0) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, "No password mapping is allowed")).
+                    addPropertyNode("password.size").addConstraintViolation();
+            isValid[0] = false;
+        }
+
+        value.getItems().forEach(item -> {
+            item.getTransformers().stream().
+                    filter(transformer -> transformer.getEngine() == ImplementationEngine.JAVA).
+                    forEach(transformer -> {
+
+                        Class<?> actionsClass = null;
+                        boolean isAssignable = false;
+                        try {
+                            actionsClass = Class.forName(transformer.getBody());
+                            isAssignable = ItemTransformer.class.isAssignableFrom(actionsClass);
+                        } catch (Exception e) {
+                            LOG.error("Invalid ItemTransformer specified: {}", transformer.getBody(), e);
+                        }
+
+                        if (actionsClass == null || !isAssignable) {
+                            context.buildConstraintViolationWithTemplate(
+                                    getTemplate(EntityViolationType.InvalidMapping,
+                                            "Invalid item trasformer class name")).
+                                    addPropertyNode("itemTransformers").addConstraintViolation();
+                            isValid[0] = false;
+                        }
+                    });
+        });
+
+        return isValid[0];
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
index e2370bb..888d7a5 100644
--- a/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
+++ b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
@@ -181,6 +181,7 @@ public class OIDCProviderDataBinderImpl implements OIDCProviderDataBinder {
         op.setEndSessionEndpoint(opTO.getEndSessionEndpoint());
         op.setHasDiscovery(opTO.getHasDiscovery());
         op.setCreateUnmatching(opTO.isCreateUnmatching());
+        op.setSelfRegUnmatching(opTO.isSelfRegUnmatching());
         op.setUpdateMatching(opTO.isUpdateMatching());
 
         if (opTO.getUserTemplate() == null) {
@@ -245,6 +246,7 @@ public class OIDCProviderDataBinderImpl implements OIDCProviderDataBinder {
         opTO.setEndSessionEndpoint(op.getEndSessionEndpoint());
         opTO.setHasDiscovery(op.getHasDiscovery());
         opTO.setCreateUnmatching(op.isCreateUnmatching());
+        opTO.setSelfRegUnmatching(op.isSelfRegUnmatching());
         opTO.setUpdateMatching(op.isUpdateMatching());
 
         if (op.getUserTemplate() != null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/fit/console-reference/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/fit/console-reference/src/main/webapp/WEB-INF/web.xml b/fit/console-reference/src/main/webapp/WEB-INF/web.xml
index 4bfe198..7497b2e 100644
--- a/fit/console-reference/src/main/webapp/WEB-INF/web.xml
+++ b/fit/console-reference/src/main/webapp/WEB-INF/web.xml
@@ -71,6 +71,11 @@ under the License.
     <param-name>oidcclient.logout.error.url</param-name>
     <param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.Login</param-value>
   </context-param>
+  
+  <context-param>
+    <param-name>oidcclient.redirect.selfreg</param-name>
+    <param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.OIDCClientSelfReg</param-value>
+  </context-param>
 
   <!-- SESSION TIMEOUT (MINUTES)-->
   <session-config>

http://git-wip-us.apache.org/repos/asf/syncope/blob/3b385e5c/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml b/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
index 03444d2..24b263a 100644
--- a/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
+++ b/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
@@ -71,7 +71,11 @@ under the License.
     <param-value>../wicket/bookmarkable/org.apache.syncope.client.enduser.pages.HomePage</param-value>
   </context-param>
 
-
+  <context-param>
+    <param-name>oidcclient.redirect.selfreg</param-name>
+    <param-value>../wicket/bookmarkable/org.apache.syncope.client.enduser.pages.OIDCClientSelfReg</param-value>
+  </context-param>
+  
   <!-- SESSION TIMEOUT (MINUTES)-->
   <session-config>
     <session-timeout>30</session-timeout>