Merge pull request #614 from nsacyber/v3_issue_612-integrationtest

[#612] Migrate integration test for DevicePageController and associated classes
This commit is contained in:
Cyrus 2023-10-31 16:07:43 -04:00 committed by GitHub
commit ab11c8e81a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 476 additions and 11 deletions

View File

@ -47,8 +47,6 @@ dependencies {
implementation 'org.apache.logging.log4j:log4j-spring-boot'
implementation 'org.projectlombok:lombok'
implementation 'commons-fileupload:commons-fileupload:1.5'
implementation 'org.junit.jupiter:junit-jupiter:5.4.2'
implementation 'org.junit.jupiter:junit-jupiter:5.4.2'
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper:10.1.5'
compileOnly 'org.projectlombok:lombok'
@ -57,7 +55,12 @@ dependencies {
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation libs.testng
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
testImplementation 'org.hsqldb:hsqldb'
}
test {
useJUnitPlatform()
}
ospackage {

View File

@ -1,23 +1,53 @@
package hirs.attestationca.portal.page;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.equalTo;
/**
* Base class for PageController tests.
*
*/
@WebAppConfiguration
//@ContextConfiguration(classes = PageTestConfiguration.class)
public class PageControllerTest extends AbstractTestNGSpringContextTests {
@SpringBootTest
@ContextConfiguration(classes = PageTestConfiguration.class) // configuration class for db setup
@ActiveProfiles("test") // sets profile for test to allow bean overriding
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // needed to use non-static BeforeAll
public abstract class PageControllerTest {
/**
* Pre-prefix path for all the Controllers.
* There's an option in Page to add prefix path used for some Controllers.
*/
private String prePrefixPath = "HIRS_AttestationCAPortal/portal/";
/**
* Contains server-side support for testing Spring MVC applications
* via WebTestClient with MockMvc for server request handling.
*/
@Autowired
private WebApplicationContext webApplicationContext;
/**
* Used to set up mocked servlet environment to test the HTTP controller
* endpoints without the need to launch the embedded servlet container.
*/
private MockMvc mockMvc;
/**
* Represents the Page for the Controller under test.
*/
private final Page page;
/**
@ -29,6 +59,15 @@ public class PageControllerTest extends AbstractTestNGSpringContextTests {
this.page = page;
}
/**
* Returns the Page's pre-prePrefix path for routing.
*
* @return the Page's pre-prePrefix path
*/
public String getPrePrefixPath() {
return prePrefixPath;
}
/**
* Returns the Page's display and routing specification.
*
@ -50,8 +89,35 @@ public class PageControllerTest extends AbstractTestNGSpringContextTests {
/**
* Sets up the test environment.
*/
// @BeforeMethod
@BeforeEach
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
/**
* Executes a test to check that the page exists, has the correct name, and basic page data in
* its model. Methods annotated with @Test in abstract classes are ignored by Spring.
*
* @throws Exception if test fails
*/
@Test
public final void doTestPagesExist() throws Exception {
// Add prefix path for page verification
String pagePath = "/" + prePrefixPath + page.getPrefixPath() + getPage().getViewName();
if (page.getPrefixPath() == null) {
pagePath = "/" + prePrefixPath + getPage().getViewName();
}
getMockMvc()
.perform(MockMvcRequestBuilders.get(pagePath))
.andExpect(status().isOk())
.andExpect(view().name(page.getViewName()))
.andExpect(forwardedUrl("/WEB-INF/jsp/" + page.getViewName() + ".jsp"))
.andExpect(model().attribute(PageController.PAGE_ATTRIBUTE, equalTo(page)))
.andExpect(model().attribute(
PageController.PAGES_ATTRIBUTE, equalTo(Page.values()))
);
}
}

View File

@ -0,0 +1,166 @@
package hirs.attestationca.portal.page;
import hirs.attestationca.portal.PageConfiguration;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Properties;
/**
* A configuration class for testing Attestation CA Portal classes that require a database.
* This class sets up a temporary in-memory database that is used for testing.
* This class also creates beans that override beans in main class PersistenceJPAConfig.
* A few 'dummy' beans had to be created to override PersistenceJPAConfig beans that were
* not needed and would interfere with the tests.
*/
//@Import({ PageConfiguration.class })
@TestConfiguration
@EnableJpaRepositories(basePackages = "hirs.attestationca.persist.entity.manager")
public class PageTestConfiguration {
/**
* Test ACA cert.
*/
public static final String FAKE_ROOT_CA = "/certificates/fakeCA.pem";
/**
* Represents the environment in which the current application is running.
* Models 2 aspects: profiles and properties (application-test.properties)
*/
@Autowired
private Environment environment;
/**
* Gets a test x509 cert as the ACA cert for ACA portal tests.
*
* @return the {@link X509Certificate} of the ACA
* @throws URISyntaxException if there's a syntax error on the path to the cert
* @throws IOException exception reading the file
*/
@Bean
public X509Certificate acaCertificate() throws URISyntaxException, IOException {
CertificateAuthorityCredential credential = new CertificateAuthorityCredential(
Files.readAllBytes(Paths.get(getClass().getResource(FAKE_ROOT_CA).toURI()))
);
return credential.getX509Certificate();
}
/**
* Overrides the {@link DataSource} with one that is configured against an in-memory HSQL DB.
*
* @return test data source
*/
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.HSQL).build();
}
/**
* Configures a session factory bean that in turn configures the hibernate session factory.
* Enables auto scanning of annotations such that entities do not need to be registered in a
* hibernate configuration file.
*
* @return entity manager factory, which provides instances of EntityManager for connecting
* to same database.
*/
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean entityManagerBean =
new LocalContainerEntityManagerFactoryBean();
entityManagerBean.setDataSource(dataSource());
entityManagerBean.setPackagesToScan("hirs.attestationca.persist.entity");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerBean.setJpaVendorAdapter(vendorAdapter);
entityManagerBean.setJpaProperties(hibernateProperties());
return entityManagerBean;
}
/**
* Generates properties using configuration file that will be used to configure the session
* factory.
*
* @return properties for hibernate session factory
*/
final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto",
environment.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect",
environment.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.current_session_context_class",
"thread");
return hibernateProperties;
}
/**
* Generates JPA transaction manager.
*
* @return transaction manager
*/
// @Bean
// public PlatformTransactionManager transactionManager() {
// final JpaTransactionManager transactionManager = new JpaTransactionManager();
// transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
// return transactionManager;
// }
/**
* @return a blank {@link PrivateKey}
* this function is only used to override the PersistenceJPAConfig privateKey bean during test
*/
@Bean
public PrivateKey privateKey() {
try {
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
PrivateKey dummy_privKey = keyGenerator.generateKeyPair().getPrivate();
return dummy_privKey;
}
catch (GeneralSecurityException e) {
throw new AssertionError(e);
}
}
/**
* @return a blank {@link java.security.KeyStore}
* this function is only used to override the PersistenceJPAConfig keyStore bean during test
*/
@Bean
public KeyStore keyStore() {
// attempt to create the key store. if that fails, print a message before failing.
try {
KeyStore dummy_keyStore = KeyStore.getInstance("JKS");
dummy_keyStore.load(null);
return dummy_keyStore;
} catch (Exception ex) {
System.out.println("\nEncountered error while creating a fake (blank) key store for testing");
throw new BeanInitializationException(ex.getMessage(), ex);
}
}
}

