http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_ru.properties
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_ru.properties
 
b/client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_ru.properties
index 424f5dc..c661008 100644
--- 
a/client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_ru.properties
+++ 
b/client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_ru.properties
@@ -31,11 +31,6 @@ confirmUnlink=\u0412\u044b 
\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u043
 confirmUnassign=\u0412\u044b 
\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e 
\u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c 
\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 
\u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0434\u043b\u044f 
\u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 
\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432?
 confirmDeprovision=\u0412\u044b 
\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e 
\u0445\u043e\u0442\u0438\u0442\u0435 
\u043e\u0442\u043e\u0437\u0432\u0430\u0442\u044c 
\u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 
\u043e\u0431\u044a\u0435\u043a\u0442\u044b?
 confirmProvision=\u0412\u044b 
\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e 
\u0445\u043e\u0442\u0438\u0442\u0435 
\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c 
\u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 
\u043e\u0431\u044a\u0435\u043a\u0442\u044b?
-
-unauthorizedInstantiationException=\u041e\u0448\u0438\u0431\u043a\u0430 
\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.
-accessControlException=\u041e\u0448\u0438\u0431\u043a\u0430 
\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 
\u043f\u0440\u0438 
\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438
 \u0441 \u044f\u0434\u0440\u043e\u043c Syncope.
-restClientException=\u041e\u0448\u0438\u0431\u043a\u0430 
\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f
 \u0441 \u044f\u0434\u0440\u043e\u043c Syncope
-pageExpiredException=\u0412\u0440\u0435\u043c\u044f 
\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f 
\u0441\u0435\u0441\u0441\u0438\u0438 
\u0438\u0441\u0442\u0435\u043a\u043b\u043e, 
\u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, 
\u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 
\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0432\u0445\u043e\u0434
 dropDownChoiceField.nullValid=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 
\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435
 DateTimeField$HoursValidator=\u0427\u0430\u0441\u044b 
\u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c 
\u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0432 
\u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435 (1, 12)
 error=\u041e\u0448\u0438\u0431\u043a\u0430
@@ -72,3 +67,4 @@ 
entitlements=\u041f\u043e\u043b\u043d\u043e\u043c\u043e\u0447\u0438\u044f
 audit=\u0410\u0443\u0434\u0438\u0442
 
connectors.confirm.reload=\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435
 \u044d\u0442\u043e\u0433\u043e 
\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f 
\u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e 
\u043e\u043f\u0430\u0441\u043d\u043e \u0434\u043b\u044f 
\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0445 
\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439. 
\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?
 intAttrNameInfo.help=\u041f\u043e\u043c\u0438\u043c\u043e 
\u0430\u0432\u0442\u043e\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f
 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, \u0432\u044b 
\u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 
\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c 
\u0433\u0440\u0443\u043f\u043f\u044b, 
\u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 
\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438 
\u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e (\u043f\u0440\u0438 
\u043d\u0430\u043b\u0438\u0447\u0438\u0438), 
\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:
+confirmGlobalLogout=Do you really want to perform global logout?

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/client/console/src/main/resources/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.html
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/resources/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.html
 
b/client/console/src/main/resources/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.html
deleted file mode 100644
index c969faa..0000000
--- 
a/client/console/src/main/resources/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-<html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
-  <wicket:head>
-    <link rel="stylesheet" type="text/css" 
href="webjars/codemirror/${codemirror.version}/lib/codemirror.css"/>
-
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/lib/codemirror.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/mode/javascript/javascript.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/edit/matchbrackets.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/edit/closebrackets.js"></script>
-    <script type="text/javascript">
-      function updateTextArea(editor) {
-        
document.getElementById("consoleLayoutInfoDefForm").children["consoleLayoutInfo"].value
 = editor.getValue();
-      }
-    </script>
-    <style>
-      .w_content_3 {
-        padding: 0;
-        color: #333333;
-        font-family: Verdana,Tahoma,sans-serif;
-        font-size: 100%;
-        border: 1px solid #BBBBBB;
-        padding: 1%;
-      }
-    </style>
-  </wicket:head>
-  <wicket:panel>
-    <div style="padding: 1%;">
-      <div class="w_content_3" id="consoleLayoutInfoDefForm">
-        <textarea wicket:id="consoleLayoutInfo" id="consoleLayoutInfo" 
name="consoleLayoutInfo" style="width: 100%; height: 350px;">
-        </textarea>
-      </div>
-    </div>
-  </wicket:panel>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$About.html
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$About.html
 
b/client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$About.html
index 006425d..29d1841 100644
--- 
a/client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$About.html
+++ 
b/client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$About.html
@@ -17,15 +17,12 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="form-group">
-        <span wicket:id="about"></span>
-      </div>
-      <div wicket:id="search">
-        <span wicket:id="clauses"></span>
-      </div>
-    </wicket:panel>
-  </body>
+  <wicket:panel>
+    <div class="form-group">
+      <span wicket:id="about"></span>
+    </div>
+    <div wicket:id="search">
+      <span wicket:id="clauses"></span>
+    </div>
+  </wicket:panel>
 </html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/client/console/src/main/resources/org/apache/syncope/client/console/notifications/TemplateContentModal.html
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/resources/org/apache/syncope/client/console/notifications/TemplateContentModal.html
 
b/client/console/src/main/resources/org/apache/syncope/client/console/notifications/TemplateContentModal.html
deleted file mode 100644
index 2f30d1f..0000000
--- 
a/client/console/src/main/resources/org/apache/syncope/client/console/notifications/TemplateContentModal.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-<html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
-  <wicket:head>
-    <link rel="stylesheet" type="text/css" 
href="webjars/codemirror/${codemirror.version}/lib/codemirror.css"/>
-
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/lib/codemirror.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/mode/xml/xml.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/edit/closetag.js"></script>
-    <script type="text/javascript">
-      function updateTextArea(editor) {
-        document.getElementById("templateDefForm").children["template"].value 
= editor.getValue();
-      }
-    </script>
-    <style>
-      .w_content_3 {
-        padding: 0;
-        color: #333333;
-        font-family: Verdana,Tahoma,sans-serif;
-        font-size: 100%;
-        border: 1px solid #BBBBBB;
-        padding: 1%;
-      }
-    </style>
-  </wicket:head>
-  <wicket:panel>
-    <div style="padding: 1%;">
-      <div class="w_content_3" id="templateDefForm">
-        <textarea wicket:id="template" id="template" name="template" 
style="width: 100%; height: 350px;">
-        </textarea>
-      </div>
-    </div>
-  </wicket:panel>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html
 
