/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.intel.mtwilson.ms.rest;
import com.intel.mtwilson.i18n.ErrorCode;
import com.intel.mtwilson.ms.business.ApiClientBO;
import com.intel.mtwilson.datatypes.*;
import com.intel.mtwilson.ms.common.MSException;
import com.intel.mtwilson.security.annotations.PermitAll;
import com.intel.mtwilson.security.annotations.RolesAllowed;
import com.intel.dcsg.cpg.rfc822.Rfc822Date;
import com.intel.dcsg.cpg.validation.ValidationUtil;
import com.intel.mtwilson.launcher.ws.ext.V1;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
//import javax.ejb.Stateless;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* REST Web Service
*
* @author dsmagadx
*/
@V1
//@Stateless
@Path("/ManagementService/resources/apiclient")
public class APIClient {
private Logger log = LoggerFactory.getLogger(getClass());
/**
* Constructor must be public for framework to instantiate this REST API.
*/
public APIClient() {
}
/**
* Retrieves representation of an instance of com.intel.mountwilson.ms.rest.APIClient
* @return an instance of java.lang.String
*/
//@RolesAllowed({"Security"})
@RequiresPermissions("users:retrieve")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ApiClientInfo getApiClientInfo(@QueryParam("fingerprint") String fingerprintHex) {
ValidationUtil.validate(fingerprintHex);
byte[] fingerprint = fromHex(fingerprintHex);
return new ApiClientBO().find(fingerprint);
}
/**
* PUT method for updating or creating an instance of APIClient
* @param content representation for the resource
* @return
*/
//@RolesAllowed({"Security"})
@RequiresPermissions({"users:store"})
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
public String updateApiClient(ApiClientUpdateRequest apiClientRequest) {
ValidationUtil.validate(apiClientRequest);
new ApiClientBO().update(apiClientRequest, null);
return "OK";
}
/**
* POST method for creating an instance of APIClient. The
* difference between this method and registerApiClient is that
* this method allows an administrator to add arbitrary credentials
* and this request is authenticated and requires the Security role,
* whereas registerApiClient is a public API (non-authenticated) and
* must be self-signed.
* @param ApiClientCreateRequest
* @return
*/
//@RolesAllowed({"Security"})
@RequiresPermissions("users:create")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
public String addApiClient(ApiClientCreateRequest apiClientRequest) {
ValidationUtil.validate(apiClientRequest);
new ApiClientBO().create(apiClientRequest);
return "OK";
}
/**
* Retrieves representation of an instance of com.intel.mountwilson.ms.rest.APIClient
* @return an instance of java.lang.String
*/
@Path("/availableRoles")
@RequiresPermissions("users:search")
//@RolesAllowed({"Security"})
@GET
@Produces(MediaType.APPLICATION_JSON)
public Role[] listAvailableRoles() {
return new Role[] { Role.Security, Role.Whitelist, Role.Attestation, Role.Report, Role.Audit, Role.AssetTagManagement,
Role.Administrator, Role.AssetTagManager, Role.Auditor, Role.Challenger, Role.HostManager, Role.ReportManager,
Role.ServerManager, Role.UserManager, Role.WhitelistManager, Role.TlsPolicyManager};
}
/**
* Returns a list of ApiClientInfo based on the search criteria provided.
* Currently only ONE search criteria at a time is supported. In future
* versions combinations may be supported (expiresBefore=... and issuerEqualTo...)
* @return an instance of java.lang.String
*/
@Path("/search")
//@RolesAllowed({"Security"})
@RequiresPermissions("users:search")
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<ApiClientInfo> searchApiClientInfo(
@QueryParam("enabledEqualTo") String enabledEqualTo,
@QueryParam("expiresAfter") String expiresAfter,
@QueryParam("expiresBefore") String expiresBefore,
@QueryParam("fingerprintEqualTo") String fingerprintEqualTo,
@QueryParam("issuerEqualTo") String issuerEqualTo,
@QueryParam("nameContains") String nameContains,
@QueryParam("nameEqualTo") String nameEqualTo,
@QueryParam("serialNumberEqualTo") String serialNumberEqualTo,
@QueryParam("statusEqualTo") String statusEqualTo
) {
// first, construct an ApiClientSearchCriteria object.
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
ApiClientSearchCriteria criteria = new ApiClientSearchCriteria();
try {
if( enabledEqualTo != null ) {
ValidationUtil.validate(enabledEqualTo);
criteria.enabledEqualTo = Boolean.valueOf(enabledEqualTo); // deserialize from "true" or "false"
}
if( expiresAfter != null ) {
ValidationUtil.validate(expiresAfter);
criteria.expiresAfter = dateFormat.parse(expiresAfter);
}
if( expiresBefore != null ) {
ValidationUtil.validate(expiresBefore);
criteria.expiresBefore = dateFormat.parse(expiresBefore);
}
if( fingerprintEqualTo != null ) {
ValidationUtil.validate(fingerprintEqualTo);
criteria.fingerprintEqualTo = Hex.decodeHex(fingerprintEqualTo.toCharArray());
}
if( issuerEqualTo != null ) {
ValidationUtil.validate(issuerEqualTo);
criteria.issuerEqualTo = issuerEqualTo;
}
if( nameContains != null ) {
ValidationUtil.validate(nameContains);
criteria.nameContains = nameContains;
}
if( nameEqualTo != null ) {
ValidationUtil.validate(nameEqualTo);
criteria.nameEqualTo = nameEqualTo;
}
if( serialNumberEqualTo != null ) {
ValidationUtil.validate(serialNumberEqualTo);
criteria.serialNumberEqualTo = Integer.valueOf(serialNumberEqualTo);
}
if( statusEqualTo != null ) {
ValidationUtil.validate(statusEqualTo);
criteria.statusEqualTo = statusEqualTo;
}
}
catch(ParseException e) {
log.error("Error parsing input.", e);
throw new MSException(ErrorCode.MS_ERROR_PARSING_INPUT, "Cannot parse date: "+e.getMessage()+" (should be yyyy-MM-dd)");
}
catch(DecoderException e) {
log.error("Error parsing input.", e);
throw new MSException(ErrorCode.MS_ERROR_PARSING_INPUT, "Cannot parse fingerprint: "+e.getMessage()+" (should be hex)");
}
return new ApiClientBO().search(criteria);
}
/**
* POST method for creating an instance of APIClient whose status is
* "Pending" and is disabled. Then a user can approve it via the
* management application. The
* difference between this method and addApiClient is that addApiClient
* allows an administrator to add arbitrary credentials and requires the
* Security role, where as this method is a public API (non-authenticated) and
* must be self-signed.
* @param ApiClientCreateRequest
* @return
*/
//@PermitAll - If nothing is specified, then the access is open to everyone
@POST
@Path("/register")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
public String registerApiClient(ApiClientCreateRequest apiClientRequest) {
ValidationUtil.validate(apiClientRequest);
log.debug("API client registration: {}", Base64.encodeBase64String(apiClientRequest.getCertificate()));
new ApiClientBO().create(apiClientRequest);
return "OK";
}
/**
* DELETE method for resource APIClient
*/
//@RolesAllowed({"Security"})
@RequiresPermissions("users:delete")
@DELETE
public void delete(@QueryParam("fingerprint") String fingerprintHex) {
ValidationUtil.validate(fingerprintHex);
byte[] fingerprint = fromHex(fingerprintHex);
ApiClientBO bo = new ApiClientBO();
ApiClientSearchCriteria criteria = new ApiClientSearchCriteria();
criteria.fingerprintEqualTo = fingerprint;
List<ApiClientInfo> userList = bo.search(criteria);
if (userList != null && userList.size() == 1) {
log.debug("Found the user to delete.");
ApiClientInfo info = userList.get(0);
//ApiClientInfo info = bo.find(fingerprint);
ApiClientUpdateRequest apiClientRequest = new ApiClientUpdateRequest();
apiClientRequest.fingerprint = fingerprint;
apiClientRequest.enabled = false;
apiClientRequest.status = ApiClientStatus.CANCELLED.toString();
if (info.comment == null || info.comment.isEmpty()){
apiClientRequest.comment = String.format("Deleted on %s", Rfc822Date.format(new Date()));
}
else{
apiClientRequest.comment = String.format("%s. Deleted on %s", info.comment, Rfc822Date.format(new Date()));
}
// Removing the roles as well
apiClientRequest.roles = new String[]{}; //info.roles;
bo.update(apiClientRequest, null);
} else {
log.debug("Did not find the user with fingerprint {} in the system. ", fingerprintHex);
}
}
private byte[] fromHex(String hex) {
try {
return Hex.decodeHex(hex.toCharArray());
} catch (DecoderException ex) {
log.error("Error parsing input.", ex);
throw new MSException(ErrorCode.MS_ERROR_PARSING_INPUT, "Invalid fingerprint");
}
}
}