View File

@ -0,0 +1,154 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.enums.HealthStatus;
import hirs.attestationca.portal.page.PageControllerTest;
import hirs.attestationca.persist.entity.userdefined.Device;
import static hirs.attestationca.portal.page.Page.DEVICES;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* Integration tests that test the URL End Points of DevicePageController.
*/
public class DevicePageControllerTest extends PageControllerTest {
/**
* Name of device
*/
private static final String DEVICE_NAME = "Test Device";
/**
* Location of test credentials for device
*/
private static final String TEST_ENDORSEMENT_CREDENTIAL
= "/endorsement_credentials/tpmcert.pem";
private static final String TEST_ENDORSEMENT_CREDENTIAL_2
= "/endorsement_credentials/ab21ccf2-tpmcert.pem";
private static final String TEST_PLATFORM_CREDENTIAL
= "/platform_credentials/Intel_pc.cer";
/**
* Device object to be stored in db for test
*/
private Device device;
/**
* Repository manager to handle data access between device entity and data storage (db).
*/
@Autowired
private DeviceRepository deviceRepository;
/**
* Repository manager to handle data access between certificate entity and data storage (db).
*/
@Autowired
private CertificateRepository certificateRepository;
/**
* Constructor providing the Page's display and routing specification.
*/
public DevicePageControllerTest() { super(DEVICES); }
/**
* Prepares a testing environment.
* @throws IOException if there is a problem constructing the test certificate
*/
@BeforeAll
public void beforeMethod() throws IOException {
// Create new device to be used in test and save it to db
device = new Device(DEVICE_NAME,null, HealthStatus.TRUSTED, AppraisalStatus.Status.PASS,
null,false,"tmp_overrideReason", "tmp_summId");
device = deviceRepository.save(device);
// Upload and save EK Cert
EndorsementCredential ec = (EndorsementCredential)
getTestCertificate(EndorsementCredential.class,
TEST_ENDORSEMENT_CREDENTIAL);
ec.setDeviceId(device.getId());
certificateRepository.save(ec);
//Add second EK Cert without a device
ec = (EndorsementCredential)
getTestCertificate(EndorsementCredential.class, TEST_ENDORSEMENT_CREDENTIAL_2);
certificateRepository.save(ec);
//Upload and save Platform Cert
PlatformCredential pc = (PlatformCredential)
getTestCertificate(PlatformCredential.class, TEST_PLATFORM_CREDENTIAL);
pc.setDeviceId(device.getId());
certificateRepository.save(pc);
}
/**
* Construct a test certificate from the given parameters.
* @param <T> the type of Certificate that will be created
* @param certificateClass the class of certificate to generate
* @param filename the location of the certificate to be used
* @return the newly-constructed Certificate
* @throws IOException if there is a problem constructing the test certificate
*/
public <T extends Certificate> Certificate getTestCertificate(
final Class<T> certificateClass,
final String filename)
throws IOException {
Path fPath;
try {
fPath = Paths.get(this.getClass().getResource(filename).toURI());
} catch (URISyntaxException e) {
throw new IOException("Could not resolve path URI", e);
}
switch (certificateClass.getSimpleName()) {
case "EndorsementCredential":
return new EndorsementCredential(fPath);
case "PlatformCredential":
return new PlatformCredential(fPath);
default:
throw new IllegalArgumentException(
String.format("Unknown certificate class %s", certificateClass.getName())
);
}
}
/**
* Tests retrieving the device list using a mocked device manager.
*
* @throws Exception if test fails
*/
@Test
public void getDeviceList() throws Exception {
// Add pre-prefix and prefix path for page verification
String pagePath = "/" + getPrePrefixPath() + getPage().getPrefixPath() + getPage().getViewName() + "/list";
if (getPage().getPrefixPath() == null) {
pagePath = "/" + getPrePrefixPath() + getPage().getViewName() + "/list";
}
// perform test
getMockMvc()
.perform(MockMvcRequestBuilders.get(pagePath))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data", hasSize(1)))
.andReturn()
;
}
}

