Skip to content

Commit

Permalink
Merge branch 'develop' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Bogdan Mocanu committed Apr 28, 2021
2 parents 2f89213 + cca0ff4 commit cdfc3ba
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ run.sh
AIS-Client-Prod-IAM_2014-2017*
mycert-preprod*
*~*
target
sign-pdf.properties

# IDE #
###################
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.swisscom.ais</groupId>
<artifactId>itext7-ais</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
<packaging>jar</packaging>
<name>itext7-ais</name>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Properties;
import java.util.function.Function;

@SuppressWarnings("unused")
public abstract class PropertiesLoader<T> {

private static final String ENV_VARIABLE_PREFIX = "${";
Expand Down Expand Up @@ -63,16 +64,23 @@ public Properties loadPropertiesFromClasspathFile(Class<?> clazz, String filepat
}
}

public String extractStringProperty(ConfigurationProvider provider, String propertyName) {
return extractProperty(provider, propertyName);
public String extractStringProperty(ConfigurationProvider provider, String propertyName, boolean mandatory) {
return extractProperty(provider, propertyName, mandatory);
}

public int extractIntProperty(ConfigurationProvider provider, String propertyName) {
return Integer.parseInt(extractProperty(provider, propertyName));
public Integer extractIntProperty(ConfigurationProvider provider, String propertyName, boolean mandatory) {
String property = extractProperty(provider, propertyName, mandatory);
if (property == null && !mandatory) {
return null;
}
return Integer.parseInt(property);
}

public String extractSecretProperty(ConfigurationProvider provider, String propertyName) {
String property = extractProperty(provider, propertyName);
public String extractSecretProperty(ConfigurationProvider provider, String propertyName, boolean mandatory) {
String property = extractProperty(provider, propertyName, mandatory);
if (property == null && !mandatory) {
return null;
}
return shouldExtractFromEnvVariable(property) ? System.getenv(extractEnvPropertyName(property)) : property;
}

Expand All @@ -89,8 +97,11 @@ public <E> E extractProperty(ConfigurationProvider provider, String propertyName
return StringUtils.isNotBlank(propertyValue) ? mapperFunction.apply(propertyValue) : defaultValue;
}

private String extractProperty(ConfigurationProvider provider, String propertyName) {
private String extractProperty(ConfigurationProvider provider, String propertyName, boolean mandatory) {
String propertyValue = provider.getProperty(propertyName);
if (StringUtils.isBlank(propertyValue) && !mandatory) {
return null;
}
validateProperty(propertyName, propertyValue);
return propertyValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,16 @@ public String getLicenseFilePath() {
@Override
protected AisClientConfiguration.Builder fromConfigurationProvider(ConfigurationProvider provider) {
return builder()
.withSignaturePollingIntervalInSeconds(extractIntProperty(provider, "client.poll.intervalInSeconds"))
.withSignaturePollingRounds(extractIntProperty(provider, "client.poll.rounds"))
.withLicenseFilePath(extractSecretProperty(provider, "license.file"));
.withSignaturePollingIntervalInSeconds(extractIntProperty(provider, "client.poll.intervalInSeconds", true))
.withSignaturePollingRounds(extractIntProperty(provider, "client.poll.rounds", true))
.withLicenseFilePath(extractSecretProperty(provider, "license.file", false));
}

private void validate() {
ValidationUtils.between(signaturePollingIntervalInSeconds, 1, 300,
"The signaturePollingIntervalInSeconds parameter of the AIS client configuration must be between 1 and 300 seconds");
ValidationUtils.between(signaturePollingIntervalInSeconds, 1, 100,
"The signaturePollingRounds parameter of the AIS client configuration must be between 1 and 100 seconds");
ValidationUtils.notBlank(licenseFilePath, "The iText license file path can not be blank.");
}

public static class Builder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@
import com.swisscom.ais.itext7.client.rest.model.signresp.ScExtendedSignatureObject;
import com.swisscom.ais.itext7.client.rest.model.signresp.SignResponse;
import com.swisscom.ais.itext7.client.rest.model.signresp.SignatureObject;
import com.swisscom.ais.itext7.client.utils.RequestUtils;
import com.swisscom.ais.itext7.client.utils.AisObjectUtils;
import com.swisscom.ais.itext7.client.utils.RequestUtils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -69,15 +70,17 @@ public AisClientImpl(AisClientConfiguration configuration, SignatureRestClient r
}

private void initialize() {
try {
LicenseKey.loadLicenseFile(configuration.getLicenseFilePath());
LicenseKey.scheduledCheck(null);
String[] licenseeInfo = LicenseKey.getLicenseeInfo();
clientLogger.info("Successfully load the {} iText license granted for company {}, with name {}, email {}, having version {} and "
+ "producer line {}. Is license expired: {}.", licenseeInfo[8], licenseeInfo[2], licenseeInfo[0], licenseeInfo[1],
licenseeInfo[6], licenseeInfo[4], licenseeInfo[7]);
} catch (LicenseKeyException e) {
clientLogger.error("Failed to load the iText license: {}", e.getMessage());
if (StringUtils.isNotBlank(configuration.getLicenseFilePath())) {
try {
LicenseKey.loadLicenseFile(configuration.getLicenseFilePath());
LicenseKey.scheduledCheck(null);
String[] licenseeInfo = LicenseKey.getLicenseeInfo();
clientLogger.info("Successfully load the {} iText license granted for company {}, with name {}, email {}, having version {} and "
+ "producer line {}. Is license expired: {}.", licenseeInfo[8], licenseeInfo[2], licenseeInfo[0], licenseeInfo[1],
licenseeInfo[6], licenseeInfo[4], licenseeInfo[7]);
} catch (LicenseKeyException e) {
clientLogger.error("Failed to load the iText license: {}", e.getMessage());
}
}
}

Expand Down Expand Up @@ -117,7 +120,7 @@ private SignatureResult performSigning(SignatureMode signatureMode, SignatureTyp
try {
List<AdditionalProfile> additionalProfiles = prepareAdditionalProfiles(profiles, documents);
AISSignRequest signRequest = RequestUtils.buildAisSignRequest(documents, signatureMode, signatureType, userData, additionalProfiles,
signWithStepUp, signWithCertificateRequest);
signWithStepUp, signWithCertificateRequest);
AISSignResponse signResponse = restClient.requestSignature(signRequest, trace);

if (signWithStepUp && !ResponseUtils.isResponseAsyncPending(signResponse)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,13 @@ public String getSignatureContactInfo() {
@Override
protected UserData.Builder fromConfigurationProvider(ConfigurationProvider provider) {
return builder()
.withClaimedIdentityName(extractStringProperty(provider, "signature.claimedIdentityName"))
.withClaimedIdentityName(extractStringProperty(provider, "signature.claimedIdentityName", true))
.withClaimedIdentityKey(provider.getProperty("signature.claimedIdentityKey"))
.withStepUpLanguage(provider.getProperty("signature.stepUp.language"))
.withStepUpMsisdn(provider.getProperty("signature.stepUp.msisdn"))
.withStepUpMessage(provider.getProperty("signature.stepUp.message"))
.withStepUpSerialNumber(provider.getProperty("signature.stepUp.serialNumber"))
.withDistinguishedName(extractStringProperty(provider, "signature.distinguishedName"))
.withDistinguishedName(extractStringProperty(provider, "signature.distinguishedName", true))
.withSignatureName(provider.getProperty("signature.name"))
.withSignatureReason(provider.getProperty("signature.reason"))
.withSignatureLocation(provider.getProperty("signature.location"))
Expand Down Expand Up @@ -181,6 +181,7 @@ public void validatePropertiesForSignature(SignatureMode signatureMode, Trace tr
}
}

@SuppressWarnings("unused")
public static class Builder {
private String transactionId = IdGenerator.generateId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,16 @@ public int getResponseTimeoutInSec() {
@Override
protected RestClientConfiguration.Builder fromConfigurationProvider(ConfigurationProvider provider) {
return builder()
.withServiceSignUrl(extractStringProperty(provider, "server.rest.signUrl"))
.withServicePendingUrl(extractStringProperty(provider, "server.rest.pendingUrl"))
.withClientKeyFile(extractStringProperty(provider, "client.auth.keyFile"))
.withClientKeyPassword(extractSecretProperty(provider, "client.auth.keyPassword"))
.withClientCertificateFile(extractStringProperty(provider, "client.cert.file"))
.withServerCertificateFile(extractStringProperty(provider, "server.cert.file"))
.withMaxTotalConnections(extractIntProperty(provider, "client.http.maxTotalConnections"))
.withMaxConnectionsPerRoute(extractIntProperty(provider, "client.http.maxConnectionsPerRoute"))
.withConnectionTimeoutInSec(extractIntProperty(provider, "client.http.connectionTimeoutInSeconds"))
.withResponseTimeoutInSec(extractIntProperty(provider, "client.http.responseTimeoutInSeconds"));
.withServiceSignUrl(extractStringProperty(provider, "server.rest.signUrl", true))
.withServicePendingUrl(extractStringProperty(provider, "server.rest.pendingUrl", true))
.withClientKeyFile(extractStringProperty(provider, "client.auth.keyFile", true))
.withClientKeyPassword(extractSecretProperty(provider, "client.auth.keyPassword", false))
.withClientCertificateFile(extractStringProperty(provider, "client.cert.file", true))
.withServerCertificateFile(extractStringProperty(provider, "server.cert.file", true))
.withMaxTotalConnections(extractIntProperty(provider, "client.http.maxTotalConnections", true))
.withMaxConnectionsPerRoute(extractIntProperty(provider, "client.http.maxConnectionsPerRoute", true))
.withConnectionTimeoutInSec(extractIntProperty(provider, "client.http.connectionTimeoutInSeconds", true))
.withResponseTimeoutInSec(extractIntProperty(provider, "client.http.responseTimeoutInSeconds", true));
}

private void validate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.apache.hc.core5.ssl.PrivateKeyStrategy;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.hc.core5.ssl.SSLContexts;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
Expand All @@ -54,9 +55,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
Expand Down Expand Up @@ -244,20 +246,43 @@ private KeyStore produceTheTrustStore(RestClientConfiguration config) {
}
}

public PrivateKey getPrivateKey(String filename, String keyPassword) throws IOException {
PEMParser pemParser = new PEMParser(new InputStreamReader(new FileInputStream(filename)));
PEMKeyPair keyPair = retrieveKeyFromParser(keyPassword, pemParser);
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
return converter.getPrivateKey(keyPair.getPrivateKeyInfo());
}
public static PrivateKey getPrivateKey(String fileName, String keyPassword) {
try {
BufferedReader br = new BufferedReader(new FileReader(fileName));
// if we read a X509 key we will get immediately a PrivateKeyInfo
// if the key is a RSA key it is necessary to create a PEMKeyPair first
PrivateKeyInfo privateKeyInfo;
PEMParser pemParser;
try {
pemParser = new PEMParser(br);
privateKeyInfo = (PrivateKeyInfo) pemParser.readObject();
} catch (Exception ignored) {
br.close();
br = new BufferedReader(new FileReader(fileName));
pemParser = new PEMParser(br);
Object pemKeyPair = pemParser.readObject();
if (pemKeyPair instanceof PEMEncryptedKeyPair) {
if (StringUtils.isBlank(keyPassword)) {
throw new AisClientException("The client private key is encrypted but there is no key password provided " +
"(check field 'client.auth.keyPassword' from the config.properties or from " +
"the REST client configuration)");
}
PEMDecryptorProvider decryptionProv = new JcePEMDecryptorProviderBuilder().build(keyPassword.toCharArray());
PEMKeyPair decryptedKeyPair = ((PEMEncryptedKeyPair) pemKeyPair).decryptKeyPair(decryptionProv);
privateKeyInfo = decryptedKeyPair.getPrivateKeyInfo();
} else {
privateKeyInfo = ((PEMKeyPair) pemKeyPair).getPrivateKeyInfo();
}
}

private PEMKeyPair retrieveKeyFromParser(String keyPassword, PEMParser pemParser) throws IOException {
if (StringUtils.isBlank(keyPassword)) {
return (PEMKeyPair) pemParser.readObject();
pemParser.close();
br.close();

JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter();
return jcaPEMKeyConverter.getPrivateKey(privateKeyInfo);
} catch (Exception e) {
throw new AisClientException("Failed to initialize the client private key", e);
}
PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) pemParser.readObject();
PEMDecryptorProvider decryptorProvider = new JcePEMDecryptorProviderBuilder().setProvider("BC").build(keyPassword.toCharArray());
return encryptedKeyPair.decryptKeyPair(decryptorProvider);
}

private PrivateKeyStrategy producePrivateKeyStrategy() {
Expand Down

0 comments on commit cdfc3ba

Please sign in to comment.