From ed67667ea4e069fb1c19708788ff82c7455a7e99 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 3 Nov 2020 17:20:21 +0100 Subject: Initialize IAIK-MOA on any request, because there is an open unknown issue with signature-verification and lost configuration states --- .../core/impl/credential/EaafKeyStoreFactory.java | 14 +++++----- .../moasig/impl/AbstractSignatureService.java | 31 +++++++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java index 955648c6..1c6e6e76 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java @@ -27,6 +27,11 @@ import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException; import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; @@ -37,12 +42,6 @@ import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricK import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.utils.FileUtils; import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; - import lombok.extern.slf4j.Slf4j; @Slf4j @@ -246,7 +245,8 @@ public class EaafKeyStoreFactory { clientUsername, clientPassword, hsmFacadeHost, port); if (rawProvider instanceof Provider) { - Security.insertProviderAt((Provider) rawProvider, 0); + Security.addProvider((Provider) rawProvider); + isHsmFacadeInitialized = true; log.info("HSM Facade is initialized. {} can provide KeyStores based on remote HSM", EaafKeyStoreFactory.class.getSimpleName()); diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java index 11881cbf..37d80337 100644 --- a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java @@ -1,20 +1,24 @@ package at.gv.egiz.eaaf.modules.sigverify.moasig.impl; +import java.security.Provider; +import java.security.Security; + import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.w3c.dom.Document; + import at.gv.egovernment.moa.spss.server.config.ConfigurationException; +import at.gv.egovernment.moa.spss.server.iaik.config.IaikConfigurator; import at.gv.egovernment.moa.spss.server.transaction.TransactionContext; import at.gv.egovernment.moa.spss.server.transaction.TransactionContextManager; import at.gv.egovernment.moaspss.logging.LoggingContext; import at.gv.egovernment.moaspss.logging.LoggingContextManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.w3c.dom.Document; - public abstract class AbstractSignatureService { private static final Logger log = LoggerFactory.getLogger(AbstractSignatureService.class); @@ -54,16 +58,31 @@ public abstract class AbstractSignatureService { } + //set Logging context into MOA-Sig if (logMgr.getLoggingContext() == null) { final LoggingContext ctx = new LoggingContext(transactionID); logMgr.setLoggingContext(ctx); } - //new IaikConfigurator().configure(moaSigConfig.getMoaSigConfig()); + //dump Java Security-Providers + if (log.isTraceEnabled()) { + dumpSecProviders("MOA-Sig Context-SetUp"); + + } + + new IaikConfigurator().configure(moaSigConfig.getMoaSigConfig()); } + private static void dumpSecProviders(String message) { + log.trace("Security Providers: {}", message); + for (final Provider provider : Security.getProviders()) { + log.trace(" - {} - {}", provider.getName(), provider.getVersion()); + + } + } + /** * Tear down thread-local context information. */ -- cgit v1.2.3 From 651b5e445023d7d7004a8a7387065454b823c581 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 4 Nov 2020 17:50:14 +0100 Subject: refactoring of SL2.0 response processing to mitigate problems with ConnectionPool of Apache http-client --- .../tasks/AbstractCreateQualEidRequestTask.java | 49 ++++---- .../auth/sl20/utils/SL20HttpBindingUtils.java | 124 +++++++++++++++++++++ .../auth/sl20/utils/SL20JsonExtractorUtils.java | 84 -------------- 3 files changed, 153 insertions(+), 104 deletions(-) diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java index 56084d94..9a041028 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java @@ -12,6 +12,19 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.jose4j.base64url.Base64Url; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; @@ -30,22 +43,9 @@ import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants; import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants.VdaAuthMethod; import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20HttpBindingUtils; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20HttpBindingUtils.Sl20ResponseHolder; import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonBuilderUtils; import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonExtractorUtils; - -import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.message.BasicNameValuePair; -import org.jose4j.base64url.Base64Url; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.i18n.LocaleContextHolder; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -113,12 +113,21 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl Base64Url.encode(sl20Req.toString().getBytes(StandardCharsets.UTF_8))); // request VDA - final HttpResponse httpResp = httpClientFactory.getHttpClient(false).execute(httpReq); - + final Sl20ResponseHolder httpResp = httpClientFactory.getHttpClient(false).execute( + httpReq, SL20HttpBindingUtils.sl20ResponseHandler()); + + //check on error on http channel + if (httpResp.getError() != null) { + log.info("Basic SL2.0 response processing has an error. HTTP-StatusCode: {} ErrorMsg: {}", + httpResp.getResponseStatus().getStatusCode(), httpResp.getError().getMessage()); + throw httpResp.getError(); + + } + // parse response log.info("Receive response from VDA ... "); - final JsonNode sl20Resp = SL20JsonExtractorUtils.getSL20ContainerFromResponse(httpResp); - final VerificationResult respPayloadContainer = SL20JsonExtractorUtils.extractSL20PayLoad(sl20Resp, null, false); + final VerificationResult respPayloadContainer = + SL20JsonExtractorUtils.extractSL20PayLoad(httpResp.getResponseBody(), null, false); if (respPayloadContainer.isValidSigned() == null) { log.debug("Receive unsigned payLoad from VDA"); @@ -139,7 +148,7 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, false); // create forward SL2.0 command - final ObjectNode sl20Forward = sl20Resp.deepCopy(); + final ObjectNode sl20Forward = httpResp.getResponseBody().deepCopy(); SL20JsonBuilderUtils.addOnlyOnceOfTwo(sl20Forward, SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD, command.deepCopy(), signedCommand); @@ -223,7 +232,7 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl final Locale locale = LocaleContextHolder.getLocale(); final String language = locale.getLanguage(); if (StringUtils.isNotEmpty(language)) { - log.trace("Find i18n context. Inject locale: {} into VDA request", locale.getLanguage()); + log.trace("Find i18n context). Inject locale: {} into VDA request", locale.getLanguage()); parameters.add(new BasicNameValuePair( SL20Constants.PARAM_SL20_REQ_AUTH_VDA_LOCALE, language.toUpperCase(locale))); diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java index 1d7c9646..d07c0e66 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java @@ -3,23 +3,129 @@ package at.gv.egiz.eaaf.modules.auth.sl20.utils; import java.io.IOException; import java.io.StringWriter; import java.net.URISyntaxException; +import java.text.MessageFormat; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.ParseException; +import org.apache.http.StatusLine; +import org.apache.http.client.ResponseHandler; import org.apache.http.client.utils.URIBuilder; +import org.apache.http.util.EntityUtils; import org.jose4j.base64url.Base64Url; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import com.fasterxml.jackson.databind.JsonNode; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; +import lombok.Data; +import lombok.Getter; + public class SL20HttpBindingUtils { private static final Logger log = LoggerFactory.getLogger(SL20HttpBindingUtils.class); + private static JsonMapper mapper = new JsonMapper(); + + @Data + @Getter + public static class Sl20ResponseHolder { + private final JsonNode responseBody; + private final StatusLine responseStatus; + private SlCommandoParserException error; + + } + + /** + * Security-Layer 2.0 specific response-handler for Apache HTTP client. + * + * @return {@link Sl20ResponseHolder} + */ + public static ResponseHandler sl20ResponseHandler() { + return response -> { + try { + final int httpStatusCode = response.getStatusLine().getStatusCode(); + if (httpStatusCode == HttpStatus.OK.value()) { + if (response.getEntity().getContentType() == null) { + throw new SlCommandoParserException("SL20 response contains NO ContentType"); + + } + + if (!response.getEntity().getContentType().getValue().startsWith("application/json")) { + throw new SlCommandoParserException( + "SL20 response with a wrong ContentType: " + response.getEntity().getContentType().getValue()); + + } + + //parse OK response from body + return new Sl20ResponseHolder(parseSL20ResultFromResponse(response.getEntity()), + response.getStatusLine()); + + } else if (httpStatusCode == HttpStatus.SEE_OTHER.value() + || httpStatusCode == HttpStatus.TEMPORARY_REDIRECT.value()) { + final Header[] locationHeader = response.getHeaders("Location"); + if (locationHeader == null) { + throw new SlCommandoParserException("Find Redirect statuscode but not Location header"); + + } + + final String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue(); + return new Sl20ResponseHolder(mapper.getMapper().readTree(Base64Url.decode(sl20RespString)), + response.getStatusLine()); + + } else if ( + httpStatusCode == HttpStatus.INTERNAL_SERVER_ERROR.value() + || httpStatusCode == HttpStatus.UNAUTHORIZED.value() + || httpStatusCode == HttpStatus.BAD_REQUEST.value()) { + log.info("SL20 response with http-code: {}. Search for error message", httpStatusCode); + + String bodyMsg = "_EMPTY_"; + try { + //extract JSON body from defined http error-codes + bodyMsg = EntityUtils.toString(response.getEntity()); + log.info("SL20 response with http-code: {0} and errorMsg: {1}", httpStatusCode, bodyMsg); + Sl20ResponseHolder holder = new Sl20ResponseHolder( + mapper.getMapper().readTree(bodyMsg), response.getStatusLine()); + return holder; + + } catch (final IOException | ParseException e) { + log.warn("SL20 response contains no valid JSON", e); + throw new SlCommandoParserException(MessageFormat.format( + "SL20 response with http-code: {0} with body: {1} and generic response-processing error: {2}", + httpStatusCode, bodyMsg, e.getMessage())); + + } + + } else { + //all other HTTP StatusCodes + throw new SlCommandoParserException(MessageFormat.format( + "SL20 response with http-code: {0} and errorMsg: {1}", + httpStatusCode, EntityUtils.toString(response.getEntity()))); + + } + + } catch (SlCommandoParserException e) { + Sl20ResponseHolder holder = new Sl20ResponseHolder(null, response.getStatusLine()); + holder.setError(e); + return holder; + + } catch (final Exception e) { + Sl20ResponseHolder holder = new Sl20ResponseHolder(null, response.getStatusLine()); + holder.setError( + new SlCommandoParserException("SL20 response parsing FAILED! Reason: " + e.getMessage(), e)); + return holder; + + } + }; + } + /** * Write SL2.0 response into http-response object * @@ -59,6 +165,24 @@ public class SL20HttpBindingUtils { httpResp.setHeader("Location", clientRedirectUri.build().toString()); } + } + + private static JsonNode parseSL20ResultFromResponse(final HttpEntity resp) throws Exception { + if (resp != null && resp.getContent() != null) { + final String rawSL20Resp = EntityUtils.toString(resp); + final JsonNode sl20Resp = mapper.getMapper().readTree(rawSL20Resp); + + // TODO: check sl20Resp type like && sl20Resp.isJsonObject() + if (sl20Resp != null) { + return sl20Resp; + + } else { + throw new SlCommandoParserException("SL2.0 can NOT parse to a JSON object"); + } + + } else { + throw new SlCommandoParserException("Can NOT find content in http response"); + } } } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java index 40ea0430..bed25c0c 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java @@ -8,12 +8,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.util.EntityUtils; -import org.jose4j.base64url.Base64Url; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -299,84 +293,6 @@ public class SL20JsonExtractorUtils { } - /** - * Extract generic transport container from httpResponse. - * - * @param httpResp Http response object - * @return JSON with SL2.0 response - * @throws SlCommandoParserException In case of an error - */ - public static JsonNode getSL20ContainerFromResponse(final HttpResponse httpResp) throws SlCommandoParserException { - try { - JsonNode sl20Resp = null; - if (httpResp.getStatusLine().getStatusCode() == 303 || httpResp.getStatusLine().getStatusCode() == 307) { - final Header[] locationHeader = httpResp.getHeaders("Location"); - if (locationHeader == null) { - throw new SlCommandoParserException("Find Redirect statuscode but not Location header"); - } - - final String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue(); - sl20Resp = mapper.getMapper().readTree(Base64Url.decode(sl20RespString)); - - } else if (httpResp.getStatusLine().getStatusCode() == 200) { - if (httpResp.getEntity().getContentType() == null) { - throw new SlCommandoParserException("SL20 response contains NO ContentType"); - } - - if (!httpResp.getEntity().getContentType().getValue().startsWith("application/json")) { - throw new SlCommandoParserException( - "SL20 response with a wrong ContentType: " + httpResp.getEntity().getContentType().getValue()); - } - sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); - - } else if (httpResp.getStatusLine().getStatusCode() == 500 || httpResp.getStatusLine().getStatusCode() == 401 - || httpResp.getStatusLine().getStatusCode() == 400) { - log.info( - "SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode() + ". Search for error message"); - - try { - sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); - - } catch (final Exception e) { - log.warn("SL20 response contains no valid JSON", e); - throw new SlCommandoParserException("SL20 response with http-code: " - + httpResp.getStatusLine().getStatusCode() + " AND NO valid JSON errormsg", e); - - } - - } else { - throw new SlCommandoParserException( - "SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode()); - } - - log.info("Find JSON object in http response"); - return sl20Resp; - - } catch (final Exception e) { - throw new SlCommandoParserException("SL20 response parsing FAILED! Reason: " + e.getMessage(), e); - - } - } - - private static JsonNode parseSL20ResultFromResponse(final HttpEntity resp) throws Exception { - if (resp != null && resp.getContent() != null) { - final String rawSL20Resp = EntityUtils.toString(resp); - final JsonNode sl20Resp = mapper.getMapper().readTree(rawSL20Resp); - - // TODO: check sl20Resp type like && sl20Resp.isJsonObject() - if (sl20Resp != null) { - return sl20Resp; - - } else { - throw new SlCommandoParserException("SL2.0 can NOT parse to a JSON object"); - } - - } else { - throw new SlCommandoParserException("Can NOT find content in http response"); - } - - } - private static JsonNode getAndCheck(final JsonNode input, final String keyID, final boolean isRequired) throws SlCommandoParserException { final JsonNode internal = input.get(keyID); -- cgit v1.2.3 From 62e36db9929c944754a3cebabcbb8227b3f8b592 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 4 Nov 2020 17:50:28 +0100 Subject: update logging --- .../AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java | 6 ++---- .../modules/sigverify/moasig/impl/AbstractSignatureService.java | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java index ebfe7500..b10f8586 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java @@ -144,8 +144,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy log.debug("Token decryption successful"); if (!(StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1)) { - log.warn("PendingRequestId has an unvalid format"); - log.debug("PendingRequestId: {}", stringToken); + log.info("PendingRequestId: {}", stringToken); throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format"); } @@ -161,8 +160,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy final DateTime now = DateTime.now(); if (timeStamp.withFieldAdded(DurationFieldType.seconds(), maxPendingRequestIdLifeTime) .isBefore(now)) { - log.warn("Token exceeds the valid period"); - log.debug("Token: {} | Now: {}", timeStamp, now); + log.info("Token exceeds the valid period. Token: {} | Now: {}", timeStamp, now); throw new PendingReqIdValidationException(internalPendingReqId, "PendingRequestId exceeds the valid period"); diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java index 37d80337..b9219ee4 100644 --- a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java @@ -49,7 +49,7 @@ public abstract class AbstractSignatureService { protected final void setUpContexts(final String transactionID) throws ConfigurationException { final TransactionContextManager txMgr = TransactionContextManager.getInstance(); final LoggingContextManager logMgr = LoggingContextManager.getInstance(); - + if (txMgr.getTransactionContext() == null) { log.debug("Set not MOA-Sig transaction context"); final TransactionContext ctx = @@ -67,7 +67,8 @@ public abstract class AbstractSignatureService { //dump Java Security-Providers if (log.isTraceEnabled()) { - dumpSecProviders("MOA-Sig Context-SetUp"); + log.trace("Set-Up verifier Bean: {}", this); + dumpSecProviders("MOA-Sig Context-Set-Up"); } -- cgit v1.2.3 From 83e19359c762bd5652dfa8e2a66d7e5a0c3f2184 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Thu, 5 Nov 2020 11:39:02 +0100 Subject: add scheduled eviction policy to clean-up expired or old http connections from pool --- .../eaaf/core/impl/http/HttpClientFactory.java | 168 +++++++++++++-------- 1 file changed, 104 insertions(+), 64 deletions(-) diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java index 647c0636..07522b56 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java @@ -4,6 +4,8 @@ import java.security.KeyStore; import java.security.Provider; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import javax.annotation.PostConstruct; @@ -23,6 +25,7 @@ import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.config.SocketConfig; +import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.LayeredConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; @@ -33,10 +36,12 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultRedirectStrategy; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; import org.apache.http.ssl.SSLContexts; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; @@ -65,10 +70,10 @@ public class HttpClientFactory implements IHttpClientFactory { public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION = "client.http.connection.timeout.connection"; public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST = - "client.http.connection.timeout.request"; - public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT = + "client.http.connection.timeout.request"; + public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT = "client.http.connection.retry.count"; - public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST = + public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST = "client.http.connection.retry.post"; public static final String PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL = "client.http.ssl.hostnameverifier.trustall"; @@ -97,9 +102,14 @@ public class HttpClientFactory implements IHttpClientFactory { public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE = "100"; public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT = "3"; public static final String DEFAUTL_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST = String.valueOf(false); + + public static final int DEFAULT_CLEANUP_RUNNER_TIME = 30000; + public static final int DEFAULT_CLEANUP_IDLE_TIME = 60; + private String defaultConfigurationId = null; - private final Map availableBuilders = new HashMap<>(); + private final Map> + availableBuilders = new HashMap<>(); /* * (non-Javadoc) @@ -114,7 +124,7 @@ public class HttpClientFactory implements IHttpClientFactory { @Override public CloseableHttpClient getHttpClient(final boolean followRedirects) { - return availableBuilders.get(defaultConfigurationId).setRedirectStrategy( + return availableBuilders.get(defaultConfigurationId).getFirst().setRedirectStrategy( buildRedirectStrategy(followRedirects)).build(); } @@ -124,30 +134,31 @@ public class HttpClientFactory implements IHttpClientFactory { log.trace("Build http client for: {}", config.getFriendlyName()); HttpClientBuilder builder = null; if (availableBuilders.containsKey(config.getUuid())) { - builder = availableBuilders.get(config.getUuid()); + builder = availableBuilders.get(config.getUuid()).getFirst(); } else { log.debug("Initialize new http-client builder for: {}", config.getFriendlyName()); - //validate configuration object + // validate configuration object config.validate(); builder = HttpClients.custom(); - - //inject request configuration + + // inject request configuration builder.setDefaultRequestConfig(buildDefaultRequestConfig()); injectInternalRetryHandler(builder, config); - - //inject basic authentication infos + + // inject basic authentication infos injectBasicAuthenticationIfRequired(builder, config); - //inject authentication if required + // inject authentication if required final LayeredConnectionSocketFactory sslConnectionFactory = getSslContext(config); // set pool connection if required - injectDefaultConnectionPoolIfRequired(builder, sslConnectionFactory); + HttpClientConnectionManager connectionManager + = injectConnectionManager(builder, sslConnectionFactory); - availableBuilders.put(config.getUuid(), builder); + availableBuilders.put(config.getUuid(), Pair.newInstance(builder, connectionManager)); } @@ -156,27 +167,45 @@ public class HttpClientFactory implements IHttpClientFactory { } - private void injectInternalRetryHandler(HttpClientBuilder builder, HttpClientConfiguration config) { + /** + * Worker that closes expired connections or connections that in idle + * for more than DEFAULT_CLEANUP_IDLE_TIME seconds. + * + */ + @Scheduled(fixedDelay = DEFAULT_CLEANUP_RUNNER_TIME) + private void httpConnectionPoolCleaner() { + log.trace("Starting http connection-pool eviction policy ... "); + for (final Entry> el + : availableBuilders.entrySet()) { + log.trace("Checking connections of http-client: {}", el.getKey()); + el.getValue().getSecond().closeExpiredConnections(); + el.getValue().getSecond().closeIdleConnections(DEFAULT_CLEANUP_IDLE_TIME, TimeUnit.SECONDS); + + } + + } + + private void injectInternalRetryHandler(HttpClientBuilder builder, HttpClientConfiguration config) { if (config.getHttpErrorRetryCount() > 0) { - log.info("Set HTTP error-retry to {} for http-client: {}", + log.info("Set HTTP error-retry to {} for http-client: {}", config.getHttpErrorRetryCount(), config.getFriendlyName()); builder.setRetryHandler(new EaafHttpRequestRetryHandler( - config.getHttpErrorRetryCount(), - config.isHttpErrorRetryPost())); - + config.getHttpErrorRetryCount(), + config.isHttpErrorRetryPost())); + if (config.getServiceUnavailStrategy() != null) { log.debug("HttpClient configuration: {} set custom ServiceUnavailableRetryStrategy: {}", config.getFriendlyName(), config.getServiceUnavailStrategy().getClass().getName()); builder.setServiceUnavailableRetryStrategy(config.getServiceUnavailStrategy()); - + } - + } else { log.info("Disable HTTP error-retry for http-client: {}", config.getFriendlyName()); builder.disableAutomaticRetries(); - + } - + } @PostConstruct @@ -190,8 +219,8 @@ public class HttpClientFactory implements IHttpClientFactory { // set default request configuration defaultHttpClientBuilder.setDefaultRequestConfig(buildDefaultRequestConfig()); injectInternalRetryHandler(defaultHttpClientBuilder, defaultHttpClientConfig); - - //inject http basic authentication + + // inject http basic authentication injectBasicAuthenticationIfRequired(defaultHttpClientBuilder, defaultHttpClientConfig); // inject authentication if required @@ -199,11 +228,13 @@ public class HttpClientFactory implements IHttpClientFactory { getSslContext(defaultHttpClientConfig); // set pool connection if required - injectDefaultConnectionPoolIfRequired(defaultHttpClientBuilder, sslConnectionFactory); + HttpClientConnectionManager connectionManager + = injectConnectionManager(defaultHttpClientBuilder, sslConnectionFactory); - //set default http client builder + // set default http client builder defaultConfigurationId = defaultHttpClientConfig.getUuid(); - availableBuilders.put(defaultConfigurationId, defaultHttpClientBuilder); + availableBuilders.put(defaultConfigurationId, + Pair.newInstance(defaultHttpClientBuilder, connectionManager)); } @@ -239,13 +270,12 @@ public class HttpClientFactory implements IHttpClientFactory { PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL, false)); config.setHttpErrorRetryCount(Integer.parseInt(basicConfig.getBasicConfiguration( - PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT, + PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT, DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT))); config.setHttpErrorRetryPost(Boolean.parseBoolean(basicConfig.getBasicConfiguration( - PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST, + PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST, DEFAUTL_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST))); - - + // validate configuration object config.validate(); @@ -280,7 +310,8 @@ public class HttpClientFactory implements IHttpClientFactory { SSLContext sslContext = null; if (httpClientConfig.getAuthMode().equals(HttpClientConfiguration.ClientAuthMode.SSL)) { log.debug("Open keyStore with type: {}", httpClientConfig.getKeyStoreConfig().getKeyStoreType()); - final Pair keyStore = keyStoreFactory.buildNewKeyStore(httpClientConfig.getKeyStoreConfig()); + final Pair keyStore = keyStoreFactory.buildNewKeyStore(httpClientConfig + .getKeyStoreConfig()); log.trace("Injecting SSL client-authentication into http client ... "); sslContext = HttpUtils.buildSslContextWithSslClientAuthentication(keyStore, @@ -290,7 +321,7 @@ public class HttpClientFactory implements IHttpClientFactory { } else { log.trace("Initializing default SSL Context ... "); sslContext = SSLContexts.createDefault(); - + } // set hostname verifier @@ -308,48 +339,37 @@ public class HttpClientFactory implements IHttpClientFactory { } - private void injectDefaultConnectionPoolIfRequired( + @Nonnull + private HttpClientConnectionManager injectConnectionManager( HttpClientBuilder builder, final LayeredConnectionSocketFactory sslConnectionFactory) { if (basicConfig.getBasicConfigurationBoolean(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE, true)) { - PoolingHttpClientConnectionManager pool; - - // set socketFactoryRegistry if SSLConnectionFactory is Set - if (sslConnectionFactory != null) { - final Registry socketFactoryRegistry = - RegistryBuilder.create() - .register("http", PlainConnectionSocketFactory.getSocketFactory()) - .register("https", sslConnectionFactory).build(); - log.trace("Inject SSLSocketFactory into pooled connection"); - pool = new PoolingHttpClientConnectionManager(socketFactoryRegistry); - - } else { - pool = new PoolingHttpClientConnectionManager(); - - } - - pool.setDefaultMaxPerRoute(Integer.parseInt( + PoolingHttpClientConnectionManager connectionPool + = new PoolingHttpClientConnectionManager(getDefaultRegistry(sslConnectionFactory)); + connectionPool.setDefaultMaxPerRoute(Integer.parseInt( basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE, DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE))); - pool.setMaxTotal(Integer.parseInt( + connectionPool.setMaxTotal(Integer.parseInt( basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL, DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL))); - - pool.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(Integer.parseInt( + connectionPool.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(Integer.parseInt( basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET, DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET)) * 1000).build()); + builder.setConnectionManager(connectionPool); + log.debug("Initalize http-client pool with, maxTotal: {} maxPerRoute: {}", + connectionPool.getMaxTotal(), connectionPool.getDefaultMaxPerRoute()); + return connectionPool; + + } else { + log.debug("Building http-client without Connection-Pool ... "); + final BasicHttpClientConnectionManager basicPool = new BasicHttpClientConnectionManager( + getDefaultRegistry(sslConnectionFactory)); + builder.setConnectionManager(basicPool); + return basicPool; - builder.setConnectionManager(pool); - log.debug("Initalize http-client pool with, maxTotal: {} maxPerRoute: {}", pool.getMaxTotal(), - pool.getDefaultMaxPerRoute()); - - } else if (sslConnectionFactory != null) { - log.trace("Inject SSLSocketFactory without connection pool"); - builder.setSSLSocketFactory(sslConnectionFactory); - } - + } private RequestConfig buildDefaultRequestConfig() { @@ -392,5 +412,25 @@ public class HttpClientFactory implements IHttpClientFactory { return redirectStrategy; } + + private static Registry getDefaultRegistry( + final LayeredConnectionSocketFactory sslConnectionFactory) { + final RegistryBuilder builder = + RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()); + + if (sslConnectionFactory != null) { + log.trace("Inject own SSLSocketFactory into pooled connection"); + builder.register("https", sslConnectionFactory); + + } else { + log.trace("Inject default SSLSocketFactory into pooled connection"); + builder.register("https", SSLConnectionSocketFactory.getSocketFactory()); + + } + + return builder.build(); + + } } -- cgit v1.2.3 From 1c19ec91df9f0cd6a010d16c9190c5d16ec5fdc8 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 6 Nov 2020 11:16:53 +0100 Subject: optimize error-handling in case with special focus on backend communication-requests --- .../impl/idp/controller/AbstractController.java | 27 ++++++++++------- .../AbstractProcessEngineSignalController.java | 4 +++ .../controller/ProtocolFinalizationController.java | 35 ++++++++++++++-------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java index 58c8c0a9..41c7a432 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java @@ -26,6 +26,14 @@ import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.text.StringEscapeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.util.SerializationUtils; +import org.springframework.web.bind.annotation.ExceptionHandler; + import at.gv.egiz.components.eventlog.api.EventConstants; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.IStatusMessenger; @@ -35,20 +43,12 @@ import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; import at.gv.egiz.eaaf.core.api.idp.auth.services.IProtocolAuthenticationService; import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.data.Pair; -import at.gv.egiz.eaaf.core.impl.utils.Random; - -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.util.SerializationUtils; -import org.springframework.web.bind.annotation.ExceptionHandler; /** * Basic application controller that implements core error-handling. @@ -74,6 +74,9 @@ public abstract class AbstractController { @Autowired protected IRevisionLogger revisionsLogger; + @Autowired + protected IPendingRequestIdGenerationStrategy reqIdGenerationStrategy; + /** * EAAF framework exception handler. * @@ -168,7 +171,9 @@ public abstract class AbstractController { } // put exception into transaction store for redirect - final String errorKey = Random.nextLongRandom(); + final String errorToken = reqIdGenerationStrategy.generateExternalPendingRequestId(); + final String errorKey = reqIdGenerationStrategy.getPendingRequestIdWithOutChecks(errorToken); + if (errorToHandle.getFirst() != null) { revisionsLogger.logEvent(errorToHandle.getFirst(), EventConstants.TRANSACTION_ERROR); @@ -189,7 +194,7 @@ public abstract class AbstractController { } - return errorKey; + return errorToken; } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java index 098bca4c..2ce728c1 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java @@ -36,6 +36,7 @@ import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.EaafIllegalStateException; +import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; /** @@ -85,6 +86,9 @@ public abstract class AbstractProcessEngineSignalController extends AbstractCont // wake up next task processEngine.signal(pendingReq); + } catch (PendingReqIdValidationException e) { + handleError(null, e, req, resp, e.getInvalidPendingReq()); + } catch (final Exception ex) { handleError(null, ex, req, resp, pendingReq); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java index 3fc31673..2a8dd756 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java @@ -24,14 +24,6 @@ import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import at.gv.egiz.components.eventlog.api.EventConstants; -import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.api.IRequestStorage; -import at.gv.egiz.eaaf.core.api.IStatusMessenger; -import at.gv.egiz.eaaf.core.api.data.EaafConstants; -import at.gv.egiz.eaaf.core.api.data.ExceptionContainer; -import at.gv.egiz.eaaf.core.exceptions.EaafException; - import org.apache.commons.text.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +33,15 @@ import org.springframework.util.SerializationUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import at.gv.egiz.components.eventlog.api.EventConstants; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IRequestStorage; +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.ExceptionContainer; +import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; +import at.gv.egiz.eaaf.core.exceptions.EaafException; + /** * Protocol finialization end-point. * @@ -55,6 +56,7 @@ public class ProtocolFinalizationController extends AbstractController { @Autowired(required = true) IRequestStorage requestStorage; + @Autowired IPendingRequestIdGenerationStrategy requestIdValidationStragegy; /** * End-Point to handle errors. @@ -68,19 +70,26 @@ public class ProtocolFinalizationController extends AbstractController { public void errorHandling(final HttpServletRequest req, final HttpServletResponse resp) throws EaafException, IOException { // receive an authentication error - final String errorid = + final String errorToken = StringEscapeUtils.escapeHtml4(req.getParameter(EaafConstants.PARAM_HTTP_ERROR_CODE)); - if (errorid != null) { + if (errorToken != null) { IRequest pendingReq = null; - try { + try { + String errorId = requestIdValidationStragegy.validateAndGetPendingRequestId(errorToken); + // load stored exception from database final byte[] containerSerialized = - transactionStorage.get(errorid, byte[].class); + transactionStorage.get(errorId, byte[].class); if (containerSerialized != null) { // remove exception if it was found - transactionStorage.remove(errorid); + transactionStorage.remove(errorId); + //final Object containerObj = EaafSerializationUtils.deserialize(containerSerialized, + // Arrays.asList( + // ExceptionContainer.class.getName() + // )); final Object containerObj = SerializationUtils.deserialize(containerSerialized); + if (containerObj instanceof ExceptionContainer) { final ExceptionContainer container = (ExceptionContainer) containerObj; final Throwable throwable = container.getExceptionThrown(); -- cgit v1.2.3 From 69132ec5bc165395458e49c421d0f38925d16ec5 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 6 Nov 2020 11:17:30 +0100 Subject: adapt logging to improve debugging --- .../java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java | 9 ++++++++- .../egiz/eaaf/core/impl/idp/controller/AbstractController.java | 4 ++-- .../core/impl/idp/controller/ProtocolFinalizationController.java | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java index 48c9d1bd..86c50be0 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java @@ -69,10 +69,17 @@ public class RequestStorage implements IRequestStorage { // search invalid pending-request for errorHandling IRequest invalidPendingRequest = null; - try { + try { if (StringUtils.isNotEmpty(e.getInvalidInternalPendingReqId())) { + log.debug("Searching for expired pendingRequest with Id: {} ... ", e.getInvalidInternalPendingReqId()); invalidPendingRequest = transactionStorage.get(e.getInvalidInternalPendingReqId(), IRequest.class); + log.debug("{} expired pendingReq. Set it into Exception ...", + invalidPendingRequest != null ? "Find" : "Find NO "); + + } else { + log.debug("Get no internal pendingRequestId. Expired pendingRequest can not be set"); + } } catch (final EaafException e1) { diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java index 41c7a432..0479a8c5 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java @@ -181,7 +181,7 @@ public abstract class AbstractController { final byte[] serializedError = SerializationUtils.serialize( new ExceptionContainer(errorToHandle.getFirst(), errorToHandle.getSecond())); - log.trace("Put 'ExceptionContainer' into cache ... "); + log.debug("Put 'ExceptionContainer' into cache with id: {}... ", errorKey); transactionStorage.put(errorKey, serializedError, -1); } else { @@ -189,7 +189,7 @@ public abstract class AbstractController { final byte[] serializedError = SerializationUtils.serialize( new ExceptionContainer(null, errorToHandle.getSecond())); - log.trace("Put 'ExceptionContainer' into cache ... "); + log.trace("Put 'ExceptionContainer' into cache with id: {}... ",errorKey); transactionStorage.put(errorKey, serializedError, -1); } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java index 2a8dd756..9511f46e 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java @@ -76,6 +76,7 @@ public class ProtocolFinalizationController extends AbstractController { IRequest pendingReq = null; try { String errorId = requestIdValidationStragegy.validateAndGetPendingRequestId(errorToken); + log.debug("Searching exception with internal error-token: {}", errorId); // load stored exception from database final byte[] containerSerialized = @@ -83,7 +84,8 @@ public class ProtocolFinalizationController extends AbstractController { if (containerSerialized != null) { // remove exception if it was found transactionStorage.remove(errorId); - + log.trace("Find exception with internal error-token: {}", errorId); + //final Object containerObj = EaafSerializationUtils.deserialize(containerSerialized, // Arrays.asList( // ExceptionContainer.class.getName() @@ -115,6 +117,7 @@ public class ProtocolFinalizationController extends AbstractController { } } else { + log.info("Find no exception with internal error-token: {}", errorId); protAuthService.handleErrorNoRedirect( new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID, null), req, resp, false); -- cgit v1.2.3 From a1eb59634b452231036cf5888d8deeda7764f823 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Mon, 9 Nov 2020 14:06:53 +0100 Subject: fix missing "transactionID" injection in protocol-finalization and error-handler steps --- .../idp/controller/ProtocolFinalizationController.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java index 9511f46e..4ff41836 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java @@ -41,6 +41,7 @@ import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.data.ExceptionContainer; import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; /** * Protocol finialization end-point. @@ -98,6 +99,9 @@ public class ProtocolFinalizationController extends AbstractController { pendingReq = container.getPendingRequest(); if (pendingReq != null) { + //set MDC variables + TransactionIdUtils.setAllLoggingVariables(pendingReq); + // build protocol-specific error message if possible protAuthService.buildProtocolSpecificErrorResponse(throwable, req, resp, pendingReq); @@ -136,6 +140,9 @@ public class ProtocolFinalizationController extends AbstractController { pendingReq.getUniqueTransactionIdentifier()); } + + //remove all Logger variables + TransactionIdUtils.removeAllLoggingVariables(); } @@ -174,9 +181,14 @@ public class ProtocolFinalizationController extends AbstractController { req, resp, false); } else { + //set MDC variables + TransactionIdUtils.setAllLoggingVariables(pendingReq); + + //perform protocol finalization steps protAuthService.finalizeAuthentication(req, resp, pendingReq); + } - + } } -- cgit v1.2.3 From 107683317c874b0349e48f9658bb712f47e40f36 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Mon, 9 Nov 2020 15:14:09 +0100 Subject: add attribute-builder for unique transactionId --- .../attributes/TransactionIdAttributeBuilder.java | 33 ++++++++++++ .../at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder | 3 +- .../TransactionIdAttributeBuilderTest.java | 60 ++++++++++++++++++++++ .../api/data/ExtendedPvpAttributeDefinitions.java | 3 ++ 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/TransactionIdAttributeBuilder.java create mode 100644 eaaf_core/src/test/java/at/gv/egiz/eaaf/core/impl/idp/auth/attributes/TransactionIdAttributeBuilderTest.java diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/TransactionIdAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/TransactionIdAttributeBuilder.java new file mode 100644 index 00000000..17b830dc --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/TransactionIdAttributeBuilder.java @@ -0,0 +1,33 @@ +package at.gv.egiz.eaaf.core.impl.idp.builder.attributes; + +import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; + +public class TransactionIdAttributeBuilder implements IAttributeBuilder, ExtendedPvpAttributeDefinitions { + + @Override + public String getName() { + return EID_TRANSACTION_ID_NAME; + + } + + @Override + public ATT build(ISpConfiguration oaParam, IAuthData authData, IAttributeGenerator g) + throws AttributeBuilderException { + return g.buildStringAttribute(EID_TRANSACTION_ID_FRIENDLY_NAME, EID_TRANSACTION_ID_NAME, + TransactionIdUtils.getTransactionId()); + + } + + @Override + public ATT buildEmpty(IAttributeGenerator g) { + return g.buildEmptyAttribute(EID_TRANSACTION_ID_FRIENDLY_NAME, EID_TRANSACTION_ID_NAME); + + } + +} diff --git a/eaaf_core/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder b/eaaf_core/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder index 30f1cb57..576d9e1e 100644 --- a/eaaf_core/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder +++ b/eaaf_core/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder @@ -12,4 +12,5 @@ at.gv.egiz.eaaf.core.impl.idp.builder.attributes.EidIdentityLinkBuilder at.gv.egiz.eaaf.core.impl.idp.builder.attributes.EidEidTokenBuilder at.gv.egiz.eaaf.core.impl.idp.builder.attributes.EidSignerCertificate at.gv.egiz.eaaf.core.impl.idp.builder.attributes.EidIdentityStatusLevelAttributeBuiler -at.gv.egiz.eaaf.core.impl.idp.builder.attributes.EidCcsUrl \ No newline at end of file +at.gv.egiz.eaaf.core.impl.idp.builder.attributes.EidCcsUrl +at.gv.egiz.eaaf.core.impl.idp.builder.attributes.TransactionIdAttributeBuilder diff --git a/eaaf_core/src/test/java/at/gv/egiz/eaaf/core/impl/idp/auth/attributes/TransactionIdAttributeBuilderTest.java b/eaaf_core/src/test/java/at/gv/egiz/eaaf/core/impl/idp/auth/attributes/TransactionIdAttributeBuilderTest.java new file mode 100644 index 00000000..d82bdf5c --- /dev/null +++ b/eaaf_core/src/test/java/at/gv/egiz/eaaf/core/impl/idp/auth/attributes/TransactionIdAttributeBuilderTest.java @@ -0,0 +1,60 @@ +package at.gv.egiz.eaaf.core.impl.idp.auth.attributes; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; +import at.gv.egiz.eaaf.core.impl.idp.builder.attributes.TransactionIdAttributeBuilder; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; + +/** + * Attribute builder to generate an attribute that holds the unique TransactionId for this process. + *
+ * The attribute-value is read from {@link TransactionIdUtils} with method getTransactionId() + * + * @author tlenz + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/SpringTest-context_eaaf_core.xml") +public class TransactionIdAttributeBuilderTest extends AbstractAttributeBuilderTest { + + private final IAttributeBuilder attrBuilder = new TransactionIdAttributeBuilder(); + + @Test + public void attributeName() { + Assert.assertEquals("Wrong attribute name", + "urn:eidgvat:attributes.transactionId", attrBuilder.getName()); + + } + + @Test + public void checkEmptyAttribute() { + String value = attrBuilder.buildEmpty(gen); + Assert.assertNull("Attr. not null", value); + + } + + @Test + public void noTransactionId() throws AttributeBuilderException, Exception { + String value = attrBuilder.build(spConfig, buildAuthData(), gen); + Assert.assertNull("Attr. not null", value); + + } + + @Test + public void withTransactionId() throws AttributeBuilderException, Exception { + TransactionIdUtils.setTransactionId(); + String transId = TransactionIdUtils.getTransactionId(); + Assert.assertNull("Inputdata is null", transId); + + String value = attrBuilder.build(spConfig, buildAuthData(), gen); + Assert.assertEquals("TransactionId", transId, value); + + } + +} diff --git a/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/api/data/ExtendedPvpAttributeDefinitions.java b/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/api/data/ExtendedPvpAttributeDefinitions.java index cf411af8..2e70770e 100644 --- a/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/api/data/ExtendedPvpAttributeDefinitions.java +++ b/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/api/data/ExtendedPvpAttributeDefinitions.java @@ -46,6 +46,9 @@ public interface ExtendedPvpAttributeDefinitions extends PvpAttributeDefinitions String EID_AUTHBLOCK_SIGNED_NAME = "urn:eidgvat:attributes.authblock.signed"; String EID_AUTHBLOCK_SIGNED_FRIENDLY_NAME = "userAuthBlock"; + String EID_TRANSACTION_ID_NAME = "urn:eidgvat:attributes.transactionId"; + String EID_TRANSACTION_ID_FRIENDLY_NAME = "transactionId"; + String EID_MIS_MANDATE_NAME = "urn:eidgvat:attributes.mis.mandate"; String EID_MIS_MANDATE_FRIENDLY_NAME = "mandate"; -- cgit v1.2.3 From 0964aa4dfbf5543fff4e023290beefaeed31f3c5 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Mon, 9 Nov 2020 18:18:52 +0100 Subject: refactor error-handling in pending-request generation-stategies --- .../PendingReqIdValidationException.java | 12 ++--- ...cryptionPendingRequestIdGenerationStrategy.java | 37 +++++-------- .../SecurePendingRequestIdGenerationStrategy.java | 59 ++++++++------------ .../eaaf/core/impl/utils/TransactionIdUtils.java | 19 +++++-- .../messages/eaaf_utils_message.properties | 11 +++- ...tionPendingRequestIdGenerationStrategyTest.java | 63 +++++----------------- 6 files changed, 77 insertions(+), 124 deletions(-) diff --git a/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/exceptions/PendingReqIdValidationException.java b/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/exceptions/PendingReqIdValidationException.java index ddc051b0..e7c968b5 100644 --- a/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/exceptions/PendingReqIdValidationException.java +++ b/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/exceptions/PendingReqIdValidationException.java @@ -15,10 +15,10 @@ public class PendingReqIdValidationException extends EaafException { * Pending-Request Id validation error. * * @param internalPendingReqId Internal Pending-Request Id - * @param reason error-message + * @param errorId Detailed Id of the error */ - public PendingReqIdValidationException(final String internalPendingReqId, @Nonnull final String reason) { - super("process.99", new Object[] { internalPendingReqId, reason }); + public PendingReqIdValidationException(final String internalPendingReqId, @Nonnull final String errorId) { + super(errorId, new Object[] { internalPendingReqId}); this.invalidInternalPendingReqId = internalPendingReqId; } @@ -27,12 +27,12 @@ public class PendingReqIdValidationException extends EaafException { * Pending-Request Id validation error. * * @param internalPendingReqId Internal Pending-Request Id - * @param reason error-message + * @param errorId Detailed Id of the error * @param e error */ - public PendingReqIdValidationException(final String internalPendingReqId, @Nonnull final String reason, + public PendingReqIdValidationException(final String internalPendingReqId, @Nonnull final String errorId, final Throwable e) { - super("process.99", new Object[] { internalPendingReqId, reason }, e); + super(errorId, new Object[] { internalPendingReqId, errorId }, e); this.invalidInternalPendingReqId = internalPendingReqId; } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java index b10f8586..83ea7da0 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java @@ -1,6 +1,6 @@ package at.gv.egiz.eaaf.core.impl.utils; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.security.Provider; import java.util.Base64; @@ -98,10 +98,10 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy } return Base64.getUrlEncoder() - .encodeToString(encToken.getCompactSerialization().getBytes("UTF-8")); + .encodeToString(encToken.getCompactSerialization().getBytes(StandardCharsets.UTF_8)); - } catch (final JoseException | UnsupportedEncodingException e) { - throw new EaafException("internal.99", new Object[] { e.getMessage() }, e); + } catch (final JoseException e) { + throw new EaafException("internal.pendingreqid.02", new Object[] { e.getMessage() }, e); } @@ -117,7 +117,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy if (!(StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1)) { log.warn("PendingRequestId has an unvalid format"); log.debug("PendingRequestId: {}", stringToken); - throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format"); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.01"); } @@ -125,13 +125,10 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy StringUtils.split(stringToken, TOKEN_SEPARATOR, ENCODED_TOKEN_PARTS); return tokenElements[1]; - } catch (final UnsupportedEncodingException e) { - throw new RuntimeException(e); - } catch (JoseException e) { log.warn("Token is NOT a valid String. Msg: {}", e.getMessage()); log.debug("TokenValue: {}", externalPendingReqId); - throw new PendingReqIdValidationException(null, "PendingReqId is NOT a valid String", e); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.05", e); } } @@ -145,7 +142,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy if (!(StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1)) { log.info("PendingRequestId: {}", stringToken); - throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format"); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.01"); } @@ -154,15 +151,13 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy final String internalPendingReqId = tokenElements[1]; final DateTime timeStamp = TOKEN_TEXTUAL_DATE_FORMAT.parseDateTime(tokenElements[0]); - - log.trace("Checking valid period ... "); final DateTime now = DateTime.now(); if (timeStamp.withFieldAdded(DurationFieldType.seconds(), maxPendingRequestIdLifeTime) .isBefore(now)) { log.info("Token exceeds the valid period. Token: {} | Now: {}", timeStamp, now); throw new PendingReqIdValidationException(internalPendingReqId, - "PendingRequestId exceeds the valid period"); + "internal.pendingreqid.06"); } log.debug("Token valid-period check successful"); @@ -172,25 +167,22 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy } catch (JoseException e) { log.warn("Token is NOT a valid encrypt. Msg: {}", e.getMessage()); log.debug("TokenValue: {}", externalPendingReqId); - throw new PendingReqIdValidationException(null, "PendingReqId is NOT a valid encrypted", e); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.04", e); } catch (final IllegalArgumentException e) { log.warn("Token is NOT a valid String. Msg: {}", e.getMessage()); log.debug("TokenValue: {}", externalPendingReqId); - throw new PendingReqIdValidationException(null, "PendingReqId is NOT a valid String", e); - - } catch (final UnsupportedEncodingException e) { - throw new RuntimeException(e); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.05", e); } } @Nonnull private String getDecryptedExternalPendingRequestId(String externalPendingReqId) - throws JoseException, PendingReqIdValidationException, UnsupportedEncodingException { + throws JoseException, PendingReqIdValidationException { if (StringUtils.isEmpty(externalPendingReqId)) { log.info("PendingReqId is 'null' or empty"); - throw new PendingReqIdValidationException(null, "PendingReqId is 'null' or empty"); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.00"); } @@ -199,8 +191,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy if (externalPendingReqIdBytes.length > maxPendingReqIdSize) { log.warn("pendingReqId size exceeds {}", maxPendingReqIdSize); - throw new PendingReqIdValidationException(null, - "pendingReqId exceeds max.size: " + maxPendingReqIdSize); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.03"); } @@ -223,7 +214,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy } - encToken.setCompactSerialization(new String(externalPendingReqIdBytes, "UTF-8")); + encToken.setCompactSerialization(new String(externalPendingReqIdBytes, StandardCharsets.UTF_8)); return encToken.getPayload(); } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java index ad6471d5..8ec5f3a8 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java @@ -1,6 +1,6 @@ package at.gv.egiz.eaaf.core.impl.utils; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; @@ -80,33 +80,22 @@ public class SecurePendingRequestIdGenerationStrategy @Override public String generateExternalPendingRequestId() throws EaafException { - try { - final String toSign = buildInternalToken(Random.nextLongRandom(), DateTime.now()); - final StringBuilder externalPendingRequestId = new StringBuilder(); - externalPendingRequestId.append(toSign); - externalPendingRequestId.append(TOKEN_SEPARATOR); - externalPendingRequestId.append(Base64.getEncoder().encodeToString(calculateHmac(toSign))); - return Base64.getUrlEncoder() - .encodeToString(externalPendingRequestId.toString().getBytes("UTF-8")); - - } catch (final UnsupportedEncodingException e) { - throw new EaafException("internal.99", new Object[] { e.getMessage() }, e); - - } + final String toSign = buildInternalToken(Random.nextLongRandom(), DateTime.now()); + final StringBuilder externalPendingRequestId = new StringBuilder(); + externalPendingRequestId.append(toSign); + externalPendingRequestId.append(TOKEN_SEPARATOR); + externalPendingRequestId.append(Base64.getEncoder().encodeToString(calculateHmac(toSign))); + return Base64.getUrlEncoder() + .encodeToString(externalPendingRequestId.toString().getBytes(StandardCharsets.UTF_8)); } @Override public String getPendingRequestIdWithOutChecks(final String externalPendingReqId) throws PendingReqIdValidationException { - try { - final String[] tokenElements = extractTokens(externalPendingReqId); - return tokenElements[1]; - - } catch (final UnsupportedEncodingException e) { - throw new RuntimeException(e); - - } + final String[] tokenElements = extractTokens(externalPendingReqId); + return tokenElements[1]; + } @Override @@ -123,8 +112,7 @@ public class SecurePendingRequestIdGenerationStrategy if (!Arrays.equals(tokenDigest, refDigist)) { log.warn("Digest of Token does NOT match"); log.debug("Token: {} | Ref: {}", tokenDigest, refDigist); - throw new PendingReqIdValidationException(null, - "Digest of pendingRequestId does NOT match"); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.04"); } log.debug("PendingRequestId HMAC digest check successful"); @@ -135,8 +123,7 @@ public class SecurePendingRequestIdGenerationStrategy .isBefore(now)) { log.warn("Token exceeds the valid period"); log.debug("Token: {} | Now: {}", timeStamp, now); - throw new PendingReqIdValidationException(internalPendingReqId, - "PendingRequestId exceeds the valid period"); + throw new PendingReqIdValidationException(internalPendingReqId, "internal.pendingreqid.06"); } log.debug("Token valid-period check successful"); @@ -146,20 +133,17 @@ public class SecurePendingRequestIdGenerationStrategy } catch (final IllegalArgumentException | EaafIllegalStateException e) { log.warn("Token is NOT a valid String. Msg: {}", e.getMessage()); log.debug("TokenValue: {}", externalPendingReqId); - throw new PendingReqIdValidationException(null, "PendingReqId is NOT a valid String", e); - - } catch (final UnsupportedEncodingException e) { - throw new RuntimeException(e); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.06", e); } } @NonNull private String[] extractTokens(@Nullable final String externalPendingReqId) - throws PendingReqIdValidationException, UnsupportedEncodingException { + throws PendingReqIdValidationException { if (StringUtils.isEmpty(externalPendingReqId)) { log.info("PendingReqId is 'null' or empty"); - throw new PendingReqIdValidationException(null, "PendingReqId is 'null' or empty"); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.00"); } @@ -168,12 +152,11 @@ public class SecurePendingRequestIdGenerationStrategy if (externalPendingReqIdBytes.length > maxPendingReqIdSize) { log.warn("pendingReqId size exceeds {}", maxPendingReqIdSize); - throw new PendingReqIdValidationException(null, - "pendingReqId exceeds max.size: " + maxPendingReqIdSize); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.03"); } - final String stringToken = new String(externalPendingReqIdBytes, "UTF-8"); + final String stringToken = new String(externalPendingReqIdBytes, StandardCharsets.UTF_8); if (StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1) { final String[] tokenElements = StringUtils.split(stringToken, TOKEN_SEPARATOR, ENCODED_TOKEN_PARTS); @@ -182,7 +165,7 @@ public class SecurePendingRequestIdGenerationStrategy } else { log.warn("PendingRequestId has an unvalid format"); log.debug("PendingRequestId: {}", stringToken); - throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format"); + throw new PendingReqIdValidationException(null, "internal.pendingreqid.01"); } @@ -243,9 +226,9 @@ public class SecurePendingRequestIdGenerationStrategy try { final Mac mac = Mac.getInstance(digistAlgorithm); mac.init(key); - return mac.doFinal(toSign.getBytes("UTF-8")); + return mac.doFinal(toSign.getBytes(StandardCharsets.UTF_8)); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException e) { log.error("Can NOT generate secure pendingRequestId", e); throw new EaafIllegalStateException( new Object[] { "Can NOT caluclate digist for secure pendingRequestId" }, e); diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java index 4c1601c0..d1613d16 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java @@ -21,7 +21,10 @@ package at.gv.egiz.eaaf.core.impl.utils; import java.util.UUID; +import javax.annotation.Nullable; + import at.gv.egiz.eaaf.core.api.IRequest; +import lombok.extern.slf4j.Slf4j; /** * Transaction Identifier Utils. @@ -29,6 +32,7 @@ import at.gv.egiz.eaaf.core.api.IRequest; * @author tlenz * */ +@Slf4j public class TransactionIdUtils { /** @@ -58,11 +62,16 @@ public class TransactionIdUtils { * * @param pendingRequest Http request object */ - public static void setAllLoggingVariables(final IRequest pendingRequest) { - setTransactionId(pendingRequest.getUniqueTransactionIdentifier()); - setSessionId(pendingRequest.getUniqueSessionIdentifier()); - setServiceProviderId(pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier()); - + public static void setAllLoggingVariables(@Nullable final IRequest pendingRequest) { + if (pendingRequest != null) { + setTransactionId(pendingRequest.getUniqueTransactionIdentifier()); + setSessionId(pendingRequest.getUniqueSessionIdentifier()); + setServiceProviderId(pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier()); + + } else { + log.warn("Can NOT set MDC variables from pendingRequest because it is 'null'"); + + } } /** diff --git a/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties b/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties index 5b398bb0..79f82af8 100644 --- a/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties +++ b/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties @@ -20,4 +20,13 @@ internal.key.01=Can not use key from Keystore: {0} Reason: {1} internal.httpclient.00=HttpClient:{0} uses http Basic-Auth, but 'Username' is NOT set internal.httpclient.01=HttpClient:{0} uses X509 client-auth, but 'KeyStoreConfig' is NOT set internal.httpclient.02=HttpClient:{0} uses KeyStore:{1}, but 'keyPassword' is NOT set -internal.httpclient.03=Can not initialize SSLContext for HttpClient:{0} Reason:{1} \ No newline at end of file +internal.httpclient.03=Can not initialize SSLContext for HttpClient:{0} Reason:{1} + +internal.pendingreqid.00=Process Token is 'null' or 'empty' +internal.pendingreqid.01=Process Token is NOT valid because it has an invalid format +internal.pendingreqid.02=Can not create process Token +internal.pendingreqid.03=Process Token is NOT valid because it reached maximum size +internal.pendingreqid.04=Process Token is NOT valid because it is cryptographically invalid +internal.pendingreqid.05=Process Token is NOT valid because it has an invalid encoding +internal.pendingreqid.06=Process Token is NOT valid because it exceeds the valid period + diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java index 34f4a3b1..8b437dcf 100644 --- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java @@ -71,10 +71,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, PendingReqId is 'null' or empty]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.00", e.getErrorId()); } } @@ -88,10 +85,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, PendingReqId is 'null' or empty]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.00", e.getErrorId()); } } @@ -105,11 +99,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " - + "PendingReqId is NOT a valid String]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.05", e.getErrorId()); } } @@ -124,11 +114,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " - + "pendingReqId exceeds max.size: 1024]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.03", e.getErrorId()); } } @@ -150,11 +136,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " - + "PendingReqId has an unvalid format]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.01", e.getErrorId()); } } @@ -177,11 +159,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " - + "PendingReqId has an unvalid format]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.01", e.getErrorId()); } } @@ -204,11 +182,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " - + "PendingReqId is NOT a valid String]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.05", e.getErrorId()); } } @@ -231,8 +205,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNotNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertTrue("Wrong errorMsg", e.getMessage().contains("PendingRequestId exceeds the valid period")); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.06", e.getErrorId()); } } @@ -254,11 +227,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " - + "PendingReqId has an unvalid format]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.01", e.getErrorId()); } } @@ -281,12 +250,8 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " - + "PendingReqId has an unvalid format]", - e.getMessage()); - + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.01", e.getErrorId()); + } } @@ -399,11 +364,7 @@ public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { } catch (PendingReqIdValidationException e) { Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); - Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); - Assert.assertEquals("Wrong errorMsg", - "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " - + "PendingReqId is NOT a valid encrypted]", - e.getMessage()); + Assert.assertEquals("Wrong errorId", "internal.pendingreqid.04", e.getErrorId()); } } -- cgit v1.2.3