View File

@ -0,0 +1,6 @@
# need to override beans in PersistenceJPAConfig
spring.main.allow-bean-definition-overriding=true
# need to override properties in application.properties and hibernate.properties
hibernate.dialect = org.hibernate.dialect.HSQLDialect
hibernate.hbm2ddl.auto = create

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC5zCCAdGgAwIBAgIBATALBgkqhkiG9w0BAQswFzEVMBMGA1UEAwwMRmFrZSBS
b290IENBMB4XDTE3MDEyNDE1MjU0MVoXDTQ3MDEyNDE1MjU0MVowFzEVMBMGA1UE
AwwMRmFrZSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
geIXUAtrlc+FY8FC/bAGC6Vg1lbok+kILT/ZmG/4vdigZ2hzFR3dVjmgWd4hp3uP
dY7E/JUEouBq24qDpPUWrHIxSCqGp9Rn+whGq6Yy7d1d0FGyskIJJ2aFr1QC+/jA
4CptLbQGhqmyALrmXFai3scUmNciuTbEb3Ap9829IdsD4F9hT557zRSocaelVCUw
6sNLU78fJfG7K3dKmKemvtprqlDlfM3nya5P6IzkRKiPpXN6Q1sL7FDkKQ3HuyBM
WqPU+AWhqhCR9hRenuTpwTxEPVPA8FRV78wkV3VLzXCG7lHPZ8xCDKAZzdbwymjU
wfm9Wr5KperE83suIcIHxQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
DwEB/wQEAwIBBjAdBgNVHQ4EFgQUWOwxOhaZ+UwcjE4sZBJAKyWPAXcwCwYJKoZI
hvcNAQELA4IBAQBzEIk46ajACN11nMYXg/dIS21UMjfpkOhv8dYzE5WMMtMhiiUG
3PnvVt/THIWResw1iW7OGjX9dTQ0mMSK59dH/eDqbLyle6HqWHJnKuZWjP5h1W2a
vKUgOvr7Oh0NelYFGUmUD+zOBWnKhUidO+R/BE0AifnnR+WbyMgpAjlWv5ErhukY
NN+wi6X8O38GM9+Q+OjF83zKOdV5CmMb0KHGr8xfE0tiqHMiJoDt+Jk4XysLUnrR
7+8qS+30a+FwErt0/dhqHI3/iEwPNc1jtuA6yP+vt4IE4sSPXUPh2Z2pm8Je2goQ
ybWqhqtMT1QoTT2E2GzJ9JBSt3yEZPEQn+kt
-----END CERTIFICATE-----