b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html
index f5b4c4d..c7271b4 100644
--- 
a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html
+++ 
b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html
@@ -58,6 +58,10 @@ under the License.
 
             <button wicket:id="submit" type="submit" class="btn btn-lg 
btn-primary btn-block btn-signin"></button>
           </fieldset>
+
+          <div wicket:id="ssoLogins">
+            <div wicket:id="ssoLogin"/>
+          </div>
         </form>
       </div>
     </div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html
 
b/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html
deleted file mode 100644
index 0b51d5e..0000000
--- 
a/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-<html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
-  <wicket:head>
-    <link rel="stylesheet" type="text/css" 
href="webjars/codemirror/${codemirror.version}/lib/codemirror.css"/>
-
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/lib/codemirror.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/mode/xml/xml.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/edit/closetag.js"></script>
-    <script type="text/javascript">
-      function updateTextArea(editor) {
-        document.getElementById("workflowDefArea").value = editor.getValue();
-      }
-    </script>
-    <style>
-      .w_content_3 {
-        padding: 0;
-        color: #333333;
-        font-family: Verdana,Tahoma,sans-serif;
-        font-size: 100%;
-        border: 1px solid #BBBBBB;
-        padding: 1%;
-      }
-    </style>
-  </wicket:head>
-  <wicket:panel>
-    <div style="padding: 1%;">
-      <div class="w_content_3">
-        <textarea wicket:id="workflowDefArea" id="workflowDefArea" 
name="workflowDefArea" style="width: 100%; height: 350px;">
-        </textarea>
-      </div>
-    </div>
-  </wicket:panel>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java
----------------------------------------------------------------------
diff --git 
a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java
 
