You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by mm...@apache.org on 2020/07/14 09:05:45 UTC
[syncope] branch master updated: SYNCOPE-1577: Support CAS protocol
for client applications (#203)
This is an automated email from the ASF dual-hosted git repository.
mmoayyed pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 4774ee8 SYNCOPE-1577: Support CAS protocol for client applications (#203)
4774ee8 is described below
commit 4774ee8c4b9ec876d802b4481fb294d60dd23b48
Author: Misagh Moayyed <mm...@gmail.com>
AuthorDate: Tue Jul 14 13:35:37 2020 +0430
SYNCOPE-1577: Support CAS protocol for client applications (#203)
---
.../syncope/common/lib/to/client/CASSPTO.java | 75 +++++++++++++++++
.../syncope/common/lib/types/ClientAppType.java | 1 +
.../apache/syncope/core/logic/ClientAppLogic.java | 45 ++++++++--
.../core/persistence/api/dao/auth/CASSPDAO.java | 24 +++++-
.../core/persistence/api/entity/auth/CASSP.java | 9 +-
.../core/persistence/jpa/dao/auth/JPACASSPDAO.java | 95 ++++++++++++++++++++++
.../persistence/jpa/entity/JPAEntityFactory.java | 4 +
.../core/persistence/jpa/entity/auth/JPACASSP.java | 28 ++++++-
.../jpa/entity/auth/JPAClientAppUtils.java | 4 +-
.../jpa/entity/auth/JPAClientAppUtilsFactory.java | 6 ++
.../core/persistence/jpa/inner/CASSPTest.java | 75 +++++++++++++++++
.../java/data/ClientAppDataBinderImpl.java | 88 +++++++++++++++++++-
.../apache/syncope/fit/core/ClientAppITCase.java | 61 ++++++++++++++
.../syncope/wa/starter/mapping/CASSPTOMapper.java | 57 +++++++++++++
14 files changed, 548 insertions(+), 24 deletions(-)
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/client/CASSPTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/client/CASSPTO.java
new file mode 100644
index 0000000..67c0ec4
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/client/CASSPTO.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.lib.to.client;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Schema(allOf = {ClientAppTO.class})
+public class CASSPTO extends ClientAppTO {
+
+ private static final long serialVersionUID = -5370888503924521351L;
+
+ private String serviceId;
+
+ public String getServiceId() {
+ return serviceId;
+ }
+
+ public void setServiceId(final String serviceId) {
+ this.serviceId = serviceId;
+ }
+
+ @JacksonXmlProperty(localName = "_class", isAttribute = true)
+ @JsonProperty("_class")
+ @Schema(name = "_class", required = true, example = "org.apache.syncope.common.lib.to.client.CASSPTO")
+ @Override
+ public String getDiscriminator() {
+ return getClass().getName();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+ CASSPTO rhs = (CASSPTO) obj;
+ return new EqualsBuilder()
+ .appendSuper(super.equals(obj))
+ .append(this.serviceId, rhs.serviceId)
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder()
+ .appendSuper(super.hashCode())
+ .append(this.serviceId)
+ .toHashCode();
+ }
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
index 3bf730e..b8cd021 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
@@ -20,6 +20,7 @@ package org.apache.syncope.common.lib.types;
public enum ClientAppType {
SAML2SP,
+ CASSP,
OIDCRP;
}
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/ClientAppLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/ClientAppLogic.java
index 0c9b0cb..ec2261b 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/ClientAppLogic.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/ClientAppLogic.java
@@ -39,8 +39,10 @@ import org.apache.syncope.common.lib.types.AMEntitlement;
import org.apache.syncope.common.lib.types.ClientAppType;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.auth.CASSPDAO;
import org.apache.syncope.core.persistence.api.dao.auth.OIDCRPDAO;
import org.apache.syncope.core.persistence.api.dao.auth.SAML2SPDAO;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
import org.apache.syncope.core.persistence.api.entity.auth.ClientApp;
import org.apache.syncope.core.persistence.api.entity.auth.ClientAppUtils;
import org.apache.syncope.core.persistence.api.entity.auth.ClientAppUtilsFactory;
@@ -74,6 +76,9 @@ public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
@Autowired
private OIDCRPDAO oidcrpDAO;
+ @Autowired
+ private CASSPDAO casspDAO;
+
@Resource(name = "anonymousUser")
private String anonymousUser;
@@ -88,7 +93,9 @@ public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
case OIDCRP:
stream = oidcrpDAO.findAll().stream().map(binder::getClientAppTO);
break;
-
+ case CASSP:
+ stream = casspDAO.findAll().stream().map(binder::getClientAppTO);
+ break;
case SAML2SP:
default:
stream = saml2spDAO.findAll().stream().map(binder::getClientAppTO);
@@ -97,7 +104,7 @@ public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
return stream.collect(Collectors.toList());
}
- private void checkType(final ClientAppType type, final ClientAppUtils clientAppUtils) {
+ private static void checkType(final ClientAppType type, final ClientAppUtils clientAppUtils) {
if (clientAppUtils.getType() != type) {
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRequest);
sce.getElements().add("Found " + type + ", expected " + clientAppUtils.getType());
@@ -118,7 +125,15 @@ public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
checkType(type, clientAppUtilsFactory.getInstance(oidcrp));
return binder.getClientAppTO(oidcrp);
+ case CASSP:
+ CASSP cassp = casspDAO.find(key);
+ if (cassp == null) {
+ throw new NotFoundException("Client app " + key + " not found");
+ }
+ checkType(type, clientAppUtilsFactory.getInstance(cassp));
+
+ return binder.getClientAppTO(cassp);
case SAML2SP:
default:
SAML2SP saml2sp = saml2spDAO.find(key);
@@ -139,7 +154,8 @@ public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
switch (type) {
case OIDCRP:
return binder.getClientAppTO(oidcrpDAO.save(binder.create(clientAppTO)));
-
+ case CASSP:
+ return binder.getClientAppTO(casspDAO.save(binder.create(clientAppTO)));
case SAML2SP:
default:
return binder.getClientAppTO(saml2spDAO.save(binder.create(clientAppTO)));
@@ -159,7 +175,14 @@ public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
binder.update(oidcrp, clientAppTO);
oidcrpDAO.save(oidcrp);
break;
-
+ case CASSP:
+ CASSP cassp = casspDAO.find(clientAppTO.getKey());
+ if (cassp == null) {
+ throw new NotFoundException("Client app " + clientAppTO.getKey() + " not found");
+ }
+ binder.update(cassp, clientAppTO);
+ casspDAO.save(cassp);
+ break;
case SAML2SP:
default:
SAML2SP saml2sp = saml2spDAO.find(clientAppTO.getKey());
@@ -181,7 +204,13 @@ public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
}
oidcrpDAO.delete(oidcrp);
break;
-
+ case CASSP:
+ CASSP cassp = casspDAO.find(key);
+ if (cassp == null) {
+ throw new NotFoundException("Client app " + key + " not found");
+ }
+ casspDAO.delete(cassp);
+ break;
case SAML2SP:
default:
SAML2SP saml2sp = saml2spDAO.find(key);
@@ -216,9 +245,9 @@ public class ClientAppLogic extends AbstractTransactionalLogic<ClientAppTO> {
}
return binder.getClientAppTO(clientApp);
- } catch (Throwable ignore) {
- LOG.debug("Unresolved reference", ignore);
- throw new UnresolvedReferenceException(ignore);
+ } catch (Throwable ex) {
+ LOG.debug("Unresolved reference", ex);
+ throw new UnresolvedReferenceException(ex);
}
}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/CASSPDAO.java
similarity index 62%
copy from common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
copy to core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/CASSPDAO.java
index 3bf730e..5c179bd 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/CASSPDAO.java
@@ -16,10 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.common.lib.types;
+package org.apache.syncope.core.persistence.api.dao.auth;
-public enum ClientAppType {
- SAML2SP,
- OIDCRP;
+import org.apache.syncope.core.persistence.api.dao.DAO;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
+import java.util.List;
+
+public interface CASSPDAO extends DAO<CASSP> {
+
+ CASSP find(String key);
+
+ CASSP findByClientAppId(Long clientAppId);
+
+ CASSP findByName(String name);
+
+ List<CASSP> findAll();
+
+ CASSP save(CASSP clientApp);
+
+ void delete(String key);
+
+ void delete(CASSP clientApp);
}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/CASSP.java
similarity index 82%
copy from common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
copy to core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/CASSP.java
index 3bf730e..88cf6a5 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/CASSP.java
@@ -16,10 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.common.lib.types;
+package org.apache.syncope.core.persistence.api.entity.auth;
-public enum ClientAppType {
- SAML2SP,
- OIDCRP;
+public interface CASSP extends ClientApp {
+ void setServiceId(String serviceId);
+
+ String getServiceId();
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPACASSPDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPACASSPDAO.java
new file mode 100644
index 0000000..c59a459
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPACASSPDAO.java
@@ -0,0 +1,95 @@
+/*
+ * 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.dao.auth;
+
+import org.apache.syncope.core.persistence.api.dao.auth.CASSPDAO;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
+import org.apache.syncope.core.persistence.jpa.dao.AbstractDAO;
+import org.apache.syncope.core.persistence.jpa.entity.auth.JPACASSP;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+
+import java.util.List;
+
+@Repository
+public class JPACASSPDAO extends AbstractDAO<CASSP> implements CASSPDAO {
+
+ @Override
+ public CASSP find(final String key) {
+ return entityManager().find(JPACASSP.class, key);
+ }
+
+ private CASSP find(final String column, final Object value) {
+ TypedQuery<CASSP> query = entityManager().createQuery(
+ "SELECT e FROM " + JPACASSP.class.getSimpleName() + " e WHERE e." + column + "=:value",
+ CASSP.class);
+ query.setParameter("value", value);
+
+ CASSP result = null;
+ try {
+ result = query.getSingleResult();
+ } catch (final NoResultException e) {
+ LOG.debug("No OIDCRP found with " + column + " {}", value, e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public CASSP findByClientAppId(final Long clientAppId) {
+ return find("clientAppId", clientAppId);
+ }
+
+ @Override
+ public CASSP findByName(final String name) {
+ return find("name", name);
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public List<CASSP> findAll() {
+ TypedQuery<CASSP> query = entityManager().createQuery(
+ "SELECT e FROM " + JPACASSP.class.getSimpleName() + " e", CASSP.class);
+
+ return query.getResultList();
+ }
+
+ @Override
+ public CASSP save(final CASSP clientApp) {
+ return entityManager().merge(clientApp);
+ }
+
+ @Override
+ public void delete(final String key) {
+ CASSP rpTO = find(key);
+ if (rpTO == null) {
+ return;
+ }
+
+ delete(rpTO);
+ }
+
+ @Override
+ public void delete(final CASSP clientApp) {
+ entityManager().remove(clientApp);
+ }
+}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
index 5db4207..5ec9130 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
@@ -58,6 +58,7 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
import org.apache.syncope.core.persistence.api.entity.auth.AuthModuleItem;
import org.apache.syncope.core.persistence.api.entity.auth.AuthProfile;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
import org.apache.syncope.core.persistence.api.entity.auth.OIDCJWKS;
import org.apache.syncope.core.persistence.api.entity.auth.OIDCRP;
import org.apache.syncope.core.persistence.api.entity.auth.SAML2IdPMetadata;
@@ -114,6 +115,7 @@ import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAPlainAttrVal
import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAARelationship;
import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAnyObject;
import org.apache.syncope.core.persistence.jpa.entity.auth.JPAAuthProfile;
+import org.apache.syncope.core.persistence.jpa.entity.auth.JPACASSP;
import org.apache.syncope.core.persistence.jpa.entity.auth.JPAOIDCJWKS;
import org.apache.syncope.core.persistence.jpa.entity.auth.JPAOIDCRP;
import org.apache.syncope.core.persistence.jpa.entity.auth.JPASAML2SP;
@@ -329,6 +331,8 @@ public class JPAEntityFactory implements EntityFactory {
result = (E) new JPAAttrReleasePolicy();
} else if (reference.equals(OIDCRP.class)) {
result = (E) new JPAOIDCRP();
+ } else if (reference.equals(CASSP.class)) {
+ result = (E) new JPACASSP();
} else if (reference.equals(SAML2SP.class)) {
result = (E) new JPASAML2SP();
} else if (reference.equals(SAML2IdPMetadata.class)) {
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPACASSP.java
similarity index 53%
copy from common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
copy to core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPACASSP.java
index 3bf730e..763930d 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/ClientAppType.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPACASSP.java
@@ -16,10 +16,30 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.common.lib.types;
+package org.apache.syncope.core.persistence.jpa.entity.auth;
-public enum ClientAppType {
- SAML2SP,
- OIDCRP;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = JPACASSP.TABLE)
+public class JPACASSP extends AbstractClientApp implements CASSP {
+
+ public static final String TABLE = "CASSP";
+
+ private static final long serialVersionUID = 6422422526695279794L;
+
+ @Column(unique = true, nullable = false)
+ private String serviceId;
+
+ public String getServiceId() {
+ return serviceId;
+ }
+
+ public void setServiceId(final String serviceId) {
+ this.serviceId = serviceId;
+ }
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAClientAppUtils.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAClientAppUtils.java
index ced3c6a..3cb32b3 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAClientAppUtils.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAClientAppUtils.java
@@ -19,6 +19,7 @@
package org.apache.syncope.core.persistence.jpa.entity.auth;
import org.apache.syncope.common.lib.types.ClientAppType;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
import org.apache.syncope.core.persistence.api.entity.auth.ClientApp;
import org.apache.syncope.core.persistence.api.entity.auth.ClientAppUtils;
import org.apache.syncope.core.persistence.api.entity.auth.OIDCRP;
@@ -42,7 +43,8 @@ public class JPAClientAppUtils implements ClientAppUtils {
switch (type) {
case OIDCRP:
return OIDCRP.class;
-
+ case CASSP:
+ return CASSP.class;
case SAML2SP:
default:
return SAML2SP.class;
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAClientAppUtilsFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAClientAppUtilsFactory.java
index 610cc63..512f999 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAClientAppUtilsFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAClientAppUtilsFactory.java
@@ -18,10 +18,12 @@
*/
package org.apache.syncope.core.persistence.jpa.entity.auth;
+import org.apache.syncope.common.lib.to.client.CASSPTO;
import org.apache.syncope.common.lib.to.client.ClientAppTO;
import org.apache.syncope.common.lib.to.client.OIDCRPTO;
import org.apache.syncope.common.lib.to.client.SAML2SPTO;
import org.apache.syncope.common.lib.types.ClientAppType;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
import org.apache.syncope.core.persistence.api.entity.auth.ClientApp;
import org.apache.syncope.core.persistence.api.entity.auth.ClientAppUtils;
import org.apache.syncope.core.persistence.api.entity.auth.ClientAppUtilsFactory;
@@ -42,6 +44,8 @@ public class JPAClientAppUtilsFactory implements ClientAppUtilsFactory {
ClientAppType type;
if (clientApp instanceof SAML2SP) {
type = ClientAppType.SAML2SP;
+ } else if (clientApp instanceof CASSP) {
+ type = ClientAppType.CASSP;
} else if (clientApp instanceof OIDCRP) {
type = ClientAppType.OIDCRP;
} else {
@@ -56,6 +60,8 @@ public class JPAClientAppUtilsFactory implements ClientAppUtilsFactory {
ClientAppType type;
if (clientAppClass == SAML2SPTO.class) {
type = ClientAppType.SAML2SP;
+ } else if (clientAppClass == CASSPTO.class) {
+ type = ClientAppType.CASSP;
} else if (clientAppClass == OIDCRPTO.class) {
type = ClientAppType.OIDCRP;
} else {
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/CASSPTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/CASSPTest.java
new file mode 100644
index 0000000..45aa0f6
--- /dev/null
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/CASSPTest.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.core.persistence.jpa.inner;
+
+import org.apache.syncope.core.persistence.api.dao.auth.CASSPDAO;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
+import org.apache.syncope.core.persistence.api.entity.policy.AccessPolicy;
+import org.apache.syncope.core.persistence.api.entity.policy.AuthPolicy;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+@Transactional("Master")
+public class CASSPTest extends AbstractClientAppTest {
+
+ @Autowired
+ private CASSPDAO casspDAO;
+
+ @Test
+ public void find() {
+ int beforeCount = casspDAO.findAll().size();
+
+ CASSP rp = entityFactory.newEntity(CASSP.class);
+ rp.setName("CAS");
+ rp.setClientAppId(UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE);
+ rp.setDescription("This is a sample CAS RP");
+ rp.setServiceId("https://syncope.apache.org/.*");
+
+ AccessPolicy accessPolicy = buildAndSaveAccessPolicy();
+ rp.setAccessPolicy(accessPolicy);
+
+ AuthPolicy authPolicy = buildAndSaveAuthPolicy();
+ rp.setAuthPolicy(authPolicy);
+
+ casspDAO.save(rp);
+
+ assertNotNull(rp);
+ assertNotNull(rp.getKey());
+
+ int afterCount = casspDAO.findAll().size();
+ assertEquals(afterCount, beforeCount + 1);
+
+
+ rp = casspDAO.findByName("CAS");
+ assertNotNull(rp);
+
+ rp = casspDAO.findByClientAppId(rp.getClientAppId());
+ assertNotNull(rp);
+
+ casspDAO.delete(rp);
+ assertNull(casspDAO.findByName("CAS"));
+ }
+}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java
index 67db455..cc811fa 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java
@@ -19,13 +19,16 @@
package org.apache.syncope.core.provisioning.java.data;
import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.client.CASSPTO;
import org.apache.syncope.common.lib.to.client.ClientAppTO;
import org.apache.syncope.common.lib.to.client.OIDCRPTO;
import org.apache.syncope.common.lib.to.client.SAML2SPTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.auth.CASSP;
import org.apache.syncope.core.persistence.api.entity.auth.ClientApp;
+import org.apache.syncope.core.persistence.api.entity.auth.OIDCRP;
import org.apache.syncope.core.persistence.api.entity.auth.SAML2SP;
import org.apache.syncope.core.persistence.api.entity.policy.AccessPolicy;
import org.apache.syncope.core.persistence.api.entity.policy.AttrReleasePolicy;
@@ -34,7 +37,6 @@ import org.apache.syncope.core.persistence.api.entity.policy.Policy;
import org.apache.syncope.core.provisioning.api.data.ClientAppDataBinder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import org.apache.syncope.core.persistence.api.entity.auth.OIDCRP;
@Component
public class ClientAppDataBinderImpl implements ClientAppDataBinder {
@@ -52,6 +54,8 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
return (T) doCreate((SAML2SPTO) clientAppTO);
} else if (clientAppTO instanceof OIDCRPTO) {
return (T) doCreate((OIDCRPTO) clientAppTO);
+ } else if (clientAppTO instanceof CASSPTO) {
+ return (T) doCreate((CASSPTO) clientAppTO);
} else {
throw new IllegalArgumentException("Unsupported client app: " + clientAppTO.getClass().getName());
}
@@ -63,6 +67,8 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
doUpdate((SAML2SP) clientApp, (SAML2SPTO) clientAppTO);
} else if (clientAppTO instanceof OIDCRPTO) {
doUpdate((OIDCRP) clientApp, (OIDCRPTO) clientAppTO);
+ } else if (clientAppTO instanceof CASSPTO) {
+ doUpdate((CASSP) clientApp, (CASSPTO) clientAppTO);
} else {
throw new IllegalArgumentException("Unsupported client app: " + clientAppTO.getClass().getName());
}
@@ -75,6 +81,8 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
return (T) getClientAppTO((SAML2SP) clientApp);
} else if (clientApp instanceof OIDCRP) {
return (T) getClientAppTO((OIDCRP) clientApp);
+ } else if (clientApp instanceof CASSP) {
+ return (T) getClientAppTO((CASSP) clientApp);
} else {
throw new IllegalArgumentException("Unsupported client app: " + clientApp.getClass().getName());
}
@@ -86,6 +94,12 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
return saml2sp;
}
+ private CASSP doCreate(final CASSPTO clientAppTO) {
+ CASSP saml2sp = entityFactory.newEntity(CASSP.class);
+ update(saml2sp, clientAppTO);
+ return saml2sp;
+ }
+
private void doUpdate(final SAML2SP clientApp, final SAML2SPTO clientAppTO) {
clientApp.setDescription(clientAppTO.getDescription());
clientApp.setName(clientAppTO.getName());
@@ -147,7 +161,7 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
}
}
- private SAML2SPTO getClientAppTO(final SAML2SP clientApp) {
+ private static SAML2SPTO getClientAppTO(final SAML2SP clientApp) {
SAML2SPTO clientAppTO = new SAML2SPTO();
clientAppTO.setName(clientApp.getName());
@@ -240,7 +254,7 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
}
}
- private OIDCRPTO getClientAppTO(final OIDCRP clientApp) {
+ private static OIDCRPTO getClientAppTO(final OIDCRP clientApp) {
OIDCRPTO clientAppTO = new OIDCRPTO();
clientAppTO.setName(clientApp.getName());
@@ -265,4 +279,72 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
return clientAppTO;
}
+
+ private void doUpdate(final CASSP clientApp, final CASSPTO clientAppTO) {
+ clientApp.setName(clientAppTO.getName());
+ clientApp.setClientAppId(clientAppTO.getClientAppId());
+ clientApp.setDescription(clientAppTO.getDescription());
+ clientApp.setServiceId(clientAppTO.getServiceId());
+
+ if (clientAppTO.getAuthPolicy() == null) {
+ clientApp.setAuthPolicy(null);
+ } else {
+ Policy policy = policyDAO.find(clientAppTO.getAuthPolicy());
+ if (policy instanceof AuthPolicy) {
+ clientApp.setAuthPolicy((AuthPolicy) policy);
+ } else {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidPolicy);
+ sce.getElements().add("Expected " + AuthPolicy.class.getSimpleName()
+ + ", found " + policy.getClass().getSimpleName());
+ throw sce;
+ }
+ }
+
+ if (clientAppTO.getAccessPolicy() == null) {
+ clientApp.setAccessPolicy(null);
+ } else {
+ Policy policy = policyDAO.find(clientAppTO.getAccessPolicy());
+ if (policy instanceof AccessPolicy) {
+ clientApp.setAccessPolicy((AccessPolicy) policy);
+ } else {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidPolicy);
+ sce.getElements().add("Expected " + AccessPolicy.class.getSimpleName()
+ + ", found " + policy.getClass().getSimpleName());
+ throw sce;
+ }
+ }
+
+ if (clientAppTO.getAttrReleasePolicy() == null) {
+ clientApp.setAttrReleasePolicy(null);
+ } else {
+ Policy policy = policyDAO.find(clientAppTO.getAttrReleasePolicy());
+ if (policy instanceof AttrReleasePolicy) {
+ clientApp.setAttrReleasePolicy((AttrReleasePolicy) policy);
+ } else {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidPolicy);
+ sce.getElements().add("Expected " + AttrReleasePolicy.class.getSimpleName()
+ + ", found " + policy.getClass().getSimpleName());
+ throw sce;
+ }
+ }
+ }
+
+ private static CASSPTO getClientAppTO(final CASSP clientApp) {
+ CASSPTO clientAppTO = new CASSPTO();
+
+ clientAppTO.setName(clientApp.getName());
+ clientAppTO.setKey(clientApp.getKey());
+ clientAppTO.setDescription(clientApp.getDescription());
+ clientAppTO.setClientAppId(clientApp.getClientAppId());
+ clientAppTO.setServiceId(clientApp.getServiceId());
+
+ clientAppTO.setAuthPolicy(clientApp.getAuthPolicy() == null
+ ? null : clientApp.getAuthPolicy().getKey());
+ clientAppTO.setAccessPolicy(clientApp.getAccessPolicy() == null
+ ? null : clientApp.getAccessPolicy().getKey());
+ clientAppTO.setAttrReleasePolicy(clientApp.getAttrReleasePolicy() == null
+ ? null : clientApp.getAttrReleasePolicy().getKey());
+
+ return clientAppTO;
+ }
}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ClientAppITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ClientAppITCase.java
index 10a0194..ba6cf59 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ClientAppITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ClientAppITCase.java
@@ -27,6 +27,8 @@ import static org.junit.jupiter.api.Assertions.fail;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.policy.AccessPolicyTO;
+import org.apache.syncope.common.lib.policy.AuthPolicyTO;
+import org.apache.syncope.common.lib.to.client.CASSPTO;
import org.apache.syncope.common.lib.to.client.OIDCRPTO;
import org.apache.syncope.common.lib.to.client.SAML2SPTO;
import org.apache.syncope.common.lib.types.ClientAppType;
@@ -34,6 +36,8 @@ import org.apache.syncope.common.lib.types.PolicyType;
import org.apache.syncope.fit.AbstractITCase;
import org.junit.jupiter.api.Test;
+import java.util.UUID;
+
public class ClientAppITCase extends AbstractITCase {
@Test
@@ -100,6 +104,11 @@ public class ClientAppITCase extends AbstractITCase {
}
@Test
+ public void createCASSP() {
+ createClientApp(ClientAppType.CASSP, buildCASSP());
+ }
+
+ @Test
public void readOIDCRP() {
OIDCRPTO oidcrpTO = buildOIDCRP();
oidcrpTO = createClientApp(ClientAppType.OIDCRP, oidcrpTO);
@@ -116,6 +125,17 @@ public class ClientAppITCase extends AbstractITCase {
}
@Test
+ public void readCASSP() {
+ CASSPTO casspTO = buildCASSP();
+ casspTO = createClientApp(ClientAppType.CASSP, casspTO);
+ CASSPTO found = clientAppService.read(ClientAppType.CASSP, casspTO.getKey());
+ assertNotNull(found);
+ assertNotNull(found.getServiceId());
+ assertNotNull(found.getAccessPolicy());
+ assertNotNull(found.getAuthPolicy());
+ }
+
+ @Test
public void updateOIDCRP() {
OIDCRPTO oidcrpTO = buildOIDCRP();
oidcrpTO = createClientApp(ClientAppType.OIDCRP, oidcrpTO);
@@ -151,4 +171,45 @@ public class ClientAppITCase extends AbstractITCase {
assertNotNull(e);
}
}
+
+ @Test
+ public void deleteCASSP() {
+ CASSPTO casspTO = buildCASSP();
+ casspTO = createClientApp(ClientAppType.CASSP, casspTO);
+
+ clientAppService.delete(ClientAppType.CASSP, casspTO.getKey());
+
+ try {
+ clientAppService.read(ClientAppType.CASSP, casspTO.getKey());
+ fail("This should not happen");
+ } catch (SyncopeClientException e) {
+ assertNotNull(e);
+ }
+ }
+
+ private CASSPTO buildCASSP() {
+ AuthPolicyTO authPolicyTO = new AuthPolicyTO();
+ authPolicyTO.setKey("AuthPolicyTest_" + getUUIDString());
+ authPolicyTO.setDescription("Authentication Policy");
+ authPolicyTO = createPolicy(PolicyType.AUTH, authPolicyTO);
+ assertNotNull(authPolicyTO);
+
+ AccessPolicyTO accessPolicyTO = new AccessPolicyTO();
+ accessPolicyTO.setKey("AccessPolicyTest_" + getUUIDString());
+ accessPolicyTO.setDescription("Access policy");
+ accessPolicyTO = createPolicy(PolicyType.ACCESS, accessPolicyTO);
+ assertNotNull(accessPolicyTO);
+
+ CASSPTO casspTO = new CASSPTO();
+ casspTO.setName("ExampleRP_" + getUUIDString());
+ casspTO.setClientAppId(UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE);
+ casspTO.setDescription("Example OIDC RP application");
+ casspTO.setServiceId("https://cassp.example.org/" + UUID.randomUUID().getMostSignificantBits());
+
+ casspTO.setAuthPolicy(authPolicyTO.getKey());
+ casspTO.setAccessPolicy(accessPolicyTO.getKey());
+ return casspTO;
+ }
+
+
}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPTOMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPTOMapper.java
new file mode 100644
index 0000000..d5b870d
--- /dev/null
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPTOMapper.java
@@ -0,0 +1,57 @@
+/*
+ * 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.wa.starter.mapping;
+
+import org.apereo.cas.services.RegexRegisteredService;
+import org.apereo.cas.services.RegisteredService;
+import org.apereo.cas.services.RegisteredServiceAccessStrategy;
+import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
+import org.apereo.cas.services.RegisteredServiceAuthenticationPolicy;
+
+import org.apache.syncope.common.lib.to.client.CASSPTO;
+import org.apache.syncope.common.lib.to.client.ClientAppTO;
+import org.springframework.stereotype.Component;
+
+@ClientAppMapFor(clientAppClass = CASSPTO.class)
+@Component
+public class CASSPTOMapper implements ClientAppMapper {
+
+ @Override
+ public RegisteredService build(
+ final ClientAppTO clientAppTO,
+ final RegisteredServiceAuthenticationPolicy authPolicy,
+ final RegisteredServiceAccessStrategy accessStrategy,
+ final RegisteredServiceAttributeReleasePolicy attributeReleasePolicy) {
+
+ CASSPTO rp = CASSPTO.class.cast(clientAppTO);
+
+ RegexRegisteredService service = new RegexRegisteredService();
+
+ service.setServiceId(rp.getServiceId());
+ service.setId(rp.getClientAppId());
+ service.setName(rp.getName());
+ service.setDescription(rp.getDescription());
+ service.setAccessStrategy(accessStrategy);
+ service.setAuthenticationPolicy(authPolicy);
+ service.setAttributeReleasePolicy(attributeReleasePolicy);
+
+ return service;
+ }
+
+}