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

[5/8] syncope git commit: [SYNCOPE-1270] implementation for OpenID Connect for Admin Console and Enduser - This closes #74

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProviderItem.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProviderItem.java b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProviderItem.java
new file mode 100644
index 0000000..69268cb
--- /dev/null
+++ b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCProviderItem.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Cacheable;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
+import org.apache.syncope.core.persistence.api.entity.OIDCProviderItem;
+import org.apache.syncope.core.persistence.jpa.entity.resource.AbstractItem;
+
+@Entity
+@Table(name = JPAOIDCProviderItem.TABLE)
+@Cacheable
+public class JPAOIDCProviderItem extends AbstractItem implements OIDCProviderItem {
+
+    public static final String TABLE = "OIDCProviderItem";
+
+    private static final long serialVersionUID = -6903418265811089724L;
+
+    @ManyToOne
+    private JPAOIDCProvider op;
+
+    @Override
+    public OIDCProvider getOP() {
+        return op;
+    }
+
+    @Override
+    public void setOP(final OIDCProvider op) {
+        checkType(op, JPAOIDCProvider.class);
+        this.op = (JPAOIDCProvider) op;
+    }
+
+    @ManyToMany(fetch = FetchType.EAGER)
+    @JoinTable(name = TABLE + "Transformer",
+            joinColumns =
+            @JoinColumn(name = "item_id"),
+            inverseJoinColumns =
+            @JoinColumn(name = "implementation_id"))
+    private List<JPAImplementation> transformers = new ArrayList<>();
+
+    @Override
+    public boolean add(final Implementation transformer) {
+        checkType(transformer, JPAImplementation.class);
+        checkImplementationType(transformer, ImplementationType.ITEM_TRANSFORMER);
+        return this.transformers.add((JPAImplementation) transformer);
+    }
+
+    @Override
+    public List<? extends Implementation> getTransformers() {
+        return transformers;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCUserTemplate.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCUserTemplate.java b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCUserTemplate.java
new file mode 100644
index 0000000..54eea72
--- /dev/null
+++ b/ext/oidcclient/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAOIDCUserTemplate.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
+import org.apache.syncope.core.persistence.api.entity.OIDCUserTemplate;
+import org.apache.syncope.core.persistence.jpa.entity.resource.AbstractAnyTemplate;
+
+@Entity
+@Table(name = JPAOIDCUserTemplate.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "op_id" }))
+public class JPAOIDCUserTemplate extends AbstractAnyTemplate implements OIDCUserTemplate {
+
+    public static final String TABLE = "OIDCUserTemplate";
+
+    private static final long serialVersionUID = 3964321047520954968L;
+
+    @ManyToOne
+    private JPAOIDCProvider op;
+
+    @Override
+    public OIDCProvider getOP() {
+        return op;
+    }
+
+    @Override
+    public void setOP(final OIDCProvider op) {
+        checkType(op, JPAOIDCProvider.class);
+        this.op = (JPAOIDCProvider) op;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/pom.xml
----------------------------------------------------------------------
diff --git a/ext/oidcclient/pom.xml b/ext/oidcclient/pom.xml
new file mode 100644
index 0000000..6bdb336
--- /dev/null
+++ b/ext/oidcclient/pom.xml
@@ -0,0 +1,55 @@
+<?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</groupId>
+    <artifactId>syncope-ext</artifactId>
+    <version>2.1.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Ext: OIDC Client</name>
+  <description>Apache Syncope Ext: OIDC Client</description>
+  <groupId>org.apache.syncope.ext</groupId>
+  <artifactId>syncope-ext-oidcclient</artifactId>
+  <packaging>pom</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../..</rootpom.basedir>
+  </properties>
+ 
+
+  <modules>
+    <module>common-lib</module>
+    <module>rest-api</module>
+    <module>logic</module>
+    <module>rest-cxf</module>
+    <module>persistence-api</module>
+    <module>persistence-jpa</module>
+    <module>agent</module>
+    <module>client-console</module>
+    <module>client-enduser</module>
+    <module>provisioning-api</module>
+    <module>provisioning-java</module>
+  </modules>
+
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/provisioning-api/pom.xml
----------------------------------------------------------------------
diff --git a/ext/oidcclient/provisioning-api/pom.xml b/ext/oidcclient/provisioning-api/pom.xml
new file mode 100644
index 0000000..3d58721
--- /dev/null
+++ b/ext/oidcclient/provisioning-api/pom.xml
@@ -0,0 +1,67 @@
+<?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-oidcclient</artifactId>
+    <version>2.1.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Ext: OIDC Client Provisioning API</name>
+  <description>Apache Syncope Ext: OIDC Client Provisioning API</description>
+  <groupId>org.apache.syncope.ext.oidcclient</groupId>
+  <artifactId>syncope-ext-oidcclient-provisioning-api</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.core</groupId>
+      <artifactId>syncope-core-provisioning-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-persistence-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-common-lib</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/OIDCProviderActions.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/OIDCProviderActions.java b/ext/oidcclient/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/OIDCProviderActions.java
new file mode 100644
index 0000000..40ea6a8
--- /dev/null
+++ b/ext/oidcclient/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/OIDCProviderActions.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.provisioning.api;
+
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
+import org.apache.syncope.common.lib.to.UserTO;
+
+public interface OIDCProviderActions {
+
+    UserTO beforeCreate(UserTO input, OIDCLoginResponseTO loginResponse);
+
+    UserTO afterCreate(UserTO input, OIDCLoginResponseTO loginResponse);
+
+    UserPatch beforeUpdate(UserPatch input, OIDCLoginResponseTO loginResponse);
+
+    UserTO afterUpdate(UserTO input, OIDCLoginResponseTO loginResponse);
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCProviderDataBinder.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCProviderDataBinder.java b/ext/oidcclient/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCProviderDataBinder.java
new file mode 100644
index 0000000..acea05d
--- /dev/null
+++ b/ext/oidcclient/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCProviderDataBinder.java
@@ -0,0 +1,32 @@
+/*
+ * 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.provisioning.api.data;
+
+import org.apache.syncope.common.lib.to.OIDCProviderTO;
+import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
+
+public interface OIDCProviderDataBinder {
+
+    OIDCProvider create(OIDCProviderTO op);
+
+    OIDCProvider update(OIDCProvider op, OIDCProviderTO opTO);
+
+    OIDCProviderTO getOIDCProviderTO(OIDCProvider op);
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/provisioning-java/pom.xml
----------------------------------------------------------------------
diff --git a/ext/oidcclient/provisioning-java/pom.xml b/ext/oidcclient/provisioning-java/pom.xml
new file mode 100644
index 0000000..962c2b7
--- /dev/null
+++ b/ext/oidcclient/provisioning-java/pom.xml
@@ -0,0 +1,61 @@
+<?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-oidcclient</artifactId>
+    <version>2.1.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Ext: OIDC Client Provisioning Java</name>
+  <description>Apache Syncope Ext: OIDC Client Provisioning Java</description>
+  <groupId>org.apache.syncope.ext.oidcclient</groupId>
+  <artifactId>syncope-ext-oidcclient-provisioning-java</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.core</groupId>
+      <artifactId>syncope-core-provisioning-java</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-provisioning-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultOIDCProviderActions.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultOIDCProviderActions.java b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultOIDCProviderActions.java
new file mode 100644
index 0000000..e6b060c
--- /dev/null
+++ b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultOIDCProviderActions.java
@@ -0,0 +1,48 @@
+/*
+ * 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.provisioning.java;
+
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.core.provisioning.api.OIDCProviderActions;
+
+public class DefaultOIDCProviderActions implements OIDCProviderActions {
+
+    @Override
+    public UserTO beforeCreate(final UserTO input, final OIDCLoginResponseTO loginResponse) {
+        return input;
+    }
+
+    @Override
+    public UserTO afterCreate(final UserTO input, final OIDCLoginResponseTO loginResponse) {
+        return input;
+    }
+
+    @Override
+    public UserPatch beforeUpdate(final UserPatch input, final OIDCLoginResponseTO loginResponse) {
+        return input;
+    }
+
+    @Override
+    public UserTO afterUpdate(final UserTO input, final OIDCLoginResponseTO loginResponse) {
+        return input;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
new file mode 100644
index 0000000..75ead03
--- /dev/null
+++ b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
@@ -0,0 +1,258 @@
+/*
+ * 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.provisioning.java.data;
+
+import java.text.ParseException;
+import java.util.stream.Collectors;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AnyTypeClassTO;
+import org.apache.syncope.common.lib.to.ItemTO;
+import org.apache.syncope.common.lib.to.OIDCProviderTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
+import org.apache.syncope.core.persistence.api.dao.OIDCProviderDAO;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.OIDCEntityFactory;
+import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
+import org.apache.syncope.core.persistence.api.entity.OIDCProviderItem;
+import org.apache.syncope.core.persistence.api.entity.OIDCUserTemplate;
+import org.apache.syncope.core.provisioning.api.IntAttrName;
+import org.apache.syncope.core.provisioning.api.data.OIDCProviderDataBinder;
+import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
+import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
+import org.apache.syncope.core.spring.BeanUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class OIDCProviderDataBinderImpl implements OIDCProviderDataBinder {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OIDCProviderDataBinder.class);
+
+    private static final String[] ITEM_IGNORE_PROPERTIES = { "key", "purpose" };
+
+    @Autowired
+    private AnyTypeDAO anyTypeDAO;
+
+    @Autowired
+    private OIDCProviderDAO oidcOPDAO;
+
+    @Autowired
+    private OIDCEntityFactory entityFactory;
+
+    @Autowired
+    private IntAttrNameParser intAttrNameParser;
+
+    @Override
+    public OIDCProvider create(final OIDCProviderTO opTO) {
+        return update(entityFactory.newEntity(OIDCProvider.class), opTO);
+
+    }
+
+    private void populateItems(
+            final OIDCProviderTO opTO,
+            final OIDCProvider op,
+            final AnyTypeClassTO allowedSchemas) {
+
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+        SyncopeClientException invalidMapping =
+                SyncopeClientException.build(ClientExceptionType.InvalidMapping);
+        SyncopeClientException requiredValuesMissing =
+                SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+
+        for (ItemTO itemTO : opTO.getItems()) {
+            if (itemTO == null) {
+                LOG.error("Null {}", ItemTO.class.getSimpleName());
+                invalidMapping.getElements().add("Null " + ItemTO.class.getSimpleName());
+            } else if (itemTO.getIntAttrName() == null) {
+                requiredValuesMissing.getElements().add("intAttrName");
+                scce.addException(requiredValuesMissing);
+            } else {
+                IntAttrName intAttrName = null;
+                try {
+                    intAttrName = intAttrNameParser.parse(itemTO.getIntAttrName(), AnyTypeKind.USER);
+                } catch (ParseException e) {
+                    LOG.error("Invalid intAttrName '{}' specified, ignoring", itemTO.getIntAttrName(), e);
+                }
+
+                if (intAttrName == null || intAttrName.getSchemaType() == null && intAttrName.getField() == null) {
+                    LOG.error("'{}' not existing", itemTO.getIntAttrName());
+                    invalidMapping.getElements().add("'" + itemTO.getIntAttrName() + "' not existing");
+                } else {
+                    boolean allowed = true;
+                    if (intAttrName.getSchemaType() != null
+                            && intAttrName.getEnclosingGroup() == null
+                            && intAttrName.getRelatedAnyObject() == null) {
+                        switch (intAttrName.getSchemaType()) {
+                            case PLAIN:
+                                allowed = allowedSchemas.getPlainSchemas().contains(intAttrName.getSchemaName());
+                                break;
+
+                            case DERIVED:
+                                allowed = allowedSchemas.getDerSchemas().contains(intAttrName.getSchemaName());
+                                break;
+
+                            case VIRTUAL:
+                                allowed = allowedSchemas.getVirSchemas().contains(intAttrName.getSchemaName());
+                                break;
+
+                            default:
+                        }
+                    }
+
+                    if (allowed) {
+                        // no mandatory condition implies mandatory condition false
+                        if (!JexlUtils.isExpressionValid(itemTO.getMandatoryCondition() == null
+                                ? "false" : itemTO.getMandatoryCondition())) {
+
+                            SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
+                                    ClientExceptionType.InvalidValues);
+                            invalidMandatoryCondition.getElements().add(itemTO.getMandatoryCondition());
+                            scce.addException(invalidMandatoryCondition);
+                        }
+
+                        OIDCProviderItem item = entityFactory.newEntity(OIDCProviderItem.class);
+                        BeanUtils.copyProperties(itemTO, item, ITEM_IGNORE_PROPERTIES);
+                        item.setOP(op);
+                        item.setPurpose(MappingPurpose.NONE);
+                        if (item.isConnObjectKey()) {
+                            if (intAttrName.getSchemaType() == SchemaType.VIRTUAL) {
+                                invalidMapping.getElements().
+                                        add("Virtual attributes cannot be set as ConnObjectKey");
+                            }
+                            if ("password".equals(intAttrName.getField())) {
+                                invalidMapping.getElements().add(
+                                        "Password attributes cannot be set as ConnObjectKey");
+                            }
+
+                            op.setConnObjectKeyItem(item);
+                        } else {
+                            op.add(item);
+                        }
+                    } else {
+                        LOG.error("'{}' not allowed", itemTO.getIntAttrName());
+                        invalidMapping.getElements().add("'" + itemTO.getIntAttrName() + "' not allowed");
+                    }
+                }
+            }
+        }
+
+        if (!invalidMapping.getElements().isEmpty()) {
+            scce.addException(invalidMapping);
+        }
+        if (scce.hasExceptions()) {
+            throw scce;
+        }
+    }
+
+    @Override
+    public OIDCProvider update(final OIDCProvider op, final OIDCProviderTO opTO) {
+        op.setAuthorizationEndpoint(opTO.getAuthorizationEndpoint());
+        op.setClientID(opTO.getClientID());
+        op.setClientSecret(opTO.getClientSecret());
+        op.setName(opTO.getName());
+        op.setIssuer(opTO.getIssuer());
+        op.setJwksUri(opTO.getJwksUri());
+        op.setTokenEndpoint(opTO.getTokenEndpoint());
+        op.setUserinfoEndpoint(opTO.getUserinfoEndpoint());
+        op.setHasDiscovery(opTO.getHasDiscovery());
+        op.setCreateUnmatching(opTO.isCreateUnmatching());
+        op.setUpdateMatching(opTO.isUpdateMatching());
+
+        if (opTO.getUserTemplate() == null) {
+            op.setUserTemplate(null);
+        } else {
+            OIDCUserTemplate userTemplate = op.getUserTemplate();
+            if (userTemplate == null) {
+                userTemplate = entityFactory.newEntity(OIDCUserTemplate.class);
+                userTemplate.setAnyType(anyTypeDAO.findUser());
+                userTemplate.setOP(op);
+                op.setUserTemplate(userTemplate);
+            }
+            userTemplate.set(opTO.getUserTemplate());
+        }
+
+        op.getItems().clear();
+        AnyTypeClassTO allowedSchemas = new AnyTypeClassTO();
+        anyTypeDAO.findUser().getClasses().forEach(anyTypeClass -> {
+            allowedSchemas.getPlainSchemas().addAll(anyTypeClass.getPlainSchemas().stream().
+                    map(Entity::getKey).collect(Collectors.toList()));
+            allowedSchemas.getDerSchemas().addAll(anyTypeClass.getDerSchemas().stream().
+                    map(Entity::getKey).collect(Collectors.toList()));
+            allowedSchemas.getVirSchemas().addAll(anyTypeClass.getVirSchemas().stream().
+                    map(Entity::getKey).collect(Collectors.toList()));
+        });
+        populateItems(opTO, op, allowedSchemas);
+
+        op.getActionsClassNames().clear();
+        op.getActionsClassNames().addAll(opTO.getActionsClassNames());
+
+        return oidcOPDAO.save(op);
+    }
+
+    private void populateItems(final OIDCProvider op, final OIDCProviderTO opTO) {
+        op.getItems().forEach(item -> {
+            ItemTO itemTO = new ItemTO();
+            itemTO.setKey(item.getKey());
+            BeanUtils.copyProperties(item, itemTO, ITEM_IGNORE_PROPERTIES);
+            itemTO.setPurpose(MappingPurpose.NONE);
+
+            if (itemTO.isConnObjectKey()) {
+                opTO.setConnObjectKeyItem(itemTO);
+            } else {
+                opTO.add(itemTO);
+            }
+        });
+    }
+
+    @Override
+    public OIDCProviderTO getOIDCProviderTO(final OIDCProvider op) {
+        OIDCProviderTO opTO = new OIDCProviderTO();
+
+        opTO.setKey(op.getKey());
+        opTO.setAuthorizationEndpoint(op.getAuthorizationEndpoint());
+        opTO.setClientID(op.getClientID());
+        opTO.setClientSecret(op.getClientSecret());
+        opTO.setName(op.getName());
+        opTO.setIssuer(op.getIssuer());
+        opTO.setJwksUri(op.getJwksUri());
+        opTO.setTokenEndpoint(op.getTokenEndpoint());
+        opTO.setUserinfoEndpoint(op.getUserinfoEndpoint());
+        opTO.setHasDiscovery(op.getHasDiscovery());
+        opTO.setCreateUnmatching(op.isCreateUnmatching());
+        opTO.setUpdateMatching(op.isUpdateMatching());
+
+        if (op.getUserTemplate() != null) {
+            opTO.setUserTemplate((UserTO) op.getUserTemplate().get());
+        }
+
+        populateItems(op, opTO);
+
+        opTO.getActionsClassNames().addAll(op.getActionsClassNames());
+
+        return opTO;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/rest-api/pom.xml
----------------------------------------------------------------------
diff --git a/ext/oidcclient/rest-api/pom.xml b/ext/oidcclient/rest-api/pom.xml
new file mode 100644
index 0000000..60c469f
--- /dev/null
+++ b/ext/oidcclient/rest-api/pom.xml
@@ -0,0 +1,77 @@
+<?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-oidcclient</artifactId>
+    <version>2.1.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Ext: OIDC Client REST API</name>
+  <description>Apache Syncope Ext: OIDC Client REST API</description>
+  <groupId>org.apache.syncope.ext.oidcclient</groupId>
+  <artifactId>syncope-ext-oidcclient-rest-api</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.common</groupId>
+      <artifactId>syncope-common-rest-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-common-lib</artifactId>      
+      <version>${project.version}</version>
+    </dependency>    
+  </dependencies>
+
+  <build>
+    <plugins>
+      <!-- Generating javadoc JAR artifact for usage with CXF's WADL generator (for core) -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <inherited>true</inherited>
+        <executions>
+          <execution>
+            <id>attach-javadocs</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCClientService.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCClientService.java b/ext/oidcclient/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCClientService.java
new file mode 100644
index 0000000..d599e75
--- /dev/null
+++ b/ext/oidcclient/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCClientService.java
@@ -0,0 +1,75 @@
+/*
+ * 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.common.rest.api.service;
+
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.security.SecurityRequirements;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import org.apache.syncope.common.lib.OIDCConstants;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.OIDCLoginRequestTO;
+import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
+
+/**
+ * REST operations for OpenID Connect Clients.
+ */
+@Tag(name = "OIDCClients")
+@SecurityRequirements({
+    @SecurityRequirement(name = "BasicAuthentication"),
+    @SecurityRequirement(name = "Bearer") })
+@Path("oidcclient/clients")
+public interface OIDCClientService extends JAXRSService {
+
+    /**
+     * Generates OpenID Connect authentication request for the Provider matching the provided op.
+     *
+     * @param redirectURI redirect URI
+     * @param op OpenID Connect Provider
+     * @return OpenID Connect authentication request
+     */
+    @POST
+    @Path("loginRequest")
+    @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    OIDCLoginRequestTO createLoginRequest(
+            @QueryParam(OIDCConstants.REDIRECT_URI) String redirectURI,
+            @QueryParam(OIDCConstants.OP) String op);
+
+    /**
+     * Uses the provided authorization code to go through the OpenID Connect tokens process and finally creates JWT for
+     * the matching user, if found.
+     *
+     * @param redirectURI redirect URI
+     * @param authorizationCode authorization code generated by the remote OpenID Connect Provider
+     * @param op OpenID Connect Provider
+     * @return JWT for the matching user plus attributes returned in the response
+     */
+    @POST
+    @Path("login")
+    @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    OIDCLoginResponseTO login(
+            @QueryParam(OIDCConstants.REDIRECT_URI) String redirectURI,
+            @QueryParam("authorizationCode") String authorizationCode,
+            @QueryParam(OIDCConstants.OP) String op);
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCProviderService.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCProviderService.java b/ext/oidcclient/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCProviderService.java
new file mode 100644
index 0000000..9705b31
--- /dev/null
+++ b/ext/oidcclient/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCProviderService.java
@@ -0,0 +1,156 @@
+/*
+ * 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.common.rest.api.service;
+
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.security.SecurityRequirements;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.OIDCProviderTO;
+import java.util.List;
+import java.util.Set;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.HttpHeaders;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+
+/**
+ * REST operations for OpenID Connect Providers.
+ */
+@Tag(name = "OIDCProviders")
+@SecurityRequirements({
+    @SecurityRequirement(name = "BasicAuthentication"),
+    @SecurityRequirement(name = "Bearer") })
+@Path("oidcclient/providers")
+public interface OIDCProviderService extends JAXRSService {
+
+    /**
+     * Returns the list of available OIDCProviderActions implementations.
+     *
+     * @return the list of available OIDCProviderActions implementations
+     */
+    @GET
+    @Path("actionsClasses")
+    @Produces({ MediaType.APPLICATION_JSON })
+    Set<String> getActionsClasses();
+
+    /**
+     * Returns a list of all defined OIDC Providers.
+     *
+     * @return list of all defined OIDC Providers
+     */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    List<OIDCProviderTO> list();
+
+    /**
+     * Returns the OIDC Provider with matching key, if available.
+     *
+     * @param key OIDC Provider's key
+     * @return OIDC Providers with matching key, if available
+     */
+    @GET
+    @Path("{key}")
+    @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    OIDCProviderTO read(@PathParam("key") String key);
+
+    /**
+     * Creates a new OIDC Provider.
+     *
+     * @param oidcProviderTO OpenID Connect Provider configuration to be stored
+     * @return Response object featuring Location header of created OIDC Provider
+     */
+    @ApiResponses(
+            @ApiResponse(responseCode = "201",
+                    description = "OIDC Provider successfully created", headers = {
+                @Header(name = RESTHeaders.RESOURCE_KEY, schema =
+                        @Schema(type = "string"),
+                        description = "Key value for the entity created"),
+                @Header(name = HttpHeaders.LOCATION, schema =
+                        @Schema(type = "string"),
+                        description = "URL of the entity created") }))
+    @POST
+    @Consumes({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    Response create(OIDCProviderTO oidcProviderTO);
+
+    /**
+     * Creates a new OIDC Provider by using its Discovery Document.
+     *
+     * @param oidcProviderTO OpenID Connect Provider configuration to be stored  
+     * @return Response object featuring Location header of created OIDC Provider
+     */
+    @ApiResponses(
+            @ApiResponse(responseCode = "201",
+                    description = "OIDC Provider successfully created", headers = {
+                @Header(name = RESTHeaders.RESOURCE_KEY, schema =
+                        @Schema(type = "string"),
+                        description = "Key value for the entity created"),
+                @Header(name = HttpHeaders.LOCATION, schema =
+                        @Schema(type = "string"),
+                        description = "URL of the entity created") }))
+    @POST
+    @Path("fromDiscovery")
+    @Consumes({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    Response createFromDiscovery(OIDCProviderTO oidcProviderTO);
+
+    /**
+     * Updates the OIDC Provider with matching key.
+     *
+     * @param oidcProviderTO OpenID Connect Provider configuration to be stored
+     */
+    @Parameter(name = "key", description = "OIDC Provider's key", in = ParameterIn.PATH, schema =
+            @Schema(type = "string"))
+    @ApiResponses(
+            @ApiResponse(responseCode = "204", description = "Operation was successful"))
+    @PUT
+    @Path("{key}")
+    @Consumes({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    void update(@NotNull OIDCProviderTO oidcProviderTO);
+
+    /**
+     * Deletes the OIDC Provider with matching key.
+     *
+     * @param key OIDC Provider key
+     */
+    @ApiResponses(
+            @ApiResponse(responseCode = "204", description = "Operation was successful"))
+    @DELETE
+    @Path("{key}")
+    @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    void delete(@PathParam("key") String key);
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/rest-cxf/pom.xml
----------------------------------------------------------------------
diff --git a/ext/oidcclient/rest-cxf/pom.xml b/ext/oidcclient/rest-cxf/pom.xml
new file mode 100644
index 0000000..38798be
--- /dev/null
+++ b/ext/oidcclient/rest-cxf/pom.xml
@@ -0,0 +1,72 @@
+<?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-oidcclient</artifactId>
+    <version>2.1.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Ext: OIDC Client REST CXF</name>
+  <description>Apache Syncope Ext: OIDC Client REST CXF</description>
+  <groupId>org.apache.syncope.ext.oidcclient</groupId>
+  <artifactId>syncope-ext-oidcclient-rest-cxf</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.core</groupId>
+      <artifactId>syncope-core-rest-cxf</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-rest-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-rest-api</artifactId>
+      <version>${project.version}</version>
+      <classifier>javadoc</classifier>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-logic</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCClientServiceImpl.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCClientServiceImpl.java b/ext/oidcclient/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCClientServiceImpl.java
new file mode 100644
index 0000000..74c14b9
--- /dev/null
+++ b/ext/oidcclient/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCClientServiceImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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.rest.cxf.service;
+
+import org.apache.syncope.common.lib.to.OIDCLoginRequestTO;
+import org.apache.syncope.common.rest.api.service.OIDCClientService;
+import org.apache.syncope.core.logic.OIDCClientLogic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
+
+@Service
+public class OIDCClientServiceImpl extends AbstractServiceImpl implements OIDCClientService {
+
+    @Autowired
+    private OIDCClientLogic logic;
+
+    @Override
+    public OIDCLoginRequestTO createLoginRequest(final String redirectURI, final String op) {
+        return logic.createLoginRequest(redirectURI, op);
+    }
+
+    @Override
+    public OIDCLoginResponseTO login(final String redirectURI, final String authorizationCode, final String op) {
+        return logic.login(redirectURI, authorizationCode, op);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/oidcclient/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCProviderServiceImpl.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCProviderServiceImpl.java b/ext/oidcclient/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCProviderServiceImpl.java
new file mode 100644
index 0000000..7af4366
--- /dev/null
+++ b/ext/oidcclient/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCProviderServiceImpl.java
@@ -0,0 +1,83 @@
+/*
+ * 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.rest.cxf.service;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.OIDCProviderTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.OIDCProviderService;
+import org.apache.syncope.core.logic.OIDCProviderLogic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class OIDCProviderServiceImpl extends AbstractServiceImpl implements OIDCProviderService {
+
+    @Autowired
+    private OIDCProviderLogic logic;
+
+    @Override
+    public Set<String> getActionsClasses() {
+        return logic.getActionsClasses();
+    }
+
+    @Override
+    public Response create(final OIDCProviderTO oidcProviderTO) {
+        String created = logic.create(oidcProviderTO);
+
+        URI location = uriInfo.getAbsolutePathBuilder().path(created).build();
+        return Response.created(location).
+                header(RESTHeaders.RESOURCE_KEY, created).
+                build();
+    }
+
+    @Override
+    public Response createFromDiscovery(final OIDCProviderTO oidcProviderTO) {
+        String created = logic.createFromDiscovery(oidcProviderTO);
+
+        URI location = uriInfo.getAbsolutePathBuilder().path(created).build();
+        return Response.created(location).
+                header(RESTHeaders.RESOURCE_KEY, created).
+                build();
+    }
+
+    @Override
+    public List<OIDCProviderTO> list() {
+        return logic.list();
+
+    }
+
+    @Override
+    public OIDCProviderTO read(final String key) {
+        return logic.read(key);
+    }
+
+    @Override
+    public void update(final OIDCProviderTO oidcProviderTO) {
+        logic.update(oidcProviderTO);
+    }
+
+    @Override
+    public void delete(final String key) {
+        logic.delete(key);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/ext/pom.xml
----------------------------------------------------------------------
diff --git a/ext/pom.xml b/ext/pom.xml
index a2aa130..d1e5b1b 100644
--- a/ext/pom.xml
+++ b/ext/pom.xml
@@ -82,6 +82,7 @@ under the License.
     <module>saml2sp</module>
     <module>elasticsearch</module>
     <module>scimv2</module>
+    <module>oidcclient</module>
   </modules>
 
 </project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/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 e206ff7..98d4504 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
@@ -30,7 +30,7 @@ import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.to.SAML2RequestTO;
 import org.apache.syncope.common.rest.api.service.SAML2SPService;
 
-@WebServlet(name = "login", urlPatterns = { "/saml2sp/login" })
+@WebServlet(name = "saml2spLogin", urlPatterns = { "/saml2sp/login" })
 public class Login extends AbstractSAML2SPServlet {
 
     private static final long serialVersionUID = 968480296813639041L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/console-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/console-reference/pom.xml b/fit/console-reference/pom.xml
index c13b264..698bc94 100644
--- a/fit/console-reference/pom.xml
+++ b/fit/console-reference/pom.xml
@@ -75,6 +75,12 @@ under the License.
     </dependency>
 
     <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-client-console</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/console-reference/src/main/resources/oidcclient-agent.properties
----------------------------------------------------------------------
diff --git a/fit/console-reference/src/main/resources/oidcclient-agent.properties b/fit/console-reference/src/main/resources/oidcclient-agent.properties
new file mode 100644
index 0000000..1d53d49
--- /dev/null
+++ b/fit/console-reference/src/main/resources/oidcclient-agent.properties
@@ -0,0 +1,26 @@
+# 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.
+conf.directory=${conf.directory}
+
+anonymousUser=${anonymousUser}
+anonymousKey=${anonymousKey}
+
+scheme=http
+host=localhost
+port=9080
+rootPath=/syncope/rest/
+useGZIPCompression=true

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/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 890e5b0..1dc41d1 100644
--- a/fit/console-reference/src/main/webapp/WEB-INF/web.xml
+++ b/fit/console-reference/src/main/webapp/WEB-INF/web.xml
@@ -53,6 +53,16 @@ under the License.
     <param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.SAML2SPSelfReg</param-value>
   </context-param>
   
+  <!-- OIDC Client Parameters -->
+  <context-param>
+    <param-name>oidcclient.login.success.url</param-name>
+    <param-value>../wicket/bookmarkable/org.apache.syncope.client.console.pages.OIDCClientLogin</param-value>
+  </context-param>
+  <context-param>
+    <param-name>oidcclient.login.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>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/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 cfd69c9..876c58f 100644
--- a/fit/console-reference/src/test/resources/rebel.xml
+++ b/fit/console-reference/src/test/resources/rebel.xml
@@ -34,6 +34,10 @@ under the License.
     </dir>
     <dir name="${basedir}/../../ext/scimv2/client-console/target/classes">
     </dir>
+    <dir name="${basedir}/../../ext/oidcclient/agent/target/classes">
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/client-console/target/classes">
+    </dir>
   </classpath>
 
   <web>
@@ -57,6 +61,10 @@ under the License.
       <dir name="${basedir}/../../ext/scimv2/client-console/target/classes">
       </dir>
     </link>
+    <link target="/">
+      <dir name="${basedir}/../../ext/oidcclient/client-console/target/classes">
+      </dir>
+    </link>
   </web>
 
 </application>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/core-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 4e5e4a1..9b5d717 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -185,6 +185,18 @@ under the License.
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-rest-cxf</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>          
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-client-console</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-test</artifactId>
       <scope>test</scope>
@@ -1099,6 +1111,17 @@ under the License.
         </dependency>
         
         <dependency>
+          <groupId>org.apache.syncope.ext.oidcclient</groupId>
+          <artifactId>syncope-ext-oidcclient-rest-cxf</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.syncope.ext.oidcclient</groupId>
+          <artifactId>syncope-ext-oidcclient-persistence-jpa</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+        
+        <dependency>
           <groupId>org.apache.syncope.ext.scimv2</groupId>
           <artifactId>syncope-ext-scimv2-rest-cxf</artifactId>
           <version>${project.version}</version>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index 759f5e4..9e7d541 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -84,6 +84,8 @@ import org.apache.syncope.common.rest.api.service.ResourceService;
 import org.apache.syncope.common.rest.api.service.GroupService;
 import org.apache.syncope.common.rest.api.service.ImplementationService;
 import org.apache.syncope.common.rest.api.service.MailTemplateService;
+import org.apache.syncope.common.rest.api.service.OIDCClientService;
+import org.apache.syncope.common.rest.api.service.OIDCProviderService;
 import org.apache.syncope.common.rest.api.service.RealmService;
 import org.apache.syncope.common.rest.api.service.ReconciliationService;
 import org.apache.syncope.common.rest.api.service.RelationshipTypeService;
@@ -252,6 +254,10 @@ public abstract class AbstractITCase {
     protected static SAML2SPService saml2SpService;
 
     protected static SAML2IdPService saml2IdPService;
+    
+    protected static OIDCClientService oidcClientService;
+
+    protected static OIDCProviderService oidcProviderService;
 
     protected static SCIMConfService scimConfService;
 
@@ -322,6 +328,8 @@ public abstract class AbstractITCase {
         camelRouteService = adminClient.getService(CamelRouteService.class);
         saml2SpService = adminClient.getService(SAML2SPService.class);
         saml2IdPService = adminClient.getService(SAML2IdPService.class);
+        oidcClientService = adminClient.getService(OIDCClientService.class);
+        oidcProviderService = adminClient.getService(OIDCProviderService.class);
         scimConfService = adminClient.getService(SCIMConfService.class);
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/core-reference/src/test/java/org/apache/syncope/fit/OIDCClientDetector.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/OIDCClientDetector.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/OIDCClientDetector.java
new file mode 100644
index 0000000..b08342e
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/OIDCClientDetector.java
@@ -0,0 +1,52 @@
+/*
+ * 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.fit;
+
+import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
+import org.apache.syncope.common.rest.api.service.OIDCProviderService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OIDCClientDetector {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OIDCClientDetector.class);
+
+    private static Boolean ENABLED;
+
+    public static boolean isOIDCClientAvailable() {
+        synchronized (LOG) {
+            if (ENABLED == null) {
+                try {
+                    new SyncopeClientFactoryBean().
+                            setAddress(AbstractITCase.ADDRESS).
+                            setContentType(SyncopeClientFactoryBean.ContentType.XML).
+                            create(new AnonymousAuthenticationHandler(
+                                    AbstractITCase.ANONYMOUS_UNAME, AbstractITCase.ANONYMOUS_KEY)).
+                            getService(OIDCProviderService.class).list();
+                    ENABLED = true;
+                } catch (Exception e) {
+                    // ignore
+                    ENABLED = false;
+                }
+            }
+        }
+        return ENABLED;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCClientITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCClientITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCClientITCase.java
new file mode 100644
index 0000000..33a9d44
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCClientITCase.java
@@ -0,0 +1,152 @@
+/*
+ * 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.fit.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.BasicAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
+import org.apache.syncope.common.lib.to.ItemTO;
+import org.apache.syncope.common.lib.to.OIDCLoginRequestTO;
+import org.apache.syncope.common.lib.to.OIDCProviderTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.rest.api.service.OIDCClientService;
+import org.apache.syncope.common.rest.api.service.OIDCProviderService;
+import org.apache.syncope.fit.AbstractITCase;
+import org.apache.syncope.fit.OIDCClientDetector;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class OIDCClientITCase extends AbstractITCase {
+
+    private static SyncopeClient anonymous;
+
+    private static SyncopeClient admin;
+
+    @BeforeClass
+    public static void setup() {
+        anonymous = new SyncopeClientFactoryBean().
+                setAddress(ADDRESS).
+                create(new AnonymousAuthenticationHandler(ANONYMOUS_UNAME, ANONYMOUS_KEY));
+
+        admin = new SyncopeClientFactoryBean().
+                setAddress(ADDRESS).
+                create(new BasicAuthenticationHandler(ADMIN_UNAME, ADMIN_PWD));
+    }
+
+    @BeforeClass
+    public static void createOIDCProviderWithoutDiscovery() throws Exception {
+        if (!OIDCClientDetector.isOIDCClientAvailable()) {
+            return;
+        }
+
+        assertTrue(oidcProviderService.list().isEmpty());
+
+        OIDCProviderTO oidcProviderTO = new OIDCProviderTO();
+        oidcProviderTO.setAuthorizationEndpoint("AuthorizationEndpoint");
+        oidcProviderTO.setClientID("ClientID");
+        oidcProviderTO.setClientSecret("ClientSecret");
+        oidcProviderTO.setIssuer("https://accounts.google.com");
+        oidcProviderTO.setJwksUri("JwksUri");
+        oidcProviderTO.setName("Google");
+        oidcProviderTO.setTokenEndpoint("TokenEndpoint");
+        oidcProviderTO.setUserinfoEndpoint("UserinfoEndpoint");
+
+        admin.getService(OIDCProviderService.class).create(oidcProviderTO);
+    }
+
+    @AfterClass
+    public static void clearProviders() throws Exception {
+        if (!OIDCClientDetector.isOIDCClientAvailable()) {
+            return;
+        }
+
+        for (OIDCProviderTO op : oidcProviderService.list()) {
+            oidcProviderService.delete(op.getKey());
+        }
+    }
+
+    @Test
+    public void createLoginRequest() {
+        Assume.assumeTrue(OIDCClientDetector.isOIDCClientAvailable());
+
+        OIDCLoginRequestTO loginRequest = anonymous.getService(OIDCClientService.class).
+                createLoginRequest("http://localhost:9080/syncope-console/oidcclient/code-consumer", "Google");
+
+        assertNotNull(loginRequest);
+        assertEquals("http://localhost:9080/syncope-console/oidcclient/code-consumer", loginRequest.getRedirectURI());
+        assertNotNull(loginRequest.getProviderAddress());
+        assertNotNull(loginRequest.getClientId());
+        assertNotNull(loginRequest.getResponseType());
+        assertNotNull(loginRequest.getScope());
+        assertNotNull(loginRequest.getState());
+    }
+
+    @Test
+    public void setProviderMapping() {
+        Assume.assumeTrue(OIDCClientDetector.isOIDCClientAvailable());
+
+        OIDCProviderTO ssoCircle = IterableUtils.find(oidcProviderService.list(), new Predicate<OIDCProviderTO>() {
+
+            @Override
+            public boolean evaluate(final OIDCProviderTO object) {
+                return "Google".equals(object.getName());
+            }
+        });
+        assertNotNull(ssoCircle);
+        assertFalse(ssoCircle.isCreateUnmatching());
+        assertNull(ssoCircle.getUserTemplate());
+        assertFalse(ssoCircle.getItems().isEmpty());
+        assertNotNull(ssoCircle.getConnObjectKeyItem());
+        assertNotEquals("fullname", ssoCircle.getConnObjectKeyItem().getIntAttrName());
+        assertNotEquals("given_name", ssoCircle.getConnObjectKeyItem().getExtAttrName());
+
+        ssoCircle.setCreateUnmatching(true);
+
+        UserTO userTemplate = new UserTO();
+        userTemplate.setRealm("'/'");
+        ssoCircle.setUserTemplate(userTemplate);
+
+        ssoCircle.getItems().clear();
+        ItemTO keyMapping = new ItemTO();
+        keyMapping.setIntAttrName("fullname");
+        keyMapping.setExtAttrName("given_name");
+        ssoCircle.setConnObjectKeyItem(keyMapping);
+
+        oidcProviderService.update(ssoCircle);
+
+        ssoCircle = oidcProviderService.read(ssoCircle.getKey());
+        assertTrue(ssoCircle.isCreateUnmatching());
+        assertEquals(userTemplate, ssoCircle.getUserTemplate());
+        assertEquals("fullname", ssoCircle.getConnObjectKeyItem().getIntAttrName());
+        assertEquals("given_name", ssoCircle.getConnObjectKeyItem().getExtAttrName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/core-reference/src/test/resources/rebel.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/rebel.xml b/fit/core-reference/src/test/resources/rebel.xml
index da4b4b1..0a3965b 100644
--- a/fit/core-reference/src/test/resources/rebel.xml
+++ b/fit/core-reference/src/test/resources/rebel.xml
@@ -103,6 +103,23 @@ under the License.
     </dir>
     <dir name="${basedir}/../../ext/scimv2/logic/target/classes">
     </dir>
+    <dir name="${basedir}/../../ext/oidcclient/common-lib/target/classes">
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/logic/target/classes">
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/persistence-api/target/classes">
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/persistence-jpa/target/classes">
+      <exclude name="org/apache/syncope/core/persistence/jpa/entity/**"/>
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/provisioning-api/target/classes">
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/provisioning-java/target/classes">
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/rest-api/target/classes">
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/rest-cxf/target/classes">
+    </dir>
   </classpath>
 
   <web>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/enduser-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/pom.xml b/fit/enduser-reference/pom.xml
index c2fe31a..127d62d 100644
--- a/fit/enduser-reference/pom.xml
+++ b/fit/enduser-reference/pom.xml
@@ -68,6 +68,12 @@ under the License.
     </dependency>
 
     <dependency>
+      <groupId>org.apache.syncope.ext.oidcclient</groupId>
+      <artifactId>syncope-ext-oidcclient-client-enduser</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/enduser-reference/src/main/resources/oidcclient-agent.properties
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/resources/oidcclient-agent.properties b/fit/enduser-reference/src/main/resources/oidcclient-agent.properties
new file mode 100644
index 0000000..1d53d49
--- /dev/null
+++ b/fit/enduser-reference/src/main/resources/oidcclient-agent.properties
@@ -0,0 +1,26 @@
+# 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.
+conf.directory=${conf.directory}
+
+anonymousUser=${anonymousUser}
+anonymousKey=${anonymousKey}
+
+scheme=http
+host=localhost
+port=9080
+rootPath=/syncope/rest/
+useGZIPCompression=true

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml b/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
index 7f61a36..81a7651 100644
--- a/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
+++ b/fit/enduser-reference/src/main/webapp/WEB-INF/web.xml
@@ -53,6 +53,16 @@ under the License.
     <param-value>../wicket/bookmarkable/org.apache.syncope.client.enduser.pages.SAML2SPSelfReg</param-value>
   </context-param>
 
+  <context-param>
+    <param-name>oidcclient.login.success.url</param-name>
+    <param-value>../wicket/bookmarkable/org.apache.syncope.client.enduser.pages.OIDCClientLogin</param-value>
+  </context-param>
+  <context-param>
+    <param-name>oidcclient.login.error.url</param-name>
+    <param-value>../wicket/bookmarkable/org.apache.syncope.client.enduser.pages.HomePage</param-value>
+  </context-param>
+
+
   <!-- SESSION TIMEOUT (MINUTES)-->
   <session-config>
     <session-timeout>30</session-timeout>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/fit/enduser-reference/src/test/resources/rebel.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/test/resources/rebel.xml b/fit/enduser-reference/src/test/resources/rebel.xml
index da15397..d544b8d 100644
--- a/fit/enduser-reference/src/test/resources/rebel.xml
+++ b/fit/enduser-reference/src/test/resources/rebel.xml
@@ -30,6 +30,10 @@ under the License.
     </dir>
     <dir name="${basedir}/../../ext/saml2sp/client-enduser/target/classes">
     </dir>
+    <dir name="${basedir}/../../ext/oidcclient/agent/target/classes">
+    </dir>
+    <dir name="${basedir}/../../ext/oidcclient/client-enduser/target/classes">
+    </dir>
   </classpath>
 
   <web>
@@ -45,6 +49,10 @@ under the License.
       <dir name="${basedir}/../../ext/saml2sp/client-enduser/target/classes">
       </dir>
     </link>
+    <link target="/">
+      <dir name="${basedir}/../../ext/oidcclient/client-enduser/target/classes">
+      </dir>
+    </link>
   </web>
 
 </application>

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 49ef0d7..e20e477 100644
--- a/pom.xml
+++ b/pom.xml
@@ -604,6 +604,16 @@ under the License.
           </exclusion>
         </exclusions>
       </dependency>
+      <dependency>
+        <groupId>org.apache.cxf</groupId>
+        <artifactId>cxf-rt-rs-security-sso-oidc</artifactId>
+        <version>${cxf.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.cxf</groupId>
+        <artifactId>cxf-rt-rs-extension-providers</artifactId>
+        <version>${cxf.version}</version>
+      </dependency>
       <!-- /CXF -->
 
       <!-- Swagger -->      

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/src/main/asciidoc/reference-guide/concepts/extensions.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/reference-guide/concepts/extensions.adoc b/src/main/asciidoc/reference-guide/concepts/extensions.adoc
index d6493b6..52d245e 100644
--- a/src/main/asciidoc/reference-guide/concepts/extensions.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/extensions.adoc
@@ -116,6 +116,39 @@ This extension adds features to all components and layers that are available, an
 <<customization-extensions,new extensions>>.
 ====
 
+==== OpenID Connect Client 
+
+This extension can be leveraged to provide http://openid.net/connect/[OpenID Connect^]-based
+https://en.wikipedia.org/wiki/Single_sign-on[Single Sign-On^] access to the <<admin-console-component>>,
+the <<enduser-component>> or any other Java EE application dealing with the <<core>>.
+
+Once installed, one or more OpenID Providers can be created either from 
+the http://openid.net/specs/openid-connect-discovery-1_0.html[discovery document^] if it is supported or from inserting 
+manually the required attributes, in any case the client_id and the secret_id from the OAuth 2.0 credential and the issuer 
+are required.
+After configuration the OpenID provider, the http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[Authorization Code Flow^]
+is going to be implemented in order to reach the user information to be used by Syncope to match the internal users.
+
+
+[NOTE]
+.Extension Sources
+====
+The source code of this extension is available from the Apache Syncope
+ifeval::["{snapshotOrRelease}" == "release"]
+https://github.com/apache/syncope/tree/syncope-{docVersion}/ext/oidcclient[source tree^]
+endif::[]
+ifeval::["{snapshotOrRelease}" == "snapshot"]
+https://github.com/apache/syncope/tree/2_0_X/ext/oidcclient[source tree^]
+endif::[]
+.
+====
+
+[TIP]
+====
+This extension adds features to all components and layers that are available, and can be taken as reference when creating
+<<customization-extensions,new extensions>>.
+====
+
 ==== Elasticsearch
 
 This extension provides an alternate internal search engine for <<users-groups-and-any-objects>>, requiring an external 

http://git-wip-us.apache.org/repos/asf/syncope/blob/797fd1cb/src/main/asciidoc/reference-guide/workingwithapachesyncope/customization.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/reference-guide/workingwithapachesyncope/customization.adoc b/src/main/asciidoc/reference-guide/workingwithapachesyncope/customization.adoc
index 80a3870..622f51f 100644
--- a/src/main/asciidoc/reference-guide/workingwithapachesyncope/customization.adoc
+++ b/src/main/asciidoc/reference-guide/workingwithapachesyncope/customization.adoc
@@ -350,6 +350,25 @@ Setup a <<keystore,keystore>> and place it under the <<properties-files-location
 the content of `core/src/main/resources/saml2sp-logic.properties` accordingly.
 
 [discrete]
+===== Enable the <<openid-connect-client>> extension
+
+Add the following dependencies to `core/pom.xml`:
+
+[source,xml,subs="verbatim,attributes"]
+----
+<dependency>
+  <groupId>org.apache.syncope.ext.oidcclient</groupId>
+  <artifactId>syncope-ext-oidcclient-rest-cxf</artifactId>
+  <version>${syncope.version}</version>
+</dependency>
+<dependency>
+  <groupId>org.apache.syncope.ext.oidcclient</groupId>
+  <artifactId>syncope-ext-oidcclient-persistence-jpa</artifactId>
+  <version>${syncope.version}</version>
+</dependency>
+----
+
+[discrete]
 ===== Enable the <<elasticsearch>> extension
 
 Add the following dependencies to `core/pom.xml`:
@@ -474,6 +493,23 @@ Add the following dependencies to `console/pom.xml`:
 Copy `console/src/main/resources/all/saml2sp-agent.properties` to `console/src/main/resources/saml2sp-agent.properties`.
 
 [discrete]
+===== Enable the <<openid-connect-client>> extension
+
+Add the following dependencies to `console/pom.xml`:
+
+[source,xml,subs="verbatim,attributes"]
+----
+<dependency>
+  <groupId>org.apache.syncope.ext.oidcclient</groupId>
+  <artifactId>syncope-ext-oidcclient-client-console</artifactId>
+  <version>${syncope.version}</version>
+</dependency>
+----
+
+Copy `console/src/main/resources/all/oidcclient-agent.properties` to `console/src/main/resources/oidcclient-agent.properties`.
+
+
+[discrete]
 ===== Enable the <<SCIM>> extension
 
 Add the following dependencies to `console/pom.xml`:
@@ -512,6 +548,22 @@ Add the following dependencies to `enduser/pom.xml`:
 
 Copy `enduser/src/main/resources/all/saml2sp-agent.properties` to `enduser/src/main/resources/saml2sp-agent.properties`.
 
+[discrete]
+===== Enable the <<openid-connect-client>> extension
+
+Add the following dependencies to `enduser/pom.xml`:
+
+[source,xml,subs="verbatim,attributes"]
+----
+<dependency>
+  <groupId>org.apache.syncope.ext.oidcclient</groupId>
+  <artifactId>syncope-ext-oidcclient-client-enduser</artifactId>
+  <version>${syncope.version}</version>
+</dependency>
+----
+
+Copy `enduser/src/main/resources/all/oidcclient-agent.properties` to `enduser/src/main/resources/oidcclient-agent.properties`.
+
 [[customization-enduser-i18n]]
 ===== i18n