View File

@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEXjCCA0agAwIBAgIUWGRkKsiikVUJWz+eO8Pz0lN6xUwwDQYJKoZIhvcNAQEF
BQAwVTELMAkGA1UEBhMCQ0gxHjAcBgNVBAoTFVNUTWljcm9lbGVjdHJvbmljcyBO
VjEmMCQGA1UEAxMdU1RNIFRQTSBFSyBJbnRlcm1lZGlhdGUgQ0EgMDIwHhcNMTQw
MTE3MDAwMDAwWhcNMjQwMTE3MDAwMDAwWjAAMIIBNzAiBgkqhkiG9w0BAQcwFaIT
MBEGCSqGSIb3DQEBCQQEVENQQQOCAQ8AMIIBCgKCAQEAqyHM8tOsFtL2QEEAX+Tq
HPdi6TOZQ3Dc1sgCgwms4jRzoIoVcTMmYZhLY2qHiM0lnFXKEwb/3ox3Hzw5/ZFW
aSizfykbGN5tSkHBlBq9i8vK5i6/WcmOk88ai+VP8+pYTiFQRVQjjnrTV8YDg0pT
HIo+ZcUHVT5shxXISu7QEQe4ZnhiNG6BQmJH2+ytcUkCDh3m3pMgGsWehEMvrOSi
IjxMgKtb8MLQ4pijB81x2Tb4Wun2O5J/uUie+QbdWbbfLWOaFcH72WV9KzHcliKm
ICNqgBO9OBbB4SSzsTZY/vZ7G/xAsDaTfQdacm/qgnoXpU33dXdmY1QJTxHc5lYc
PwIDAQABo4IBZDCCAWAwHwYDVR0jBBgwFoAUVx+Aa0fM55v6NZR87Yi40QBa4J4w
QgYDVR0gBDswOTA3BgRVHSAAMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cuc3Qu
Y29tL1RQTS9yZXBvc2l0b3J5LzBVBgNVHREBAf8ESzBJpEcwRTEWMBQGBWeBBQIB
DAtpZDo1MzU0NEQyMDEXMBUGBWeBBQICDAxTVDMzWlAyNFBWU1AxEjAQBgVngQUC
AwwHaWQ6MEQwQzB/BgNVHQkEeDB2MBYGBWeBBQIQMQ0wCwwDMS4yAgECAgF0MCAG
BWeBBQISMRcwFQIBAAEB/6ADCgEBoQMKAQCiAwoBADA6BgNVBTQxMzAkMCIGCSqG
SIb3DQEBBzAVohMwEQYJKoZIhvcNAQEJBARUQ1BBMAswCQYFKw4DAhoFADAMBgNV
HRMBAf8EAjAAMBMGA1UdJQEB/wQJMAcGBWeBBQgBMA0GCSqGSIb3DQEBBQUAA4IB
AQCN1xBDK47IE+Hs5/GcC8GG55A9THUocrVwGCXi5rN1CT7QnlypzEgxAhVBFZKI
X+AZLjB5HRczAlCH7kqbfNEGjcSMLQP61+7bkvAPcdfJtr9nLR8eK/tIlRcsXX33
vE7HcnuDvuzyumb9x+RFT6tol/MhSVVA9/ETyTa4v9n2kZHQVo5KycU0fIUvQ0xe
CxU0kIdR8S6LcpBT1nSr8I8wgtaqKaoqQrMfBjAqVJYpogCUe2OLhRT8KzP/Ow3m
OarP5jgMM+rQpOHeqb/BxIrUl77ER2BJ7LIVIuCLl+cOUgsdTz46ZhY0HKVmKotu
0LThZ6mEE8+9rcaQtZsmYbRx
-----END CERTIFICATE-----

