CCM NG: Revised Im/Export system for entities in org.libreccm-security

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5706 8810af33-2d31-482b-a856-94f89814c4df
jensp 2018-10-03 08:08:35 +00:00
parent 6775ae7491
commit 2d6e92ea43
64 changed files with 728 additions and 535 deletions

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.imexport;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
/**
* Base class for importers/exporters. Implementations must be annotated with
* {@link Procsses} to register the implementation in the Import/Export service.
*
* Implementations must also be CDI beans. It is recommended that the beans are
* {@link RequestScoped}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @param <T> The type of the entity which is processed by the implementation.
*/
public abstract class AbstractEntityImExporter<T extends Exportable> {
private final ObjectMapper objectMapper = new ObjectMapper();
protected abstract Class<T> getEntityClass();
public T importEntity(final String data) throws ImportExpection {
try {
return objectMapper.readValue(data, getEntityClass());
} catch (IOException ex) {
throw new ImportExpection(ex);
}
}
public String exportEntity(final Exportable entity) throws ExportException {
try {
return objectMapper.writeValueAsString(entity);
} catch (JsonProcessingException ex) {
throw new ExportException(String.format(
"Failed to export entity \"%s\" of type \"%s\".",
entity.getUuid(),
getEntityClass().getName()),
ex);
}
}
protected abstract void saveImportedEntity(T entity);
}

View File