b/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java
deleted file mode 100644
index d6a2065..0000000
--- 
a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.panels;
-
-import org.apache.syncope.common.lib.to.CamelRouteTO;
-import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.head.OnLoadHeaderItem;
-import org.apache.wicket.markup.html.form.TextArea;
-import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.PropertyModel;
-
-public class CamelRoutesDetailsPanel extends Panel {
-
-    private static final long serialVersionUID = -768345003061796383L;
-
-    public CamelRoutesDetailsPanel(final String id, final CamelRouteTO 
camelRoute) {
-        super(id);
-
-        TextArea<String> routeDefArea = new TextArea<>("route", new 
PropertyModel<String>(camelRoute, "content"));
-        routeDefArea.setMarkupId("route").setOutputMarkupPlaceholderTag(true);
-        add(routeDefArea);
-    }
-
-    @Override
-    public void renderHead(final IHeaderResponse response) {
-        super.renderHead(response);
-        response.render(OnLoadHeaderItem.forScript(
-                "CodeMirror.fromTextArea(document.getElementById('route'), {"
-                + "  lineNumbers: true, "
-                + "  lineWrapping: true, "
-                + "  autoCloseTags: true, "
-                + "  mode: 'text/html', "
-                + "  autoRefresh: true"
-                + "}).on('change', updateTextArea);"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDirectoryPanel.java
----------------------------------------------------------------------
diff --git 
a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDirectoryPanel.java
 
b/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDirectoryPanel.java
index 9c6f201..a4b4df5 100644
--- 
a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDirectoryPanel.java
+++ 
b/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDirectoryPanel.java
@@ -28,26 +28,26 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
 import 
org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.pages.CamelRoutes;
 import 
org.apache.syncope.client.console.panels.CamelRoutesDirectoryPanel.CamelRoutesProvider;
 import org.apache.syncope.client.console.rest.CamelRoutesRestClient;
 import 
org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
+import 
org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import 
org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
-import org.apache.syncope.client.console.wizards.AbstractModalPanelBuilder;
-import org.apache.syncope.client.console.wizards.AjaxWizard;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.XMLEditorPanel;
 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.common.lib.to.CamelRouteTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.CamelEntitlement;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.event.Broadcast;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 import 
org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.model.CompoundPropertyModel;
 import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
 import org.apache.wicket.model.ResourceModel;
 
 public class CamelRoutesDirectoryPanel extends DirectoryPanel<
@@ -55,11 +55,14 @@ public class CamelRoutesDirectoryPanel extends 
DirectoryPanel<
 
     private static final long serialVersionUID = 3727444742501082182L;
 
+    private static final String PREF_CAMEL_ROUTES_PAGINATOR_ROWS = 
"camel.routes.paginator.rows";
+
+    private final BaseModal<String> utilityModal = new BaseModal<>("outer");
+
     private final AnyTypeKind anyTypeKind;
 
     public CamelRoutesDirectoryPanel(final String id, final PageReference 
pageRef, final AnyTypeKind anyTypeKind) {
-        super(id, new Builder<CamelRouteTO, CamelRouteTO, 
CamelRoutesRestClient>(
-                new CamelRoutesRestClient(), pageRef) {
+        super(id, new Builder<CamelRouteTO, CamelRouteTO, 
CamelRoutesRestClient>(new CamelRoutesRestClient(), pageRef) {
 
             private static final long serialVersionUID = 8769126634538601689L;
 
@@ -68,47 +71,17 @@ public class CamelRoutesDirectoryPanel extends 
DirectoryPanel<
                 throw new UnsupportedOperationException();
             }
         }.disableCheckBoxes());
+        setOutputMarkupId(true);
 
         this.anyTypeKind = anyTypeKind;
         setFooterVisibility(true);
-        modal.addSubmitButton();
-        modal.size(Modal.Size.Large);
-        initResultTable();
-
-        this.addNewItemPanelBuilder(new 
AbstractModalPanelBuilder<CamelRouteTO>(new CamelRouteTO(), pageRef) {
-
-            private static final long serialVersionUID = -6388405037134399367L;
-
-            @Override
-            public WizardModalPanel<CamelRouteTO> build(final String id, final 
int index, final AjaxWizard.Mode mode) {
-                return new CamelRoutesModalPanel(modal, newModelObject(), 
pageRef) {
-
-                    private static final long serialVersionUID = 
-6227956682141146095L;
-
-                    @Override
-                    public void onSubmit(final AjaxRequestTarget target, final 
Form<?> form) {
-                        try {
-                            restClient.update(getItem());
-                            info(getString(Constants.OPERATION_SUCCEEDED));
-                            modal.close(target);
-                        } catch (Exception e) {
-                            LOG.error("While creating or updating 
CamelRouteTO", e);
-                            error(getString(Constants.ERROR) + ": " + 
e.getMessage());
-                        }
-                        ((BasePage) 
pageRef.getPage()).getNotificationPanel().refresh(target);
-                    }
-                };
-            }
-        }, false);
-    }
 
-    private CamelRoutesDirectoryPanel(
-            final String id,
-            final Builder<CamelRouteTO, CamelRouteTO, CamelRoutesRestClient> 
builder,
-            final AnyTypeKind anyTypeKind) {
+        addOuterObject(utilityModal);
+        setWindowClosedReloadCallback(utilityModal);
+        utilityModal.size(Modal.Size.Large);
+        utilityModal.addSubmitButton();
 
-        super(id, builder);
-        this.anyTypeKind = anyTypeKind;
+        initResultTable();
     }
 
     @Override
@@ -118,7 +91,7 @@ public class CamelRoutesDirectoryPanel extends 
DirectoryPanel<
 
     @Override
     protected String paginatorRowsKey() {
-        return CamelRoutes.PREF_CAMEL_ROUTES_PAGINATOR_ROWS;
+        return PREF_CAMEL_ROUTES_PAGINATOR_ROWS;
     }
 
     @Override
@@ -143,15 +116,36 @@ public class CamelRoutesDirectoryPanel extends 
DirectoryPanel<
                 ActionLinksPanel<CamelRouteTO> panel = 
ActionLinksPanel.<CamelRouteTO>builder().
                         add(new ActionLink<CamelRouteTO>() {
 
-                    private static final long serialVersionUID = 
-3722207913631435501L;
-
-                    @Override
-                    public void onClick(final AjaxRequestTarget target, final 
CamelRouteTO ignore) {
-                        CamelRouteTO actual = 
restClient.read(model.getObject().getKey());
-                        send(CamelRoutesDirectoryPanel.this, Broadcast.EXACT,
-                                new AjaxWizard.EditItemActionEvent<>(actual, 
target));
-                    }
-                }, ActionLink.ActionType.EDIT, CamelEntitlement.ROUTE_UPDATE).
+                            private static final long serialVersionUID = 
-3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget 
target, final CamelRouteTO ignore) {
+                                final CamelRouteTO route = 
restClient.read(model.getObject().getKey());
+
+                                utilityModal.header(Model.of(route.getKey()));
+                                utilityModal.setContent(new XMLEditorPanel(
+                                        utilityModal, new 
PropertyModel<String>(route, "content"), filtered, pageRef) {
+
+                                    private static final long serialVersionUID 
= 5488080606102212554L;
+
+                                    @Override
+                                    public void onSubmit(final 
AjaxRequestTarget target, final Form<?> form) {
+                                        try {
+                                            restClient.update(route);
+                                            
info(getString(Constants.OPERATION_SUCCEEDED));
+                                            modal.close(target);
+                                        } catch (Exception e) {
+                                            LOG.error("While creating or 
updating CamelRouteTO", e);
+                                            error(getString(Constants.ERROR) + 
": " + e.getMessage());
+                                        }
+                                        ((BasePage) 
pageRef.getPage()).getNotificationPanel().refresh(target);
+                                    }
+
+                                });
+                                utilityModal.show(true);
+                                target.add(utilityModal);
+                            }
+                        }, ActionLink.ActionType.EDIT, 
CamelEntitlement.ROUTE_UPDATE).
                         build(componentId);
 
                 return panel;

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesModalPanel.java
----------------------------------------------------------------------
diff --git 
a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesModalPanel.java
 
b/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesModalPanel.java
deleted file mode 100644
index 8141c78..0000000
--- 
a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesModalPanel.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.panels;
-
-import 
org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.common.lib.to.CamelRouteTO;
-import org.apache.wicket.PageReference;
-
-public class CamelRoutesModalPanel extends AbstractModalPanel<CamelRouteTO> {
-
-    private static final long serialVersionUID = 2053048734388383021L;
-
-    private final CamelRouteTO camelRouteTO;
-
-    public CamelRoutesModalPanel(
-            final BaseModal<CamelRouteTO> modal,
-            final CamelRouteTO camelRouteTO,
-            final PageReference pageRef) {
-
-        super(modal, pageRef);
-        this.camelRouteTO = camelRouteTO;
-        add(new CamelRoutesDetailsPanel("camelRouteDetailsPanel", 
this.camelRouteTO));
-    }
-
-    @Override
-    public CamelRouteTO getItem() {
-        return this.camelRouteTO;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html
----------------------------------------------------------------------
diff --git 
a/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html
 
b/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html
deleted file mode 100644
index 663a6b3..0000000
--- 
a/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-<html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
-  <wicket:head>
-    <link rel="stylesheet" type="text/css" 
href="webjars/codemirror/${codemirror.version}/lib/codemirror.css"/>
-
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/lib/codemirror.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/mode/xml/xml.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
-    <script type="text/javascript" 
src="webjars/codemirror/${codemirror.version}/addon/edit/closetag.js"></script>
-    <script type="text/javascript">
-      function updateTextArea(editor) {
-        document.getElementById("routeDefForm").children["route"].value = 
editor.getValue();
-      }
-    </script>
-    <style>
-      .w_content_3 {
-        padding: 0;
-        color: #333333;
-        font-family: Verdana,Tahoma,sans-serif;
-        font-size: 100%;
-        border: 1px solid #BBBBBB;
-        padding: 1%;
-      }
-    </style>
-  </wicket:head>
-  <wicket:panel>
-    <div style="padding: 1%;">
-      <div class="w_content_3" id="routeDefForm">
-        <textarea wicket:id="route" id="route" name="route" style="width: 
100%; height: 350px;">
-        </textarea>
-      </div>
-    </div>
-  </wicket:panel>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesModalPanel.html
----------------------------------------------------------------------
diff --git 
a/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesModalPanel.html
 
b/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesModalPanel.html
deleted file mode 100644
index 783f516..0000000
--- 
a/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesModalPanel.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-<html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
-  <wicket:extend>
-    <div wicket:id="camelRouteDetailsPanel">[camelRouteDetailsPanel]</div>
-  </wicket:extend>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
 
b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
index 6461a47..eaea49f 100644
--- 
a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
+++ 
b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
@@ -54,7 +54,7 @@ public class AssertionConsumer extends HttpServlet {
                 request.setAttribute("responseTO", responseTO);
                 
request.getRequestDispatcher("loginSuccess.jsp").forward(request, response);
             } else {
-                response.sendRedirect(successURL);
+                response.sendRedirect(successURL + "?sloSupported=" + 
responseTO.isSloSupported());
             }
         } catch (Exception e) {
             LOG.error("While processing authentication response from IdP", e);
@@ -66,7 +66,7 @@ public class AssertionConsumer extends HttpServlet {
 
                 e.printStackTrace(response.getWriter());
             } else {
-                response.sendRedirect(errorURL + "?message=" + e.getMessage());
+                response.sendRedirect(errorURL + "?errorMessage=" + 
e.getMessage());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Login.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Login.java
 
b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Login.java
index 198f6b3..a04376d 100644
--- 
a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Login.java
+++ 
b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Login.java
@@ -56,7 +56,7 @@ public class Login extends SAML2PostBinding {
 
                 e.printStackTrace(response.getWriter());
             } else {
-                response.sendRedirect(errorURL + "?message=" + e.getMessage());
+                response.sendRedirect(errorURL + "?errorMessage=" + 
e.getMessage());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
 
b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
index b41d004..ec59499 100644
--- 
a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
+++ 
b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
@@ -61,7 +61,7 @@ public class Logout extends SAML2PostBinding {
 
                 e.printStackTrace(response.getWriter());
             } else {
-                response.sendRedirect(errorURL + "?message=" + e.getMessage());
+                response.sendRedirect(errorURL + "?errorMessage=" + 
e.getMessage());
             }
         }
     }
@@ -98,7 +98,7 @@ public class Logout extends SAML2PostBinding {
 
                 e.printStackTrace(response.getWriter());
             } else {
-                response.sendRedirect(errorURL + "?message=" + e.getMessage());
+                response.sendRedirect(errorURL + "?errorMessage=" + 
e.getMessage());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/client-console/pom.xml
----------------------------------------------------------------------
diff --git a/ext/saml2sp/client-console/pom.xml 
b/ext/saml2sp/client-console/pom.xml
new file mode 100644
index 0000000..cf533a6
--- /dev/null
+++ b/ext/saml2sp/client-console/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope.ext</groupId>
+    <artifactId>syncope-ext-saml2sp</artifactId>
+    <version>2.0.3-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Extensions: SAML 2.0 SP Client Console</name>
+  <description>Apache Syncope Extensions: SAML 2.0 SP Client 
Console</description>
+  <groupId>org.apache.syncope.ext.saml2sp</groupId>
+  <artifactId>syncope-ext-saml2sp-client-console</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.syncope.ext.saml2sp</groupId>
+      <artifactId>syncope-ext-saml2sp-common-lib</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.saml2sp</groupId>
+      <artifactId>syncope-ext-saml2sp-rest-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.saml2sp</groupId>
+      <artifactId>syncope-ext-saml2sp-agent</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.client</groupId>
+      <artifactId>syncope-client-console</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+    </plugins>
+    
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPBeforeLogout.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPBeforeLogout.java
 
b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPBeforeLogout.java
new file mode 100644
index 0000000..22ccb35
--- /dev/null
+++ 
b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPBeforeLogout.java
@@ -0,0 +1,37 @@
+/*
+ * 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.UrlUtils;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.http.handler.RedirectRequestHandler;
+
+public class SAML2SPBeforeLogout extends WebPage {
+
+    private static final long serialVersionUID = 4666948447239743855L;
+
+    public SAML2SPBeforeLogout() {
+        super();
+
+        RequestCycle.get().scheduleRequestHandlerAfterCurrent(new 
RedirectRequestHandler(
+                UrlUtils.rewriteToContextRelative("saml2sp/logout", 
RequestCycle.get())));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPLogin.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPLogin.java
 
b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPLogin.java
new file mode 100644
index 0000000..6b975cb
--- /dev/null
+++ 
b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPLogin.java
@@ -0,0 +1,70 @@
+/*
+ * 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.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.wicket.authentication.IAuthenticationStrategy;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.wicket.markup.html.WebPage;
+
+public class SAML2SPLogin extends WebPage {
+
+    private static final long serialVersionUID = -245801838574917258L;
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(SAML2SPLogin.class);
+
+    public SAML2SPLogin(final PageParameters parameters) {
+        super(parameters);
+
+        String token = (String) ((ServletWebRequest) 
getRequest()).getContainerRequest().
+                
getSession().getAttribute(org.apache.syncope.ext.saml2lsp.agent.Constants.SAML2SPJWT);
+        if (StringUtils.isBlank(token)) {
+            LOG.error("No JWT found, redirecting to default greeter");
+
+            PageParameters params = new PageParameters();
+            params.add("errorMessage", "accessControlException");
+            setResponsePage(Login.class, params);
+        }
+
+        IAuthenticationStrategy strategy = 
getApplication().getSecuritySettings().getAuthenticationStrategy();
+
+        if (SyncopeConsoleSession.get().authenticate(token)) {
+            if (parameters.get("sloSupported").toBoolean(false)) {
+                SyncopeConsoleSession.get().setAttribute(
+                        
org.apache.syncope.client.console.commons.Constants.BEFORE_LOGOUT_PAGE,
+                        SAML2SPBeforeLogout.class);
+            }
+
+            // If login has been called because the user was not yet logged 
in, than continue to the
+            // original destination, otherwise to the Home page
+            continueToOriginalDestination();
+            setResponsePage(getApplication().getHomePage());
+        } else {
+            PageParameters params = new PageParameters();
+            params.add("errorMessage", "accessControlException");
+            setResponsePage(Login.class, params);
+        }
+        strategy.remove();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPLogout.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPLogout.java
 
b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPLogout.java
new file mode 100644
index 0000000..16cf481
--- /dev/null
+++ 
b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/pages/SAML2SPLogout.java
@@ -0,0 +1,39 @@
+/*
+ * 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.syncope.client.console.SyncopeConsoleSession;
+import org.apache.wicket.markup.html.WebPage;
+
+public class SAML2SPLogout extends WebPage {
+
+    private static final long serialVersionUID = 4666948447239743855L;
+
+    public SAML2SPLogout() {
+        super();
+
+        // this is needed because the actual logout was already performed by 
the SAML agent
+        SyncopeConsoleSession.get().cleanup();
+
+        SyncopeConsoleSession.get().invalidate();
+
+        setResponsePage(getApplication().getHomePage());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/panels/SAMLSSOLoginFormPanel.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/panels/SAMLSSOLoginFormPanel.java
 
b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/panels/SAMLSSOLoginFormPanel.java
new file mode 100644
index 0000000..b3fab14
--- /dev/null
+++ 
b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/panels/SAMLSSOLoginFormPanel.java
@@ -0,0 +1,107 @@
+/*
+ * 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 java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.common.lib.to.SAML2IdPTO;
+import org.apache.syncope.common.rest.api.service.SAML2IdPService;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.request.UrlUtils;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.http.handler.RedirectRequestHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SAMLSSOLoginFormPanel extends SSOLoginFormPanel {
+
+    private static final long serialVersionUID = -5252094098970677128L;
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(SAMLSSOLoginFormPanel.class);
+
+    public SAMLSSOLoginFormPanel(final String id) {
+        super(id);
+
+        List<SAML2IdPTO> available =
+                
SyncopeConsoleSession.get().getAnonymousClient().getService(SAML2IdPService.class).list();
+
+        final Model<SAML2IdPTO> model = new Model<>();
+        AjaxDropDownChoicePanel<SAML2IdPTO> idps =
+                new AjaxDropDownChoicePanel<>("idps", "SAML 2.0", model, 
false);
+        idps.setChoices(available);
+        idps.setChoiceRenderer(new IChoiceRenderer<SAML2IdPTO>() {
+
+            private static final long serialVersionUID = 1814750973898916102L;
+
+            @Override
+            public Object getDisplayValue(final SAML2IdPTO object) {
+                return object.getName();
+            }
+
+            @Override
+            public String getIdValue(final SAML2IdPTO object, final int index) 
{
+                return object.getEntityID();
+            }
+
+            @Override
+            public SAML2IdPTO getObject(final String id, final IModel<? 
extends List<? extends SAML2IdPTO>> choices) {
+                return IterableUtils.find(choices.getObject(), new 
Predicate<SAML2IdPTO>() {
+
+                    @Override
+                    public boolean evaluate(final SAML2IdPTO object) {
+                        return object.getEntityID().equals(id);
+                    }
+                });
+            }
+        });
+        idps.getField().add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                if (model.getObject() != null) {
+                    try {
+                        
RequestCycle.get().scheduleRequestHandlerAfterCurrent(new 
RedirectRequestHandler(
+                                
UrlUtils.rewriteToContextRelative("saml2sp/login?idp="
+                                        + URLEncoder.encode(
+                                                
model.getObject().getEntityID(), StandardCharsets.UTF_8.name()),
+                                        RequestCycle.get())));
+                    } catch (Exception e) {
+                        LOG.error("Could not redirect to the selected IdP {}", 
model.getObject().getEntityID(), e);
+                    }
+                }
+            }
+        });
+        idps.setOutputMarkupPlaceholderTag(true);
+        idps.setVisible(!available.isEmpty());
+        add(idps);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/client-console/src/main/resources/org/apache/syncope/client/console/panels/SAMLSSOLoginFormPanel.html
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/client-console/src/main/resources/org/apache/syncope/client/console/panels/SAMLSSOLoginFormPanel.html
 
b/ext/saml2sp/client-console/src/main/resources/org/apache/syncope/client/console/panels/SAMLSSOLoginFormPanel.html
new file mode 100644
index 0000000..8dfeef4
--- /dev/null
+++ 
b/ext/saml2sp/client-console/src/main/resources/org/apache/syncope/client/console/panels/SAMLSSOLoginFormPanel.html
@@ -0,0 +1,25 @@
+<!--
+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="form-group">
+      <span wicket:id="idps"></span>
+    </div>
+  </wicket:panel>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
 
b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
index 9b5eb20..d22dfcd 100644
--- 
a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
+++ 
b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
@@ -40,10 +40,14 @@ public class SAML2IdPTO extends AbstractBaseBean implements 
EntityTO {
 
     private String entityID;
 
+    private String name;
+
     private String metadata;
 
     private boolean useDeflateEncoding;
 
+    private boolean logoutSupported;
+
     private final List<MappingItemTO> mappingItems = new ArrayList<>();
 
     @Override
@@ -65,6 +69,14 @@ public class SAML2IdPTO extends AbstractBaseBean implements 
EntityTO {
         this.entityID = entityID;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
     public String getMetadata() {
         return metadata;
     }
@@ -81,6 +93,14 @@ public class SAML2IdPTO extends AbstractBaseBean implements 
EntityTO {
         this.useDeflateEncoding = useDeflateEncoding;
     }
 
+    public boolean isLogoutSupported() {
+        return logoutSupported;
+    }
+
+    public void setLogoutSupported(final boolean logoutSupported) {
+        this.logoutSupported = logoutSupported;
+    }
+
     public MappingItemTO getConnObjectKeyItem() {
         return IterableUtils.find(getMappingItems(), new 
Predicate<MappingItemTO>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java
 
b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java
index b6ece53..941d7c5 100644
--- 
a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java
+++ 
b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java
@@ -48,6 +48,10 @@ public class SAML2LoginResponseTO extends AbstractBaseBean {
 
     private final Set<AttrTO> attrs = new HashSet<>();
 
+    private String idp;
+
+    private boolean sloSupported;
+
     public String getNameID() {
         return nameID;
     }
@@ -117,4 +121,20 @@ public class SAML2LoginResponseTO extends AbstractBaseBean 
{
         return attrs;
     }
 
+    public String getIdp() {
+        return idp;
+    }
+
+    public void setIdp(final String idp) {
+        this.idp = idp;
+    }
+
+    public boolean isSloSupported() {
+        return sloSupported;
+    }
+
+    public void setSloSupported(final boolean sloSupported) {
+        this.sloSupported = sloSupported;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/types/SAML2SPEntitlement.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/types/SAML2SPEntitlement.java
 
b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/types/SAML2SPEntitlement.java
index 985bf8b..b0d4769 100644
--- 
a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/types/SAML2SPEntitlement.java
+++ 
b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/types/SAML2SPEntitlement.java
@@ -28,8 +28,6 @@ public final class SAML2SPEntitlement {
 
     public static final String IDP_READ = "IDP_READ";
 
-    public static final String IDP_LIST = "IDP_LIST";
-
     public static final String IDP_IMPORT = "IDP_IMPORT";
 
     public static final String IDP_UPDATE = "IDP_UPDATE";

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/AbstractSAML2Logic.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/AbstractSAML2Logic.java
 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/AbstractSAML2Logic.java
new file mode 100644
index 0000000..01c04ea
--- /dev/null
+++ 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/AbstractSAML2Logic.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.logic;
+
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.core.logic.init.SAML2SPLoader;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public abstract class AbstractSAML2Logic<T extends AbstractBaseBean> extends 
AbstractTransactionalLogic<T> {
+
+    @Autowired
+    protected SAML2SPLoader loader;
+
+    protected void check() {
+        if (!loader.isInited()) {
+            throw new IllegalStateException("Keystore setup did not work 
properly, SAML 2.0 SP features disabled");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
index 3f6b4a3..eb1a94f 100644
--- 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
+++ 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
@@ -55,11 +55,7 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 @Component
-public class SAML2IdPLogic extends AbstractTransactionalLogic<SAML2IdPTO> {
-
-    static {
-        OpenSAMLUtil.initSamlEngine(false);
-    }
+public class SAML2IdPLogic extends AbstractSAML2Logic<SAML2IdPTO> {
 
     @Autowired
     private SAML2IdPCache cache;
@@ -73,14 +69,20 @@ public class SAML2IdPLogic extends 
AbstractTransactionalLogic<SAML2IdPTO> {
     @Autowired
     private SAML2ReaderWriter saml2rw;
 
-    @PreAuthorize("hasRole('" + SAML2SPEntitlement.IDP_LIST + "')")
+    private SAML2IdPTO complete(final SAML2IdPTO input) {
+        SAML2IdPEntity idp = cache.get(input.getEntityID());
+        
input.setLogoutSupported(idp.getSLOLocation(SAMLConstants.SAML2_POST_BINDING_URI)
 != null);
+        return input;
+    }
+
+    @PreAuthorize("isAuthenticated()")
     @Transactional(readOnly = true)
     public List<SAML2IdPTO> list() {
         return CollectionUtils.collect(idpDAO.findAll(), new 
Transformer<SAML2IdP, SAML2IdPTO>() {
 
             @Override
             public SAML2IdPTO transform(final SAML2IdP input) {
-                return binder.getIdPTO(input);
+                return complete(binder.getIdPTO(input));
             }
         }, new ArrayList<SAML2IdPTO>());
     }
@@ -88,12 +90,14 @@ public class SAML2IdPLogic extends 
AbstractTransactionalLogic<SAML2IdPTO> {
     @PreAuthorize("hasRole('" + SAML2SPEntitlement.IDP_READ + "')")
     @Transactional(readOnly = true)
     public SAML2IdPTO read(final String key) {
+        check();
+
         SAML2IdP idp = idpDAO.find(key);
         if (idp == null) {
             throw new NotFoundException("SAML 2.0 IdP '" + key + "'");
         }
 
-        return binder.getIdPTO(idp);
+        return complete(binder.getIdPTO(idp));
     }
 
     private List<SAML2IdPTO> importIdPs(final InputStream input) throws 
Exception {
@@ -130,6 +134,7 @@ public class SAML2IdPLogic extends 
AbstractTransactionalLogic<SAML2IdPTO> {
         for (EntityDescriptor idpEntityDescriptor : idpEntityDescriptors) {
             SAML2IdPTO idpTO = new SAML2IdPTO();
             idpTO.setEntityID(idpEntityDescriptor.getEntityID());
+            idpTO.setName(idpEntityDescriptor.getEntityID());
             idpTO.setUseDeflateEncoding(false);
             try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                 saml2rw.write(new OutputStreamWriter(baos), 
idpEntityDescriptor, false);
@@ -149,6 +154,8 @@ public class SAML2IdPLogic extends 
AbstractTransactionalLogic<SAML2IdPTO> {
 
     @PreAuthorize("hasRole('" + SAML2SPEntitlement.IDP_IMPORT + "')")
     public List<String> importFromMetadata(final InputStream input) {
+        check();
+
         List<String> imported = new ArrayList<>();
 
         try {
@@ -170,6 +177,8 @@ public class SAML2IdPLogic extends 
AbstractTransactionalLogic<SAML2IdPTO> {
 
     @PreAuthorize("hasRole('" + SAML2SPEntitlement.IDP_UPDATE + "')")
     public void update(final SAML2IdPTO saml2IdpTO) {
+        check();
+
         SAML2IdP saml2Idp = idpDAO.find(saml2IdpTO.getKey());
         if (saml2Idp == null) {
             throw new NotFoundException("SAML 2.0 IdP '" + saml2IdpTO.getKey() 
+ "'");
@@ -186,6 +195,8 @@ public class SAML2IdPLogic extends 
AbstractTransactionalLogic<SAML2IdPTO> {
 
     @PreAuthorize("hasRole('" + SAML2SPEntitlement.IDP_DELETE + "')")
     public void delete(final String key) {
+        check();
+
         SAML2IdP idp = idpDAO.find(key);
         if (idp == null) {
             throw new NotFoundException("SAML 2.0 IdP '" + key + "'");
@@ -213,7 +224,7 @@ public class SAML2IdPLogic extends 
AbstractTransactionalLogic<SAML2IdPTO> {
 
         if (key != null) {
             try {
-                return binder.getIdPTO(idpDAO.find(key));
+                return complete(binder.getIdPTO(idpDAO.find(key)));
             } catch (Throwable ignore) {
                 LOG.debug("Unresolved reference", ignore);
                 throw new UnresolvedReferenceException(ignore);

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
index f452208..a61590f 100644
--- 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
+++ 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
@@ -52,7 +52,6 @@ import org.apache.syncope.common.lib.to.MappingItemTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
-import org.apache.syncope.core.logic.init.SAML2SPLoader;
 import org.apache.syncope.core.logic.saml2.SAML2ReaderWriter;
 import org.apache.syncope.core.logic.saml2.SAML2IdPCache;
 import org.apache.syncope.core.logic.saml2.SAML2IdPEntity;
@@ -75,7 +74,6 @@ import 
org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
 import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
 import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
 import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.apache.wss4j.common.saml.OpenSAMLUtil;
 import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.schema.XSString;
@@ -127,7 +125,7 @@ import 
org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.stereotype.Component;
 
 @Component
-public class SAML2SPLogic extends AbstractTransactionalLogic<AbstractBaseBean> 
{
+public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
 
     private static final Integer JWT_RELAY_STATE_DURATION = 5;
 
@@ -143,10 +141,6 @@ public class SAML2SPLogic extends 
AbstractTransactionalLogic<AbstractBaseBean> {
 
     private static final RandomBasedGenerator UUID_GENERATOR = 
Generators.randomBasedGenerator();
 
-    static {
-        OpenSAMLUtil.initSamlEngine(false);
-    }
-
     @Autowired
     private JwsSignatureVerifier jwsSignatureCerifier;
 
@@ -154,9 +148,6 @@ public class SAML2SPLogic extends 
AbstractTransactionalLogic<AbstractBaseBean> {
     private AccessTokenDataBinder accessTokenDataBinder;
 
     @Autowired
-    private SAML2SPLoader loader;
-
-    @Autowired
     private SAML2IdPCache cache;
 
     @Autowired
@@ -185,6 +176,8 @@ public class SAML2SPLogic extends 
AbstractTransactionalLogic<AbstractBaseBean> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.ANONYMOUS + "')")
     public void getMetadata(final String spEntityID, final OutputStream os) {
+        check();
+
         try {
             EntityDescriptor spEntityDescriptor = new 
EntityDescriptorBuilder().buildObject();
             spEntityDescriptor.setEntityID(spEntityID);
@@ -256,8 +249,8 @@ public class SAML2SPLogic extends 
AbstractTransactionalLogic<AbstractBaseBean> {
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.ANONYMOUS + "')")
-    public SAML2RequestTO createLoginRequest(
-            final String spEntityID, final String idpEntityID) {
+    public SAML2RequestTO createLoginRequest(final String spEntityID, final 
String idpEntityID) {
+        check();
 
         // 1. look for IdP
         SAML2IdPEntity idp = StringUtils.isBlank(idpEntityID) ? 
cache.getFirst() : cache.get(idpEntityID);
@@ -416,6 +409,8 @@ public class SAML2SPLogic extends 
AbstractTransactionalLogic<AbstractBaseBean> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.ANONYMOUS + "')")
     public SAML2LoginResponseTO validateLoginResponse(final InputStream 
response) {
+        check();
+
         // 1. extract raw SAML response and relay state
         Pair<String, String> extracted;
         try {
@@ -478,6 +473,8 @@ public class SAML2SPLogic extends 
AbstractTransactionalLogic<AbstractBaseBean> {
 
         // 6. prepare the result: find matching user (if any) and return the 
received attributes
         SAML2LoginResponseTO responseTO = new SAML2LoginResponseTO();
+        responseTO.setIdp(idp.getId());
+        
responseTO.setSloSupported(idp.getSLOLocation(SAMLConstants.SAML2_POST_BINDING_URI)
 != null);
 
         NameID nameID = null;
         String keyValue = null;
@@ -553,6 +550,8 @@ public class SAML2SPLogic extends 
AbstractTransactionalLogic<AbstractBaseBean> {
 
     @PreAuthorize("isAuthenticated() and not(hasRole('" + 
StandardEntitlement.ANONYMOUS + "'))")
     public SAML2RequestTO createLogoutRequest(final String accessToken, final 
String spEntityID) {
+        check();
+
         // 1. fetch the current JWT used for Syncope authentication
         JwsJwtCompactConsumer consumer = new 
JwsJwtCompactConsumer(accessToken);
         if (!consumer.verifySignatureWith(jwsSignatureCerifier)) {
@@ -615,6 +614,8 @@ public class SAML2SPLogic extends 
AbstractTransactionalLogic<AbstractBaseBean> {
 
     @PreAuthorize("isAuthenticated() and not(hasRole('" + 
StandardEntitlement.ANONYMOUS + "'))")
     public void validateLogoutResponse(final String accessToken, final 
InputStream response) {
+        check();
+
         // 1. fetch the current JWT used for Syncope authentication
         JwsJwtCompactConsumer consumer = new 
JwsJwtCompactConsumer(accessToken);
         if (!consumer.verifySignatureWith(jwsSignatureCerifier)) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/init/SAML2SPLoader.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/init/SAML2SPLoader.java
 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/init/SAML2SPLoader.java
index dee85ef..c4f4507 100644
--- 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/init/SAML2SPLoader.java
+++ 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/init/SAML2SPLoader.java
@@ -30,13 +30,17 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.core.persistence.api.SyncopeLoader;
 import org.apache.syncope.core.provisioning.api.EntitlementsHolder;
 import org.apache.syncope.common.lib.types.SAML2SPEntitlement;
+import org.apache.syncope.core.logic.saml2.SAML2ReaderWriter;
+import org.apache.syncope.core.logic.saml2.SAML2Signer;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.spring.ResourceWithFallbackLoader;
+import org.apache.wss4j.common.saml.OpenSAMLUtil;
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.security.credential.Credential;
 import org.opensaml.security.credential.impl.KeyStoreCredentialResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 @Component
@@ -53,6 +57,18 @@ public class SAML2SPLoader implements SyncopeLoader {
         return argument;
     }
 
+    static {
+        OpenSAMLUtil.initSamlEngine(false);
+    }
+
+    @Autowired
+    private SAML2ReaderWriter saml2rw;
+
+    @Autowired
+    private SAML2Signer signer;
+
+    private boolean inited;
+
     private KeyStore keystore;
 
     private String keyPass;
@@ -120,11 +136,21 @@ public class SAML2SPLoader implements SyncopeLoader {
 
             this.credential = resolver.resolveSingle(new CriteriaSet(new 
EntityIdCriterion(certAlias)));
             LOG.debug("SAML 2.0 Service Provider certificate loaded");
+
+            saml2rw.init();
+            signer.init();
+
+            inited = true;
         } catch (Exception e) {
-            throw new RuntimeException("Could not initialize the SAML 2.0 
Service Provider certificate", e);
+            LOG.error("Could not initialize the SAML 2.0 Service Provider 
certificate", e);
+            inited = false;
         }
     }
 
+    public boolean isInited() {
+        return inited;
+    }
+
     public KeyStore getKeyStore() {
         return keystore;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
index 23b3a38..964759a 100644
--- 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
+++ 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
@@ -47,22 +47,17 @@ import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.saml2.core.Response;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.w3c.dom.Document;
 
 @Component
-public class SAML2ReaderWriter implements InitializingBean {
+public class SAML2ReaderWriter {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(SAML2ReaderWriter.class);
 
     private static final TransformerFactory TRANSFORMER_FACTORY = 
TransformerFactory.newInstance();
 
-    static {
-        OpenSAMLUtil.initSamlEngine(false);
-    }
-
     @Autowired
     private SAML2SPLoader loader;
 
@@ -70,8 +65,7 @@ public class SAML2ReaderWriter implements InitializingBean {
 
     private SAML2IdPCallbackHandler callbackHandler;
 
-    @Override
-    public void afterPropertiesSet() throws Exception {
+    public void init() {
         protocolValidator = new SAMLProtocolResponseValidator();
         protocolValidator.setKeyInfoMustBeAvailable(true);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java
 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java
index 9a03627..cf30aa0 100644
--- 
a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java
+++ 
b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java
@@ -34,16 +34,11 @@ import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator;
 import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory;
 import org.opensaml.xmlsec.signature.Signature;
 import org.opensaml.xmlsec.signature.support.SignatureConstants;
-import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 @Component
-public class SAML2Signer implements InitializingBean {
-
-    static {
-        OpenSAMLUtil.initSamlEngine(false);
-    }
+public class SAML2Signer {
 
     @Autowired
     private SAML2SPLoader loader;
@@ -55,8 +50,7 @@ public class SAML2Signer implements InitializingBean {
 
     private String signatureAlgorithm;
 
-    @Override
-    public void afterPropertiesSet() throws Exception {
+    public void init() {
         X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new 
X509KeyInfoGeneratorFactory();
         keyInfoGeneratorFactory.setEmitEntityCertificate(true);
         keyInfoGenerator = keyInfoGeneratorFactory.newInstance();

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java
 
b/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java
index d3372c2..a71579f 100644
--- 
a/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java
+++ 
b/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java
@@ -27,6 +27,10 @@ public interface SAML2IdP extends Entity {
 
     void setEntityID(String entityID);
 
+    String getName();
+
+    void setName(String name);
+
     byte[] getMetadata();
 
     void setMetadata(byte[] metadata);

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java
 
b/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java
index 1b46051..879b3e5 100644
--- 
a/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java
+++ 
b/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java
@@ -49,9 +49,12 @@ public class JPASAML2IdP extends AbstractGeneratedKeyEntity 
implements SAML2IdP
 
     public static final String TABLE = "SAML2IdP";
 
-    @Column(nullable = false)
+    @Column(unique = true, nullable = false)
     private String entityID;
 
+    @Column(unique = true, nullable = false)
+    private String name;
+
     @Lob
     @Basic(fetch = FetchType.EAGER)
     private Byte[] metadata;
@@ -75,6 +78,16 @@ public class JPASAML2IdP extends AbstractGeneratedKeyEntity 
implements SAML2IdP
     }
 
     @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    @Override
     public byte[] getMetadata() {
         return metadata == null ? null : ArrayUtils.toPrimitive(metadata);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/pom.xml
----------------------------------------------------------------------
diff --git a/ext/saml2sp/pom.xml b/ext/saml2sp/pom.xml
index dc0af30..bf1cd9f 100644
--- a/ext/saml2sp/pom.xml
+++ b/ext/saml2sp/pom.xml
@@ -47,6 +47,7 @@ under the License.
     <module>logic</module>
     <module>rest-cxf</module>
     <module>agent</module>
+    <module>client-console</module>
   </modules>
 
 </project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
----------------------------------------------------------------------
diff --git 
a/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
 
b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
index 2687e0b..351c487 100644
--- 
a/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
+++ 
b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
@@ -169,6 +169,7 @@ public class SAML2IdPDataBinderImpl implements 
SAML2IdPDataBinder {
     @Override
     public SAML2IdP update(final SAML2IdP idp, final SAML2IdPTO idpTO) {
         idp.setEntityID(idpTO.getEntityID());
+        idp.setName(idpTO.getName());
         idp.setMetadata(Base64.decode(idpTO.getMetadata()));
         idp.setUseDeflateEncoding(idpTO.isUseDeflateEncoding());
 
@@ -211,6 +212,7 @@ public class SAML2IdPDataBinderImpl implements 
SAML2IdPDataBinder {
 
         idpTO.setKey(idp.getKey());
         idpTO.setEntityID(idp.getEntityID());
+        idpTO.setName(idp.getName());
         idpTO.setUseDeflateEncoding(idp.isUseDeflateEncoding());
         idpTO.setMetadata(Base64.encode(idp.getMetadata()));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/fit/console-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/console-reference/pom.xml b/fit/console-reference/pom.xml
index 2d589d9..4790a1d 100644
--- a/fit/console-reference/pom.xml
+++ b/fit/console-reference/pom.xml
@@ -64,7 +64,7 @@ under the License.
     
     <dependency>
       <groupId>org.apache.syncope.ext.saml2sp</groupId>
-      <artifactId>syncope-ext-saml2sp-agent</artifactId>
+      <artifactId>syncope-ext-saml2sp-client-console</artifactId>
       <version>${project.version}</version>
     </dependency>
     

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/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 c9508a8..66a800e 100644
--- a/fit/console-reference/src/main/webapp/WEB-INF/web.xml
+++ b/fit/console-reference/src/main/webapp/WEB-INF/web.xml
@@ -29,10 +29,28 @@ under the License.
     <param-name>configuration</param-name>
     <param-value>deployment</param-value>
   </context-param>
-
+  
+  <context-param>
+    <param-name>saml2sp.login.success.url</param-name>
+    
<param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.SAML2SPLogin</param-value>
+  </context-param>
+  <context-param>
+    <param-name>saml2sp.login.error.url</param-name>
+    
<param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.Login</param-value>
+  </context-param>
+  
+  <context-param>
+    <param-name>saml2sp.logout.success.url</param-name>
+    
<param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.SAML2SPLogout</param-value>
+  </context-param>
+  <context-param>
+    <param-name>saml2sp.logout.error.url</param-name>
+    
<param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.Login</param-value>
+  </context-param>
+  
   <!-- SESSION TIMEOUT (MINUTES)-->
   <session-config>
     <session-timeout>30</session-timeout>
   </session-config>
 
-</web-app>
\ No newline at end of file
+</web-app>

http://git-wip-us.apache.org/repos/asf/syncope/blob/0ce5b4cd/fit/console-reference/src/test/resources/rebel.xml
----------------------------------------------------------------------
diff --git a/fit/console-reference/src/test/resources/rebel.xml 
b/fit/console-reference/src/test/resources/rebel.xml
index 022ee5d..f1189d5 100644
--- a/fit/console-reference/src/test/resources/rebel.xml
+++ b/fit/console-reference/src/test/resources/rebel.xml
@@ -30,6 +30,8 @@ under the License.
     </dir>
     <dir name="${basedir}/../../ext/saml2sp/agent/target/classes">
     </dir>
+    <dir name="${basedir}/../../ext/saml2sp/client-console/target/classes">
+    </dir>
   </classpath>
 
   <web>
@@ -45,6 +47,10 @@ under the License.
       <dir name="${basedir}/../../ext/camel/client-console/target/classes">
       </dir>
     </link>
+    <link target="/">
+      <dir name="${basedir}/../../ext/saml2sp/client-console/target/classes">
+      </dir>
+    </link>
   </web>
 
 </application>

Reply via email to