package edu.harvard.iq.dataverse.api;
import edu.harvard.iq.dataverse.authorization.groups.impl.ipaddress.IpGroup;
import edu.harvard.iq.dataverse.authorization.groups.impl.ipaddress.IpGroupProvider;
import edu.harvard.iq.dataverse.authorization.groups.impl.shib.ShibGroup;
import edu.harvard.iq.dataverse.authorization.groups.impl.shib.ShibGroupProvider;
import edu.harvard.iq.dataverse.util.json.JsonParser;
import javax.ejb.Stateless;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import static edu.harvard.iq.dataverse.util.json.JsonPrinter.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.annotation.PostConstruct;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonString;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.PathParam;
/**
*
* @author michael
*/
@Path("admin/groups")
@Stateless
public class Groups extends AbstractApiBean {
private static final Logger logger = Logger.getLogger(Groups.class.getName());
private IpGroupProvider ipGroupPrv;
private ShibGroupProvider shibGroupPrv;
Pattern legalGroupName = Pattern.compile("^[-_a-zA-Z0-9]+$");
@PostConstruct
void postConstruct() {
ipGroupPrv = groupSvc.getIpGroupProvider();
shibGroupPrv = groupSvc.getShibGroupProvider();
}
/**
* Creates a new {@link IpGroup}. The name of the group is based on the
* {@code alias:} field, but might be changed to ensure uniqueness.
* @param dto
* @return Response describing the created group or the error that prevented
* that group from being created.
*/
@POST
@Path("ip")
public Response postIpGroup( JsonObject dto ){
try {
IpGroup grp = new JsonParser().parseIpGroup(dto);
grp.setGroupProvider( ipGroupPrv );
grp.setPersistedGroupAlias(
ipGroupPrv.findAvailableName(
grp.getPersistedGroupAlias()==null ? "ipGroup" : grp.getPersistedGroupAlias()));
grp = ipGroupPrv.store(grp);
return created("/groups/ip/" + grp.getPersistedGroupAlias(), json(grp) );
} catch ( Exception e ) {
logger.log( Level.WARNING, "Error while storing a new IP group: " + e.getMessage(), e);
return error(Response.Status.INTERNAL_SERVER_ERROR, "Error: " + e.getMessage() );
}
}
/**
* Creates or updates the {@link IpGroup} named {@code groupName}.
* @param groupName Name of the group.
* @param dto data of the group.
* @return Response describing the created group or the error that prevented
* that group from being created.
*/
@PUT
@Path("ip/{groupName}")
public Response putIpGroups( @PathParam("groupName") String groupName, JsonObject dto ){
try {
if ( groupName == null || groupName.trim().isEmpty() ) {
return badRequest("Group name cannot be empty");
}
if ( ! legalGroupName.matcher(groupName).matches() ) {
return badRequest("Group name can contain only letters, digits, and the chars '-' and '_'");
}
IpGroup grp = new JsonParser().parseIpGroup(dto);
grp.setGroupProvider( ipGroupPrv );
grp.setPersistedGroupAlias( groupName );
grp = ipGroupPrv.store(grp);
return created("/groups/ip/" + grp.getPersistedGroupAlias(), json(grp) );
} catch ( Exception e ) {
logger.log( Level.WARNING, "Error while storing a new IP group: " + e.getMessage(), e);
return error(Response.Status.INTERNAL_SERVER_ERROR, "Error: " + e.getMessage() );
}
}
@GET
@Path("ip")
public Response listIpGroups() {
return ok( ipGroupPrv.findGlobalGroups()
.stream().map(g->json(g)).collect(toJsonArray()) );
}
@GET
@Path("ip/{groupIdtf}")
public Response getIpGroup( @PathParam("groupIdtf") String groupIdtf ) {
IpGroup grp;
if ( isNumeric(groupIdtf) ) {
grp = ipGroupPrv.get( Long.parseLong(groupIdtf) );
} else {
grp = ipGroupPrv.get(groupIdtf);
}
return (grp == null) ? notFound( "Group " + groupIdtf + " not found") : ok(json(grp));
}
@DELETE
@Path("ip/{groupIdtf}")
public Response deleteIpGroup( @PathParam("groupIdtf") String groupIdtf ) {
IpGroup grp;
if ( isNumeric(groupIdtf) ) {
grp = ipGroupPrv.get( Long.parseLong(groupIdtf) );
} else {
grp = ipGroupPrv.get(groupIdtf);
}
if (grp == null) return notFound( "Group " + groupIdtf + " not found");
try {
ipGroupPrv.deleteGroup(grp);
return ok("Group " + grp.getAlias() + " deleted.");
} catch ( Exception topExp ) {
// get to the cause (unwraps EJB exception wrappers).
Throwable e = topExp;
while ( e.getCause() != null ) {
e = e.getCause();
}
if ( e instanceof IllegalArgumentException ) {
return error(Response.Status.BAD_REQUEST, e.getMessage());
} else {
throw topExp;
}
}
}
@GET
@Path("shib")
public Response listShibGroups() {
JsonArrayBuilder arrBld = Json.createArrayBuilder();
for (ShibGroup g : shibGroupPrv.findGlobalGroups()) {
arrBld.add(json(g));
}
return ok(arrBld);
}
@POST
@Path("shib")
public Response createShibGroup(JsonObject shibGroupInput) {
String expectedNameKey = "name";
JsonString name = shibGroupInput.getJsonString(expectedNameKey);
if (name == null) {
return error(Response.Status.BAD_REQUEST, "required field missing: " + expectedNameKey);
}
String expectedAttributeKey = "attribute";
JsonString attribute = shibGroupInput.getJsonString(expectedAttributeKey);
if (attribute == null) {
return error(Response.Status.BAD_REQUEST, "required field missing: " + expectedAttributeKey);
}
String expectedPatternKey = "pattern";
JsonString pattern = shibGroupInput.getJsonString(expectedPatternKey);
if (pattern == null) {
return error(Response.Status.BAD_REQUEST, "required field missing: " + expectedPatternKey);
}
ShibGroup shibGroupToPersist = new ShibGroup(name.getString(), attribute.getString(), pattern.getString(), shibGroupPrv);
ShibGroup persitedShibGroup = shibGroupPrv.persist(shibGroupToPersist);
if (persitedShibGroup != null) {
return ok("Shibboleth group persisted: " + persitedShibGroup);
} else {
return error(Response.Status.BAD_REQUEST, "Could not persist Shibboleth group");
}
}
@DELETE
@Path("shib/{primaryKey}")
public Response deleteShibGroup( @PathParam("primaryKey") String id ) {
ShibGroup doomed = shibGroupPrv.get(id);
if (doomed != null) {
boolean deleted;
try {
deleted = shibGroupPrv.delete(doomed);
} catch (Exception ex) {
return error(Response.Status.BAD_REQUEST, ex.getMessage());
}
if (deleted) {
return ok("Shibboleth group " + id + " deleted");
} else {
return error(Response.Status.BAD_REQUEST, "Could not delete Shibboleth group with an id of " + id);
}
} else {
return error(Response.Status.BAD_REQUEST, "Could not find Shibboleth group with an id of " + id);
}
}
}