parent
422f37747d
commit
38d541c18d
|
|
@ -92,6 +92,12 @@
|
||||||
<artifactId>flyway-core</artifactId>
|
<artifactId>flyway-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- OpenAPI/Swagger Annoations for documenting the RESTful API
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger.core.v3</groupId>
|
||||||
|
<artifactId>swagger-annotations</artifactId>
|
||||||
|
</dependency>-->
|
||||||
|
|
||||||
<!-- Dependencies for log4j 2 -->
|
<!-- Dependencies for log4j 2 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,10 @@
|
||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package org.libreccm.core.api;
|
package org.libreccm.api;
|
||||||
|
|
||||||
import org.libreccm.api.CorsFilter;
|
import org.libreccm.security.GroupsApi;
|
||||||
import org.libreccm.api.DefaultResponseHeaders;
|
import org.libreccm.security.RolesApi;
|
||||||
import org.libreccm.api.PreflightRequestFilter;
|
|
||||||
import org.libreccm.security.UsersApi;
|
import org.libreccm.security.UsersApi;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
@ -20,17 +19,22 @@ import javax.ws.rs.core.Application;
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
*/
|
*/
|
||||||
@ApplicationPath("/api")
|
@ApplicationPath("/api/admin")
|
||||||
public class CcmCoreApi extends Application {
|
public class AdminApi extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Class<?>> getClasses() {
|
public Set<Class<?>> getClasses() {
|
||||||
|
|
||||||
final Set<Class<?>> classes = new HashSet<>();
|
final Set<Class<?>> classes = new HashSet<>();
|
||||||
|
|
||||||
classes.add(CorsFilter.class);
|
classes.add(CorsFilter.class);
|
||||||
classes.add(DefaultResponseHeaders.class);
|
classes.add(DefaultResponseHeaders.class);
|
||||||
classes.add(PreflightRequestFilter.class);
|
classes.add(PreflightRequestFilter.class);
|
||||||
|
|
||||||
|
classes.add(GroupsApi.class);
|
||||||
|
classes.add(RolesApi.class);
|
||||||
classes.add(UsersApi.class);
|
classes.add(UsersApi.class);
|
||||||
|
|
||||||
|
|
||||||
return classes;
|
return classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,466 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.core.CoreConstants;
|
||||||
|
import org.libreccm.core.api.ExtractedIdentifier;
|
||||||
|
import org.libreccm.core.api.IdentifierExtractor;
|
||||||
|
import org.libreccm.core.api.JsonArrayCollector;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import javax.enterprise.context.RequestScoped;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.json.JsonArray;
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.json.JsonObjectBuilder;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.DefaultValue;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.WebApplicationException;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
@RequestScoped
|
||||||
|
@Path("/groups")
|
||||||
|
public class GroupsApi {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private IdentifierExtractor identifierExtractor;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private GroupManager groupManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private GroupRepository groupRepository;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private RoleManager roleManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private RoleRepository roleRepository;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private UserManager userManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public JsonArray getGroups(
|
||||||
|
@QueryParam("limit") @DefaultValue("20") final int limit,
|
||||||
|
@QueryParam("offset") @DefaultValue("0") final int offset
|
||||||
|
) {
|
||||||
|
return groupRepository
|
||||||
|
.findAll(limit, offset)
|
||||||
|
.stream()
|
||||||
|
.map(Group::buildJson)
|
||||||
|
.map(JsonObjectBuilder::build)
|
||||||
|
.collect(new JsonArrayCollector());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{groupIdentifier}")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public JsonObject getGroup(
|
||||||
|
@PathParam("groupIdentifier") final String identifierParam
|
||||||
|
) {
|
||||||
|
return findGroup(identifierParam).toJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public Response addGroup(final JsonObject groupData) {
|
||||||
|
if (groupData.isNull("name")
|
||||||
|
|| groupData.getString("name").matches("\\s*")) {
|
||||||
|
return Response
|
||||||
|
.status(Response.Status.BAD_REQUEST)
|
||||||
|
.entity("Name of new group is missing.")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
final String name = groupData.getString("name");
|
||||||
|
|
||||||
|
if (groupRepository.findByName(name).isPresent()) {
|
||||||
|
return Response
|
||||||
|
.status(Response.Status.CONFLICT)
|
||||||
|
.entity(
|
||||||
|
String.format(
|
||||||
|
"A group with the name %s already exists.",
|
||||||
|
name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Group group = new Group();
|
||||||
|
group.setName(name);
|
||||||
|
groupRepository.save(group);
|
||||||
|
|
||||||
|
return Response
|
||||||
|
.status(Response.Status.CREATED)
|
||||||
|
.contentLocation(
|
||||||
|
URI.create(String.format("/api/groups/%s", group.getName()))
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{groupIdentifier}")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public Response updateGroup(
|
||||||
|
@PathParam("groupIdentifier") final String groupIdentifier,
|
||||||
|
final JsonObject groupData
|
||||||
|
) {
|
||||||
|
final Group group = findGroup(groupIdentifier);
|
||||||
|
|
||||||
|
boolean updated = false;
|
||||||
|
if (!groupData.isNull("name")
|
||||||
|
&& !groupData.getString("name").matches("\\s*")
|
||||||
|
&& !groupData.getString("name").equals(group.getName())) {
|
||||||
|
group.setName(groupData.getString("name"));
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updated) {
|
||||||
|
groupRepository.save(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response
|
||||||
|
.status(Response.Status.OK)
|
||||||
|
.entity(
|
||||||
|
String.format(
|
||||||
|
"Group %s updated successfully.", group.getName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{groupIdentifier}")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public Response deleteGroup(
|
||||||
|
@PathParam("groupIdentifier") final String groupIdentifier
|
||||||
|
) {
|
||||||
|
final Group group = findGroup(groupIdentifier);
|
||||||
|
final String name = group.getName();
|
||||||
|
groupRepository.delete(group);
|
||||||
|
return Response
|
||||||
|
.ok(String.format("Group %s deleted successfully.", name))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{groupIdentifier}/members")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public JsonArray getMembers(
|
||||||
|
@PathParam("groupIdentifier") final String groupIdentifier
|
||||||
|
) {
|
||||||
|
return findGroup(groupIdentifier)
|
||||||
|
.getMemberships()
|
||||||
|
.stream()
|
||||||
|
.map(GroupMembership::toJson)
|
||||||
|
.collect(new JsonArrayCollector());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{groupIdentifier}/members/{userIdentifier}")
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public Response addMember(
|
||||||
|
@PathParam("groupIdentifier") final String groupIdentifier,
|
||||||
|
@PathParam("userIdentifier") final String userIdentifier
|
||||||
|
) {
|
||||||
|
final Group group = findGroup(groupIdentifier);
|
||||||
|
final User user = findUser(userIdentifier);
|
||||||
|
|
||||||
|
groupManager.addMemberToGroup(user, group);
|
||||||
|
|
||||||
|
return Response
|
||||||
|
.ok(
|
||||||
|
String.format(
|
||||||
|
"User %s successfully added to group %s.",
|
||||||
|
user.getName(),
|
||||||
|
group.getName()
|
||||||
|
)
|
||||||
|
).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{groupIdentifier}/members/{userIdentifier}")
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public Response removeMember(
|
||||||
|
@PathParam("groupIdentifier") final String groupIdentifier,
|
||||||
|
@PathParam("userIdentifier") final String userIdentifier
|
||||||
|
) {
|
||||||
|
final Group group = findGroup(groupIdentifier);
|
||||||
|
final User user = findUser(userIdentifier);
|
||||||
|
|
||||||
|
groupManager.removeMemberFromGroup(user, group);
|
||||||
|
|
||||||
|
return Response
|
||||||
|
.ok()
|
||||||
|
.entity(
|
||||||
|
String.format(
|
||||||
|
"User %s successfully removed to group %s.",
|
||||||
|
user.getName(),
|
||||||
|
group.getName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{groupIdentifier}/roles")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public JsonArray getRoleMemberships(
|
||||||
|
@PathParam("groupIdentifier")
|
||||||
|
final String groupIdentifier
|
||||||
|
) {
|
||||||
|
return findGroup(groupIdentifier)
|
||||||
|
.getRoleMemberships()
|
||||||
|
.stream()
|
||||||
|
.map(RoleMembership::toJson)
|
||||||
|
.collect(new JsonArrayCollector());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{groupIdentifier}/groups/{roleIdentifier}")
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public Response addRoleMembership(
|
||||||
|
@PathParam("groupIdentifier")
|
||||||
|
final String groupIdentifier,
|
||||||
|
@PathParam("roleIdentifier")
|
||||||
|
final String roleIdentifier
|
||||||
|
) {
|
||||||
|
final Group group = findGroup(groupIdentifier);
|
||||||
|
final Role role = findRole(roleIdentifier);
|
||||||
|
|
||||||
|
roleManager.assignRoleToParty(role, group);
|
||||||
|
|
||||||
|
return Response
|
||||||
|
.ok()
|
||||||
|
.entity(
|
||||||
|
String.format(
|
||||||
|
"Role %s successfully assigned to group %s.",
|
||||||
|
role.getName(),
|
||||||
|
group.getName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{groupIdentifier}/groups/{roleIdentifier}")
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public Response removeRoleMembership(
|
||||||
|
@PathParam("groupIdentifier")
|
||||||
|
final String groupIdentifier,
|
||||||
|
@PathParam("roleIdentifier")
|
||||||
|
final String roleIdentifier
|
||||||
|
) {
|
||||||
|
final Group group = findGroup(groupIdentifier);
|
||||||
|
final Role role = findRole(roleIdentifier);
|
||||||
|
|
||||||
|
roleManager.removeRoleFromParty(role, group);
|
||||||
|
|
||||||
|
return Response
|
||||||
|
.ok()
|
||||||
|
.entity(
|
||||||
|
String.format(
|
||||||
|
"Role %s successfully removed from group %s.",
|
||||||
|
role.getName(),
|
||||||
|
group.getName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Group findGroup(final String groupIdentifier) {
|
||||||
|
final ExtractedIdentifier identifier = identifierExtractor
|
||||||
|
.extractIdentifier(groupIdentifier);
|
||||||
|
|
||||||
|
switch (identifier.getType()) {
|
||||||
|
case ID:
|
||||||
|
return groupRepository
|
||||||
|
.findById(Long.parseLong(identifier.getIdentifier()))
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No group with ID %s found",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND
|
||||||
|
)
|
||||||
|
);
|
||||||
|
case UUID:
|
||||||
|
return groupRepository
|
||||||
|
.findByUuid(identifier.getIdentifier())
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No group with UUID %s found.",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND
|
||||||
|
)
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return groupRepository
|
||||||
|
.findByName(identifier.getIdentifier())
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No group with name %s found.",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Role findRole(final String roleIdentifier) {
|
||||||
|
final ExtractedIdentifier identifier = identifierExtractor
|
||||||
|
.extractIdentifier(roleIdentifier);
|
||||||
|
|
||||||
|
switch (identifier.getType()) {
|
||||||
|
case ID:
|
||||||
|
return roleRepository
|
||||||
|
.findById(Long.parseLong(identifier.getIdentifier()))
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No role with ID %s found.",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND
|
||||||
|
)
|
||||||
|
);
|
||||||
|
case UUID:
|
||||||
|
return roleRepository
|
||||||
|
.findByUuid(identifier.getIdentifier())
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No role with UUID %s found.",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND
|
||||||
|
)
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return roleRepository
|
||||||
|
.findByName(identifier.getIdentifier())
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No role with name %s found.",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private User findUser(final String identifierParam) {
|
||||||
|
final ExtractedIdentifier identifier = identifierExtractor
|
||||||
|
.extractIdentifier(identifierParam);
|
||||||
|
|
||||||
|
switch (identifier.getType()) {
|
||||||
|
case ID:
|
||||||
|
return userRepository
|
||||||
|
.findById(Long.parseLong(identifier.getIdentifier()))
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No user with ID %s found.",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND)
|
||||||
|
);
|
||||||
|
case UUID:
|
||||||
|
return userRepository
|
||||||
|
.findByUuid(identifier.getIdentifier())
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No user with UUID %s found.",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND)
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return userRepository
|
||||||
|
.findByName(identifier.getIdentifier())
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
String.format(
|
||||||
|
"No user with name %s found.",
|
||||||
|
identifier.getIdentifier()
|
||||||
|
),
|
||||||
|
Response.Status.NOT_FOUND)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,6 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
|
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
|
||||||
import org.hibernate.search.annotations.Field;
|
import org.hibernate.search.annotations.Field;
|
||||||
import org.hibernate.validator.constraints.NotBlank;
|
|
||||||
import org.libreccm.l10n.LocalizedString;
|
import org.libreccm.l10n.LocalizedString;
|
||||||
import org.libreccm.workflow.TaskAssignment;
|
import org.libreccm.workflow.TaskAssignment;
|
||||||
|
|
||||||
|
|
@ -57,6 +56,7 @@ import javax.persistence.NamedQuery;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.OrderBy;
|
import javax.persistence.OrderBy;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.libreccm.security;
|
||||||
|
|
||||||
|
import javax.enterprise.context.RequestScoped;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
@RequestScoped
|
||||||
|
@Path("/roles")
|
||||||
|
public class RolesApi {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -46,6 +46,8 @@ import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Provides RESTful API endpoints for managing users. Access to all endpoints
|
||||||
|
* defined by this class requires admin privileges.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
*/
|
*/
|
||||||
|
|
@ -74,6 +76,14 @@ public class UsersApi {
|
||||||
@Inject
|
@Inject
|
||||||
private UserRepository userRepository;
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all users.
|
||||||
|
*
|
||||||
|
* @param limit How many users should be retrieved?
|
||||||
|
* @param offset The first user to retrieve
|
||||||
|
*
|
||||||
|
* @return A JSON array with the all users.
|
||||||
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/")
|
@Path("/")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
|
@ -92,6 +102,13 @@ public class UsersApi {
|
||||||
.collect(new JsonArrayCollector());
|
.collect(new JsonArrayCollector());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a specific user.
|
||||||
|
*
|
||||||
|
* @param identifierParam The identifier for the user.
|
||||||
|
*
|
||||||
|
* @return A JSON representation of the user.
|
||||||
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/{userIdentifier}")
|
@Path("/{userIdentifier}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
|
@ -104,6 +121,19 @@ public class UsersApi {
|
||||||
return findUser(identifierParam).toJson();
|
return findUser(identifierParam).toJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user.
|
||||||
|
*
|
||||||
|
* @param userData The data from which the user is generated.
|
||||||
|
*
|
||||||
|
* @return A HTTP response indicating the success or failure of the user
|
||||||
|
* generation. A 201 (Created) response code is send if the user was
|
||||||
|
* created successfully together with the URL of the new user. If
|
||||||
|
* the provided data does not contain a required value a response
|
||||||
|
* with the 400 (Bad Request) status code is returned. If a user
|
||||||
|
* with the name provided by the user data already exists a response
|
||||||
|
* with a 409 (Conflict) response is returned.
|
||||||
|
*/
|
||||||
@POST
|
@POST
|
||||||
@Path("/")
|
@Path("/")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
|
@ -111,7 +141,6 @@ public class UsersApi {
|
||||||
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Response addUser(final JsonObject userData) {
|
public Response addUser(final JsonObject userData) {
|
||||||
|
|
||||||
final String givenName;
|
final String givenName;
|
||||||
if (userData.isNull("givenName")) {
|
if (userData.isNull("givenName")) {
|
||||||
givenName = null;
|
givenName = null;
|
||||||
|
|
@ -188,6 +217,16 @@ public class UsersApi {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a user.
|
||||||
|
*
|
||||||
|
* @param userIdentifier The identifier of the user to update.
|
||||||
|
* @param userData The updated of the user. Please note that the name
|
||||||
|
* of a user can't be updated. If the user data
|
||||||
|
* contains a value for this property it is ignored.
|
||||||
|
*
|
||||||
|
* @return A 200 (OK) response if the user is succesfully updated.
|
||||||
|
*/
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/{userIdentifier}")
|
@Path("/{userIdentifier}")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
|
@ -195,8 +234,7 @@ public class UsersApi {
|
||||||
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Response updateUser(
|
public Response updateUser(
|
||||||
@PathParam("userIdentifier")
|
@PathParam("userIdentifier") final String userIdentifier,
|
||||||
final String userIdentifier,
|
|
||||||
final JsonObject userData
|
final JsonObject userData
|
||||||
) {
|
) {
|
||||||
final User user = findUser(userIdentifier);
|
final User user = findUser(userIdentifier);
|
||||||
|
|
@ -236,6 +274,12 @@ public class UsersApi {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a user.
|
||||||
|
*
|
||||||
|
* @param userIdentifier The identifier of the user to delete.
|
||||||
|
* @return A 200 (OK) response if the user was deleted successfully.
|
||||||
|
*/
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{userIdentifier}")
|
@Path("/{userIdentifier}")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
|
@ -243,8 +287,7 @@ public class UsersApi {
|
||||||
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Response deleteUser(
|
public Response deleteUser(
|
||||||
@PathParam("userIdentifier")
|
@PathParam("userIdentifier") final String userIdentifier
|
||||||
final String userIdentifier
|
|
||||||
) {
|
) {
|
||||||
final User user = findUser(userIdentifier);
|
final User user = findUser(userIdentifier);
|
||||||
final String name = user.getName();
|
final String name = user.getName();
|
||||||
|
|
@ -262,8 +305,7 @@ public class UsersApi {
|
||||||
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public JsonArray getGroupMemberships(
|
public JsonArray getGroupMemberships(
|
||||||
@PathParam("userIdentifier")
|
@PathParam("userIdentifier") final String userIdentifier
|
||||||
final String userIdentifier
|
|
||||||
) {
|
) {
|
||||||
return findUser(userIdentifier)
|
return findUser(userIdentifier)
|
||||||
.getGroupMemberships()
|
.getGroupMemberships()
|
||||||
|
|
@ -278,10 +320,8 @@ public class UsersApi {
|
||||||
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Response addGroupMembership(
|
public Response addGroupMembership(
|
||||||
@PathParam("userIdentifier")
|
@PathParam("userIdentifier") final String userIdentifier,
|
||||||
final String userIdentifier,
|
@PathParam("groupIdentifier") final String groupIdentifier
|
||||||
@PathParam("groupIdentifier")
|
|
||||||
final String groupIdentifier
|
|
||||||
) {
|
) {
|
||||||
final User user = findUser(userIdentifier);
|
final User user = findUser(userIdentifier);
|
||||||
final Group group = findGroup(groupIdentifier);
|
final Group group = findGroup(groupIdentifier);
|
||||||
|
|
@ -306,10 +346,8 @@ public class UsersApi {
|
||||||
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Response removeGroupMembership(
|
public Response removeGroupMembership(
|
||||||
@PathParam("userIdentifier")
|
@PathParam("userIdentifier") final String userIdentifier,
|
||||||
final String userIdentifier,
|
@PathParam("groupIdentifier") final String groupIdentifier
|
||||||
@PathParam("groupIdentifier")
|
|
||||||
final String groupIdentifier
|
|
||||||
) {
|
) {
|
||||||
final User user = findUser(userIdentifier);
|
final User user = findUser(userIdentifier);
|
||||||
final Group group = findGroup(groupIdentifier);
|
final Group group = findGroup(groupIdentifier);
|
||||||
|
|
@ -320,7 +358,7 @@ public class UsersApi {
|
||||||
.ok()
|
.ok()
|
||||||
.entity(
|
.entity(
|
||||||
String.format(
|
String.format(
|
||||||
"User %s successfully removed to group %s.",
|
"User %s successfully removed from group %s.",
|
||||||
user.getName(),
|
user.getName(),
|
||||||
group.getName()
|
group.getName()
|
||||||
)
|
)
|
||||||
|
|
@ -358,9 +396,9 @@ public class UsersApi {
|
||||||
) {
|
) {
|
||||||
final User user = findUser(userIdentifier);
|
final User user = findUser(userIdentifier);
|
||||||
final Role role = findRole(roleIdentifier);
|
final Role role = findRole(roleIdentifier);
|
||||||
|
|
||||||
roleManager.assignRoleToParty(role, user);
|
roleManager.assignRoleToParty(role, user);
|
||||||
|
|
||||||
return Response
|
return Response
|
||||||
.ok()
|
.ok()
|
||||||
.entity(
|
.entity(
|
||||||
|
|
@ -386,9 +424,9 @@ public class UsersApi {
|
||||||
) {
|
) {
|
||||||
final User user = findUser(userIdentifier);
|
final User user = findUser(userIdentifier);
|
||||||
final Role role = findRole(roleIdentifier);
|
final Role role = findRole(roleIdentifier);
|
||||||
|
|
||||||
roleManager.removeRoleFromParty(role, user);
|
roleManager.removeRoleFromParty(role, user);
|
||||||
|
|
||||||
return Response
|
return Response
|
||||||
.ok()
|
.ok()
|
||||||
.entity(
|
.entity(
|
||||||
|
|
|
||||||
17
pom.xml
17
pom.xml
|
|
@ -720,6 +720,23 @@
|
||||||
<artifactId>woodstox-core-asl</artifactId>
|
<artifactId>woodstox-core-asl</artifactId>
|
||||||
<version>4.4.1</version>
|
<version>4.4.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- OpenAPI Spec Generation -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger.core.v3</groupId>
|
||||||
|
<artifactId>swagger-jaxrs2</artifactId>
|
||||||
|
<version>2.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger.core.v3</groupId>
|
||||||
|
<artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
|
||||||
|
<version>2.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger.core.v3</groupId>
|
||||||
|
<artifactId>swagger-annotations</artifactId>
|
||||||
|
<version>2.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
**********************
|
**********************
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue