mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-24 07:06:46 +00:00
[#25] Make ACA exception handling more descriptive
This commit is contained in:
parent
6847c814af
commit
87be5a396b
@ -3,6 +3,9 @@ package hirs.attestationca;
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import hirs.attestationca.exceptions.CertificateProcessingException;
|
||||
import hirs.attestationca.exceptions.IdentityProcessingException;
|
||||
import hirs.attestationca.exceptions.UnexpectedServerException;
|
||||
import hirs.data.persist.AppraisalStatus;
|
||||
import hirs.data.persist.BIOSComponentInfo;
|
||||
import hirs.data.persist.BaseboardComponentInfo;
|
||||
@ -238,7 +241,8 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
if (publicKeyModulus != null) {
|
||||
ekPublicKey = assemblePublicKey(publicKeyModulus.toByteArray());
|
||||
} else {
|
||||
throw new IllegalArgumentException("TPM 1.2 Provisioning requires RSA EKC");
|
||||
throw new IdentityProcessingException("TPM 1.2 Provisioning requires EK "
|
||||
+ "Credentials to be created with RSA");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Could not retrieve the public key modulus from the EK cert");
|
||||
@ -277,7 +281,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
|
||||
if (deviceInfoReport == null) {
|
||||
LOG.error("Failed to deserialize Device Info Report");
|
||||
throw new IllegalArgumentException("Device Info Report failed to deserialize "
|
||||
throw new IdentityProcessingException("Device Info Report failed to deserialize "
|
||||
+ "from Identity Request");
|
||||
}
|
||||
|
||||
@ -382,7 +386,8 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
LOG.info("Got identity claim");
|
||||
|
||||
if (ArrayUtils.isEmpty(identityClaim)) {
|
||||
throw new IllegalArgumentException("identityClaim cannot be null or empty");
|
||||
LOG.error("Identity claim empty throwing exception.");
|
||||
throw new IdentityProcessingException("identityClaim cannot be null or empty");
|
||||
}
|
||||
|
||||
// attempt to deserialize Protobuf IdentityClaim
|
||||
@ -466,7 +471,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
try {
|
||||
request = ProvisionerTpm2.CertificateRequest.parseFrom(certificateRequest);
|
||||
} catch (InvalidProtocolBufferException ipbe) {
|
||||
throw new IdentityProcessingException(
|
||||
throw new CertificateProcessingException(
|
||||
"Could not deserialize certificate request", ipbe);
|
||||
}
|
||||
|
||||
@ -512,7 +517,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
} else {
|
||||
LOG.error("Could not process credential request. Invalid nonce provided: "
|
||||
+ request.getNonce().toString());
|
||||
throw new IdentityProcessingException("Invalid nonce given in request");
|
||||
throw new CertificateProcessingException("Invalid nonce given in request");
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,7 +529,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
RSAPublicKey parsePublicKey(final byte[] publicArea) {
|
||||
int pubLen = publicArea.length;
|
||||
if (pubLen < RSA_MODULUS_LENGTH) {
|
||||
throw new IdentityProcessingException(
|
||||
throw new IllegalArgumentException(
|
||||
"EK or AK public data segment is not long enough");
|
||||
}
|
||||
// public data ends with 256 byte modulus
|
||||
@ -661,7 +666,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
|
||||
if (deviceInfoReport == null) {
|
||||
LOG.error("Failed to deserialize Device Info Report");
|
||||
throw new IllegalArgumentException("Device Info Report failed to deserialize "
|
||||
throw new IdentityProcessingException("Device Info Report failed to deserialize "
|
||||
+ "from Identity Claim");
|
||||
}
|
||||
|
||||
@ -882,7 +887,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
return keyFactory.generatePublic(keySpec);
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
throw new IdentityProcessingException(
|
||||
throw new UnexpectedServerException(
|
||||
"Encountered unexpected error creating public key: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@ -948,7 +953,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
} catch (NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException
|
||||
| InvalidKeyException | BadPaddingException
|
||||
| InvalidAlgorithmParameterException e) {
|
||||
throw new IdentityProcessingException(
|
||||
throw new CertificateProcessingException(
|
||||
"Encountered error while generating ACA session key: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@ -1004,7 +1009,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
} catch (BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException
|
||||
| InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException
|
||||
| CertificateEncodingException e) {
|
||||
throw new IdentityProcessingException(
|
||||
throw new CertificateProcessingException(
|
||||
"Encountered error while generating Identity Response: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@ -1066,7 +1071,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
.setProvider("BC").getCertificate(holder);
|
||||
return certificate;
|
||||
} catch (IOException | OperatorCreationException | CertificateException e) {
|
||||
throw new IdentityProcessingException("Encountered error while generating "
|
||||
throw new CertificateProcessingException("Encountered error while generating "
|
||||
+ "identity credential: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@ -1159,7 +1164,8 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
| InvalidKeyException | InvalidAlgorithmParameterException
|
||||
| NoSuchPaddingException e) {
|
||||
throw new IdentityProcessingException(
|
||||
"Encountered error while making credential: " + e.getMessage(), e);
|
||||
"Encountered error while making the identity claim challenge: "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1418,7 +1424,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
* Helper method to extract a DER encoded ASN.1 certificate from an X509 certificate.
|
||||
*
|
||||
* @param certificate the X509 certificate to be converted to DER encoding
|
||||
* @throws {@link IdentityProcessingException} if error occurs during encoding retrieval
|
||||
* @throws {@link UnexpectedServerException} if error occurs during encoding retrieval
|
||||
* @return the byte array representing the DER encoded certificate
|
||||
*/
|
||||
private byte[] getDerEncodedCertificate(final X509Certificate certificate) {
|
||||
@ -1426,7 +1432,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
return certificate.getEncoded();
|
||||
} catch (CertificateEncodingException e) {
|
||||
LOG.error("Error converting certificate to ASN.1 DER Encoding.", e);
|
||||
throw new IdentityProcessingException(
|
||||
throw new UnexpectedServerException(
|
||||
"Encountered error while converting X509 Certificate: "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
@ -1441,7 +1447,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
* @param endorsementCredential the endorsement credential used to generate the AC
|
||||
* @param platformCredentials the platform credentials used to generate the AC
|
||||
* @param device the device to which the attestation certificate is tied
|
||||
* @throws {@link IdentityProcessingException} if error occurs in persisting the Attestation
|
||||
* @throws {@link CertificateProcessingException} if error occurs in persisting the Attestation
|
||||
* Certificate
|
||||
*/
|
||||
private void saveAttestationCertificate(final byte[] derEncodedAttestationCertificate,
|
||||
@ -1456,7 +1462,7 @@ public abstract class AbstractAttestationCertificateAuthority
|
||||
certificateManager.save(attCert);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error saving generated Attestation Certificate to database.", e);
|
||||
throw new IdentityProcessingException(
|
||||
throw new CertificateProcessingException(
|
||||
"Encountered error while storing Attestation Certificate: "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
package hirs.attestationca;
|
||||
|
||||
/**
|
||||
* A simple POJO that will provide a clean error message to clients making
|
||||
* REST requests to the ACA. It is to be serialized to JSON for the return message.
|
||||
*/
|
||||
public class AcaRestError {
|
||||
|
||||
private String error;
|
||||
|
||||
/**
|
||||
* Basic constructor necessary for Jackson JSON serialization to work properly.
|
||||
*/
|
||||
public AcaRestError() {
|
||||
// Don't remove this constructor as it's required for JSON mapping
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor for creating this class normally.
|
||||
*
|
||||
* @param error the error message to store in this object
|
||||
*/
|
||||
public AcaRestError(final String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple getter to get the error message stored in this object.
|
||||
*
|
||||
* @return the error message
|
||||
*/
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple setter to get the error message stored in this object.
|
||||
*
|
||||
* @param error the new error message to store in this object
|
||||
*/
|
||||
public void setError(final String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
}
|
@ -54,8 +54,8 @@ import hirs.utils.LogConfigurationUtil;
|
||||
@PropertySource(value = "file:/etc/hirs/aca/aca.properties",
|
||||
ignoreResourceNotFound = true)
|
||||
})
|
||||
@ComponentScan({ "hirs.attestationca", "hirs.attestationca.service", "hirs.validation",
|
||||
"hirs.data.service" })
|
||||
@ComponentScan({ "hirs.attestationca", "hirs.attestationca.service", "hirs.attestationca.rest",
|
||||
"hirs.validation", "hirs.data.service" })
|
||||
@Import(HibernateConfiguration.class)
|
||||
@EnableWebMvc
|
||||
public class AttestationCertificateAuthorityConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
@ -0,0 +1,27 @@
|
||||
package hirs.attestationca.exceptions;
|
||||
|
||||
/**
|
||||
* Generic exception thrown while a {@link hirs.attestationca.AttestationCertificateAuthority}
|
||||
* is processing a newly created Attestation Certificate for a validated identity.
|
||||
*/
|
||||
public class CertificateProcessingException extends RuntimeException {
|
||||
/**
|
||||
* Constructs a generic instance of this exception using the specified reason.
|
||||
*
|
||||
* @param reason for the exception
|
||||
*/
|
||||
public CertificateProcessingException(final String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a instance of this exception with the specified reason and backing root
|
||||
* exception.
|
||||
*
|
||||
* @param reason for this exception
|
||||
* @param rootException causing this exception
|
||||
*/
|
||||
public CertificateProcessingException(final String reason, final Throwable rootException) {
|
||||
super(reason, rootException);
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package hirs.attestationca;
|
||||
package hirs.attestationca.exceptions;
|
||||
|
||||
/**
|
||||
* Generic exception thrown while a {@link AttestationCertificateAuthority} is processing a newly
|
||||
* submitted Identity.
|
||||
* Generic exception thrown while a {@link hirs.attestationca.AttestationCertificateAuthority}
|
||||
* is processing a newly submitted Identity.
|
||||
*/
|
||||
public class IdentityProcessingException extends RuntimeException {
|
||||
/**
|
@ -0,0 +1,27 @@
|
||||
package hirs.attestationca.exceptions;
|
||||
|
||||
/**
|
||||
* Generic exception thrown when a {@link hirs.attestationca.AttestationCertificateAuthority}
|
||||
* encounters an unexpected condition that can't be handled.
|
||||
*/
|
||||
public class UnexpectedServerException extends RuntimeException {
|
||||
/**
|
||||
* Constructs a generic instance of this exception using the specified reason.
|
||||
*
|
||||
* @param reason for the exception
|
||||
*/
|
||||
public UnexpectedServerException(final String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a instance of this exception with the specified reason and backing root
|
||||
* exception.
|
||||
*
|
||||
* @param reason for this exception
|
||||
* @param rootException causing this exception
|
||||
*/
|
||||
public UnexpectedServerException(final String reason, final Throwable rootException) {
|
||||
super(reason, rootException);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Custom exceptions of the {@link hirs.attestationca.AttestationCertificateAuthority}.
|
||||
*/
|
||||
package hirs.attestationca.exceptions;
|
@ -0,0 +1,72 @@
|
||||
package hirs.attestationca.rest;
|
||||
|
||||
import hirs.attestationca.AcaRestError;
|
||||
import hirs.attestationca.exceptions.CertificateProcessingException;
|
||||
import hirs.attestationca.exceptions.IdentityProcessingException;
|
||||
import hirs.attestationca.exceptions.UnexpectedServerException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
/**
|
||||
* Handle processing of exceptions for ACA REST API.
|
||||
*/
|
||||
@ControllerAdvice
|
||||
public class AttestationCertificateAuthorityExceptionHandler
|
||||
extends ResponseEntityExceptionHandler {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
AttestationCertificateAuthorityExceptionHandler.class);
|
||||
|
||||
/**
|
||||
* Method to handle errors of the type {@link CertificateProcessingException},
|
||||
* {@link IdentityProcessingException}, and {@link IllegalArgumentException}
|
||||
* that are thrown when performing a RESTful operation.
|
||||
*
|
||||
* @param ex exception that was thrown
|
||||
* @param request the web request that started the RESTful operation
|
||||
* @return the response entity that will form the message returned to the client
|
||||
*/
|
||||
@ExceptionHandler({ CertificateProcessingException.class, IdentityProcessingException.class,
|
||||
IllegalArgumentException.class })
|
||||
public final ResponseEntity<Object> handleExpectedExceptions(final Exception ex,
|
||||
final WebRequest request) {
|
||||
LOGGER.error(String.format("The ACA has encountered an expected exception: %s",
|
||||
ex.getMessage()), ex);
|
||||
return handleGeneralException(ex, HttpStatus.BAD_REQUEST, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle errors of the type {@link IllegalStateException} and
|
||||
* {@link UnexpectedServerException} that are thrown when performing a RESTful operation.
|
||||
*
|
||||
* @param ex exception that was thrown
|
||||
* @param request the web request that started the RESTful operation
|
||||
* @return the response entity that will form the message returned to the client
|
||||
*/
|
||||
@ExceptionHandler({ IllegalStateException.class, UnexpectedServerException.class })
|
||||
public final ResponseEntity<Object> handleUnexpectedExceptions(final Exception ex,
|
||||
final WebRequest request) {
|
||||
LOGGER.error(String.format("The ACA has encountered an unexpected exception: %s",
|
||||
ex.getMessage()), ex);
|
||||
return handleGeneralException(ex, HttpStatus.INTERNAL_SERVER_ERROR, request);
|
||||
}
|
||||
|
||||
private ResponseEntity<Object> handleGeneralException(final Exception ex,
|
||||
final HttpStatus responseStatus,
|
||||
final WebRequest request) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
return handleExceptionInternal(ex, new AcaRestError(ex.getMessage()),
|
||||
headers, responseStatus, request);
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +1,14 @@
|
||||
package hirs.attestationca.rest;
|
||||
|
||||
import hirs.attestationca.IdentityProcessingException;
|
||||
import hirs.persist.DBManager;
|
||||
import hirs.persist.TPM2ProvisionerState;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
@ -72,8 +68,7 @@ public class RestfulAttestationCertificateAuthority
|
||||
@Override
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/identity-request/process", method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
public byte[] processIdentityRequest(@RequestBody final byte[] request) {
|
||||
return super.processIdentityRequest(request);
|
||||
}
|
||||
@ -87,8 +82,7 @@ public class RestfulAttestationCertificateAuthority
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/identity-claim-tpm2/process",
|
||||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
public byte[] processIdentityClaimTpm2(@RequestBody final byte[] request) {
|
||||
return super.processIdentityClaimTpm2(request);
|
||||
}
|
||||
@ -103,8 +97,7 @@ public class RestfulAttestationCertificateAuthority
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/request-certificate-tpm2",
|
||||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
public byte[] processCertificateRequest(@RequestBody final byte[] request) {
|
||||
return super.processCertificateRequest(request);
|
||||
}
|
||||
@ -118,28 +111,9 @@ public class RestfulAttestationCertificateAuthority
|
||||
*/
|
||||
@Override
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/public-key", method = RequestMethod.GET,
|
||||
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
@RequestMapping(value = "/public-key", method = RequestMethod.GET)
|
||||
public byte[] getPublicKey() {
|
||||
return super.getPublicKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle processing of exceptions for ACA REST API.
|
||||
* @param e exception thrown during invocation of ACA REST API
|
||||
* @return exception thrown during invocation of ACA REST API
|
||||
*/
|
||||
@ExceptionHandler
|
||||
@ResponseBody
|
||||
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public Exception handleException(final Exception e) {
|
||||
if (e instanceof IdentityProcessingException) {
|
||||
LOG.error("Processing exception while provisioning", e.getMessage(), e);
|
||||
} else {
|
||||
LOG.error(String.format("Encountered unexpected error while processing identity "
|
||||
+ "claim: %s", e.getMessage()), e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
*
|
||||
* @param credential the credential whose CA chain should be retrieved
|
||||
* @return A keystore ontaining all relevant CA credentials to the given certificate's
|
||||
* organization
|
||||
* organization or null if the keystore can't be assembled
|
||||
*/
|
||||
public KeyStore getCaChain(final Certificate credential) {
|
||||
KeyStore caKeyStore = null;
|
||||
|
@ -1,6 +1,7 @@
|
||||
package hirs.attestationca;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import hirs.attestationca.exceptions.IdentityProcessingException;
|
||||
import hirs.utils.HexUtils;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
@ -158,9 +159,9 @@ public class AbstractAttestationCertificateAuthorityTest {
|
||||
|
||||
/**
|
||||
* Tests {@link AbstractAttestationCertificateAuthority#processIdentityClaimTpm2(byte[])}
|
||||
* where the byte array is null. Expects an illegal argument exception to be thrown.
|
||||
* where the byte array is null. Expects an identity processing exception to be thrown.
|
||||
*/
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
@Test(expectedExceptions = IdentityProcessingException.class)
|
||||
public void testProcessIdentityClaimTpm2NullRequest() {
|
||||
aca.processIdentityClaimTpm2(null);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ class RestfulClientProvisioner {
|
||||
static const char * const PROP_FILE_LOC;
|
||||
static const char * const PROP_ACA_FQDN;
|
||||
static const char * const PROP_ACA_PORT;
|
||||
static const char * const ACA_ERROR_FIELDNAME;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -47,6 +47,27 @@ namespace file_utils {
|
||||
int readSize);
|
||||
} // namespace file_utils
|
||||
|
||||
namespace json_utils {
|
||||
|
||||
/**
|
||||
* Utility class that provides functions to parse information from ACA
|
||||
* output.
|
||||
*/
|
||||
class JSONFieldParser {
|
||||
public:
|
||||
/**
|
||||
* Parses the target field of the provided JSON object as a string.
|
||||
*
|
||||
* @param jsonObject the JSON-formatted object
|
||||
* @param jsonFieldName the name of the field to parse from the JSON object
|
||||
* @return the value of the target field in the JSON object
|
||||
*/
|
||||
static std::string parseJsonStringField(const std::string& jsonObject,
|
||||
const std::string& jsonFieldName);
|
||||
};
|
||||
|
||||
} // namespace json_utils
|
||||
|
||||
namespace string_utils {
|
||||
/**
|
||||
* Converts a binary string to a hex string.
|
||||
|
@ -19,6 +19,7 @@ using hirs::pb::IdentityClaimResponse;
|
||||
using hirs::pb::CertificateRequest;
|
||||
using hirs::pb::CertificateResponse;
|
||||
using hirs::properties::Properties;
|
||||
using hirs::json_utils::JSONFieldParser;
|
||||
using hirs::string_utils::binaryToHex;
|
||||
using std::string;
|
||||
using std::stringstream;
|
||||
@ -31,6 +32,8 @@ const char * const RestfulClientProvisioner::PROP_ACA_FQDN
|
||||
= "ATTESTATION_CA_FQDN";
|
||||
const char * const RestfulClientProvisioner::PROP_ACA_PORT
|
||||
= "ATTESTATION_CA_PORT";
|
||||
const char * const RestfulClientProvisioner::ACA_ERROR_FIELDNAME
|
||||
= "error";
|
||||
|
||||
RestfulClientProvisioner::RestfulClientProvisioner() {
|
||||
Properties props(PROP_FILE_LOC);
|
||||
@ -66,7 +69,9 @@ string RestfulClientProvisioner::sendIdentityClaim(
|
||||
+ "process"},
|
||||
cpr::Body{identityClaimByteString},
|
||||
cpr::Header{{"Content-Type",
|
||||
"application/octet-stream"}},
|
||||
"application/octet-stream"},
|
||||
{"Accept",
|
||||
"application/octet-stream, application/json"}},
|
||||
cpr::VerifySsl{false});
|
||||
|
||||
// Check ACA response, should be 200 if successful
|
||||
@ -91,8 +96,11 @@ string RestfulClientProvisioner::sendIdentityClaim(
|
||||
|
||||
} else {
|
||||
stringstream errormsg;
|
||||
errormsg << "Couldn't communicate with ACA server. "
|
||||
<< "Received response code: " << to_string(r.status_code);
|
||||
errormsg << "Error communicating with ACA server. "
|
||||
<< "Received response code: " << to_string(r.status_code)
|
||||
<< "\n\nError message fom ACA was: "
|
||||
<< JSONFieldParser::parseJsonStringField(r.text,
|
||||
ACA_ERROR_FIELDNAME);
|
||||
throw HirsRuntimeException(errormsg.str(),
|
||||
"RestfulClientProvisioner::sendIdentityClaim");
|
||||
}
|
||||
@ -110,7 +118,9 @@ string RestfulClientProvisioner::sendAttestationCertificateRequest(
|
||||
+ "/request-certificate-tpm2"},
|
||||
cpr::Body{certificateRequestByteString},
|
||||
cpr::Header{{"Content-Type",
|
||||
"application/octet-stream"}},
|
||||
"application/octet-stream"},
|
||||
{"Accept",
|
||||
"application/octet-stream, application/json"}},
|
||||
cpr::VerifySsl{false});
|
||||
|
||||
// Check ACA response, should be 200 if successful
|
||||
@ -131,9 +141,11 @@ string RestfulClientProvisioner::sendAttestationCertificateRequest(
|
||||
|
||||
} else {
|
||||
stringstream errormsg;
|
||||
errormsg << "Couldn't communicate with ACA server. "
|
||||
errormsg << "Error communicating with ACA server. "
|
||||
<< "Received response code: " << to_string(r.status_code)
|
||||
<< "\n\nWith message body: " << r.text;
|
||||
<< "\n\nError message from ACA was: "
|
||||
<< JSONFieldParser::parseJsonStringField(r.text,
|
||||
ACA_ERROR_FIELDNAME);
|
||||
throw HirsRuntimeException(errormsg.str(),
|
||||
"RestfulClientProvisioner::sendAttestationCertificateRequest");
|
||||
}
|
||||
|
@ -34,6 +34,25 @@ using hirs::exception::HirsRuntimeException;
|
||||
|
||||
namespace hirs {
|
||||
|
||||
namespace json_utils {
|
||||
|
||||
string JSONFieldParser::parseJsonStringField(const std::string &jsonObject,
|
||||
const std::string &jsonFieldName) {
|
||||
stringstream regexPatternStream;
|
||||
regexPatternStream << "(?i)\\\""
|
||||
<< jsonFieldName
|
||||
<< "\\\"\\s*:\\s*\\\"(.*)\\\"";
|
||||
|
||||
string value;
|
||||
if (RE2::PartialMatch(jsonObject, regexPatternStream.str(), &value)) {
|
||||
return value;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace json_utils
|
||||
|
||||
namespace file_utils {
|
||||
|
||||
/**
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
using hirs::file_utils::dirExists;
|
||||
using hirs::file_utils::fileExists;
|
||||
using hirs::json_utils::JSONFieldParser;
|
||||
using hirs::string_utils::binaryToHex;
|
||||
using hirs::string_utils::contains;
|
||||
using hirs::string_utils::longToHex;
|
||||
@ -58,6 +59,57 @@ class UtilsTest : public :: testing::Test {
|
||||
|
||||
const char UtilsTest::kFileName[] = "bitsAndBytes";
|
||||
|
||||
TEST_F(UtilsTest, ParseJsonFieldSuccess) {
|
||||
stringstream jsonObject;
|
||||
jsonObject << R"({"error":"identityClaim cannot be null or empty"})";
|
||||
|
||||
string errorMessage = JSONFieldParser::parseJsonStringField(
|
||||
jsonObject.str(), "error");
|
||||
string expectedOutput = "identityClaim cannot be null or empty";
|
||||
ASSERT_EQ(expectedOutput, errorMessage);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, ParseJsonFieldSuccessCaseInsensitive) {
|
||||
stringstream jsonObject;
|
||||
jsonObject << R"({"ERROR":"identityClaim cannot be null or empty"})";
|
||||
|
||||
string errorMessage = JSONFieldParser::parseJsonStringField(
|
||||
jsonObject.str(), "error");
|
||||
string expectedOutput = "identityClaim cannot be null or empty";
|
||||
ASSERT_EQ(expectedOutput, errorMessage);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, ParseJsonFieldSuccessWhiteSpaces) {
|
||||
stringstream jsonObject;
|
||||
jsonObject << R"({"error" : "identityClaim cannot be null or empty"})";
|
||||
|
||||
string errorMessage = JSONFieldParser::parseJsonStringField(
|
||||
jsonObject.str(), "error");
|
||||
string expectedOutput = "identityClaim cannot be null or empty";
|
||||
ASSERT_EQ(expectedOutput, errorMessage);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, ParseJsonFieldSuccessMultiJsonFields) {
|
||||
stringstream jsonObject;
|
||||
jsonObject << R"({"error" : "identityClaim cannot be null or empty",)"
|
||||
<< "\n" << R"("endpoint":"url.com"})";
|
||||
|
||||
string errorMessage = JSONFieldParser::parseJsonStringField(
|
||||
jsonObject.str(), "error");
|
||||
string expectedOutput = "identityClaim cannot be null or empty";
|
||||
ASSERT_EQ(expectedOutput, errorMessage);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, ParseJsonFieldInvalidJson) {
|
||||
stringstream jsonObject;
|
||||
jsonObject << R"({error:"identityClaim cannot be null or empty"})";
|
||||
|
||||
string errorMessage = JSONFieldParser::parseJsonStringField(
|
||||
jsonObject.str(), "error");
|
||||
string expectedOutput = "";
|
||||
ASSERT_EQ(expectedOutput, errorMessage);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, DirectoryExists) {
|
||||
mkdir(kFileName, 0755);
|
||||
ASSERT_TRUE(dirExists(kFileName));
|
||||
|
Loading…
Reference in New Issue
Block a user