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 2021/04/09 06:39:43 UTC

[syncope] branch master updated: [SYNCOPE-1545] WA > OIDC 1.0 (#260)

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/master by this push:
     new 88db9c4  [SYNCOPE-1545] WA > OIDC 1.0 (#260)
88db9c4 is described below

commit 88db9c46dc99dd214f9cac7adae708345178263f
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Fri Apr 9 08:38:57 2021 +0200

    [SYNCOPE-1545] WA > OIDC 1.0 (#260)
---
 .../apache/syncope/client/console/pages/WA.java    |   3 +-
 .../apache/syncope/client/console/panels/OIDC.java | 180 +++++++++++++++++++++
 .../client/console/rest/OIDCJWKSRestClient.java    |  41 ++---
 .../panels/AuthModuleDirectoryPanel_ru.properties  |   3 -
 .../apache/syncope/client/console/panels/OIDC.html |  54 +++++++
 .../syncope/client/console/panels/OIDC.properties  |  20 +++
 .../client/console/panels/OIDC_fr_CA.properties    |  20 +++
 .../client/console/panels/OIDC_it.properties       |  20 +++
 .../client/console/panels/OIDC_ja.properties       |  20 +++
 .../client/console/panels/OIDC_pt_BR.properties    |  20 +++
 .../client/console/panels/OIDC_ru.properties       |  20 +++
 .../syncope/client/console/widgets/JobWidget.java  |  31 +---
 .../common/rest/api/service/OIDCJWKSService.java   |   5 +-
 .../apache/syncope/core/logic/OIDCJWKSLogic.java   |   8 +-
 .../core/rest/cxf/service/OIDCJWKSServiceImpl.java |  12 +-
 .../persistence/jpa/entity/auth/JPAOIDCJWKS.java   |   2 +
 .../jpa/entity/auth/JPASAML2IdPEntity.java         |   2 +-
 .../provisioning/api/data/OIDCJWKSDataBinder.java  |   4 +-
 .../java/data/OIDCJWKSDataBinderImpl.java          |   8 +-
 .../syncope/client/console/pages/OIDCC4UI.java     |   2 +-
 .../syncope/client/console/pages/OIDCC4UI.html     |   4 +-
 .../apache/syncope/fit/core/OIDCJWKSITCase.java    |   2 +-
 pom.xml                                            |   2 +-
 .../oidc/SyncopeWAOIDCJWKSGeneratorService.java    |   2 +-
 24 files changed, 396 insertions(+), 89 deletions(-)

diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
index b8fb6d9..4009f64 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
@@ -34,6 +34,7 @@ import org.apache.syncope.client.console.SyncopeWebApplication;
 import org.apache.syncope.client.console.annotations.AMPage;
 import org.apache.syncope.client.console.panels.AuthModuleDirectoryPanel;
 import org.apache.syncope.client.console.clientapps.ClientApps;
+import org.apache.syncope.client.console.panels.OIDC;
 import org.apache.syncope.client.console.panels.SAML2;
 import org.apache.syncope.client.console.panels.WAConfigDirectoryPanel;
 import org.apache.syncope.client.console.rest.WAConfigRestClient;
@@ -173,7 +174,7 @@ public class WA extends BasePage {
 
             @Override
             public Panel getPanel(final String panelId) {
-                return new AjaxTextFieldPanel(panelId, panelId, Model.of(""));
+                return new OIDC(panelId, waPrefix, getPageReference());
             }
         });
 
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDC.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDC.java
new file mode 100644
index 0000000..ab04dda
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDC.java
@@ -0,0 +1,180 @@
+/*
+ * 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.panels;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.rest.OIDCJWKSRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.JsonEditorPanel;
+import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
+import org.apache.syncope.common.lib.to.OIDCJWKSTO;
+import org.apache.syncope.common.lib.types.AMEntitlement;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OIDC extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(OIDC.class);
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    private final BaseModal<String> viewModal = new BaseModal<String>("viewModal") {
+
+        private static final long serialVersionUID = 389935548143327858L;
+
+        @Override
+        protected void onConfigure() {
+            super.onConfigure();
+            setFooterVisible(true);
+        }
+    };
+
+    private final AjaxLink<Void> view;
+
+    private final AjaxLink<Void> generate;
+
+    private final AjaxLink<Void> delete;
+
+    public OIDC(final String id, final String waPrefix, final PageReference pageRef) {
+        super(id);
+        setOutputMarkupId(true);
+
+        add(viewModal);
+        viewModal.size(Modal.Size.Extra_large);
+        viewModal.setWindowClosedCallback(target -> viewModal.show(false));
+
+        WebMarkupContainer container = new WebMarkupContainer("container");
+        add(container.setOutputMarkupId(true));
+
+        AtomicReference<OIDCJWKSTO> oidcjwksto = OIDCJWKSRestClient.get();
+
+        view = new AjaxLink<>("view") {
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                String pretty;
+                try {
+                    pretty = MAPPER.writerWithDefaultPrettyPrinter().
+                            writeValueAsString(MAPPER.readTree(oidcjwksto.get().getJson()));
+                } catch (IOException e) {
+                    LOG.error("Could not pretty-print", e);
+                    pretty = oidcjwksto.get().getJson();
+                }
+
+                viewModal.header(Model.of("JSON Web Key Sets"));
+                target.add(viewModal.setContent(new JsonEditorPanel(viewModal, Model.of(pretty), true, pageRef)));
+                viewModal.show(true);
+            }
+
+            @Override
+            protected void onComponentTag(final ComponentTag tag) {
+                super.onComponentTag(tag);
+
+                if (oidcjwksto.get() == null) {
+                    tag.put("class", "btn btn-app disabled");
+                }
+            }
+        };
+        view.setEnabled(oidcjwksto.get() != null);
+        container.add(view.setOutputMarkupId(true));
+        MetaDataRoleAuthorizationStrategy.authorize(view, ENABLE, AMEntitlement.OIDC_JWKS_READ);
+
+        generate = new AjaxLink<>("generate") {
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    oidcjwksto.set(OIDCJWKSRestClient.generate());
+                    generate.setEnabled(false);
+                    view.setEnabled(true);
+
+                    SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
+                    target.add(container);
+                } catch (Exception e) {
+                    LOG.error("While generating OIDC JWKS", e);
+                    SyncopeConsoleSession.get().onException(e);
+                }
+                ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
+            }
+
+            @Override
+            protected void onComponentTag(final ComponentTag tag) {
+                super.onComponentTag(tag);
+
+                if (oidcjwksto.get() != null) {
+                    tag.put("class", "btn btn-app disabled");
+                }
+            }
+        };
+        generate.setEnabled(oidcjwksto.get() == null);
+        container.add(generate.setOutputMarkupId(true));
+        MetaDataRoleAuthorizationStrategy.authorize(generate, ENABLE, AMEntitlement.OIDC_JWKS_GENERATE);
+
+        delete = new AjaxLink<>("delete") {
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    OIDCJWKSRestClient.delete();
+                    oidcjwksto.set(null);
+                    generate.setEnabled(true);
+                    view.setEnabled(false);
+
+                    SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
+                    target.add(container);
+                } catch (Exception e) {
+                    LOG.error("While deleting OIDC JWKS", e);
+                    SyncopeConsoleSession.get().onException(e);
+                }
+                ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
+            }
+
+            @Override
+            protected void onComponentTag(final ComponentTag tag) {
+                super.onComponentTag(tag);
+
+                if (oidcjwksto.get() == null) {
+                    tag.put("class", "btn btn-app disabled");
+                }
+            }
+        };
+        delete.setEnabled(oidcjwksto.get() != null);
+        container.add(delete.setOutputMarkupId(true));
+        MetaDataRoleAuthorizationStrategy.authorize(delete, ENABLE, AMEntitlement.OIDC_JWKS_DELETE);
+
+        String wellKnownURI = waPrefix + "/oidc/.well-known/openid-configuration";
+        container.add(new ExternalLink("wellKnownURI", wellKnownURI, wellKnownURI));
+    }
+}
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/OIDCJWKSRestClient.java
similarity index 51%
copy from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
copy to client/am/console/src/main/java/org/apache/syncope/client/console/rest/OIDCJWKSRestClient.java
index 81aee2c..340634c 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/OIDCJWKSRestClient.java
@@ -16,41 +16,34 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.syncope.core.rest.cxf.service;
+package org.apache.syncope.client.console.rest;
 
-import java.net.URI;
+import java.util.concurrent.atomic.AtomicReference;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
 import org.apache.syncope.common.lib.types.JWSAlgorithm;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.core.logic.OIDCJWKSLogic;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
 import org.apache.syncope.common.rest.api.service.OIDCJWKSService;
 
-@Service
-public class OIDCJWKSServiceImpl extends AbstractServiceImpl implements OIDCJWKSService {
+public class OIDCJWKSRestClient extends BaseRestClient {
 
-    @Autowired
-    private OIDCJWKSLogic logic;
+    private static final long serialVersionUID = -1392090291817187902L;
 
-    @Override
-    public OIDCJWKSTO read() {
-        return logic.read();
+    public static AtomicReference<OIDCJWKSTO> get() {
+        AtomicReference<OIDCJWKSTO> result = new AtomicReference<>();
+        try {
+            result.set(getService(OIDCJWKSService.class).get());
+        } catch (Exception e) {
+            LOG.debug("While getting OIDC JKS", e);
+        }
+        return result;
     }
 
-    @Override
-    public Response generate(final int size, final JWSAlgorithm algorithm) {
-        OIDCJWKSTO jwks = logic.generate(size, algorithm);
-        URI location = uriInfo.getAbsolutePathBuilder().path(jwks.getKey()).build();
-        return Response.created(location).
-                header(RESTHeaders.RESOURCE_KEY, jwks.getKey()).
-                entity(jwks).
-                build();
+    public static OIDCJWKSTO generate() {
+        Response response = getService(OIDCJWKSService.class).generate(2048, JWSAlgorithm.RS256);
+        return response.readEntity(OIDCJWKSTO.class);
     }
 
-    @Override
-    public void delete() {
-        logic.delete();
+    public static void delete() {
+        getService(OIDCJWKSService.class).delete();
     }
 }
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ru.properties
index 3fcebae..a6fd786 100644
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ru.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ru.properties
@@ -15,11 +15,8 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-# any.edit=\u00d0\u0098\u00d0\u00b7\u00d0\u00bc\u00d0\u00b5\u00d0\u00bd\u00d0\u00b8\u00d1\u0082\u00d1\u008c \u00d0\u00bf\u00d0\u00b0\u00d1\u0080\u00d0\u00b0\u00d0\u00bc\u00d0\u00b5\u00d1\u0082\u00d1\u0080 ${key}
 any.edit=\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 ${key}
-# any.new=\u00d0\u00a1\u00d0\u00be\u00d0\u00b7\u00d0\u00b4\u00d0\u00b0\u00d1\u0082\u00d1\u008c \u00d0\u00bf\u00d0\u00b0\u00d1\u0080\u00d0\u00b0\u00d0\u00bc\u00d0\u00b5\u00d1\u0082\u00d1\u0080
 any.new=New Auth Module
-# any.edit=\u00d0\u0098\u00d0\u00b7\u00d0\u00bc\u00d0\u00b5\u00d0\u00bd\u00d0\u00b8\u00d1\u0082\u00d1\u008c \u00d0\u00bf\u00d0\u00b0\u00d1\u0080\u00d0\u00b0\u00d0\u00bc\u00d0\u00b5\u00d1\u0082\u00d1\u0080
 any.edit=Edit Auth Module
 description=Description
 type=Type
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.html
new file mode 100644
index 0000000..e95ce63
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.html
@@ -0,0 +1,54 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div class="row" wicket:id="container">
+      <div class="col-md-6">
+        <div class="card card-gray">
+          <div class="card-header">
+            <h3 class="card-title">JSON Web Key Sets</h3>
+          </div>
+          <div class="card-body" style="text-align: center;">
+            <a wicket:id="view" class="btn btn-app">
+              <i class="fas fa-eye"></i> <wicket:message key="view"/>
+            </a>
+            <a wicket:id="generate" class="btn btn-app">
+              <i class="fa fa-edit"></i> <wicket:message key="generate"/>
+            </a>
+            <a wicket:id="delete" class="btn btn-app">
+              <i class="fas fa-trash-alt"></i> <wicket:message key="delete"/>
+            </a>
+          </div>
+        </div>
+      </div>
+      <div class="col-md-6">
+        <div class="card card-gray">
+          <div class="card-header">
+            <h3 class="card-title">Well-Known URI</h3>
+          </div>
+          <div class="card-body" style="text-align: center;">
+            <a wicket:id="wellKnownURI"/>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div wicket:id="viewModal"/>
+  </wicket:panel>
+</html>
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.properties
new file mode 100644
index 0000000..7c83852
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+view=View
+generate=Generate
+delete=Delete
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_fr_CA.properties
new file mode 100644
index 0000000..7c83852
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_fr_CA.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+view=View
+generate=Generate
+delete=Delete
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_it.properties
new file mode 100644
index 0000000..f55ab92
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_it.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+view=Vedi
+generate=Genera
+delete=Cancella
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_ja.properties
new file mode 100644
index 0000000..7c83852
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_ja.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+view=View
+generate=Generate
+delete=Delete
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_pt_BR.properties
new file mode 100644
index 0000000..7c83852
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_pt_BR.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+view=View
+generate=Generate
+delete=Delete
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_ru.properties
new file mode 100644
index 0000000..7c83852
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC_ru.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+view=View
+generate=Generate
+delete=Delete
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java
index 934eb46..4bbd68d 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java
@@ -47,7 +47,6 @@ import org.apache.syncope.client.console.wicket.ajax.IndicatorAjaxTimerBehavior;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal.WindowClosedCallback;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksTogglePanel;
@@ -144,37 +143,13 @@ public class JobWidget extends BaseWidget {
         super(id);
         setOutputMarkupId(true);
         add(modal);
-        modal.setWindowClosedCallback(new WindowClosedCallback() {
-
-            private static final long serialVersionUID = 8804221891699487139L;
-
-            @Override
-            public void onClose(final AjaxRequestTarget target) {
-                modal.show(false);
-            }
-        });
+        modal.setWindowClosedCallback(target -> modal.show(false));
 
         add(detailModal);
-        detailModal.setWindowClosedCallback(new WindowClosedCallback() {
-
-            private static final long serialVersionUID = 8804221891699487139L;
-
-            @Override
-            public void onClose(final AjaxRequestTarget target) {
-                detailModal.show(false);
-            }
-        });
+        detailModal.setWindowClosedCallback(target -> detailModal.show(false));
 
         add(reportModal);
-        reportModal.setWindowClosedCallback(new WindowClosedCallback() {
-
-            private static final long serialVersionUID = 8804221891699487139L;
-
-            @Override
-            public void onClose(final AjaxRequestTarget target) {
-                reportModal.show(false);
-            }
-        });
+        reportModal.setWindowClosedCallback(target -> reportModal.show(false));
 
         reportModal.size(Modal.Size.Large);
 
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
index b2a8346..e108097 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
@@ -50,14 +50,11 @@ public interface OIDCJWKSService extends JAXRSService {
 
     @GET
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    OIDCJWKSTO read();
+    OIDCJWKSTO get();
 
     @ApiResponses({
         @ApiResponse(responseCode = "201",
                 description = "JWKS successfully created", headers = {
-                    @Header(name = RESTHeaders.RESOURCE_KEY, schema =
-                            @Schema(type = "string"),
-                            description = "UUID generated for the entity created"),
                     @Header(name = HttpHeaders.LOCATION, schema =
                             @Schema(type = "string"),
                             description = "URL of the entity created") }),
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
index 3720a30..8b2ab8c 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
@@ -46,9 +46,9 @@ public class OIDCJWKSLogic extends AbstractTransactionalLogic<OIDCJWKSTO> {
     @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_READ + "') "
             + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
     @Transactional(readOnly = true)
-    public OIDCJWKSTO read() {
+    public OIDCJWKSTO get() {
         return Optional.ofNullable(dao.get()).
-                map(binder::get).
+                map(binder::getOIDCJWKSTO).
                 orElseThrow(() -> new NotFoundException("OIDC JWKS not found"));
     }
 
@@ -57,7 +57,7 @@ public class OIDCJWKSLogic extends AbstractTransactionalLogic<OIDCJWKSTO> {
     public OIDCJWKSTO generate(final int size, final JWSAlgorithm algorithm) {
         OIDCJWKS jwks = dao.get();
         if (jwks == null) {
-            return binder.get(dao.save(binder.create(size, algorithm)));
+            return binder.getOIDCJWKSTO(dao.save(binder.create(size, algorithm)));
         }
         throw new DuplicateException("OIDC JWKS already set");
     }
@@ -74,6 +74,6 @@ public class OIDCJWKSLogic extends AbstractTransactionalLogic<OIDCJWKSTO> {
         if (jwks == null) {
             throw new UnresolvedReferenceException();
         }
-        return binder.get(jwks);
+        return binder.getOIDCJWKSTO(jwks);
     }
 }
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
index 81aee2c..67c1b82 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
@@ -22,7 +22,6 @@ import java.net.URI;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
 import org.apache.syncope.common.lib.types.JWSAlgorithm;
-import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.core.logic.OIDCJWKSLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -35,18 +34,15 @@ public class OIDCJWKSServiceImpl extends AbstractServiceImpl implements OIDCJWKS
     private OIDCJWKSLogic logic;
 
     @Override
-    public OIDCJWKSTO read() {
-        return logic.read();
+    public OIDCJWKSTO get() {
+        return logic.get();
     }
 
     @Override
     public Response generate(final int size, final JWSAlgorithm algorithm) {
         OIDCJWKSTO jwks = logic.generate(size, algorithm);
-        URI location = uriInfo.getAbsolutePathBuilder().path(jwks.getKey()).build();
-        return Response.created(location).
-                header(RESTHeaders.RESOURCE_KEY, jwks.getKey()).
-                entity(jwks).
-                build();
+        URI location = uriInfo.getAbsolutePathBuilder().build();
+        return Response.created(location).entity(jwks).build();
     }
 
     @Override
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCJWKS.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCJWKS.java
index 0e12628..ab0e512 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCJWKS.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCJWKS.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity.auth;
 
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Lob;
 import javax.persistence.Table;
@@ -32,6 +33,7 @@ public class JPAOIDCJWKS extends AbstractGeneratedKeyEntity implements OIDCJWKS
 
     private static final long serialVersionUID = 47352617217394093L;
 
+    @Column(nullable = false)
     @Lob
     private String json;
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2IdPEntity.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2IdPEntity.java
index 887deb9..c892e68 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2IdPEntity.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2IdPEntity.java
@@ -34,7 +34,7 @@ public class JPASAML2IdPEntity extends AbstractProvidedKeyEntity implements SAML
 
     private static final long serialVersionUID = 57352617217394093L;
 
-    @Column(nullable = true)
+    @Column(nullable = false)
     @Lob
     private byte[] metadata;
 
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCJWKSDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCJWKSDataBinder.java
index 6a68e65..7443afc 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCJWKSDataBinder.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCJWKSDataBinder.java
@@ -24,9 +24,7 @@ import org.apache.syncope.core.persistence.api.entity.auth.OIDCJWKS;
 
 public interface OIDCJWKSDataBinder {
 
-    OIDCJWKSTO get(OIDCJWKS jwks);
+    OIDCJWKSTO getOIDCJWKSTO(OIDCJWKS jwks);
 
     OIDCJWKS create(int size, JWSAlgorithm algorithm);
-
-    OIDCJWKS update(OIDCJWKS jwks, OIDCJWKSTO jwksTO);
 }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCJWKSDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCJWKSDataBinderImpl.java
index d75c697..7344ebb 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCJWKSDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCJWKSDataBinderImpl.java
@@ -46,7 +46,7 @@ public class OIDCJWKSDataBinderImpl implements OIDCJWKSDataBinder {
     private EntityFactory entityFactory;
 
     @Override
-    public OIDCJWKSTO get(final OIDCJWKS jwks) {
+    public OIDCJWKSTO getOIDCJWKSTO(final OIDCJWKS jwks) {
         return new OIDCJWKSTO.Builder().json(jwks.getJson()).key(jwks.getKey()).build();
     }
 
@@ -69,10 +69,4 @@ public class OIDCJWKSDataBinderImpl implements OIDCJWKSDataBinder {
             throw sce;
         }
     }
-
-    @Override
-    public OIDCJWKS update(final OIDCJWKS jwks, final OIDCJWKSTO jwksTO) {
-        jwks.setJson(jwksTO.getJson());
-        return jwks;
-    }
 }
diff --git a/ext/oidcc4ui/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCC4UI.java b/ext/oidcc4ui/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCC4UI.java
index 364a0f8..d0c3c6f 100644
--- a/ext/oidcc4ui/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCC4UI.java
+++ b/ext/oidcc4ui/client-console/src/main/java/org/apache/syncope/client/console/pages/OIDCC4UI.java
@@ -32,7 +32,7 @@ import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 
-@ExtPage(label = "OpenID Connect 1.0 C4UI", icon = "fab fa-openid", 
+@ExtPage(label = "OIDC 1.0 C4UI", icon = "fab fa-openid", 
         listEntitlement = OIDC4UIEntitlement.OP_READ, priority = 300)
 public class OIDCC4UI extends BaseExtPage {
 
diff --git a/ext/oidcc4ui/client-console/src/main/resources/org/apache/syncope/client/console/pages/OIDCC4UI.html b/ext/oidcc4ui/client-console/src/main/resources/org/apache/syncope/client/console/pages/OIDCC4UI.html
index b076c13..bff8ea8 100644
--- a/ext/oidcc4ui/client-console/src/main/resources/org/apache/syncope/client/console/pages/OIDCC4UI.html
+++ b/ext/oidcc4ui/client-console/src/main/resources/org/apache/syncope/client/console/pages/OIDCC4UI.html
@@ -31,7 +31,7 @@ under the License.
                 <a wicket:id="dashboardBr"><i class="fa fa-tachometer-alt"></i> <wicket:message key="dashboard"></wicket:message></a>
               </li>
               <li class="breadcrumb-item"><wicket:message key="extensions"/></li>
-              <li class="breadcrumb-item active">OpenID Connect 1.0 C4UI</li>
+              <li class="breadcrumb-item active">OIDC 1.0 C4UI</li>
             </ol>
           </div>
         </div>
@@ -46,4 +46,4 @@ under the License.
       </div>
     </section>
   </wicket:extend>
-</html>
\ No newline at end of file
+</html>
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSITCase.java
index 0e7c96b..9f800df 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSITCase.java
@@ -53,7 +53,7 @@ public class OIDCJWKSITCase extends AbstractITCase {
         try {
             oidcJWKSService.delete();
 
-            waOIDCJWKSService.read();
+            waOIDCJWKSService.get();
             fail("Should not locate an OIDC JWKS");
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.NotFound, e.getType());
diff --git a/pom.xml b/pom.xml
index 3a17ebc..5196cad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -457,7 +457,7 @@ under the License.
     <h2.version>1.4.200</h2.version>
 
     <junit.version>5.7.1</junit.version>
-    <mockito.version>3.8.0</mockito.version>
+    <mockito.version>3.9.0</mockito.version>
 
     <swagger-core.version>2.1.7</swagger-core.version>
     <swagger-ui.version>3.46.0</swagger-ui.version>
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
index 11944ba..23f254d 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
@@ -59,7 +59,7 @@ public class SyncopeWAOIDCJWKSGeneratorService implements OidcJsonWebKeystoreGen
         OIDCJWKSService service = waRestClient.getSyncopeClient().getService(OIDCJWKSService.class);
         OIDCJWKSTO jwksTO = null;
         try {
-            jwksTO = service.read();
+            jwksTO = service.get();
         } catch (SyncopeClientException e) {
             if (e.getType() == ClientExceptionType.NotFound) {
                 try {