Commit 120d6ba8 authored by Francesco Chicchiricco's avatar Francesco Chicchiricco
Browse files

[CRV-19] Working (mock) choreography enactment

parent 0e78bfef
......@@ -71,6 +71,7 @@ public class FederationServerPropagationActions extends DefaultPropagationAction
// 2. check security groups and choreographies
Set<String> securityGroups = new HashSet<>();
Set<String> choreographyGroupKeys = new HashSet<>();
Set<String> choreographyGroups = new HashSet<>();
userDAO.findAllGroups(user).forEach((group) -> {
GPlainAttr isChoreography = group.getPlainAttr("isChoreography");
......@@ -78,6 +79,7 @@ public class FederationServerPropagationActions extends DefaultPropagationAction
&& !isChoreography.getValues().isEmpty()
&& isChoreography.getValues().get(0).getBooleanValue()) {
choreographyGroupKeys.add(group.getKey());
choreographyGroups.add(group.getName());
} else {
securityGroups.add(group.getName());
......@@ -104,14 +106,17 @@ public class FederationServerPropagationActions extends DefaultPropagationAction
attributes.add(AttributeBuilder.build(CHOREOGRAPHIES, choreographyGroups));
// 3. add per-service username / password attributes
user.getPlainAttrs().stream().filter((attr)
-> (attr.getMembership() != null
&& choreographyGroups.contains(attr.getMembership().getRightEnd().getName())
&& !attr.getValuesAsStrings().isEmpty())).forEachOrdered((attr) -> {
attributes.add(AttributeBuilder.build(
attr.getSchema().getKey(), attr.getValuesAsStrings().get(0)));
});
choreographyGroupKeys.stream().
map((choreographyKey) -> user.getMembership(choreographyKey)).
filter((membership) -> (membership != null)).
forEachOrdered((membership) -> {
user.getPlainAttrs(membership).stream().
filter((attr) -> (!attr.getValuesAsStrings().isEmpty())).forEachOrdered((attr) -> {
attributes.add(AttributeBuilder.build(
attr.getSchema().getKey(), attr.getValuesAsStrings().get(0)));
});
});
task.setAttributes(attributes);
}
......
......@@ -540,7 +540,11 @@ we are happy to inform you that the password request was execute successfully fo
<SyncopeSchema id="Service Security Description - content"/>
<PlainSchema id="Service Security Description - content" mandatoryCondition="false" mimeType="application/xml"
multivalue="0" readonly="0" type="Binary" uniqueConstraint="0" anyTypeClass_id="Service"/>
<SyncopeSchema id="Service Authentication Type"/>
<PlainSchema id="Service Authentication Type" mandatoryCondition="true"
multivalue="0" readonly="0" type="Enum" uniqueConstraint="0" enumerationValues="NONE;SHARED;PER_USER"
anyTypeClass_id="Service"/>
<SyncopeSchema id="Service Role Description"/>
<PlainSchema id="Service Role Description" mandatoryCondition="false"
multivalue="0" readonly="0" type="String" uniqueConstraint="0" anyTypeClass_id="Service Role"/>
......@@ -598,13 +602,14 @@ we are happy to inform you that the password request was execute successfully fo
realm_id="ea696a4f-e77a-4ef1-be67-8f8093bc8686"
creator="admin" lastModifier="admin"
creationDate="2016-08-12T13:14:52+0200" lastChangeDate="2016-08-12T13:14:52+0200"/>
<UDynGroupMembership id="e81494e2-0359-4e3f-9494-e20359ce3f47" fiql="$roles==Service Provider Approver"
group_id="0635553c-3f38-4a6d-b555-3c3f382a6ddb"/>
<SyncopeGroup id="4b7fb23c-183a-4531-bfb2-3c183a453195" name="EndUserApprover"
realm_id="ea696a4f-e77a-4ef1-be67-8f8093bc8686"
creator="admin" lastModifier="admin"
creationDate="2016-08-12T12:52:23+0200" lastChangeDate="2016-08-12T12:52:23+0200" />
<UDynGroupMembership id="bb03ac60-35de-4176-83ac-6035de417678" fiql="$roles==EndUser Approver" group_id="4b7fb23c-183a-4531-bfb2-3c183a453195"/>
<UDynGroupMembership id="e81494e2-0359-4e3f-9494-e20359ce3f47" fiql="$roles==Service Provider Approver" group_id="0635553c-3f38-4a6d-b555-3c3f382a6ddb"/>
<UDynGroupMembership id="bb03ac60-35de-4176-83ac-6035de417678" fiql="$roles==EndUser Approver"
group_id="4b7fb23c-183a-4531-bfb2-3c183a453195"/>
<!-- [END] CHOReVOLUTION -->
</dataset>
......@@ -541,6 +541,10 @@ we are happy to inform you that the password request was execute successfully fo
<SyncopeSchema id="Service Security Description - content"/>
<PlainSchema id="Service Security Description - content" mandatoryCondition="false" mimeType="application/xml"
multivalue="0" readonly="0" type="Binary" uniqueConstraint="0" anyTypeClass_id="Service"/>
<SyncopeSchema id="Service Authentication Type"/>
<PlainSchema id="Service Authentication Type" mandatoryCondition="true"
multivalue="0" readonly="0" type="Enum" uniqueConstraint="0" enumerationValues="NONE;SHARED;PER_USER"
anyTypeClass_id="Service"/>
 
<SyncopeSchema id="Service Role Description"/>
<PlainSchema id="Service Role Description" mandatoryCondition="false"
......@@ -599,25 +603,32 @@ we are happy to inform you that the password request was execute successfully fo
realm_id="ea696a4f-e77a-4ef1-be67-8f8093bc8686"
creator="admin" lastModifier="admin"
creationDate="2016-08-12T13:14:52+0200" lastChangeDate="2016-08-12T13:14:52+0200"/>
<UDynGroupMembership id="e81494e2-0359-4e3f-9494-e20359ce3f47" fiql="$roles==Service Provider Approver"
group_id="0635553c-3f38-4a6d-b555-3c3f382a6ddb"/>
<SyncopeGroup id="4b7fb23c-183a-4531-bfb2-3c183a453195" name="EndUserApprover"
realm_id="ea696a4f-e77a-4ef1-be67-8f8093bc8686"
creator="admin" lastModifier="admin"
creationDate="2016-08-12T12:52:23+0200" lastChangeDate="2016-08-12T12:52:23+0200" />
<UDynGroupMembership id="bb03ac60-35de-4176-83ac-6035de417678" fiql="$roles==EndUser Approver"
group_id="4b7fb23c-183a-4531-bfb2-3c183a453195"/>
 
<AnyObject id="ef028fc9-23bb-491b-828f-c923bb791bf5" name="Default"
realm_id="ea696a4f-e77a-4ef1-be67-8f8093bc8686" type_id="ENACTMENT ENGINE"
creator="admin" lastModifier="admin"
creationDate="2016-09-19T12:52:23+0200" lastChangeDate="2016-09-19T12:52:23+0200" />
<APlainAttr id="956a8440-1df7-4ed6-b156-04173ca47528" owner_id="ef028fc9-23bb-491b-828f-c923bb791bf5" schema_id="enactmentEngineBaseURL"/>
<APlainAttrValue id="15f64e99-20cc-42ec-a77a-3396dea4248f" attribute_id="956a8440-1df7-4ed6-b156-04173ca47528" stringValue="http://localhost:9080/choremocks/rest/v1/choreography"/>
<APlainAttr id="9ecee738-f994-4acd-8ee7-38f9946acdc0" owner_id="ef028fc9-23bb-491b-828f-c923bb791bf5" schema_id="enactmentEngineUsername"/>
<APlainAttrValue id="42337c7c-7ff5-4fe6-b37c-7c7ff57fe646" attribute_id="9ecee738-f994-4acd-8ee7-38f9946acdc0" stringValue="admin"/>
<APlainAttr id="c8339c3a-b592-4d6a-b39c-3ab592dd6a93" owner_id="ef028fc9-23bb-491b-828f-c923bb791bf5" schema_id="enactmentEnginePassword"/>
<APlainAttrValue id="a49233c5-d6d0-4cd7-9233-c5d6d0acd707" attribute_id="c8339c3a-b592-4d6a-b39c-3ab592dd6a93" stringValue="SxxjoySCp6mqzrV8q/BwXQ== "/>
<UDynGroupMembership id="bb03ac60-35de-4176-83ac-6035de417678" fiql="$roles==EndUser Approver" group_id="4b7fb23c-183a-4531-bfb2-3c183a453195"/>
<UDynGroupMembership id="e81494e2-0359-4e3f-9494-e20359ce3f47" fiql="$roles==Service Provider Approver" group_id="0635553c-3f38-4a6d-b555-3c3f382a6ddb"/>
<APlainAttr id="956a8440-1df7-4ed6-b156-04173ca47528" owner_id="ef028fc9-23bb-491b-828f-c923bb791bf5"
schema_id="enactmentEngineBaseURL"/>
<APlainAttrValue id="15f64e99-20cc-42ec-a77a-3396dea4248f" attribute_id="956a8440-1df7-4ed6-b156-04173ca47528"
stringValue="http://localhost:9080/choremocks/rest/v1/choreography"/>
<APlainAttr id="9ecee738-f994-4acd-8ee7-38f9946acdc0" owner_id="ef028fc9-23bb-491b-828f-c923bb791bf5"
schema_id="enactmentEngineUsername"/>
<APlainAttrValue id="42337c7c-7ff5-4fe6-b37c-7c7ff57fe646" attribute_id="9ecee738-f994-4acd-8ee7-38f9946acdc0"
stringValue="admin"/>
<APlainAttr id="c8339c3a-b592-4d6a-b39c-3ab592dd6a93" owner_id="ef028fc9-23bb-491b-828f-c923bb791bf5"
schema_id="enactmentEnginePassword"/>
<APlainAttrValue id="a49233c5-d6d0-4cd7-9233-c5d6d0acd707" attribute_id="c8339c3a-b592-4d6a-b39c-3ab592dd6a93"
stringValue="SxxjoySCp6mqzrV8q/BwXQ=="/>
<!-- [END] CHOReVOLUTION -->
 
<!-- [START] Choreography Execution Data -->
......@@ -47,6 +47,11 @@ limitations under the License.
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>eu.chorevolution.ee</groupId>
<artifactId>chorspec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
......
......@@ -18,16 +18,21 @@ package org.apache.syncope.core.logic;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import eu.chorevolution.datamodel.Choreography;
import eu.chorevolution.datamodel.ExistingService;
import eu.chorevolution.datamodel.ServiceGroup;
import eu.chorevolution.idm.common.ChorevolutionEntitlement;
import eu.chorevolution.idm.common.types.ChoreographyAction;
import eu.chorevolution.idm.common.types.ChoreographyOperation;
import eu.chorevolution.idm.common.types.ServiceAction;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
......@@ -38,24 +43,32 @@ import org.apache.cxf.common.util.Base64Utility;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.syncope.common.lib.AbstractBaseBean;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.patch.AnyObjectPatch;
import org.apache.syncope.common.lib.patch.GroupPatch;
import org.apache.syncope.common.lib.patch.MembershipPatch;
import org.apache.syncope.common.lib.to.AnyObjectTO;
import org.apache.syncope.common.lib.to.AnyTypeClassTO;
import org.apache.syncope.common.lib.to.AttrTO;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.PlainSchemaTO;
import org.apache.syncope.common.lib.to.TypeExtensionTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.spring.security.Encryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@Component
public class ChoreographyLogic extends AbstractTransactionalLogic<AbstractBaseBean> {
public class ChoreographyLogic extends AbstractLogic<AbstractBaseBean> {
private static final String SERVICE_TYPE = "SERVICE";
private static final String ENACTMENT_ENGINE_TYPE = "ENACTMENT ENGINE";
......@@ -67,6 +80,24 @@ public class ChoreographyLogic extends AbstractTransactionalLogic<AbstractBaseBe
private static final String CHOREOGRAPHY_ID_SCHEMA = "id";
private static String SECRET_KEY;
static {
InputStream propStream = null;
try {
propStream = Encryptor.class.getResourceAsStream("/security.properties");
Properties props = new Properties();
props.load(propStream);
SECRET_KEY = props.getProperty("secretKey");
} catch (Exception e) {
LOG.error("Could not read security parameters", e);
} finally {
org.apache.commons.io.IOUtils.closeQuietly(propStream);
}
}
@Autowired
private GroupLogic groupLogic;
......@@ -74,10 +105,10 @@ public class ChoreographyLogic extends AbstractTransactionalLogic<AbstractBaseBe
private AnyObjectLogic anyObjectLogic;
@Autowired
private PlainSchemaDAO plainSchemaDAO;
private AnyTypeClassLogic anyTypeClassLogic;
@Autowired
private AnySearchDAO searchDAO;
private SchemaLogic schemaLogic;
private WebClient getWebClient(final String enactmentEngineKey, final String endpoint) throws Exception {
AnyObjectTO enactmentEngine = anyObjectLogic.read(enactmentEngineKey);
......@@ -110,7 +141,8 @@ public class ChoreographyLogic extends AbstractTransactionalLogic<AbstractBaseBe
if (plainAttrs.containsKey(ENACTMENT_ENGINE_PASSWORD)) {
List<String> values = plainAttrs.get(ENACTMENT_ENGINE_PASSWORD).getValues();
if (!values.isEmpty()) {
PlainSchema enactmentEnginePasswordSchema = plainSchemaDAO.find(ENACTMENT_ENGINE_PASSWORD);
PlainSchemaTO enactmentEnginePasswordSchema =
schemaLogic.read(SchemaType.PLAIN, ENACTMENT_ENGINE_PASSWORD);
password = Encryptor.getInstance(enactmentEnginePasswordSchema.getSecretKey()).
decode(values.get(0), enactmentEnginePasswordSchema.getCipherAlgorithm());
}
......@@ -158,7 +190,9 @@ public class ChoreographyLogic extends AbstractTransactionalLogic<AbstractBaseBe
AttributeCond idCond = new AttributeCond(AttributeCond.Type.EQ);
idCond.setSchema(CHOREOGRAPHY_ID_SCHEMA);
idCond.setExpression(id);
List<Group> candidates = searchDAO.search(SearchCond.getLeafCond(idCond), AnyTypeKind.GROUP);
List<GroupTO> candidates = groupLogic.search(
SearchCond.getLeafCond(idCond),
1, 1, Collections.<OrderByClause>emptyList(), SyncopeConstants.ROOT_REALM, false);
if (candidates.isEmpty()) {
throw new NotFoundException("Choreography " + id);
}
......@@ -206,16 +240,22 @@ public class ChoreographyLogic extends AbstractTransactionalLogic<AbstractBaseBe
operation, id, name, message);
byte[] chorSpecXML = null;
Choreography chorSpec = null;
if (enactedChorSpec != null) {
try {
chorSpecXML = IOUtils.readBytesFromStream(enactedChorSpec);
} catch (IOException e) {
chorSpec = Choreography.fromXML(new ByteArrayInputStream(chorSpecXML));
} catch (Exception e) {
throw new BadRequestException("While reading enacted chorSpec for choreography " + id, e);
}
}
if (chorSpec == null) {
throw new BadRequestException("Cloud not parse enacted chorSpec for choreography " + id);
}
switch (operation) {
case CREATE:
// 1. create the choreography group
GroupTO choreography = new GroupTO();
choreography.setName(name);
choreography.setRealm(SyncopeConstants.ROOT_REALM);
......@@ -225,7 +265,69 @@ public class ChoreographyLogic extends AbstractTransactionalLogic<AbstractBaseBe
choreography.getPlainAttrs().add(
new AttrTO.Builder().schema("chorSpec").value(Base64Utility.encode(chorSpecXML)).build());
groupLogic.create(choreography, false).getEntity();
choreography = groupLogic.create(choreography, false).getEntity();
final String key = choreography.getKey();
AnyTypeClassTO anyTypeClassTO = new AnyTypeClassTO();
anyTypeClassTO.setKey(name + " Type Extension");
for (ServiceGroup serviceGroup : chorSpec.getServiceGroups()) {
serviceGroup.getServices().stream().
filter((service) -> (service instanceof ExistingService)).forEachOrdered((service) -> {
try {
AnyObjectTO serviceTO = anyObjectLogic.read(service.getName());
if (!SERVICE_TYPE.equals(serviceTO.getType())) {
throw new NotFoundException(SERVICE_TYPE + " " + service.getName());
}
// 2. add the relevant services to the group, according to the chorSpec,
// and save the security filter URL
AnyObjectPatch servicePatch = new AnyObjectPatch();
servicePatch.setKey(serviceTO.getKey());
servicePatch.getMemberships().add(
new MembershipPatch.Builder().group(key).build());
anyObjectLogic.update(servicePatch, false);
// 3. for each service requiring per-user authentication, create the
// Username and Password schemas, for USER type extension
AttrTO serviceAuth = serviceTO.getPlainAttrMap().get("Service Authentication Type");
if (serviceAuth != null && !serviceAuth.getValues().isEmpty()
&& serviceAuth.getValues().get(0).equals("PER_USER")) {
PlainSchemaTO username = new PlainSchemaTO();
username.setKey(service.getName() + " Username");
username.setType(AttrSchemaType.String);
username.setMandatoryCondition("true");
schemaLogic.create(SchemaType.PLAIN, username);
anyTypeClassTO.getPlainSchemas().add(username.getKey());
PlainSchemaTO password = new PlainSchemaTO();
password.setKey(service.getName() + " Password");
password.setType(AttrSchemaType.Encrypted);
password.setCipherAlgorithm(CipherAlgorithm.AES);
password.setSecretKey(SECRET_KEY);
password.setMandatoryCondition("true");
schemaLogic.create(SchemaType.PLAIN, password);
anyTypeClassTO.getPlainSchemas().add(password.getKey());
}
} catch (NotFoundException e) {
LOG.error("Could not find service {} in the inventory, ignoring", service.getName(), e);
}
});
}
if (!anyTypeClassTO.getPlainSchemas().isEmpty()) {
anyTypeClassLogic.create(anyTypeClassTO);
TypeExtensionTO typeExtension = new TypeExtensionTO();
typeExtension.setAnyType(AnyTypeKind.USER.name());
typeExtension.getAuxClasses().add(anyTypeClassTO.getKey());
GroupPatch groupPatch = new GroupPatch();
groupPatch.setKey(key);
groupPatch.getTypeExtensions().add(typeExtension);
groupLogic.update(groupPatch, false);
}
break;
case UPDATE:
......
......@@ -31,7 +31,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
* REST services to be invoked by the Studio for operating on choreographies and / or their services.
* REST operations for acting on choreographies and / or their services.
*/
@Path("chors")
public interface ChoreographyService extends JAXRSService {
......
......@@ -135,6 +135,12 @@ limitations under the License.
<artifactId>sf-provision-data</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>eu.chorevolution.ee</groupId>
<artifactId>chorspec</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment