/*
* Copyright (C) 2011-2012 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson;
import com.intel.mtwilson.i18n.ErrorCode;
import com.intel.mtwilson.security.http.apache.ApacheHmacHttpAuthorization;
import com.intel.mtwilson.security.http.apache.ApacheRsaHttpAuthorization;
import com.intel.mountwilson.as.hostmanifestreport.data.HostManifestReportType;
import com.intel.mountwilson.as.hosttrustreport.data.HostsTrustReportType;
import com.intel.mtwilson.api.MtWilson;
import com.intel.dcsg.cpg.crypto.CryptographyException;
import com.intel.dcsg.cpg.crypto.HmacCredential;
import com.intel.dcsg.cpg.crypto.PasswordHash;
import com.intel.mtwilson.api.*;
import com.intel.dcsg.cpg.crypto.RsaCredential;
import com.intel.dcsg.cpg.crypto.RsaCredentialX509;
import com.intel.dcsg.cpg.crypto.SimpleKeystore;
import com.intel.dcsg.cpg.x509.X509Util;
import com.intel.mtwilson.model.*;
import com.intel.mtwilson.datatypes.*;
import com.intel.mtwilson.datatypes.xml.HostTrustXmlResponse;
import com.intel.mtwilson.datatypes.xml.HostTrustXmlResponseList;
import com.intel.dcsg.cpg.io.ConfigurationUtil;
import com.intel.mtwilson.security.http.*;
import com.intel.dcsg.cpg.tls.policy.TlsPolicy;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import static javax.ws.rs.core.MediaType.*;
import javax.ws.rs.core.MultivaluedMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intel.dcsg.cpg.rfc822.Headers;
//import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.intel.dcsg.cpg.xml.JAXB;
import com.intel.mtwilson.security.http.apache.ApacheBasicHttpAuthorization;
import java.util.Locale;
import org.apache.http.auth.UsernamePasswordCredentials;
/**
* This class has many constructors to provide convenience for developers.
* However, too many options may be confusing.
* Based on developer feedback, we should retain the most useful constructors
* and deprecate the rest.
* Two candidates for KEEPING are (File) and (URL,Hmac/RsaCredential,SimpleKeystore).
* Those two constructors provide the two extremes: with (File), all properties in a file,
* developer specifies the path for easy integration into any system); with
* (URL,Hmac/RsaCredential,SimpleKeystore) a developer is able to instantiate a secure
* ApiClient completely in Java without requiring a configuration file (it will enable
* requireTrustedCertificate and verifyHostname).
* @since 0.5.2
* @author jbuhacoff
*/
public class ApiClient implements MtWilson, AttestationService, WhitelistService, ManagementService {
private static Logger log = LoggerFactory.getLogger(ApiClient.class);
// private JerseyHttpClient httpClient;
private ApacheHttpClient httpClient;
private URL baseURL; // https://attestationservice.local:443
private String attestationServicePath = "/AttestationService/resources"; // or /AttestationHandler/resources
private String whitelistServicePath = "/WLMService/resources";
private String managementServicePath = "/ManagementService/resources";
// private Credential credential;
// private HmacCredential hmacCredential;
// private RsaCredential rsaCredential;
protected static final ObjectMapper mapper = new ObjectMapper();
private static final String defaultConfigurationFilename = "mtwilson.properties";
// private ClassLoader jaxbClassLoader = null;
private JAXB jaxb = new JAXB();
private Locale locale = Locale.getDefault();
private SimpleKeystore keystore;
/**
* Loads configuration from the specified file.
*
* The configuration file must include the web service base URL and
* authentication information.
*
* @param configurationFilename
* @throws ClientException that may wrap NoSuchAlgorithmException, KeyManagementException, MalformedURLException, UnsupportedEncodingException, KeyStoreException, IOException, UnrecoverableEntryException, or CertificateException
* @throws IOException if there was a problem reading the specified file
*/
public ApiClient(File configurationFile) throws ClientException, IOException {
this(ConfigurationUtil.fromPropertiesFile(configurationFile));
log.debug("Initialized with configuration file: "+configurationFile.getAbsolutePath());
}
public ApiClient(Properties properties) throws ClientException {
this(new MapConfiguration(properties));
}
/**
* Instantiates an ApiClient using the provided configuration. It must
* include the base URL and authentication credentials.
*
* @param config
* @throws ClientException that may wrap NoSuchAlgorithmException, KeyManagementException, MalformedURLException, UnsupportedEncodingException, KeyStoreException, IOException, UnrecoverableEntryException, or CertificateException
*/
public ApiClient(Configuration config) throws ClientException {
try {
setBaseURL(config.getString("mtwilson.api.baseurl"));
//log.debug("Base URL: "+baseURL.toExternalForm());
/*
httpClient = new JerseyHttpClient(baseURL.toExternalForm(), config.getString("mtwilson.api.clientId"), config.getString("mtwilson.api.secretKey"));
*/
setKeystore(config);
setHttpClientWithConfig(config);
}
catch(Exception e) {
throw new ClientException("Cannot initialize client", e);
}
}
/**
* Instantiates an ApiClient using the provided base URL and authentication
* credential, and using configuration information from the provided properties.
*
* @param baseURL
* @param credential
* @param properties
* @throws ClientException that may wrap NoSuchAlgorithmException, KeyManagementException, MalformedURLException, UnsupportedEncodingException, KeyStoreException, IOException, or CertificateException
*/
public ApiClient(URL baseURL, HmacCredential credential, Properties properties) throws ClientException {
try {
setBaseURL(baseURL);
Configuration config = new MapConfiguration(properties);
setKeystore(config);
setLocale(properties);
log.debug("Base URL: "+baseURL.toExternalForm());
httpClient = new ApacheHttpClient(baseURL, new ApacheHmacHttpAuthorization(credential), keystore, config);
httpClient.setLocale(locale);
log.debug("HMAC-256 Identity: "+new String(credential.identity(), "UTF-8"));
}
catch(Exception e) {
throw new ClientException("Cannot initialize client", e);
}
}
/**
* Instantiates an ApiClient using the provided base URL and authentication
* credential, and using configuration information from the provided properties.
*
* @param baseURL
* @param credential
* @param properties
* @throws ClientException that may wrap NoSuchAlgorithmException, KeyManagementException, MalformedURLException, UnsupportedEncodingException, KeyStoreException, IOException, or CertificateException
*/
public ApiClient(URL baseURL, RsaCredential credential, Properties properties) throws ClientException {
try {
setBaseURL(baseURL);
Configuration config = new MapConfiguration(properties);
setKeystore(config);
setLocale(properties);
log.debug("Base URL: "+baseURL.toExternalForm());
httpClient = new ApacheHttpClient(baseURL, new ApacheRsaHttpAuthorization(credential), keystore, config);
httpClient.setLocale(locale);
log.debug("RSA Identity: "+new String(credential.identity(), "UTF-8"));
}
catch(Exception e) {
throw new ClientException("Cannot initialize client", e);
}
}
/**
* This constructor automatically enables requireTrustedCertificate and verifyHostname
* because a keystore is specified. If you want to specify a keystore yet not
* require trusted certificates or verify hostnames, use the Configuration constructor.
* @param baseURL
* @param credential
* @param keystore
* @throws ClientException that may wrap NoSuchAlgorithmException, KeyManagementException, MalformedURLException, UnsupportedEncodingException, KeyStoreException, IOException, or CertificateException
*/
public ApiClient(URL baseURL, HmacCredential credential, SimpleKeystore keystore, Configuration config) throws ClientException {
try {
setBaseURL(baseURL);
setKeystore(keystore);
setLocale(config);
log.debug("Base URL: "+baseURL.toExternalForm());
httpClient = new ApacheHttpClient(baseURL, new ApacheHmacHttpAuthorization(credential), keystore, config);
httpClient.setLocale(locale);
log.debug("HMAC-256 Identity: "+new String(credential.identity(), "UTF-8"));
}
catch(Exception e) {
throw new ClientException("Cannot initialize client", e);
}
}
/**
* This constructor automatically enables requireTrustedCertificate and verifyHostname
* because a keystore is specified. If you want to specify a keystore yet not
* require trusted certificates or verify hostnames, use the Configuration constructor.
* @param baseURL
* @param credential
* @param keystore
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
* @throws MalformedURLException
* @throws UnsupportedEncodingException
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
*/
public ApiClient(URL baseURL, RsaCredential credential, SimpleKeystore keystore, Configuration config) throws ClientException {
try {
setBaseURL(baseURL);
setKeystore(keystore);
setLocale(config);
log.debug("Base URL: "+baseURL.toExternalForm());
httpClient = new ApacheHttpClient(baseURL, new ApacheRsaHttpAuthorization(credential), keystore, config);
httpClient.setLocale(locale);
log.debug("RSA Identity: "+new String(credential.identity(), "UTF-8"));
}
catch(Exception e) {
throw new ClientException("Cannot initialize client", e);
}
}
public ApiClient(URL baseURL, RsaCredential credential, SimpleKeystore keystore, TlsPolicy tlsPolicy) throws ClientException {
try {
setBaseURL(baseURL);
setKeystore(keystore);
log.debug("Base URL: "+baseURL.toExternalForm());
httpClient = new ApacheHttpClient(baseURL, new ApacheRsaHttpAuthorization(credential), keystore, tlsPolicy);
httpClient.setLocale(locale);
log.debug("RSA Identity: "+new String(credential.identity(), "UTF-8"));
}
catch(Exception e) {
throw new ClientException("Cannot initialize client", e);
}
}
private void setBaseURL(URL url) {
if( url == null ) {
throw new IllegalArgumentException("Base URL must not be null");
}
baseURL = url;
}
private void setBaseURL(String url) throws MalformedURLException {
if( url == null ) {
throw new IllegalArgumentException("Base URL must not be null");
}
baseURL = new URL(url);
}
/**
* Prefers RSA-SHA256 authentication (mtwilson.api.keystore and mtwilson.api.key.alias),
* then HMAC-SHA256 authentication (mtwilson.api.clientId and mtwilson.api.secretKey),
* then no authentication.
*
* @param config
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws CertificateException
* @throws UnrecoverableEntryException
* @throws IOException
* @throws KeyManagementException
*/
private void setHttpClientWithConfig(Configuration config) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableEntryException, IOException, KeyManagementException, com.intel.dcsg.cpg.crypto.CryptographyException {
// if( config.containsKey("mtwilson.api.keystore") && config.containsKey("mtwilson.api.keystore.password") && config.containsKey("mtwilson.api.key.alias") ) {
if( keystore != null ) {
RsaCredentialX509 rsaCredential = keystore.getRsaCredentialX509(config.getString("mtwilson.api.key.alias"), config.getString("mtwilson.api.key.password"));
// RsaCredential rsaCredential = RsaUtil.fromKeystore(config);
setKeystore(config);
setLocale(config);
httpClient = new ApacheHttpClient(baseURL, new ApacheRsaHttpAuthorization(rsaCredential), keystore, config);
httpClient.setLocale(locale);
Hex hex = new Hex();
log.debug("RSA Identity: "+hex.encode(rsaCredential.identity()));
}
else if( config.containsKey("mtwilson.api.clientId") && config.containsKey("mtwilson.api.secretKey") ) {
HmacCredential hmacCredential = new HmacCredential(config.getString("mtwilson.api.clientId"), config.getString("mtwilson.api.secretKey"));
setKeystore(config);
setLocale(config);
httpClient = new ApacheHttpClient(baseURL, new ApacheHmacHttpAuthorization(hmacCredential), keystore, config);
httpClient.setLocale(locale);
log.debug("HMAC-256 Identity: "+new String(hmacCredential.identity(), "UTF-8"));
}
else if( config.containsKey("mtwilson.api.username") && config.containsKey("mtwilson.api.password") ) {
UsernamePasswordCredentials passwordCredential = new UsernamePasswordCredentials(config.getString("mtwilson.api.username"), config.getString("mtwilson.api.password"));
setKeystore(config);
setLocale(config);
httpClient = new ApacheHttpClient(baseURL, new ApacheBasicHttpAuthorization(passwordCredential), keystore, config);
httpClient.setLocale(locale);
log.debug("HTTP BASIC Identity: {}", config.getString("mtwilson.api.username"));
}
else {
// no authentication
setKeystore(config);
setLocale(config);
httpClient = new ApacheHttpClient(baseURL, null, keystore, config);
httpClient.setLocale(locale);
log.info("No identity configured");
}
}
private void setKeystore(Configuration config) throws KeyManagementException {
if( config != null && config.containsKey("mtwilson.api.keystore") && config.containsKey("mtwilson.api.keystore.password") ) {
keystore = new SimpleKeystore(new File(config.getString("mtwilson.api.keystore")), config.getString("mtwilson.api.keystore.password"));
}
else if( config != null && config.containsKey("javax.net.ssl.keyStore") && config.containsKey("javax.net.ssl.keyStorePassword") ) {
keystore = new SimpleKeystore(new File(config.getString("javax.net.ssl.keyStore")), config.getString("javax.net.ssl.keyStorePassword"));
}
}
public final void setKeystore(SimpleKeystore keystore) {
this.keystore = keystore;
}
private void setLocale(Properties properties) {
String language = properties.getProperty("user.language","");
String country = properties.getProperty("user.country","");
if( !language.isEmpty() && !country.isEmpty() ) {
locale = new Locale(language, country);
}
if( !language.isEmpty() ) {
locale = new Locale(language);
}
}
private void setLocale(Configuration config) {
String language = config.getString("user.language","");
String country = config.getString("user.country","");
if( !language.isEmpty() && !country.isEmpty() ) {
locale = new Locale(language, country);
}
if( !language.isEmpty() ) {
locale = new Locale(language);
}
}
public void setLocale(Locale locale) {
this.locale = locale;
if( httpClient != null ) {
httpClient.setLocale(locale);
}
}
/**
* Some environments such as OSGi require the use of their own ClassLoader
* when using JAXB. Use this method to set the ClassLoader that should be
* used when deserializing XML responses with JAXB.
* The default is to use the system class loader.
* @param classLoader to use with JAXB, or null to use the default class loader
*/
public void setJaxbClassLoader(ClassLoader classLoader) {
// jaxbClassLoader = classLoader;
jaxb.setJaxbClassLoader(classLoader);
}
/**
* Call this to ensure that all HTTP connections and files are closed
* when your are done using the API Client.
*/
public void close() {
// connectionManager.shutdown();
}
private String querystring(MultivaluedMap<String,String> query) {
URLCodec urlsafe = new URLCodec("UTF-8");
String queryString = "";
ArrayList<String> params = new ArrayList<String>();
for( String key : query.keySet() ) {
if( query.get(key) == null ) {
params.add(key+"=");
}
else {
for( String value : query.get(key) ) {
try {
params.add(key+"="+urlsafe.encode(value));
} catch (EncoderException ex) {
log.error("Cannot encode query parameter: {}", value, ex);
}
}
}
queryString = StringUtils.join(params, "&");
}
return queryString;
}
protected String asurl(String apiPath) {
return baseURL.toExternalForm().concat(attestationServicePath).concat(apiPath);
}
protected String asurl(String apiPath, MultivaluedMap<String,String> query) {
return baseURL.toExternalForm().concat(attestationServicePath).concat(apiPath).concat("?").concat(querystring(query));
}
protected String wlmurl(String apiPath) {
return baseURL.toExternalForm().concat(whitelistServicePath).concat(apiPath);
}
protected String wlmurl(String apiPath, MultivaluedMap<String,String> query) {
return baseURL.toExternalForm().concat(whitelistServicePath).concat(apiPath).concat("?").concat(querystring(query));
}
protected String msurl(String apiPath) {
return baseURL.toExternalForm().concat(managementServicePath).concat(apiPath);
}
protected String msurl(String apiPath, MultivaluedMap<String,String> query) {
return baseURL.toExternalForm().concat(managementServicePath).concat(apiPath).concat("?").concat(querystring(query));
}
protected ApiResponse httpGet(String path) throws IOException, ApiException, SignatureException {
return httpClient.get(path);
}
protected ApiResponse httpGet(String path, Headers headers) throws IOException, ApiException, SignatureException {
return httpClient.get(path, headers);
}
protected ApiResponse httpDelete(String path) throws IOException, ApiException, SignatureException {
return httpClient.delete(path);
}
protected ApiResponse httpDelete(String path, Headers headers) throws IOException, ApiException, SignatureException {
return httpClient.delete(path, headers);
}
protected ApiResponse httpPut(String path, ApiRequest body) throws IOException, ApiException, SignatureException {
return httpClient.put(path, body);
}
protected ApiResponse httpPut(String path, ApiRequest body, Headers headers) throws IOException, ApiException, SignatureException {
return httpClient.put(path, body, headers);
}
protected ApiResponse httpPost(String path, ApiRequest body) throws IOException, ApiException, SignatureException {
return httpClient.post(path, body);
}
protected ApiResponse httpPost(String path, ApiRequest body, Headers headers) throws IOException, ApiException, SignatureException {
return httpClient.post(path, body, headers);
}
// only call this if the Http Status is NOT OK in order to convert the response to an ApiException
private ApiException error(ApiResponse response) throws IOException, ApiException {
if( response.contentType.isCompatible(APPLICATION_JSON_TYPE) ) {
// a json error response from the web application. we need to provide the error message to the user.
ErrorResponse errorResponse;
try {
//log.debug("Parsing JSON error response: "+new String(response.content, "UTF-8"));
log.debug("Parsing JSON error response: "+new String(response.content, "UTF-8"));
errorResponse = json(new String(response.content, "UTF-8"), ErrorResponse.class);
}
catch(Exception e) {
// cannot parse the json response, so include the entire response for the user. we ignore the exception "e" because it just means we couldn't parse the response.
//e.printstacktrace()
// Daniel, do something to print the stack trace so you can follow it.
//
return new ApiException(response, "Cannot parse response: "+e.getMessage(), ErrorCode.UNKNOWN_ERROR);
}
return new ApiException(response, errorResponse.getErrorMessage(), ErrorCode.valueOf(errorResponse.getErrorCode()));
}
else if( response.contentType.isCompatible(TEXT_HTML_TYPE) ) {
// typically html error message generated by web application container; we can ignore the html content because its generic
String errorMessage = response.httpReasonPhrase;
HtmlErrorParser errorParser = new HtmlErrorParser(new String(response.content, "UTF-8"));
if( errorParser.getRootCause() != null ) {
errorMessage = errorMessage.concat(": "+errorParser.getRootCause());
}
return new ApiException(response, errorMessage, httpErrorCode(response.httpStatusCode));
}
else {
// a non-json, non-html error response from the web application: so we include the response in the exception message. http 401 unauthorized responses are included here.
return new ApiException(response, new String(response.content, "UTF-8"), httpErrorCode(response.httpStatusCode));
}
}
private ErrorCode httpErrorCode(int httpErrorCode) {
ErrorCode e;
switch(httpErrorCode) {
case 200: e = ErrorCode.OK; break;
case 400: e = ErrorCode.HTTP_INVALID_REQUEST; break;
case 401: e = ErrorCode.HTTP_UNAUTHORIZED; break;
case 403: e = ErrorCode.HTTP_FORBIDDEN; break;
case 404: e = ErrorCode.HTTP_NOT_FOUND; break;
case 500: e = ErrorCode.HTTP_INTERNAL_SERVER_ERROR; break;
default: e = ErrorCode.UNKNOWN_ERROR; break;
}
return e;
}
private byte[] content(ApiResponse response) throws IOException, ApiException {
log.trace("Status: {} {}", response.httpStatusCode, response.httpReasonPhrase);
//log.trace("Content-Type: {}", response.contentType.toString()); #2014-02-17 rksavinx removed due to dependency issue with tomcat for org.glassfish.jersey
log.trace("Content: {}", response.content);
if( response.httpStatusCode == HttpStatus.SC_OK ) {
return response.content;
} else if (response.httpStatusCode == HttpStatus.SC_NO_CONTENT) {
return new byte[0];
} else {
throw error(response);
}
}
/*
private <T> T deserialize(HttpResponse response, Class<T> valueType) throws IOException, ApiException {
String body = responsebody(response);
String contentType = response.getEntity() != null && response.getEntity().getContentType() != null ? response.getEntity().getContentType().getValue() : "";
if( "application/json".equals(contentType) ) {
return fromJSON(body, valueType);
}
else {
return null;
}
}*/
private String text(ApiResponse response) throws IOException, ApiException {
return new String(content(response), "UTF-8");
}
private byte[] binary(ApiResponse response) throws IOException, ApiException {
return content(response);
}
private <T> T json(ApiResponse response, Class<T> valueType) throws IOException, ApiException {
if( response.httpStatusCode == HttpStatus.SC_OK && response.contentType.isCompatible(APPLICATION_JSON_TYPE) ) {
return json(new String(response.content, "UTF-8"), valueType);
}
else if( response.httpStatusCode == HttpStatus.SC_OK ) {
log.error("Unexpected content type {} in response", response.contentType.toString());
throw new ApiException(response, "Unexpected content type in response: "+response.contentType.toString());
}
else {
throw error(response);
}
}
private <T> T json(String document, Class<T> valueType) throws IOException, ApiException {
if( document == null ) {
throw new ApiException("Response from server has no content");
}
try {
return mapper.readValue(document, valueType);
}
catch(com.fasterxml.jackson.core.JsonParseException e) {
log.error("Cannot parse response: "+document);
throw new ApiException("Cannot parse response: "+document, e);
}
}
private <T> T fromJSON(ApiResponse response, Class<T> valueType) throws IOException, ApiException {
return json(response, valueType);
}
private ApiRequest toJSON(Object value) throws IOException {
return new ApiRequest(APPLICATION_JSON_TYPE, mapper.writeValueAsString(value));
}
private <T> T xml(ApiResponse response, Class<T> valueType) throws IOException, ApiException {
if( response.httpStatusCode == HttpStatus.SC_OK && response.contentType.isCompatible(APPLICATION_XML_TYPE) ) {
return xml(new String(response.content, "UTF-8"), valueType);
}
else if( response.httpStatusCode == HttpStatus.SC_OK ) {
log.error("Unexpected content type {} in response", response.contentType.toString());
throw new ApiException(response, "Unexpected content type in response: "+response.contentType.toString());
}
else {
throw error(response);
}
}
private <T> T xml(String document, Class<T> valueType) throws IOException, ApiException {
try {
// bug #1038 use secure xml parsing settings
return jaxb.read(document, valueType);
}
catch(Exception e) {
throw new ApiException("Cannot parse response: "+document, e);
}
}
private <T> T fromXML(ApiResponse response, Class<T> valueType) throws IOException, ApiException, JAXBException {
return xml(response, valueType);
}
/**
*
* @param response an HttpResponse from GET, PUT, POST, or DELETE request
* @return String content from server response
* @throws IOException
*/
/*
private String plaintext(HttpResponse response) throws IOException {
return IOUtils.toString(response.getEntity().getContent(), "UTF-8");
}
*/
// Attestation Service API
/**
* javax.ws.rs.core.MediaType.APPLICATION_JSON application/json
* @param hostname
*/
@Override
public HostLocation getHostLocation(Hostname hostname) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
HostLocation location = fromJSON(httpGet(asurl("/hosts/location", query)), HostLocation.class);
return location;
}
@Override
public boolean addHostLocation(HostLocation hostLocObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(asurl("/hosts/location"), toJSON(hostLocObj)));
return "true".equals(result);
}
/**
*
* @param trustStatusString like "BIOS:1,VMM:1" from API version 0.5.1
* @return
*/
private HostTrustStatus parseHostTrustStatusString(String trustStatusString) {
HostTrustStatus trustStatus = new HostTrustStatus();
String[] parts = trustStatusString.split(",");
for (String part : parts) {
String[] subParts = part.split(":");
if (subParts[0].equals("BIOS")) {
trustStatus.bios = subParts[1].equals("1");
}
else if(subParts[0].equals("VMM")) {
trustStatus.vmm = subParts[1].equals("1");
}
}
return trustStatus;
}
/**
* /hosts/trust?hostname=1.2.3.4
* Response is PLAINTEXT ("BIOS:1,VMM:1") but needs to be changed to JSON on server (todo) so we support both.
* @param hostname
* @return
*/
@Override
public HostTrustResponse getHostTrust(Hostname hostname) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
// need to support both formats: "BIOS:1,VMM:1" from 0.5.1 and JSON from 0.5.2
ApiResponse response = httpClient.get(asurl("/hosts/trust", query));
HostTrustResponse trust;
if( response.httpStatusCode == HttpStatus.SC_OK ) {
if( APPLICATION_JSON_TYPE.equals(response.contentType) ) {
trust = json(response, HostTrustResponse.class);
}
else if( TEXT_PLAIN_TYPE.equals(response.contentType) ) {
trust = new HostTrustResponse(hostname, parseHostTrustStatusString(text(response)));
}
else {
throw new ApiException(response, "Unexpected content type in response: "+response.contentType, ErrorCode.UNKNOWN_ERROR.getErrorCode());
}
return trust;
}
else {
throw error(response);
}
}
@Override
public HostResponse addHost(TxtHost host) throws IOException, ApiException, SignatureException, MalformedURLException {
HostResponse added = fromJSON(httpPost(asurl("/hosts"), toJSON(new TxtHostRecord(host))), HostResponse.class);
return added;
}
@Override
public HostConfigResponseList addHosts(TxtHostRecordList hostRecords) throws IOException, ApiException, SignatureException {
HostConfigResponseList results = fromJSON(httpPost(asurl("/hosts/bulk"), toJSON(hostRecords)), HostConfigResponseList.class);
return results;
}
@Override
public HostResponse updateHost(TxtHost host) throws IOException, ApiException, SignatureException, MalformedURLException {
HostResponse added = fromJSON(httpPut(asurl("/hosts"), toJSON(new TxtHostRecord(host))), HostResponse.class);
return added;
}
@Override
public HostConfigResponseList updateHosts(TxtHostRecordList hostRecords) throws IOException, ApiException, SignatureException {
HostConfigResponseList results = fromJSON(httpPut(asurl("/hosts/bulk"), toJSON(hostRecords)), HostConfigResponseList.class);
return results;
}
@Override
public HostResponse deleteHost(Hostname hostname) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
HostResponse deleted = fromJSON(httpDelete(asurl("/hosts", query)), HostResponse.class);
return deleted;
}
@Override
public AttestationReport getAttestationFailureReport(Hostname hostname) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
query.add("failure_only", Boolean.toString(true));
AttestationReport report = fromJSON(httpGet(asurl("/hosts/reports/attestationreport", query)), AttestationReport.class);
return report;
}
@Override
public AttestationReport getAttestationReport(Hostname hostname) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
AttestationReport report = fromJSON(httpGet(asurl("/hosts/reports/attestationreport", query)), AttestationReport.class);
return report;
}
@Override
public X509Certificate getTlsCertificateForTrustedHost(Hostname hostname) throws IOException, ApiException, SignatureException {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Returns a set of X509Certificate objects comprised of the Mt Wilson Root CA and any intermediate CA's that
* are available.
*
* Note: this method returns only CA certs, which does NOT return the server's TLS certificate or SAML certificate.
*
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException Do
*/
/*
@Override
public Set<X509Certificate> getCaCertificates() throws IOException, ApiException, SignatureException {
try {
List<X509Certificate> rootCaCerts = X509Util.decodePemCertificates(rootca);
List<X509Certificate> privacyCaCerts = X509Util.decodePemCertificates(privacyca);
List<X509Certificate> samlCaCerts = X509Util.decodePemCertificates(samlca);
List<X509Certificate> tlsCaCerts = X509Util.decodePemCertificates(tlsca);
HashSet<X509Certificate> cacerts = new HashSet<X509Certificate>();
cacerts.addAll(rootCaCerts);
cacerts.addAll(privacyCaCerts);
cacerts.addAll(samlCaCerts);
cacerts.addAll(tlsCaCerts);
for(X509Certificate cert : cacerts) {
if( cert.getBasicConstraints() == -1 ) { // -1 indicates the certificate is not a CA cert; 0 and above indicates a CA cert
cacerts.remove(cert);
}
}
return cacerts;
} catch (CertificateException ex) {
throw new ApiException("Invalid certificate", ex);
}
}*/
@Override
public X509Certificate getSamlCertificate() throws IOException, ApiException, SignatureException {
byte[] certificateBytes = binary(httpGet(msurl("/saml/certificate")));
X509Certificate certificate;
try {
certificate = X509Util.decodeDerCertificate(certificateBytes);
} catch (CertificateException ex) {
throw new ApiException("Cannot read certificate from response", ex);
}
return certificate;
}
@Override
public Set<X509Certificate> getRootCaCertificates() throws IOException, ApiException, SignatureException {
String rootca = text(httpGet(msurl("/ca/certificate/rootca/current")));
try {
List<X509Certificate> rootCaCerts = X509Util.decodePemCertificates(rootca);
HashSet<X509Certificate> cacerts = new HashSet<X509Certificate>();
cacerts.addAll(rootCaCerts);
// we expect that these are all CA certs, so we are not specifically checking:
/*
for(X509Certificate cert : cacerts) {
if( cert.getBasicConstraints() == -1 ) { // -1 indicates the certificate is not a CA cert; 0 and above indicates a CA cert
cacerts.remove(cert);
}
}*/
return cacerts;
} catch (CertificateException ex) {
throw new ApiException("Invalid certificate", ex);
}
}
@Override
public Set<X509Certificate> getPrivacyCaCertificates() throws IOException, ApiException, SignatureException {
String privacyca = text(httpGet(msurl("/ca/certificate/privacyca/current")));
try {
List<X509Certificate> privacyCaCerts = X509Util.decodePemCertificates(privacyca);
HashSet<X509Certificate> cacerts = new HashSet<X509Certificate>();
cacerts.addAll(privacyCaCerts);
// we expect that these are all CA certs, so we are not specifically checking:
/*
for(X509Certificate cert : cacerts) {
if( cert.getBasicConstraints() == -1 ) { // -1 indicates the certificate is not a CA cert; 0 and above indicates a CA cert
cacerts.remove(cert);
}
}*/
return cacerts;
} catch (CertificateException ex) {
throw new ApiException("Invalid certificate", ex);
}
}
// includes the server's saml certificate and any root certificates if available
@Override
public Set<X509Certificate> getSamlCertificates() throws IOException, ApiException, SignatureException {
String samlca = text(httpGet(msurl("/ca/certificate/saml/current")));
try {
List<X509Certificate> samlCaCerts = X509Util.decodePemCertificates(samlca);
HashSet<X509Certificate> certs = new HashSet<X509Certificate>();
certs.addAll(samlCaCerts);
return certs;
} catch (CertificateException ex) {
throw new ApiException("Invalid certificate", ex);
}
}
// includes the server's tls certificate and any root certificates if available
@Override
public Set<X509Certificate> getTlsCertificates() throws IOException, ApiException, SignatureException {
String tlsca = text(httpGet(msurl("/ca/certificate/tls/current")));
try {
List<X509Certificate> tlsCaCerts = X509Util.decodePemCertificates(tlsca);
HashSet<X509Certificate> certs = new HashSet<X509Certificate>();
certs.addAll(tlsCaCerts);
return certs;
} catch (CertificateException ex) {
throw new ApiException("Invalid certificate", ex);
}
}
/* @Override
public CaInfo getCaStatus() throws IOException, ApiException, SignatureException {
throw new UnsupportedOperationException("Not supported yet.");
}*/
/**
* @param newPasswordString to authorize new hosts
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
/* @Override
public void enableCaWithPassword(String newPasswordString) throws IOException, ApiException, SignatureException {
try {
Password newPassword = new Password(newPasswordString, new byte[0]);
// String result =
text(httpPost(msurl("/ca/enable"), toJSON(newPassword.toString())));
//return "true".equals(result);
}
catch(CryptographyException e) {
throw new ApiException("Cannot hash password", e);
}
}*/
/**
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
/* @Override
public void disableCa() throws IOException, ApiException, SignatureException {
//String result =
text(httpPost(msurl("/ca/disable"), null));
}*/
@Override
public List<AuditLogEntry> searchAuditLog(AuditLogSearchCriteria criteria) throws IOException, ApiException, SignatureException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public HostTrustResponse getHostTrustByAik(Sha1Digest aikSha1) throws IOException, ApiException, SignatureException {
HostTrustResponse trust = fromJSON(httpGet(asurl("/hosts/aik-"+aikSha1.toString()+"/trust.json")), HostTrustResponse.class);
return trust;
}
@Override
public HostResponse registerHostByFindingMLE(TxtHostRecord hostObj) throws IOException, ApiException, SignatureException {
HostResponse result = fromJSON(httpPost(asurl("/hosts/mle"), toJSON(hostObj)), HostResponse.class);
return result;
}
@Override
public String checkMatchingMLEExists(TxtHostRecord hostObj) throws IOException, ApiException, SignatureException {
return text(httpPost(asurl("/hosts/mle/verify"), toJSON(hostObj)));
//return result;
}
/* @Override
public X509Certificate getCurrentTrustCertificateByAik(Sha1Digest aikSha1) throws IOException, ApiException, SignatureException {
byte[] trust = binary(httpGet(asurl("/hosts/aik-"+aikSha1.toString()+"/trustcert.x509")));
try {
X509Certificate cert = X509Util.decodeDerCertificate(trust);
return cert;
}
catch(Exception e) {
throw new IOException("Cannot decode X509 certificate ("+trust.length+" bytes)");
}
}*/
// this is required so that the jackson mapper will create an instance of ListMleData (List<TxtHostRecordV1>) instead of creating an instance of List<LinkedHashMap> when parsing server responses
public static class ListHostData extends ArrayList<TxtHostRecord> { };
@Override
public List<TxtHostRecord> queryForHosts(String searchCriteria) throws IOException, ApiException, SignatureException {
log.debug("queryForHosts no hardwareUuid");
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("searchCriteria", searchCriteria);
ListHostData results = fromJSON(httpGet(asurl("/hosts", query)), ListHostData.class);
return results;
}
@Override
public List<TxtHostRecord> queryForHosts(String searchCriteria, boolean includeHardware) throws IOException, ApiException, SignatureException {
log.debug("queryForHosts includeHardwareUuid["+includeHardware+"]");
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("searchCriteria", searchCriteria);
query.add("includeHardwareUuid",String.valueOf(includeHardware));
query.add("includeTlsPolicy",String.valueOf(false));
ListHostData results = fromJSON(httpGet(asurl("/hosts", query)), ListHostData.class);
return results;
}
@Override
public List<TxtHostRecord> queryForHosts2(String searchCriteria) throws IOException, ApiException, SignatureException {
log.debug("queryForHosts2");
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("searchCriteria", searchCriteria);
query.add("includeHardwareUuid",String.valueOf(true));
query.add("includeTlsPolicy",String.valueOf(true));
ListHostData results = fromJSON(httpGet(asurl("/hosts", query)), ListHostData.class);
return results;
}
/**
* javax.ws.rs.core.MediaType.APPLICATION_XML application/xml
* @param hostnames
*/
@Override
public OpenStackHostTrustLevelReport pollHosts(List<Hostname> hostnames) throws IOException, ApiException, SignatureException {
OpenStackHostTrustLevelQuery input = new OpenStackHostTrustLevelQuery();
input.hosts = hostnames.toArray(new Hostname[0]);
OpenStackHostTrustLevelReport output = fromJSON(httpPost(asurl("/PollHosts"), toJSON(input)), OpenStackHostTrustLevelReport.class);
return output;
}
@Override
public HostsTrustReportType getHostTrustReport (List<Hostname> hostnames) throws IOException, ApiException, SignatureException, JAXBException {
String hostNamesCSV = StringUtils.join(hostnames, ",");
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostNames", hostNamesCSV);
HostsTrustReportType report = fromXML(httpGet(asurl("/hosts/reports/trust", query)), HostsTrustReportType.class);
return report;
}
@Override
public HostManifestReportType getHostManifestReport (Hostname hostname) throws IOException, ApiException, SignatureException, JAXBException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
HostManifestReportType report = fromXML(httpGet(asurl("/hosts/reports/manifest", query)), HostManifestReportType.class);
return report;
}
/**
* application/samlassertion+xml
*
* @param hostname
*/
@Override
public String getSamlForHost(Hostname hostname) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
// By default we will get it from cache.
query.add("force_verify", Boolean.toString(false));
String saml = text(httpGet(asurl("/saml/assertions/host", query))); // NOTE: we are returning the raw XML document, we don't try to instantiate any Java object via the xml() funciton. The client can create a TrustAssertion object using this XML string in order to parse it.
return saml;
}
@Override
public String getSamlForHost(Hostname hostname, boolean forceVerify) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
query.add("force_verify", Boolean.toString(forceVerify));
String saml = text(httpGet(asurl("/saml/assertions/host", query))); // NOTE: we are returning the raw XML document, we don't try to instantiate any Java object via the xml() funciton. The client can create a TrustAssertion object using this XML string in order to parse it.
return saml;
}
@Override
public String getSamlForHostByAik(Sha1Digest aikSha1, boolean forceVerify) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("force_verify", Boolean.toString(forceVerify));
String saml = text(httpGet(asurl("/hosts/aik-"+aikSha1.toString()+"/trust.saml", query))); // NOTE: we are returning the raw XML document, we don't try to instantiate any Java object via the xml() funciton. The client can create a TrustAssertion object using this XML string in order to parse it.
return saml;
}
public TrustAssertion verifyTrustAssertion(String saml) throws IOException, ApiException, SignatureException {
X509Certificate[] trustedSamlCertificates;
try {
trustedSamlCertificates = keystore.getTrustedCertificates(SimpleKeystore.SAML);
}
catch(KeyStoreException e) {
throw new ApiException("Cannot load trusted SAML certificates", e);
}
catch(NoSuchAlgorithmException e) {
throw new ApiException("Cannot load trusted SAML certificates", e);
}
catch(UnrecoverableEntryException e) {
throw new ApiException("Cannot load trusted SAML certificates", e);
}
catch(CertificateEncodingException e) {
throw new ApiException("Cannot load trusted SAML certificates", e);
}
catch(Exception e) {
throw new ApiException("Cannot load SAML certificates: keystore not loaded", e);
}
TrustAssertion trustAssertion = new TrustAssertion(trustedSamlCertificates, saml);
return trustAssertion;
}
/**
* @param hostnames
* @param forceVerify
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public List<HostTrustXmlResponse> getSamlForMultipleHosts(Set<Hostname> hostnames, boolean forceVerify) throws IOException, ApiException, SignatureException {
// prepare the request
String hostnamesCSV = StringUtils.join(hostnames, ","); // calls toString() on each hostname
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hosts", hostnamesCSV);
query.add("force_verify", Boolean.toString(forceVerify));
// make the request and parse the xml response
HostTrustXmlResponseList list = xml(httpGet(asurl("/hosts/bulk/trust/saml", query)), HostTrustXmlResponseList.class);
return list.getHost(); // get the list of <Host> elements inside the root <Hosts> element... it's an automatically generated method name. would have been nice if they named it getHostList()
}
/**
* this method is used only by OpenSourceVMMHelper which is being replaced by IntelHostAgent; also the service implementation of this method only supports hosts with trust agents (even though vmware hosts also have their own attestation report)
* @param hostname
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
/*@Override
public String getHostAttestationReport(Hostname hostname) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hostName", hostname.toString());
String attReport = text(httpGet(asurl("/hosts/reports/attestation", query)));
return attReport;
}*/
@Override
public boolean importAssetTagCertificate(AssetTagCertCreateRequest aTagObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(asurl("/assetTagCert"), toJSON(aTagObj)));
return "true".equals(result);
}
@Override
public boolean revokeAssetTagCertificate(AssetTagCertRevokeRequest aTagObj) throws IOException, ApiException, SignatureException {
String result = text(httpPut(asurl("/assetTagCert"), toJSON(aTagObj)));
return "true".equals(result);
}
// Whitelist Management API
@Override
public boolean addMLE(MleData mle) throws IOException, ApiException, SignatureException {
String result = text(httpPost(wlmurl("/mles"), toJSON(mle)));
return "true".equals(result);
}
@Override
public boolean updateMLE(MleData mle) throws IOException, ApiException, SignatureException {
String result = text(httpPut(wlmurl("/mles"), toJSON(mle)));
return "true".equals(result);
}
@Override
public BulkHostTrustResponse getTrustForMultipleHosts(Set<Hostname> hostnames, boolean forceVerify) throws IOException, ApiException, SignatureException {
// prepare the request
String hostnamesCSV = StringUtils.join(hostnames, ","); // calls toString() on each hostname
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("hosts", hostnamesCSV);
query.add("force_verify", Boolean.toString(forceVerify));
// make the request and parse the xml response
return json(httpGet(asurl("/hosts/bulk/trust", query)), BulkHostTrustResponse.class);
}
// this is required so that the jackson mapper will create an instance of ListMleData (List<MleData>) instead of creating an instance of List<LinkedHashMap>
public static class ListMleData extends ArrayList<MleData> { };
@Override
public List<MleData> searchMLE(String name) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("searchCriteria", name);
ListMleData results = fromJSON(httpGet(wlmurl("/mles", query)), ListMleData.class);
return results;
}
/**
* Also known as GetMLEDetails
*
* @param criteria
*/
@Override
public MleData getMLEManifest(MLESearchCriteria criteria) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("mleName", criteria.mleName);
query.add("mleVersion", criteria.mleVersion);
query.add("osName", criteria.osName);
query.add("osVersion", criteria.osVersion);
query.add("oemName", criteria.oemName);
MleData mle = fromJSON(httpGet(wlmurl("/mles/manifest", query)), MleData.class);
return mle;
}
@Override
public boolean deleteMLE(MLESearchCriteria criteria) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("mleName", criteria.mleName);
query.add("mleVersion", criteria.mleVersion);
query.add("osName", criteria.osName);
query.add("osVersion", criteria.osVersion);
query.add("oemName", criteria.oemName);
String result = fromJSON(httpDelete(wlmurl("/mles", query)), String.class);
return "true".equals(result);
}
// this is required so that the jackson mapper will create an instance of ListOemData (List<OemData>) instead of creating an instance of List<LinkedHashMap>
public static class ListOemData extends ArrayList<OemData> { };
@Override
public List<OemData> listAllOEM() throws IOException, ApiException, SignatureException {
ListOemData results = fromJSON(httpGet(wlmurl("/oem")), ListOemData.class);
return results;
}
@Override
public boolean addOEM(OemData oem) throws IOException, ApiException, SignatureException {
String result = text(httpPost(wlmurl("/oem"), toJSON(oem)));
return "true".equals(result);
}
@Override
public boolean updateOEM(OemData oem) throws IOException, ApiException, SignatureException {
String result = text(httpPut(wlmurl("/oem"), toJSON(oem)));
return "true".equals(result);
}
@Override
public boolean deleteOEM(String name) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("Name", name);
String result = text(httpDelete(wlmurl("/oem", query)));
return "true".equals(result);
}
// this is required so that the jackson mapper will create an instance of ListOsData (List<OsData>) instead of creating an instance of List<LinkedHashMap>
public static class ListOsData extends ArrayList<OsData> { };
@Override
public List<OsData> listAllOS() throws IOException, ApiException, SignatureException {
//ArrayList<OsData> results = fromJSON(GET(wlmurl("/os")), ArrayList.class);
ListOsData results = fromJSON(httpGet(wlmurl("/os")), ListOsData.class);
return results;
}
@Override
public boolean updateOS(OsData os) throws IOException, ApiException, SignatureException {
String result = text(httpPut(wlmurl("/os"), toJSON(os)));
return "true".equals(result);
}
@Override
public boolean addOS(OsData os) throws IOException, ApiException, SignatureException {
String result = text(httpPost(wlmurl("/os"), toJSON(os)));
return "true".equals(result);
}
@Override
public boolean deleteOS(OsData os) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("Name", os.getName());
query.add("Version", os.getVersion());
String result = text(httpDelete(wlmurl("/os", query)));
return "true".equals(result);
}
// Registration API
public void register(ApiClientCreateRequest apiClient) throws IOException, ApiException, SignatureException {
httpPost(msurl("/apiclient/register"), toJSON(apiClient));
//return "true".equals(result);
}
@Override
public boolean registerApiClient(ApiClientCreateRequest apiClient) throws IOException, ApiException, SignatureException {
String result = text(httpPost(msurl("/apiclient/register"), toJSON(apiClient)));
// return true;
return "OK".equalsIgnoreCase(result);
}
// Credential Management API
// this is required so that the jackson mapper will create an instance of ListOsData (List<OsData>) instead of creating an instance of List<LinkedHashMap>
public static class ListApiClientInfo extends ArrayList<ApiClientInfo> { };
@Override
public List<ApiClientInfo> searchApiClients(ApiClientSearchCriteria criteria) throws IOException, ApiException, SignatureException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
ArrayList<BasicNameValuePair> queryList = new ArrayList<BasicNameValuePair>();
if( criteria.enabledEqualTo != null ) {
queryList.add(new BasicNameValuePair("enabledEqualTo", String.valueOf(criteria.enabledEqualTo))); // boolean will serialize to "true" or "false"
}
if( criteria.expiresAfter != null ) {
queryList.add(new BasicNameValuePair("expiresAfter", dateFormat.format(criteria.expiresAfter)));
}
if( criteria.expiresBefore != null ) {
queryList.add(new BasicNameValuePair("expiresBefore", dateFormat.format(criteria.expiresBefore)));
}
if( criteria.fingerprintEqualTo != null ) {
queryList.add(new BasicNameValuePair("fingerprintEqualTo", new String(Hex.encodeHex(criteria.fingerprintEqualTo))));
}
if( criteria.issuerEqualTo != null ) {
queryList.add(new BasicNameValuePair("issuerEqualTo", criteria.issuerEqualTo));
}
if( criteria.nameContains != null ) {
queryList.add(new BasicNameValuePair("nameContains", criteria.nameContains));
}
if( criteria.nameEqualTo != null ) {
queryList.add(new BasicNameValuePair("nameEqualTo", criteria.nameEqualTo));
}
if( criteria.serialNumberEqualTo != null ) {
queryList.add(new BasicNameValuePair("serialNumberEqualTo", String.valueOf(criteria.serialNumberEqualTo)));
}
if( criteria.statusEqualTo != null ) {
queryList.add(new BasicNameValuePair("statusEqualTo", criteria.statusEqualTo));
}
if( criteria.commentContains != null ) {
queryList.add(new BasicNameValuePair("commentContains", criteria.commentContains));
}
String queryString = URLEncodedUtils.format(queryList, "UTF-8");
ListApiClientInfo results = fromJSON(httpGet(msurl("/apiclient/search?"+queryString)), ListApiClientInfo.class);
return results;
}
@Override
public List<ApiClientInfo> listPendingAccessRequests() throws IOException, ApiException, SignatureException {
ApiClientSearchCriteria criteria = new ApiClientSearchCriteria();
criteria.enabledEqualTo = false;
criteria.statusEqualTo = "Pending";
return searchApiClients(criteria);
}
@Override
public boolean updateApiClient(ApiClientUpdateRequest apiClient) throws IOException, ApiException, SignatureException {
String result = text(httpPut(msurl("/apiclient"), toJSON(apiClient)));
log.debug("updateApiClient: result is {}.", result);
return "OK".equals(result);
}
@Override
public boolean deleteApiClient(byte[] fingerprint) throws IOException, ApiException, SignatureException {
// String fingerprintBase64 = new String(Base64.encodeBase64(fingerprint));
String fingerprintHex = new String(Hex.encodeHex(fingerprint));
String result = text(httpDelete(msurl(String.format("/apiclient?fingerprint=%s", fingerprintHex))));
log.debug("deleteApiClient: result is {}.", result);
return result.isEmpty();
}
@Override
public ApiClientInfo getApiClientInfo(byte[] fingerprint) throws IOException, ApiException, SignatureException {
// String fingerprintBase64 = new String(Base64.encodeBase64(fingerprint));
String fingerprintHex = new String(Hex.encodeHex(fingerprint));
ApiClientInfo result = fromJSON(httpGet(msurl(String.format("/apiclient?fingerprint=%s", fingerprintHex))), ApiClientInfo.class);
return result;
}
@Override
public Role[] listAvailableRoles() throws IOException, ApiException, SignatureException {
Role[] roles = fromJSON(httpGet(msurl("/apiclient/availableRoles")), Role[].class);
return roles;
}
/**
* Added By: Sudhir on June 26, 2012
*
* Process the add request into the PCR manifest table.
*
* @param pcrObj : White List data to be added to the PCR Manifest table
* NOTE: OS Details need to be provided only when the associated MLE is of VMM type.
* For MLEs of BIOS type OEM Details have to be provided
* @return : "true" if success or else exception.
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public boolean addPCRWhiteList(PCRWhiteList pcrObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(wlmurl("/mles/whitelist/pcr"), toJSON(pcrObj)));
return "true".equals(result);
}
/**
* Added By: Sudhir on June 26, 2012
*
* Processes the update request into the PCR manifest table.
*
* @param pcrObj : White List data to be updated in the PCR Manifest table.
* NOTE: OS Details need to be provided only when the associated MLE is of VMM type.
* For MLEs of BIOS type OEM Details have to be provided
* @return : "true" if success or else exception.
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public boolean updatePCRWhiteList(PCRWhiteList pcrObj) throws IOException, ApiException, SignatureException {
String result = text(httpPut(wlmurl("/mles/whitelist/pcr"), toJSON(pcrObj)));
return "true".equals(result);
}
/**
* Added By: Sudhir on June 26, 2012
*
* Processes the delete request from the PCR manifest table.
*
* @param pcrObj : White List data to be from the PCR Manifest table.
* NOTE: PCR name along with MLE details need to be provided. No need to
* specify PCR Digest value. OS Details need to be provided only when the
* associated MLE is of VMM type. For MLEs of BIOS type OEM Details have to be provided.
* @return : "true" if success or else exception.
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public boolean deletePCRWhiteList(PCRWhiteList pcrObj) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("pcrName", pcrObj.getPcrName());
query.add("mleName", pcrObj.getMleName());
query.add("mleVersion", pcrObj.getMleVersion());
query.add("osName", pcrObj.getOsName());
query.add("osVersion", pcrObj.getOsVersion());
query.add("oemName", pcrObj.getOemName());
String result = text(httpDelete(wlmurl("/mles/whitelist/pcr", query)));
return "true".equals(result);
}
/**
* Added By: Sudhir on June 26, 2012
*
* Process the add request into the Module manifest table.
*
* @param moduleObj : White List data to be added to the Module Manifest table
* NOTE: OS Details need to be provided only when the associated MLE is of VMM type.
* For MLEs of BIOS type OEM Details have to be provided
* @return : "true" if success or else exception.
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public boolean addModuleWhiteList(ModuleWhiteList moduleObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(wlmurl("/mles/whitelist/module"), toJSON(moduleObj)));
return "true".equals(result);
}
/**
* Added By: Sudhir on June 26, 2012
*
* Processes the update request into the Module manifest table.
*
* @param moduleObj : White List data to be updated in the Module Manifest table.
* NOTE: OS Details need to be provided only when the associated MLE is of VMM type.
* For MLEs of BIOS type OEM Details have to be provided
* @return : "true" if success or else exception.
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public boolean updateModuleWhiteList(ModuleWhiteList moduleObj) throws IOException, ApiException, SignatureException {
String result = text(httpPut(wlmurl("/mles/whitelist/module"), toJSON(moduleObj)));
return "true".equals(result);
}
/**
* Added By: Sudhir on June 26, 2012
*
* Processes the delete request from the Module manifest table.
*
* @param moduleObj : White List data to be deleted from the Module Manifest table.
* NOTE: Component & Event names along with MLE details need to be provided.
* OS Details need to be provided only when the associated MLE is of VMM type.
* For MLEs of BIOS type OEM Details have to be provided.
* @return : "true" if success or else exception.
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public boolean deleteModuleWhiteList(ModuleWhiteList moduleObj) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("componentName", moduleObj.getComponentName());
query.add("eventName", moduleObj.getEventName());
query.add("mleName", moduleObj.getMleName());
query.add("mleVersion", moduleObj.getMleVersion());
query.add("osName", moduleObj.getOsName());
query.add("osVersion", moduleObj.getOsVersion());
query.add("oemName", moduleObj.getOemName());
String result = text(httpDelete(wlmurl("/mles/whitelist/module", query)));
return "true".equals(result);
}
//
/**
* This is required so that the jackson mapper will create an instance of ListModuleWhiteList
* (List<ModuleWhiteList>) instead of creating an instance of List<LinkedHashMap>
*/
public static class ListModuleWhiteList extends ArrayList<ModuleWhiteList> { };
/**
* Added By: Sudhir on June 26, 2012
*
* Retrieves the list of all the Module white list for the specified MLE.
*
* @param mleName : Name of the measured launch environment (MLE) associated with the white list.
* @param mleVersion : Version of the MLE or Hypervisor
* @param osName : Name of the OS running the hypervisor. OS Details need to be provided only
* when the associated MLE is of VMM type.
* @param osVersion : Version of the OS
* @param oemName : OEM vendor of the hardware system. OEM Details have to be provided only
* when the associated MLE is of BIOS type.
* @return : List of module white lists.
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public List<ModuleWhiteList> listModuleWhiteListForMLE(String mleName, String mleVersion,
String osName, String osVersion, String oemName) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("mleName", mleName);
query.add("mleVersion", mleVersion);
query.add("osName", osName);
query.add("osVersion", osVersion);
query.add("oemName", oemName);
ListModuleWhiteList results = fromJSON(httpGet(wlmurl("/mles/whitelist/module", query)), ListModuleWhiteList.class);
return results;
}
/**
* Author: Sudhir
*
* This function registers the specified host with mount wilson. The main difference between this and the addHost
* function of the Attestation service is that this automatically creates the required OEM, OS, BIOS MLE and VMM MLE
* configurations without any user intervention.
*
* @param hostObj
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public boolean registerHost(TxtHostRecord hostObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(msurl("/host"), toJSON(hostObj)));
return "true".equals(result);
}
@Override
public boolean registerHost(HostConfigData hostConfigObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(msurl("/host/custom"), toJSON(hostConfigObj)));
return "true".equals(result);
}
/**
* Author : Sudhir
*
* This function automates the white list database configuration using the details of the host provided. If
* need this function also configures the OEM, OS, BIOS MLE, VMM MLE and also registers the host. The reason
* why the registration happens is because unless the host is registered, the Trust Agent cannot take the
* ownership of the TPM and retrieve the boot time measurements. Whereas this is not the case with VMware. But
* since we want both the implementation to be similar even for VMware hosts, we will register the host if it is
* not already done so.
*
* @param hostObj
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public boolean configureWhiteList(TxtHostRecord hostObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(msurl("/host/whitelist"), toJSON(hostObj)));
return "true".equals(result);
}
@Override
public boolean configureWhiteList(HostConfigData hostConfigObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(msurl("/host/whitelist/custom"), toJSON(hostConfigObj)));
return "true".equals(result);
}
@Override
public boolean addMleSource(MleSource mleSourceObj) throws IOException, ApiException, SignatureException {
String result = text(httpPost(wlmurl("/mles/source"), toJSON(mleSourceObj)));
return "true".equals(result);
}
@Override
public boolean updateMleSource(MleSource mleSourceObj) throws IOException, ApiException, SignatureException {
String result = text(httpPut(wlmurl("/mles/source"), toJSON(mleSourceObj)));
return "true".equals(result);
}
@Override
public boolean deleteMleSource(MleData mleDataObj) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("mleName", mleDataObj.getName());
query.add("mleVersion", mleDataObj.getVersion());
query.add("osName", mleDataObj.getOsName());
query.add("osVersion", mleDataObj.getOsVersion());
query.add("oemName", mleDataObj.getOemName());
String result = text(httpDelete(wlmurl("/mles/source", query)));
return "true".equals(result);
}
@Override
public String getMleSource(MleData mleDataObj) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("mleName", mleDataObj.getName());
query.add("mleVersion", mleDataObj.getVersion());
query.add("osName", mleDataObj.getOsName());
query.add("osVersion", mleDataObj.getOsVersion());
query.add("oemName", mleDataObj.getOemName());
String result = text(httpGet(wlmurl("/mles/source", query)));
return result;
}
/**
* This method support multiple host registration/updates with a single call. Since the user has passed in the simple TxtHostRecord
* object, we will use the default values for the white list target (BIOS: OEM and VMM:OEM). If those white lists are not defined then
* error messages would be sent back to the caller.
*
* @param hostRecords
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public HostConfigResponseList registerHosts(TxtHostRecordList hostRecords) throws IOException, ApiException, SignatureException {
HostConfigResponseList result = fromJSON(httpPost(msurl("/host/bulk"), toJSON(hostRecords)), HostConfigResponseList.class);
return result;
}
/**
* This method similar to the above one is used for multiple host registration/update in a single call. The only difference is that in this the user
* would specify which White List the host has to use during registration
* @param hostRecords
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public HostConfigResponseList registerHosts(HostConfigDataList hostRecords) throws IOException, ApiException, SignatureException {
HostConfigResponseList results = fromJSON(httpPost(msurl("/host/bulk/custom"), toJSON(hostRecords)), HostConfigResponseList.class);
return results;
}
/**
* Retrieves list of available i18n locales
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public String[] getLocales() throws IOException, ApiException, SignatureException {
String localesParsed = text(httpGet(msurl("/i18n/locales"))).replaceAll("\\s+", "");
return localesParsed.substring(1, localesParsed.length() - 1).split(",");
}
/**
* Retrieves locale for specific portal user
*
* @param username
* @return
* @throws IOException
* @throws ApiException
* @throws SignatureException
*/
@Override
public String getLocaleForUser(String username) throws IOException, ApiException, SignatureException {
MultivaluedMap<String,String> query = new MultivaluedMapImpl();
query.add("username", username);
String userLocale = text(httpGet(msurl("/i18n/locale", query)));
return userLocale;
}
@Override
public String setLocaleForUser(PortalUserLocale pul) throws IOException, ApiException, SignatureException {
log.debug("Calling api to set locale [{}] for user [{}]", pul.getLocale(), pul.getUser());
String resp = text(httpPost(msurl("/i18n/locale"), toJSON(pul)));
log.debug("resp: {}",resp);
return resp;
}
}