@ -35,7 +35,7 @@ import java.util.stream.Collectors;
* method. With the returned list of nodes call the
* {@link #orderImExporters(java.util.List)} method. The list returned by
* {@link #orderImExporters(java.util.List)} contains all
* {@link EntityImExporter} in the order.
* {@link AbstractEntityImExporter}s in the order.
*
* This class is <strong>not</strong> not part of the public API.
*
@ -50,9 +50,9 @@ final class EntityImExporterTreeManager {
.getLogger(EntityImExporterTreeManager.class);
/**
* Initialises the tree with the provided list of {@link EntityImExporter}s.
* Initialises the tree with the provided list of {@link AbstractEntityImExporter}s.
*
* @param imExporters The available {@link EntityImExporter}s.
* @param imExporters The available {@link AbstractEntityImExporter}s.
*
* @return An ordered list of the tree nodes.
*
@ -62,7 +62,7 @@ final class EntityImExporterTreeManager {
* cycle is detected in the dependency tree.
*/
public List<EntityImExporterTreeNode> generateTree(
final List<EntityImExporter<?>> imExporters)
final List<AbstractEntityImExporter<?>> imExporters)
throws DependencyException {
LOGGER.info("Starting to generate dependency tree...");
@ -81,7 +81,7 @@ final class EntityImExporterTreeManager {
node -> node));
//Add the dependency relations to the nodes
for (final EntityImExporter<?> imExporter : imExporters) {
for (final AbstractEntityImExporter<?> imExporter : imExporters) {
addDependencyRelations(imExporter, nodes);
}
@ -184,7 +184,7 @@ final class EntityImExporterTreeManager {
/**
* Helper method for adding the dependency relations for an
* {@link EntityImExporter} to the nodes.
* {@link AbstractEntityImExporter} to the nodes.
*
* @param imExporter The current {@link EntityImExporter}.
* @param nodes The map of nodes.
@ -192,7 +192,7 @@ final class EntityImExporterTreeManager {
* @throws DependencyException If something goes wrong.
*/
private void addDependencyRelations(
final EntityImExporter<?> imExporter,
final AbstractEntityImExporter<?> imExporter,
final Map<String, EntityImExporterTreeNode> nodes)
throws DependencyException {

View File

@ -29,7 +29,7 @@ import java.util.Objects;
*/
final class EntityImExporterTreeNode {
private EntityImExporter<?> entityImExporter;
private AbstractEntityImExporter<?> entityImExporter;
private List<EntityImExporterTreeNode> dependentImExporters;
@ -44,18 +44,19 @@ final class EntityImExporterTreeNode {
}
public EntityImExporterTreeNode(
final EntityImExporter<?> entityImExporter) {
final AbstractEntityImExporter<?> entityImExporter) {
this();
this.entityImExporter = entityImExporter;
}
public EntityImExporter<?> getEntityImExporter() {
public AbstractEntityImExporter<?> getEntityImExporter() {
return entityImExporter;
}
void setEntityImExporter(final EntityImExporter<?> entityImExporter) {
void setEntityImExporter(
final AbstractEntityImExporter<?> entityImExporter) {
this.entityImExporter = entityImExporter;
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.imexport;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ExportException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of <code>ExportException</code> without detail message.
*/
public ExportException() {
super();
}
/**
* Constructs an instance of <code>ExportException</code> with the specified detail message.
*
* @param msg The detail message.
*/
public ExportException(final String msg) {
super(msg);
}
/**
* Constructs an instance of <code>ExportException</code> which wraps the
* specified exception.
*
* @param exception The exception to wrap.
*/
public ExportException(final Exception exception) {
super(exception);
}
/**
* Constructs an instance of <code>ExportException</code> with the specified message which also wraps the
* specified exception.
*
* @param msg The detail message.
* @param exception The exception to wrap.
*/
public ExportException(final String msg, final Exception exception) {
super(msg, exception);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2018 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.imexport;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ImportExpection extends Exception {
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of <code>ImportExpection</code> without detail message.
*/
public ImportExpection() {
super();
}
/**
* Constructs an instance of <code>ImportExpection</code> with the specified detail message.
*
* @param msg The detail message.
*/
public ImportExpection(final String msg) {
super(msg);
}
/**
* Constructs an instance of <code>ImportExpection</code> which wraps the
* specified exception.
*
* @param exception The exception to wrap.
*/
public ImportExpection(final Exception exception) {
super(exception);
}
/**
* Constructs an instance of <code>ImportExpection</code> with the specified message which also wraps the
* specified exception.
*
* @param msg The detail message.
* @param exception The exception to wrap.
*/
public ImportExpection(final String msg, final Exception exception) {
super(msg, exception);
}
}

View File

@ -26,11 +26,15 @@ import org.libreccm.files.FileAlreadyExistsException;
import org.libreccm.files.FileDoesNotExistException;
import org.libreccm.files.InsufficientPermissionsException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
@ -39,6 +43,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
@ -68,7 +74,7 @@ public class ImportExport {
@Inject
@Any
private Instance<EntityImExporter<?>> imExporters;
private Instance<AbstractEntityImExporter<?>> imExporters;
/**
* Exports the provided entities. The export will be written to a to the
@ -138,7 +144,7 @@ public class ImportExport {
throw new UnexpectedErrorException(ex);
}
for(final Map.Entry<String, List<Exportable>> entry
for (final Map.Entry<String, List<Exportable>> entry
: typeEntityMap.entrySet()) {
createExportedEntities(exportName,
@ -162,10 +168,10 @@ public class ImportExport {
throw new UnexpectedErrorException(ex);
}
final Instance<EntityImExporter<?>> instance = imExporters
final Instance<AbstractEntityImExporter<?>> instance = imExporters
.select(new ProcessesLiteral(clazz));
final EntityImExporter<?> imExporter;
final AbstractEntityImExporter<?> imExporter;
if (instance.isUnsatisfied()) {
throw new UnexpectedErrorException(String.format(
"No EntityImExporter for entity type \"%s\" available.",
@ -195,10 +201,23 @@ public class ImportExport {
throw new UnexpectedErrorException(ex);
}
final JsonObject exportedEntity = imExporter.exportEntity(entity);
try (JsonWriter writer = Json.createWriter(outputStream)) {
writer.writeObject(exportedEntity);
final String exportedEntity;
try {
exportedEntity = imExporter.exportEntity(entity);
} catch (ExportException ex) {
throw new UnexpectedErrorException(ex);
}
try (final OutputStreamWriter writer = new OutputStreamWriter(
outputStream, StandardCharsets.UTF_8)) {
writer.write(exportedEntity);
} catch (IOException ex) {
throw new UnexpectedErrorException(ex);
}
// try (JsonWriter writer = Json.createWriter(outputStream)) {
// writer.writeObject(exportedEntity);
// }
}
return filesArrayBuilder;
@ -235,7 +254,8 @@ public class ImportExport {
throw new UnexpectedErrorException(ex);
}
final List<EntityImExporter<?>> imExportersList = new ArrayList<>();
final List<AbstractEntityImExporter<?>> imExportersList
= new ArrayList<>();
imExporters.forEach(imExporter -> imExportersList.add(imExporter));
try {
@ -270,7 +290,8 @@ public class ImportExport {
private boolean filterImporters(final ImportManifest manifest,
final EntityImExporterTreeNode node) {
final EntityImExporter<?> imExporter = node.getEntityImExporter();
final AbstractEntityImExporter<?> imExporter = node
.getEntityImExporter();
final String type = imExporter
.getClass()
.getAnnotation(Processes.class).value().getName();
@ -280,7 +301,7 @@ public class ImportExport {
private void importEntitiesOfType(
final String importName,
final EntityImExporter<?> entityImExporter) {
final AbstractEntityImExporter<?> entityImExporter) {
final String type = entityImExporter
.getClass()
@ -313,7 +334,7 @@ public class ImportExport {
private void importEntity(final String importName,
final String type,
final String fileName,
final EntityImExporter<?> imExporter) {
final AbstractEntityImExporter<?> imExporter) {
final String filePath = String.format("imports/%s/%s/%s",
importName,
@ -322,15 +343,20 @@ public class ImportExport {
try (final InputStream inputStream
= ccmFiles.createInputStream(filePath)) {
final JsonReader reader = Json.createReader(inputStream);
final JsonObject data = reader.readObject();
final String data = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
// final JsonReader reader = Json.createReader(inputStream);
// final JsonObject data = reader.readObject();
imExporter.importEntity(data);
} catch (IOException
| FileDoesNotExistException
| FileAccessException
| InsufficientPermissionsException ex) {
| InsufficientPermissionsException
| ImportExpection ex) {
throw new UnexpectedErrorException(ex);
}

View File

@ -21,7 +21,6 @@ package org.libreccm.security;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.libreccm.portation.Portable;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
@ -35,6 +34,8 @@ import java.util.Set;
import static org.libreccm.core.CoreConstants.CORE_XML_NS;
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
import org.libreccm.imexport.Exportable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.NamedAttributeNode;
@ -58,6 +59,10 @@ import javax.persistence.Table;
@Entity
@Table(name = "GROUPS", schema = DB_SCHEMA)
@NamedQueries({
@NamedQuery(
name = "Group.findByUuid",
query = "SELECT g FROM Group g WHERE g.uuid = :uuid"
),
@NamedQuery(
name = "Group.findByName",
query = "SELECT g FROM Group g WHERE g.name = :name "
@ -105,8 +110,8 @@ import javax.persistence.Table;
@XmlRootElement(name = "user-group", namespace = CORE_XML_NS)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
resolver = GroupIdResolver.class,
property = "name")
public class Group extends Party implements Serializable, Portable {
property = "uuid")
public class Group extends Party implements Serializable, Exportable {
private static final long serialVersionUID = -4800759206452780739L;

View File

@ -26,7 +26,7 @@ import javax.enterprise.context.RequestScoped;
import java.io.Serializable;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @author <a href="mailto:tosmers@uni-bremen.de">Tobias Osmers</a>
* @version created on 3/23/17
*/
@RequestScoped
@ -43,14 +43,15 @@ public class GroupIdResolver implements Serializable, ObjectIdResolver {
@Override
public Object resolveId(final ObjectIdGenerator.IdKey id) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final GroupRepository groupRepo = cdiUtil
.findBean(GroupRepository.class);
return groupRepo
.findByName(id.key.toString())
.findByUuid(id.key.toString())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Group with name %s in the database.",
.format("No Group with uuid %s in the database.",
id.key.toString())));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
* Copyright (C) 2018 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -18,35 +18,34 @@
*/
package org.libreccm.security;
import org.libreccm.portation.AbstractMarshaller;
import org.libreccm.portation.Marshals;
import org.libreccm.imexport.AbstractEntityImExporter;
import org.libreccm.imexport.Processes;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @version created on 11/7/16
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Marshals(Group.class)
public class GroupMarshaller extends AbstractMarshaller<Group> {
private static final long serialVersionUID = 5004457104585052013L;
@Processes(Group.class)
public class GroupImExporter extends AbstractEntityImExporter<Group>{
@Inject
private GroupRepository groupRepository;
@Override
protected Class<Group> getObjectClass() {
protected Class<Group> getEntityClass() {
return Group.class;
}
@Override
@Transactional(Transactional.TxType.REQUIRED)
protected void insertIntoDb(Group portableObject) {
portableObject.setPartyId(portableObject.getPartyId() * -1);
groupRepository.save(portableObject);
protected void saveImportedEntity(final Group entity) {
groupRepository.save(entity);
}
}

View File

@ -26,8 +26,10 @@ import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
/**
* Manager class providing methods for adding and removing members to and from
@ -74,6 +76,7 @@ public class GroupManager implements Serializable {
}
final GroupMembership membership = new GroupMembership();
membership.setUuid(UUID.randomUUID().toString());
membership.setGroup(group);
membership.setMember(user);

View File

@ -20,34 +20,50 @@ package org.libreccm.security;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import org.libreccm.portation.Portable;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import java.io.Serializable;
import java.util.Objects;
import static org.libreccm.core.CoreConstants.CORE_XML_NS;
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.libreccm.imexport.Exportable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* A association class representing the assoication between a {@link User} and
* a {@code Group}.
* A association class representing the association between a {@link User} and a
* {@code Group}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Entity
@Table(name = "GROUP_MEMBERSHIPS", schema = DB_SCHEMA)
@NamedQueries({
@NamedQuery(name = "GroupMembership.findByUuid",
query = "SELECT m FROM GroupMembership m WHERE m.uuid = :uuid")
,
@NamedQuery(name = "GroupMembership.findByGroupAndUser",
query = "SELECT m FROM GroupMembership m "
+ "WHERE m.member = :member AND m.group = :group")})
@XmlRootElement(name = "group-membership", namespace = CORE_XML_NS)
@JsonIdentityInfo(generator = GroupMembershipIdGenerator.class,
property = "customMemId")
public class GroupMembership implements Serializable, Portable {
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "uuid")
public class GroupMembership implements Serializable, Exportable {
private static final long serialVersionUID = 83192968306850665L;
@ -57,6 +73,10 @@ public class GroupMembership implements Serializable, Portable {
@XmlElement(name = "membership-id", namespace = CORE_XML_NS)
private long membershipId;
@Column(name = "UUID", unique = true, nullable = false)
@XmlElement(name = "uuid", namespace = CORE_XML_NS)
private String uuid;
@ManyToOne
@JoinColumn(name = "GROUP_ID")
@XmlTransient
@ -77,6 +97,15 @@ public class GroupMembership implements Serializable, Portable {
this.membershipId = membershipId;
}
@Override
public String getUuid() {
return uuid;
}
protected void setUuid(final String uuid) {
this.uuid = uuid;
}
public Group getGroup() {
return group;
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.security;
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @version created on 3/23/17
*/
public class GroupMembershipIdGenerator extends ObjectIdGenerator<String> {
private static final long serialVersionUID = 5256221797846627835L;
@Override
public Class<?> getScope() {
return GroupMembership.class;
}
@Override
public boolean canUseFor(final ObjectIdGenerator<?> gen) {
return gen instanceof GroupMembershipIdGenerator;
}
@Override
public ObjectIdGenerator<String> forScope(final Class<?> scope) {
return this;
}
@Override
public ObjectIdGenerator<String> newForSerialization(final Object context) {
return this;
}
@Override
public IdKey key(final Object key) {
if (key == null) {
return null;
}
return new IdKey(GroupMembership.class, GroupMembership.class, key);
}
@Override
public String generateId(final Object forPojo) {
if (!(forPojo instanceof GroupMembership)) {
throw new IllegalArgumentException(
"Only GroupMembership instances are supported.");
}
final GroupMembership membership = (GroupMembership) forPojo;
return String.format("{%s}{%s}",
membership.getGroup().getName(),
membership.getMember().getName());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
* Copyright (C) 2018 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -18,37 +18,37 @@
*/
package org.libreccm.security;
import org.libreccm.portation.AbstractMarshaller;
import org.libreccm.portation.Marshals;
import org.libreccm.imexport.AbstractEntityImExporter;
import org.libreccm.imexport.DependsOn;
import org.libreccm.imexport.Processes;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @version created on 11/7/16
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Marshals(GroupMembership.class)
public class GroupMembershipMarshaller extends AbstractMarshaller<GroupMembership> {
private static final long serialVersionUID = -1920271635191667015L;
@Processes(GroupMembership.class)
@DependsOn({User.class, Group.class})
public class GroupMembershipImExporter extends AbstractEntityImExporter<GroupMembership> {
@Inject
private EntityManager entityManager;
@Override
protected Class<GroupMembership> getObjectClass() {
protected Class<GroupMembership> getEntityClass() {
return GroupMembership.class;
}
@Override
@Transactional(Transactional.TxType.REQUIRED)
protected void insertIntoDb(final GroupMembership portableObject) {
portableObject.setMembershipId(portableObject.getMembershipId() * -1);
entityManager.merge(portableObject);
entityManager.flush();
protected void saveImportedEntity(final GroupMembership entity) {
entityManager.persist(entity);
}
}

View File

@ -61,6 +61,19 @@ public class GroupRepository extends AbstractEntityRepository<Long, Group> {
return entity.getPartyId() == 0;
}
public Optional<Group> findByUuid(final String uuid) {
final TypedQuery<Group> query = getEntityManager()
.createNamedQuery("Group.findByUuid", Group.class);
query.setParameter("uuid", uuid);
final List<Group> result = query.getResultList();
if (result.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(result.get(0));
}
}
/**
* Finds a group by its name.
*

View File

@ -18,6 +18,8 @@
*/
package org.libreccm.security;
import static org.libreccm.core.CoreConstants.*;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@ -33,9 +35,6 @@ import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import static org.libreccm.core.CoreConstants.CORE_XML_NS;
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
@ -62,6 +61,10 @@ import javax.persistence.Table;
@Table(name = "PARTIES", schema = DB_SCHEMA)
@Inheritance(strategy = InheritanceType.JOINED)
@NamedQueries({
@NamedQuery(
name = "Party.findByUuid",
query = "SELECT p FROM Party p WHERE p.uuid = :uuid"
),
@NamedQuery(
name = "Party.findByName",
query = "SELECT p FROM Party p WHERE p.name = :name")
@ -86,7 +89,7 @@ import javax.persistence.Table;
})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
resolver = PartyIdResolver.class,
property = "name")
property = "uuid")
public class Party implements Serializable {
private static final long serialVersionUID = 3319997992281332204L;
@ -94,9 +97,11 @@ public class Party implements Serializable {
@Id
@Column(name = "PARTY_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
@XmlElement(name = "party-id", namespace = CORE_XML_NS)
private long partyId;
@Column(name = "UUID", unique = true, nullable = false)
@XmlElement(name = "uuid", namespace = CORE_XML_NS)
private String uuid;
/**
@ -105,6 +110,7 @@ public class Party implements Serializable {
*/
@Column(name = "NAME", length = 256, nullable = false)
@NotNull
@XmlElement(name = "name", namespace = CORE_XML_NS)
// @Pattern(regexp = "[a-zA-Z0-9\\-_\\.]*")
private String name;

View File

@ -26,7 +26,7 @@ import javax.enterprise.context.RequestScoped;
import java.io.Serializable;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @author <a href="mailto:tosmers@uni-bremen.de">Tobias Osmers</a>
* @version created on 3/23/17
*/
@RequestScoped
@ -43,14 +43,15 @@ public class PartyIdResolver implements Serializable, ObjectIdResolver {
@Override
public Object resolveId(final ObjectIdGenerator.IdKey id) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final PartyRepository partyRepository = cdiUtil
.findBean(PartyRepository.class);
return partyRepository
.findByName(id.key.toString())
.findByUuid(id.key.toString())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Party with name %s in the database.",
.format("No Party with uuid %s in the database.",
id.key.toString())));
}

View File

@ -67,6 +67,20 @@ public class PartyRepository extends AbstractEntityRepository<Long, Party> {
party.setUuid(UUID.randomUUID().toString());
}
public Optional<Party> findByUuid(final String uuid) {
final TypedQuery<Party> query = getEntityManager().createNamedQuery(
"Party.findByUuid", Party.class);
query.setParameter("uuid", uuid);
final List<Party> result = query.getResultList();
if (result.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(result.get(0));
}
}
/**
* Finds a {@link Party} (which can be a user or group) by its name.
*

View File

@ -24,13 +24,13 @@ import org.hibernate.search.annotations.ContainedIn;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.libreccm.core.CcmObject;
import org.libreccm.portation.Portable;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
@ -38,6 +38,9 @@ import java.util.Objects;
import static org.libreccm.core.CoreConstants.CORE_XML_NS;
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.libreccm.imexport.Exportable;
/**
* A permission grants a privilege on an object or system wide to {@link Role}.
*
@ -46,6 +49,9 @@ import static org.libreccm.core.CoreConstants.DB_SCHEMA;
@Entity
@Table(name = "PERMISSIONS", schema = DB_SCHEMA)
@NamedQueries({
@NamedQuery(name = "Permission.findByUuid",
query = "SELECT p FROM Permission p WHERE p.uuid = :uuid")
,
@NamedQuery(name = "Permission.findByCustomPermId",
query = "SELECT p FROM Permission p "
+ "WHERE p.grantedPrivilege = :privilege "
@ -93,10 +99,10 @@ import static org.libreccm.core.CoreConstants.DB_SCHEMA;
})
@XmlRootElement(name = "permission", namespace = CORE_XML_NS)
@XmlAccessorType(XmlAccessType.FIELD)
@JsonIdentityInfo(generator = PermissionIdGenerator.class,
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
resolver = PermissionIdResolver.class,
property = "customPermId")
public class Permission implements Serializable, Portable {
property = "uuid")
public class Permission implements Serializable, Exportable {
private static final long serialVersionUID = -5178045844045517958L;
@ -109,6 +115,10 @@ public class Permission implements Serializable, Portable {
@XmlElement(name = "permission-id", namespace = CORE_XML_NS)
private long permissionId;
@Column(name = "UUID", unique = true, nullable = false)
@XmlElement(name = "uuid", namespace = CORE_XML_NS)
private String uuid;
/**
* The granted privilege.
*/
@ -192,6 +202,15 @@ public class Permission implements Serializable, Portable {
this.permissionId = permissionId;
}
@Override
public String getUuid() {
return uuid;
}
protected void setUuid(final String uuid) {
this.uuid = uuid;
}
public String getGrantedPrivilege() {
return grantedPrivilege;
}

View File

@ -1,78 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.security;
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @version created on 3/23/17
*/
public class PermissionIdGenerator extends ObjectIdGenerator<String> {
private static final long serialVersionUID = -8762745860290577542L;
@Override
public Class<?> getScope() {
return Permission.class;
}
@Override
public boolean canUseFor(final ObjectIdGenerator<?> gen) {
return gen instanceof PermissionIdGenerator;
}
@Override
public ObjectIdGenerator<String> forScope(final Class<?> scope) {
return this;
}
@Override
public ObjectIdGenerator<String> newForSerialization(final Object context) {
return this;
}
@Override
public IdKey key(final Object key) {
if (key == null) {
return null;
}
return new IdKey(Permission.class, Permission.class, key);
}
@Override
public String generateId(final Object forPojo) {
if (!(forPojo instanceof Permission)) {
throw new IllegalArgumentException(
"Only Permission instances are supported.");
}
final Permission permission = (Permission) forPojo;
if (permission.getGrantee() == null &&
permission.getObject() == null) {
throw new IllegalStateException();
}
return String.join("_",
permission.getGrantedPrivilege(),
String.valueOf(permission.getGrantee().getName()),
String.valueOf(permission.getObject().getUuid())
);
}
}

View File

@ -21,13 +21,10 @@ package org.libreccm.security;
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdResolver;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.CcmObject;
import org.libreccm.core.CcmObjectRepository;
import org.libreccm.core.UnexpectedErrorException;
import javax.enterprise.context.RequestScoped;
import java.io.Serializable;
import java.util.Optional;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
@ -47,43 +44,16 @@ public class PermissionIdResolver implements Serializable, ObjectIdResolver {
@Override
public Object resolveId(final ObjectIdGenerator.IdKey id) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final CcmObjectRepository ccmObjectRepository = cdiUtil
.findBean(CcmObjectRepository.class);
final RoleRepository roleRepository = cdiUtil
.findBean(RoleRepository.class);
final PermissionRepository permissionRepository = cdiUtil
.findBean(PermissionRepository.class);
String[] customPermId = id.key.toString().split("_");
String privilege = customPermId[0];
final String granteeName = customPermId[1];
final String objectUuid = customPermId[2];
final Optional<CcmObject> object = ccmObjectRepository
.findObjectByUuid(objectUuid);
final Optional<Role> grantee = roleRepository
.findByName(granteeName);
if (!grantee.isPresent()) {
throw new UnexpectedErrorException(String.format(
"Role with id \"%s\" was not found in the database," +
" but has been associated with a permission.",
granteeName));
}
Optional<Permission> permission = permissionRepository
.findByCustomPermId(privilege,
grantee.get(),
object.orElse(null));
if (!permission.isPresent()) {
throw new UnexpectedErrorException(String.format(
"Permission with privilege \"%s\", grantee \"%s and " +
"object \"%s\" was not found in the database.",
privilege, grantee.toString(), object.toString()));
}
return permission.get();
return permissionRepository
.findByUuid(id.key.toString())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Permission with UUID %s in the database.",
id.key.toString())));
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
* Copyright (C) 2018 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -18,33 +18,36 @@
*/
package org.libreccm.security;
import org.libreccm.portation.AbstractMarshaller;
import org.libreccm.portation.Marshals;
import org.libreccm.imexport.AbstractEntityImExporter;
import org.libreccm.imexport.DependsOn;
import org.libreccm.imexport.Processes;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @version created on 11/7/16
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Marshals(User.class)
public class UserMarshaller extends AbstractMarshaller<User> {
private static final long serialVersionUID = -7857346915894246160L;
@Processes(Permission.class)
@DependsOn({Role.class})
public class PermissionImExporter extends AbstractEntityImExporter<Permission>{
@Inject
private UserRepository userRepository;
private PermissionRepository permissionRepository;
@Override
protected Class<User> getObjectClass() {
return User.class;
protected Class<Permission> getEntityClass() {
return Permission.class;
}
@Override
@Transactional(Transactional.TxType.REQUIRED)
protected void insertIntoDb(User portableObject) {
userRepository.save(portableObject);
protected void saveImportedEntity(final Permission entity) {
permissionRepository.save(entity);
}
}

View File

@ -23,7 +23,9 @@ import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import java.util.Optional;
import java.util.UUID;
/**
* A repository class for {@link Permission}.
@ -53,13 +55,27 @@ public class PermissionRepository
}
@Override
public boolean isNew(Permission entity) {
public boolean isNew(final Permission entity) {
if (entity == null) {
throw new IllegalArgumentException("Can't save null");
}
return entity.getPermissionId() == 0;
}
@Override
public void initNewEntity(final Permission permission) {
permission.setUuid(UUID.randomUUID().toString());
}
public Optional<Permission> findByUuid(final String uuid) {
final TypedQuery<Permission> query = getEntityManager()
.createNamedQuery("Permission.findByUuid", Permission.class);
query.setParameter("uuid", uuid);
return getSingleResult(query);
}
/**
* Finds a {@link Permission} by the privilege, the grantee and the object.
* Where the grantee has been granted the given privilege on the given

View File

@ -24,17 +24,45 @@ import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.hibernate.search.annotations.Field;
import org.hibernate.validator.constraints.NotBlank;
import org.libreccm.l10n.LocalizedString;
import org.libreccm.portation.Portable;
import org.libreccm.workflow.TaskAssignment;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import java.io.Serializable;
import java.util.*;
import static org.libreccm.core.CoreConstants.CORE_XML_NS;
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
import org.libreccm.imexport.Exportable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.persistence.AssociationOverride;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
/**
* A role is basically a collection a {@link Permission}s and {@code Task}s.
*
@ -43,6 +71,8 @@ import static org.libreccm.core.CoreConstants.DB_SCHEMA;
@Entity
@Table(name = "CCM_ROLES", schema = DB_SCHEMA)
@NamedQueries({
@NamedQuery(name = "Role.findByUuid",
query = "SELECT r FROM Role r WHERE r.uuid = :uuid"),
@NamedQuery(name = "Role.findByName",
query = "SELECT r FROM Role r "
+ "WHERE r.name = :name")
@ -118,8 +148,8 @@ import static org.libreccm.core.CoreConstants.DB_SCHEMA;
@SuppressWarnings({"PMD.ShortClassName", "PMD.TooManyMethods"})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
resolver = RoleIdResolver.class,
property = "name")
public class Role implements Serializable, Portable {
property = "uuid")
public class Role implements Serializable, Exportable {
private static final long serialVersionUID = -7121296514181469687L;
@ -134,6 +164,10 @@ public class Role implements Serializable, Portable {
@XmlElement(name = "role-id", namespace = CORE_XML_NS)
private long roleId;
@Column(name = "UUID", unique = true, nullable = false)
@XmlElement(name = "uuid", namespace = CORE_XML_NS)
private String uuid;
/**
* The name of the role. May only contain the letters a to z, A to Z, the
* numbers 0 to 9, the {@code -} (dash) and the {@code _} (underscore).
@ -194,6 +228,15 @@ public class Role implements Serializable, Portable {
this.roleId = roleId;
}
@Override
public String getUuid() {
return uuid;
}
protected void setUuid(final String uuid) {
this.uuid = uuid;
}
public String getName() {
return name;
}

View File

@ -48,9 +48,9 @@ public class RoleIdResolver implements Serializable, ObjectIdResolver {
.findBean(RoleRepository.class);
return roleRepository
.findByName(id.key.toString())
.findByUuid(id.key.toString())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Role with name %s in the database.",
.format("No Role with uuid %s in the database.",
id.key.toString())));
}

View File

@ -16,25 +16,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.imexport;
package org.libreccm.security;
import javax.enterprise.context.RequestScoped;
import javax.json.JsonObject;
import org.libreccm.imexport.AbstractEntityImExporter;
import org.libreccm.imexport.Processes;
import javax.inject.Inject;
/**
* Interface for importers/exporters. Implementations must be annotated with
* {@link Procsses} to register the implementation in the Import/Export service.
*
* Implementations must also be CDI beans. It is recommended that the beans
* are {@link RequestScoped}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @param <T> The type of the entity which is processed by the implementation.
*/
public interface EntityImExporter<T extends Exportable> {
@Processes(Role.class)
public class RoleImExporter extends AbstractEntityImExporter<Role> {
T importEntity(JsonObject data);
@Inject
private RoleRepository roleRepository;
JsonObject exportEntity(Exportable entity);
@Override
protected Class<Role> getEntityClass() {
return Role.class;
}
@Override
protected void saveImportedEntity(final Role entity) {
roleRepository.save(entity);
}
}

View File

@ -33,6 +33,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
@ -83,6 +84,7 @@ public class RoleManager implements Serializable {
}
final RoleMembership membership = new RoleMembership();
membership.setUuid(UUID.randomUUID().toString());
membership.setRole(role);
membership.setMember(party);

View File

@ -1,50 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.security;
import org.libreccm.portation.AbstractMarshaller;
import org.libreccm.portation.Marshals;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @version created on 11/7/16
*/
@RequestScoped
@Marshals(Role.class)
public class RoleMarshaller extends AbstractMarshaller<Role> {
private static final long serialVersionUID = -2150833120444479902L;
@Inject
private RoleRepository roleRepository;
@Override
protected Class<Role> getObjectClass() {
return Role.class;
}
@Override
@Transactional(Transactional.TxType.REQUIRED)
protected void insertIntoDb(Role portableObject) {
roleRepository.save(portableObject);
}
}

View File

@ -20,18 +20,31 @@ package org.libreccm.security;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import org.libreccm.portation.Portable;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import java.io.Serializable;
import java.util.Objects;
import static org.libreccm.core.CoreConstants.CORE_XML_NS;
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.libreccm.imexport.Exportable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* Association class representing the association between a {@link Role} and a
* {@code Party}.
@ -41,14 +54,17 @@ import static org.libreccm.core.CoreConstants.DB_SCHEMA;
@Entity
@Table(name = "ROLE_MEMBERSHIPS", schema = DB_SCHEMA)
@NamedQueries({
@NamedQuery(name = "RoleMembership.findByUuid",
query = "SELECT m FROM RoleMembership m WHERE m.uuid = :uuid")
,
@NamedQuery(name = "RoleMembership.findByRoleAndMember",
query = "SELECT m FROM RoleMembership m "
+ "WHERE m.member = :member AND m.role = :role")
})
@XmlRootElement(name = "role-membership", namespace = CORE_XML_NS)
@JsonIdentityInfo(generator = RoleMembershipIdGenerator.class,
property = "customMemId")
public class RoleMembership implements Serializable, Portable {
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "uuid")
public class RoleMembership implements Serializable, Exportable {
private static final long serialVersionUID = -3049727720697964793L;
@ -58,6 +74,10 @@ public class RoleMembership implements Serializable, Portable {
@XmlElement(name = "membership-id", namespace = CORE_XML_NS)
private long membershipId;
@Column(name = "UUID", unique = true, nullable = false)
@XmlElement(name = "uuid", namespace = CORE_XML_NS)
private String uuid;
@ManyToOne
@JoinColumn(name = "ROLE_ID")
@XmlTransient
@ -78,6 +98,15 @@ public class RoleMembership implements Serializable, Portable {
this.membershipId = membershipId;
}
@Override
public String getUuid() {
return uuid;
}
protected void setUuid(final String uuid) {
this.uuid = uuid;
}
public Role getRole() {
return role;
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.security;
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @version created on 3/23/17
*/
public class RoleMembershipIdGenerator extends ObjectIdGenerator<String> {
private static final long serialVersionUID = 801410727263488529L;
@Override
public Class<?> getScope() {
return RoleMembership.class;
}
@Override
public boolean canUseFor(final ObjectIdGenerator<?> gen) {
return gen instanceof RoleMembershipIdGenerator;
}
@Override
public ObjectIdGenerator<String> forScope(final Class<?> scope) {
return this;
}
@Override
public ObjectIdGenerator<String> newForSerialization(final Object context) {
return this;
}
@Override
public IdKey key(final Object key) {
if (key == null) {
return null;
}
return new IdKey(RoleMembership.class, RoleMembership.class, key);
}
@Override
public String generateId(final Object forPojo) {
if (!(forPojo instanceof RoleMembership)) {
throw new IllegalArgumentException(
"Only RoleMembership instances are supported.");
}
final RoleMembership membership = (RoleMembership) forPojo;
return String.format("{%s}{%s}",
membership.getRole().getName(),
membership.getMember().getName());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
* Copyright (C) 2018 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -18,38 +18,37 @@
*/
package org.libreccm.security;
import org.libreccm.portation.AbstractMarshaller;
import org.libreccm.portation.Marshals;
import org.libreccm.imexport.AbstractEntityImExporter;
import org.libreccm.imexport.DependsOn;
import org.libreccm.imexport.Processes;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
/**
* @author <a href="mailto:tosmers@uni-bremen.de">Tobias Osmers</a>
* @version created on 11/7/16
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Marshals(Permission.class)
public class PermissionMarshaller extends AbstractMarshaller<Permission> {
private static final long serialVersionUID = -5145925775270121916L;
@Processes(RoleMembership.class)
@DependsOn({User.class, Group.class, Role.class})
public class RoleMembershipImExporter
extends AbstractEntityImExporter<RoleMembership>{
@Inject
private EntityManager entityManager;
@Override
protected Class<Permission> getObjectClass() {
return Permission.class;
protected Class<RoleMembership> getEntityClass() {
return RoleMembership.class;
}
@Override
@Transactional(Transactional.TxType.REQUIRED)
protected void insertIntoDb(Permission portableObject) {
if (portableObject.getPermissionId() == 0) {
entityManager.persist(portableObject);
} else {
entityManager.merge(portableObject);
}
protected void saveImportedEntity(final RoleMembership entity) {
entityManager.persist(entity);
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.security;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.portation.AbstractMarshaller;
import org.libreccm.portation.Marshals;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
/**
* @author <a href="mailto:tosmers@uni-bremen.de">Tobias Osmers</a>
* @version created on 11/7/16
*/
@RequestScoped
@Marshals(RoleMembership.class)
public class RoleMembershipMarshaller extends AbstractMarshaller<RoleMembership> {
private static final long serialVersionUID = 1304404004268502935L;
private static final Logger LOGGER = LogManager.getLogger(RoleMembershipMarshaller.class);
@Inject
private EntityManager entityManager;
@Override
protected Class<RoleMembership> getObjectClass() {
return RoleMembership.class;
}
@Override
@Transactional(Transactional.TxType.REQUIRED)
protected void insertIntoDb(final RoleMembership portableObject) {
portableObject.setMembershipId(portableObject.getMembershipId() * -1);
entityManager.merge(portableObject);
entityManager.flush();
}
}

View File

@ -26,8 +26,10 @@ import javax.enterprise.context.RequestScoped;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* Repository class for {@link Role} entities.
@ -62,12 +64,28 @@ public class RoleRepository extends AbstractEntityRepository<Long, Role> {
return entity.getRoleId() == 0;
}
@Override
public void initNewEntity(final Role role) {
role.setUuid(UUID.randomUUID().toString());
}
public long count() {
final TypedQuery<Long> query = getEntityManager().createNamedQuery(
"Role.count", Long.class);
return query.getSingleResult();
}
public Optional<Role> findByUuid(final String uuid) {
final TypedQuery<Role> query = getEntityManager()
.createNamedQuery("Role.findByUuid", Role.class);
query.setParameter("uuid", uuid);
return getSingleResult(query);
}
/**
* Finds a role a its name.
*

View File

@ -22,7 +22,6 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.libreccm.core.EmailAddress;
import org.libreccm.portation.Portable;
import javax.validation.constraints.NotNull;
@ -73,6 +72,9 @@ import javax.xml.bind.annotation.XmlTransient;
@Entity
@Table(name = "USERS", schema = DB_SCHEMA)
@NamedQueries({
@NamedQuery(name = "User.findByUuid",
query = "SELECT u FROM User u WHERE u.uuid = :uuid")
,
@NamedQuery(name = "User.findByName",
query = "SELECT u FROM User u WHERE u.name = :name "
+ "ORDER BY u.name, "
@ -151,8 +153,8 @@ import javax.xml.bind.annotation.XmlTransient;
@SuppressWarnings({"PMD.ShortClassName", "PMD.LongVariable"})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
resolver = UserIdResolver.class,
property = "name")
public class User extends Party implements Serializable, Exportable, Portable {
property = "uuid")
public class User extends Party implements Serializable, Exportable {
private static final long serialVersionUID = 4035223413596611393L;

View File

@ -26,11 +26,12 @@ import javax.enterprise.context.RequestScoped;
import java.io.Serializable;
/**
* @author <a href="mailto:tosmers@uni-bremen.de>Tobias Osmers</a>
* @version created on 3/23/17
* @author <a href="mailto:tosmers@uni-bremen.de">Tobias Osmers</a>
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class UserIdResolver implements Serializable, ObjectIdResolver {
private static final long serialVersionUID = -2541656707906049331L;
@Override
@ -43,12 +44,13 @@ public class UserIdResolver implements Serializable, ObjectIdResolver {
@Override
public Object resolveId(final ObjectIdGenerator.IdKey id) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final UserRepository userRepository = cdiUtil
.findBean(UserRepository.class);
return userRepository
.findByName(id.key.toString())
.findByUuid(id.key.toString())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No User with name %s in the database.",
id.key.toString())));

View File

@ -18,12 +18,12 @@
*/
package org.libreccm.security;
import org.libreccm.imexport.EntityImExporter;
import org.libreccm.imexport.Exportable;
import org.libreccm.imexport.AbstractEntityImExporter;
import org.libreccm.imexport.Processes;
import javax.enterprise.context.RequestScoped;
import javax.json.JsonObject;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
@ -31,16 +31,21 @@ import javax.json.JsonObject;
*/
@RequestScoped
@Processes(User.class)
public class UserImExporter implements EntityImExporter<User> {
public class UserImExporter extends AbstractEntityImExporter<User> {
@Inject
private UserRepository userRepository;
@Override
public User importEntity(final JsonObject data) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
protected Class<User> getEntityClass() {
return User.class;
}
@Override
public JsonObject exportEntity(final Exportable entity) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
@Transactional(Transactional.TxType.REQUIRED)
protected void saveImportedEntity(final User entity) {
userRepository.save(entity);
}
}

View File

@ -61,6 +61,14 @@ public class UserRepository extends AbstractEntityRepository<Long, User> {
return user.getPartyId() == 0;
}
public Optional<User> findByUuid(final String uuid) {
final TypedQuery<User> query = getEntityManager().createNamedQuery(
"User.findByUuid", User.class);
query.setParameter("uuid", uuid);
return getSingleResult(query);
}
/**
* Finds a user by its user name.
*

View File

@ -0,0 +1,5 @@
alter table CCM_CORE.ROLES
add column UUID varchar(255) not null;
alter table CCM_CORE.ROLES
add constraint UK_rfmsjqsq6kagolsod3ufkugll unique (UUID);

View File

@ -0,0 +1,6 @@
alter table CCM_CORE.PERMISSIONS
add column UUID varchar(255) not null;
alter table CCM_CORE.PERMISSIONS
add constraint UK_p50se7rdexv7xnkiqsl6ijyti unique (UUID);

View File

@ -0,0 +1,7 @@
alter table CCM_CORE.GROUP_MEMBERSHIPS
add column UUID varchar(255) not null;
alter table CCM_CORE.GROUP_MEMBERSHIPS
add constraint UK_kkdoia60bmiwhhdru169p3n9g unique (UUID);

View File

@ -0,0 +1,7 @@
alter table CCM_CORE.ROLE_MEMBERSHIPS
add column UUID varchar(255) not null;
alter table CCM_CORE.ROLE_MEMBERSHIPS
add constraint UK_82wdq214bfs99eii71fp50s97 unique (UUID);

View File

@ -0,0 +1,5 @@
alter table CCM_CORE.ROLES
add column UUID varchar(255) not null;
alter table CCM_CORE.ROLES
add constraint UK_rfmsjqsq6kagolsod3ufkugll unique (UUID);

View File

@ -0,0 +1,6 @@
alter table CCM_CORE.PERMISSIONS
add column UUID varchar(255) not null;
alter table CCM_CORE.PERMISSIONS
add constraint UK_p50se7rdexv7xnkiqsl6ijyti unique (UUID);

View File

@ -0,0 +1,7 @@
alter table CCM_CORE.GROUP_MEMBERSHIPS
add column UUID varchar(255) not null;
alter table CCM_CORE.GROUP_MEMBERSHIPS
add constraint UK_kkdoia60bmiwhhdru169p3n9g unique (UUID);

View File

@ -0,0 +1,7 @@
alter table CCM_CORE.ROLE_MEMBERSHIPS
add column UUID varchar(255) not null;
alter table CCM_CORE.ROLE_MEMBERSHIPS
add constraint UK_82wdq214bfs99eii71fp50s97 unique (UUID);

View File

@ -4,6 +4,7 @@ drop sequence if exists HIBERNATE_SEQUENCE;
create schema CCM_CORE;
create table CCM_CORE.APPLICATIONS (
APPLICATION_TYPE varchar(1024) not null,
PRIMARY_URL varchar(1024) not null,
@ -94,6 +95,7 @@ drop sequence if exists HIBERNATE_SEQUENCE;
create table CCM_CORE.CCM_ROLES (
ROLE_ID bigint not null,
NAME varchar(512) not null,
UUID varchar(255) not null,
primary key (ROLE_ID)
);
@ -541,11 +543,11 @@ drop sequence if exists HIBERNATE_SEQUENCE;
SETTING_ID bigint not null,
CONFIGURATION_CLASS varchar(512) not null,
NAME varchar(512) not null,
SETTING_VALUE_LONG bigint,
SETTING_VALUE_BIG_DECIMAL decimal(19,2),
SETTING_VALUE_BOOLEAN boolean,
SETTING_VALUE_STRING varchar(1024),
SETTING_VALUE_DOUBLE double,
SETTING_VALUE_LONG bigint,
SETTING_VALUE_STRING varchar(1024),
primary key (SETTING_ID)
);
@ -771,6 +773,9 @@ drop sequence if exists HIBERNATE_SEQUENCE;
alter table CCM_CORE.CCM_OBJECTS
add constraint UK_1cm71jlagvyvcnkqvxqyit3wx unique (UUID);
alter table CCM_CORE.CCM_ROLES
add constraint UK_rfmsjqsq6kagolsod3ufkugll unique (UUID);
alter table CCM_CORE.HOSTS
add constraint UK9ramlv6uxwt13v0wj7q0tucsx unique (SERVER_NAME, SERVER_PORT);

View File

@ -2,8 +2,6 @@ drop schema if exists CCM_CORE cascade;
drop sequence if exists HIBERNATE_SEQUENCE;
create schema CCM_CORE;
create table CCM_CORE.APPLICATIONS (
APPLICATION_TYPE varchar(1024) not null,
PRIMARY_URL varchar(1024) not null,
@ -94,6 +92,7 @@ drop sequence if exists HIBERNATE_SEQUENCE;
create table CCM_CORE.CCM_ROLES (
ROLE_ID int8 not null,
NAME varchar(512) not null,
UUID varchar(255) not null,
primary key (ROLE_ID)
);
@ -541,11 +540,11 @@ drop sequence if exists HIBERNATE_SEQUENCE;
SETTING_ID int8 not null,
CONFIGURATION_CLASS varchar(512) not null,
NAME varchar(512) not null,
SETTING_VALUE_LONG int8,
SETTING_VALUE_BIG_DECIMAL numeric(19, 2),
SETTING_VALUE_BOOLEAN boolean,
SETTING_VALUE_STRING varchar(1024),
SETTING_VALUE_DOUBLE float8,
SETTING_VALUE_LONG int8,
SETTING_VALUE_STRING varchar(1024),
primary key (SETTING_ID)
);
@ -771,6 +770,9 @@ drop sequence if exists HIBERNATE_SEQUENCE;
alter table CCM_CORE.CCM_OBJECTS
add constraint UK_1cm71jlagvyvcnkqvxqyit3wx unique (UUID);
alter table CCM_CORE.CCM_ROLES
add constraint UK_rfmsjqsq6kagolsod3ufkugll unique (UUID);
alter table CCM_CORE.HOSTS
add constraint UK9ramlv6uxwt13v0wj7q0tucsx unique (SERVER_NAME, SERVER_PORT);

View File

@ -1,7 +1,9 @@
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
ccm_core.ccm_objects:
- object_id: -20001

View File

@ -1,7 +1,9 @@
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
ccm_core.ccm_objects:
- object_id: -20001

View File

@ -1,7 +1,9 @@
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
ccm_core.ccm_objects:
- object_id: -20001

View File

@ -1,7 +1,9 @@
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
ccm_core.ccm_objects:
- object_id: -20001

View File

@ -1,7 +1,9 @@
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
ccm_core.ccm_objects:
- object_id: -20001

View File

@ -1,7 +1,9 @@
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
ccm_core.ccm_objects:
- object_id: -20001

View File

@ -1,7 +1,9 @@
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
ccm_core.ccm_objects:
- object_id: -20001

View File

@ -1,7 +1,9 @@
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
ccm_core.ccm_objects:
- object_id: -20001

View File

@ -82,10 +82,13 @@ ccm_core.group_memberships:
member_id: -30
ccm_core.ccm_roles:
- role_id: -2000
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -2100
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
- role_id: -2200
uuid: 0e73623c-8d6a-4544-88a4-e4b104e7c0b6
name: role3
ccm_core.role_memberships:
# role1 <-> jdoe

View File

@ -82,10 +82,13 @@ ccm_core.group_memberships:
member_id: -30
ccm_core.ccm_roles:
- role_id: -2000
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -2100
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
- role_id: -2200
uuid: 0e73623c-8d6a-4544-88a4-e4b104e7c0b6
name: role3
ccm_core.role_memberships:
# role1 <-> group3

View File

@ -82,10 +82,13 @@ ccm_core.group_memberships:
member_id: -30
ccm_core.ccm_roles:
- role_id: -2000
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -2100
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
- role_id: -2200
uuid: 0e73623c-8d6a-4544-88a4-e4b104e7c0b6
name: role3
ccm_core.role_memberships:
# role1 <-> jdoe

View File

@ -1,5 +1,7 @@
ccm_core.ccm_roles:
- role_id: -10
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: administrator
- role_id: -30
uuid: 0e73623c-8d6a-4544-88a4-e4b104e7c0b6
name: reader

View File

@ -1,7 +1,10 @@
ccm_core.ccm_roles:
- role_id: -10
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: administrator
- role_id: -20
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: writer
- role_id: -30
uuid: 0e73623c-8d6a-4544-88a4-e4b104e7c0b6
name: reader

View File

@ -1,9 +1,13 @@
ccm_core.ccm_roles:
- role_id: -10
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: administrator
- role_id: -20
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: user
- role_id: -30
uuid: 0e73623c-8d6a-4544-88a4-e4b104e7c0b6
name: reader
- role_id: -40
uuid: 9feb2623-671a-4fd4-bd3f-1adc7f51f62e
name: editor

View File

@ -1,7 +1,10 @@
ccm_core.ccm_roles:
- role_id: -10
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: administrator
- role_id: -20
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: user
- role_id: -30
uuid: 0e73623c-8d6a-4544-88a4-e4b104e7c0b6
name: reader

View File

@ -98,10 +98,13 @@ ccm_core.group_memberships:
member_id: -41003
ccm_core.ccm_roles:
- role_id: -10001
uuid: 42038ba3-35b9-4894-843f-cb39ae1be763
name: role1
- role_id: -10002
uuid: c821a93d-78aa-4b87-ac1b-3e3229e0fdd9
name: role2
- role_id: -10003
uuid: 0e73623c-8d6a-4544-88a4-e4b104e7c0b6
name: public-role
ccm_core.role_memberships:
# role1 <-> group1