View File

@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEXjCCA0agAwIBAgIUS5gujeW5kYvYdMJZlIUT6s3F0cwwDQYJKoZIhvcNAQEF
BQAwVTELMAkGA1UEBhMCQ0gxHjAcBgNVBAoTFVNUTWljcm9lbGVjdHJvbmljcyBO
VjEmMCQGA1UEAxMdU1RNIFRQTSBFSyBJbnRlcm1lZGlhdGUgQ0EgMDIwHhcNMTQw
MjIyMDAwMDAwWhcNMjQwMjIyMDAwMDAwWjAAMIIBNzAiBgkqhkiG9w0BAQcwFaIT
MBEGCSqGSIb3DQEBCQQEVENQQQOCAQ8AMIIBCgKCAQEAsdTxu5pRjEOgA0tCNYgn
NmAqLzIxBTBft4pMBGdEk922dvBLvQySN13YnvVF6FnYCc0Y+5hSAZiRCcXpr/M3
6wx5YkePCPss06KQMujy3X9jwxTU0cDbKTjKCmFpQqCqiGIk2f7mss8yIABlwT3R
cBBbcDpGn2wYi5s9UhUfCOQ6D7qEPKJEi5IQC7/oyu5zT5FMUANdsebxrYpALcKK
8/mp5Rwj+xmaAg/+OC9jIeFGLYYu/hQr/1BPYSVicfuIFdc/0VzyJO5KMRozvV3I
2dbzQwqUD4xUxPR+f7VC+3p641Mb7WobIZH7wJm2k0M8HWeErytA66WtAoueU89O
iQIDAQABo4IBZDCCAWAwHwYDVR0jBBgwFoAUVx+Aa0fM55v6NZR87Yi40QBa4J4w
QgYDVR0gBDswOTA3BgRVHSAAMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cuc3Qu
Y29tL1RQTS9yZXBvc2l0b3J5LzBVBgNVHREBAf8ESzBJpEcwRTEWMBQGBWeBBQIB
DAtpZDo1MzU0NEQyMDEXMBUGBWeBBQICDAxTVDMzWlAyNFBWU1AxEjAQBgVngQUC
AwwHaWQ6MEQwQzB/BgNVHQkEeDB2MBYGBWeBBQIQMQ0wCwwDMS4yAgECAgF0MCAG
BWeBBQISMRcwFQIBAAEB/6ADCgEBoQMKAQCiAwoBADA6BgNVBTQxMzAkMCIGCSqG
SIb3DQEBBzAVohMwEQYJKoZIhvcNAQEJBARUQ1BBMAswCQYFKw4DAhoFADAMBgNV
HRMBAf8EAjAAMBMGA1UdJQEB/wQJMAcGBWeBBQgBMA0GCSqGSIb3DQEBBQUAA4IB
AQAb50G/d9D18ahy6RScXObaazgrNZHcF0otH9W1uJzXgSQPjFFYbHAh2+EGI8uD
90Hj9XgZYmcGv0pUHcFw7msNamr3c/Or8+pLPnu5OZtr4jCEZ7/Z75v0Z825Ov8R
N+JIxB9RT0Yd3KAPQsp4d45NHWOPBQPgBi/pW/eJqPO2MJD0uraRqAlNrUD3ppc7
xxsmOoOhyUFcs14KyrgIWNazx+4EElAKU3PthU70cszFAQM2hw/EYBfRwQ5rVZd7
V2x9hMC4POgACE6gVIDV/mHoZe6AfGQKveblJEX9gOccI28vnT14d0CwhN/SvgZF
JigA9V7w26ecFRWXpm79utMU
-----END CERTIFICATE-----