summaryrefslogtreecommitdiff
path: root/eaaf_core/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core/src/main/java')
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java30
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/utils/IPendingRequestIdGenerationStrategy.java31
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/PendingReqIdValidationException.java59
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java161
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java20
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java35
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java188
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SimplePendingRequestIdGenerationStrategy.java25
8 files changed, 483 insertions, 66 deletions
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java
index ab928ae5..56179d55 100644
--- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java
@@ -46,6 +46,7 @@ package at.gv.egiz.eaaf.core.api;
import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;
/**
* @author tlenz
@@ -53,12 +54,37 @@ import at.gv.egiz.eaaf.core.exceptions.EAAFException;
*/
public interface IRequestStorage {
- public IRequest getPendingRequest(String pendingReqID);
+ /**
+ * Get a pending-request from storage
+ *
+ * @param pendingReqID Id of the pending request
+ * @return
+ * @throws PendingReqIdValidationException if the pendingRequestId was invalid
+ */
+ public IRequest getPendingRequest(String pendingReqID) throws PendingReqIdValidationException;
+ /**
+ * Store a pending-request in storage
+ *
+ * @param pendingRequest
+ * @throws EAAFException
+ */
public void storePendingRequest(IRequest pendingRequest) throws EAAFException;
- public void removePendingRequest(String requestID);
+ /**
+ * Remove a pending-request from storage
+ *
+ * @param pendingReqId Id of the pending request
+ */
+ public void removePendingRequest(String pendingReqId);
+ /**
+ * change the pendingRequestId of a pending-request
+ *
+ * @param pendingRequest current pending-reqeust
+ * @return new pending-requestId
+ * @throws EAAFException
+ */
public String changePendingRequestID(IRequest pendingRequest) throws EAAFException;
}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/utils/IPendingRequestIdGenerationStrategy.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/utils/IPendingRequestIdGenerationStrategy.java
new file mode 100644
index 00000000..443404eb
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/utils/IPendingRequestIdGenerationStrategy.java
@@ -0,0 +1,31 @@
+package at.gv.egiz.eaaf.core.api.utils;
+
+import org.springframework.lang.NonNull;
+import org.springframework.lang.Nullable;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;
+
+public interface IPendingRequestIdGenerationStrategy {
+
+ /**
+ * Generate a new external pending-request id
+ *
+ * @return
+ * @throws EAAFException
+ */
+ @NonNull
+ public String generateExternalPendingRequestId() throws EAAFException;
+
+ /**
+ * Validate a pendingRequestId according to implemented strategy
+ *
+ * @param pendingReqId pending-request Id that should be validated
+ * @return internalPendingRequestId
+ * @throws PendingReqIdValidationException
+ */
+ @NonNull
+ public String validateAndGetPendingRequestId(@Nullable String pendingReqId) throws PendingReqIdValidationException;
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/PendingReqIdValidationException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/PendingReqIdValidationException.java
new file mode 100644
index 00000000..57317092
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/PendingReqIdValidationException.java
@@ -0,0 +1,59 @@
+package at.gv.egiz.eaaf.core.exceptions;
+
+import org.springframework.lang.NonNull;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+public class PendingReqIdValidationException extends EAAFException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6886402432880791308L;
+
+ private final String invalidInternalPendingReqId;
+ private IRequest invalidPendingReq;
+
+ /**
+ *
+ * @param pendingReqId
+ * @param reason
+ */
+ public PendingReqIdValidationException(String internalPendingReqId, @NonNull String reason) {
+ super("process.99", new Object[] {internalPendingReqId, reason});
+ this.invalidInternalPendingReqId = internalPendingReqId;
+
+ }
+
+ public PendingReqIdValidationException(String internalPendingReqId, @NonNull String reason, Throwable e) {
+ super("process.99", new Object[] {internalPendingReqId, reason}, e );
+ this.invalidInternalPendingReqId = internalPendingReqId;
+ }
+
+ /**
+ * Get the invalid pending-request
+ *
+ * @return
+ */
+ public IRequest getInvalidPendingReq() {
+ return invalidPendingReq;
+ }
+
+
+ /**
+ * Get the internal invalid pending-request id
+ *
+ * @return
+ */
+ public String getInvalidInternalPendingReqId() {
+ return invalidInternalPendingReqId;
+ }
+
+ public void setInvalidPendingReq(IRequest invalidPendingReq) {
+ this.invalidPendingReq = invalidPendingReq;
+
+ }
+
+
+
+}
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 e4288e62..2115d9b0 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
@@ -26,6 +26,7 @@
*******************************************************************************/
package at.gv.egiz.eaaf.core.impl.idp.auth;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,35 +36,55 @@ import at.gv.egiz.eaaf.core.api.IRequest;
import at.gv.egiz.eaaf.core.api.IRequestStorage;
import at.gv.egiz.eaaf.core.api.idp.process.ProcessInstanceStoreDAO;
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.EAAFStorageException;
+import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;
import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;
-import at.gv.egiz.eaaf.core.impl.utils.Random;
import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
@Service("RequestStorage")
public class RequestStorage implements IRequestStorage{
private static final Logger log = LoggerFactory.getLogger(RequestStorage.class);
- @Autowired ITransactionStorage transactionStorage;
- @Autowired ProcessInstanceStoreDAO processInstanceStore;
-
+ @Autowired(required=true) ITransactionStorage transactionStorage;
+ @Autowired(required=true) ProcessInstanceStoreDAO processInstanceStore;
+ @Autowired(required=true) IPendingRequestIdGenerationStrategy pendingReqIdGenerationStrategy;
+
@Override
- public IRequest getPendingRequest(String pendingReqID) {
+ public IRequest getPendingRequest(String pendingReqID) throws PendingReqIdValidationException {
try {
- IRequest pendingRequest = transactionStorage.get(pendingReqID, IRequest.class);
- if (pendingRequest == null) {
- log.info("No PendingRequst found with pendingRequestID " + pendingReqID);
- return null;
-
- }
+ final String internalPendingReqId =
+ pendingReqIdGenerationStrategy.validateAndGetPendingRequestId(pendingReqID);
+ log.debug("PendingReqId is valid");
+
+ //get pending-request from storage
+ final IRequest pendingRequest = getInternalPendingRequest(internalPendingReqId);
//set transactionID and sessionID to Logger
TransactionIDUtils.setAllLoggingVariables(pendingRequest);
return pendingRequest;
-
+
+ } catch (final PendingReqIdValidationException e) {
+ log.info("PendingRequestId is invalid. Reason: {} ", e.getMessage());
+
+ // search invalid pending-request for errorHandling
+ IRequest invalidPendingRequest = null;
+ try {
+ if (StringUtils.isNotEmpty(e.getInvalidInternalPendingReqId()))
+ invalidPendingRequest = transactionStorage.get(e.getInvalidInternalPendingReqId(), IRequest.class);
+
+ } catch (final EAAFException e1) {
+ log.info("No PendingRequst found with pendingRequestID " + pendingReqID);
+ return null;
+
+ }
+
+ e.setInvalidPendingReq(invalidPendingRequest);
+ throw e;
+
} catch (EAAFException | NullPointerException e) {
log.info("No PendingRequst found with pendingRequestID " + pendingReqID);
return null;
@@ -74,17 +95,27 @@ public class RequestStorage implements IRequestStorage{
@Override
public void storePendingRequest(IRequest pendingRequest) throws EAAFException {
try {
- if (pendingRequest instanceof IRequest)
- transactionStorage.put(((IRequest)pendingRequest).getPendingRequestId(), pendingRequest, -1);
-
- else
+ if (pendingRequest instanceof IRequest) {
+ try {
+ //validate pending-requestId
+ final String internalPendingRequestId = pendingReqIdGenerationStrategy.validateAndGetPendingRequestId(pendingRequest.getPendingRequestId());
+
+ //store pending request
+ transactionStorage.put(internalPendingRequestId, pendingRequest, -1);
+
+ } catch (final PendingReqIdValidationException e) {
+ log.warn("Invalid pending-request-Id. Reason: {}", e.getMessage());
+ log.warn("Do NOT store pending-request with invalid pending-request-Id. The process will break soon!");
+
+ }
+
+ } else
throw new EAAFException("PendigRequest is NOT of type 'IRequest'", null);
-
-
- } catch (EAAFException e) {
- log.warn("PendingRequest with ID=" + ((IRequest)pendingRequest).getPendingRequestId() +
+
+ } catch (final EAAFException e) {
+ log.warn("PendingRequest with ID=" + pendingRequest.getPendingRequestId() +
" can not stored.", e);
- throw new EAAFStorageException("PendingRequest with Id: " + ((IRequest)pendingRequest).getPendingRequestId()
+ throw new EAAFStorageException("PendingRequest with Id: " + pendingRequest.getPendingRequestId()
+ " can not be stored", e);
}
@@ -92,25 +123,35 @@ public class RequestStorage implements IRequestStorage{
}
@Override
- public void removePendingRequest(String requestID) {
+ public void removePendingRequest(String pendingReqID) {
- if (requestID != null) {
-
- //remove process-management execution instance
+ if (pendingReqID != null) {
+ String internalPendingReqId = null;
try {
- IRequest pendingReq = getPendingRequest(requestID);
-
- if (pendingReq != null &&
- pendingReq.getProcessInstanceId() != null)
- processInstanceStore.remove(pendingReq.getProcessInstanceId());
-
- } catch (EAAFException e) {
- log.warn("Removing process associated with pending-request:" + requestID + " FAILED.", e);
+ internalPendingReqId = pendingReqIdGenerationStrategy.validateAndGetPendingRequestId(pendingReqID);
+
+ } catch (final PendingReqIdValidationException e) {
+ internalPendingReqId = e.getInvalidInternalPendingReqId();
}
-
- transactionStorage.remove(requestID);
+ try {
+ //remove process-management execution instance#
+ if (internalPendingReqId != null) {
+ final IRequest pendingReq = getInternalPendingRequest(internalPendingReqId);
+ if (pendingReq != null &&
+ pendingReq.getProcessInstanceId() != null)
+ processInstanceStore.remove(pendingReq.getProcessInstanceId());
+
+ //remove pending-request
+ transactionStorage.remove(internalPendingReqId);
+ }
+
+ } catch (final EAAFException e) {
+ log.warn("Removing process associated with pending-request:" + pendingReqID + " FAILED.", e);
+
+ }
+
}
}
@@ -119,25 +160,59 @@ public class RequestStorage implements IRequestStorage{
*/
@Override
public String changePendingRequestID(IRequest pendingRequest) throws EAAFException {
-
+
+ //TODO!!!!
+
if (pendingRequest instanceof RequestImpl) {
- String newRequestID = Random.nextHexRandom32();
- String oldRequestID = pendingRequest.getPendingRequestId();
+ //final String newRequestID = Random.nextHexRandom32();
+ final String newRequestID = pendingReqIdGenerationStrategy.generateExternalPendingRequestId();
+ ((RequestImpl)pendingRequest).setPendingRequestId(newRequestID);
- log.debug("Change pendingRequestID from " + pendingRequest.getPendingRequestId()
- + " to " + newRequestID);
+ String newInternalPendingRequestId = null;
+ try {
+ newInternalPendingRequestId = pendingReqIdGenerationStrategy.validateAndGetPendingRequestId(newRequestID);
+
+ } catch (final PendingReqIdValidationException e) {
+ throw new EAAFException("internal.99", new Object[]{"Generate invalid pendingRequestId. Something looks WRONG"}, e);
+
+ }
+
+ String oldInternalRequestID = null;
+ try {
+ oldInternalRequestID =
+ pendingReqIdGenerationStrategy.validateAndGetPendingRequestId(pendingRequest.getPendingRequestId());
- ((RequestImpl)pendingRequest).setPendingRequestId(newRequestID);
- transactionStorage.changeKey(oldRequestID, newRequestID, pendingRequest);
+ } catch (final PendingReqIdValidationException e) {
+ //it's no problem, because it must be valid before when pending-request was loaded and we change it now
+ oldInternalRequestID = e.getInvalidInternalPendingReqId();
+
+ }
- //only delete oldRequestID, no change.
+ log.debug("Change pendingRequestID from " + pendingRequest.getPendingRequestId()
+ + " to " + newRequestID);
+
+ transactionStorage.changeKey(oldInternalRequestID, newInternalPendingRequestId, pendingRequest);
+ //only delete oldRequestID, no change.
return newRequestID;
} else {
log.error("PendingRequest object is not of type 'RequestImpl.class'");
throw new EAAFException("PendingRequest object is not of type 'RequestImpl.class'", null);
+
}
}
+
+ private IRequest getInternalPendingRequest(String internalPendingReqId) throws EAAFException {
+ final IRequest pendingRequest = transactionStorage.get(internalPendingReqId, IRequest.class);
+ if (pendingRequest == null) {
+ log.info("No PendingRequst found with pendingRequestID " + internalPendingReqId);
+ return null;
+
+ }
+
+ return pendingRequest;
+
+ }
}
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 4e58868b..1da8036c 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
@@ -27,6 +27,7 @@
package at.gv.egiz.eaaf.core.impl.idp.controller;
import java.io.IOException;
+
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -47,6 +48,7 @@ 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.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.utils.Random;
@@ -105,7 +107,7 @@ public abstract class AbstractController {
}
protected void handleError(final String errorMessage, final Throwable exceptionThrown,
- final HttpServletRequest req, final HttpServletResponse resp, final IRequest pendingReq) throws IOException, EAAFException {
+ final HttpServletRequest req, final HttpServletResponse resp, IRequest pendingReq) throws IOException, EAAFException {
Throwable loggedException = null;
final Throwable extractedException = extractOriginalExceptionFromProcessException(exceptionThrown);
@@ -115,13 +117,17 @@ public abstract class AbstractController {
//set original exception
loggedException = ((TaskExecutionException) extractedException).getOriginalException();
- //use TaskExecutionException directly, if no Original Exeception is included
- if (loggedException == null)
- loggedException = exceptionThrown;
-
- } else
+ } else if (exceptionThrown instanceof PendingReqIdValidationException) {
+ log.trace("Find pendingRequestId validation exception. Looking for invalid pending-request ... ");
+ if (((PendingReqIdValidationException) exceptionThrown).getInvalidPendingReq() != null)
+ pendingReq = ((PendingReqIdValidationException) exceptionThrown).getInvalidPendingReq();
+
+ }
+
+ //use TaskExecutionException directly, if no Original Exeception is included
+ if (loggedException == null)
loggedException = exceptionThrown;
-
+
try {
//switch to protocol-finalize method to generate a protocol-specific error message
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java
index 527b79a1..5667fad7 100644
--- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java
@@ -41,6 +41,7 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.lang.NonNull;
import at.gv.egiz.eaaf.core.api.IRequest;
import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
@@ -61,11 +62,11 @@ public abstract class RequestImpl implements IRequest, Serializable{
public static final String DATAID_REQUESTER_IP_ADDRESS = "reqestImpl_requesterIPAddr";
private static final long serialVersionUID = 1L;
-
+
private String module = null;
private String action = null;
- private String pendingRequestId;
+ private String pendingRequestId = null;
private String processInstanceId;
private String internalSSOSessionId;
@@ -92,7 +93,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
private boolean needUserConsent = false;
- private Map<String, Object> genericDataStorage = new HashMap<String, Object>();
+ private final Map<String, Object> genericDataStorage = new HashMap<String, Object>();
@@ -100,10 +101,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
* @throws ConfigurationException
*
*/
- public final void initialize(HttpServletRequest req, IConfiguration authConfig) throws EAAFException {
- //set pendingRequestId
- pendingRequestId = Random.nextLongRandom();
-
+ public final void initialize(HttpServletRequest req, IConfiguration authConfig) throws EAAFException {
//set unique transaction identifier for logging
uniqueTransactionIdentifer = Random.nextLongRandom();
TransactionIDUtils.setTransactionId(uniqueTransactionIdentifer);
@@ -113,12 +111,12 @@ public abstract class RequestImpl implements IRequest, Serializable{
//genericDataStorage.put(EAAFConstants.VALUE_SESSIONID, Random.nextLongRandom());
//check if End-Point is valid
- String authURLString = HTTPUtils.extractAuthURLFromRequest(req);
+ final String authURLString = HTTPUtils.extractAuthURLFromRequest(req);
URL authReqURL;
try {
authReqURL = new URL(authURLString);
- } catch (MalformedURLException e) {
+ } catch (final MalformedURLException e) {
log.error("IDP AuthenticationServiceURL Prefix is not a valid URL." + authURLString, e);
throw new EAAFAuthenticationException("errorId", new Object[]{authURLString}, e);
@@ -131,7 +129,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
}
//set unique session identifier
- String uniqueID = (String) req.getAttribute(EAAFConstants.UNIQUESESSIONIDENTIFIER);
+ final String uniqueID = (String) req.getAttribute(EAAFConstants.UNIQUESESSIONIDENTIFIER);
if (StringUtils.isNotEmpty(uniqueID))
this.uniqueSessionIdentifer = uniqueID;
@@ -145,7 +143,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
try {
setRawDataToTransaction(DATAID_REQUESTER_IP_ADDRESS, req.getRemoteAddr());
- } catch (EAAFStorageException e) {
+ } catch (final EAAFStorageException e) {
log.info("Can NOT store remote IP address into 'pendingRequest'." , e);
}
@@ -203,7 +201,11 @@ public abstract class RequestImpl implements IRequest, Serializable{
}
@Override
+ @NonNull
public final String getPendingRequestId() {
+ if (pendingRequestId == null)
+ throw new IllegalStateException("No PendingRequestId set!!!");
+
return pendingRequestId;
}
@@ -333,6 +335,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
return isAuthenticated;
}
+ @Override
public final void setAuthenticated(boolean isAuthenticated) {
this.isAuthenticated = isAuthenticated;
}
@@ -341,6 +344,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
public final boolean needSingleSignOnFunctionality() {
return needSSO;
}
+ @Override
public final void setNeedSingleSignOnFunctionality(boolean needSSO) {
this.needSSO = needSSO;
@@ -352,6 +356,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
}
+ @Override
public final void setNeedUserConsent(boolean needConsent) {
this.needUserConsent = needConsent;
@@ -362,6 +367,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
return this.isAbortedByUser;
}
+ @Override
public final void setAbortedByUser(boolean isAborted) {
this.isAbortedByUser = isAborted;
@@ -381,17 +387,18 @@ public abstract class RequestImpl implements IRequest, Serializable{
@Override
public final <T> T getRawData(String key, final Class<T> clazz) {
if (StringUtils.isNotEmpty(key)) {
- Object data = genericDataStorage.get(key);
+ final Object data = genericDataStorage.get(key);
if (data == null)
return null;
try {
@SuppressWarnings("unchecked")
+ final
T test = (T) data;
return test;
- } catch (Exception e) {
+ } catch (final Exception e) {
log.warn("Generic request-data object can not be casted to requested type", e);
return null;
@@ -438,7 +445,7 @@ public abstract class RequestImpl implements IRequest, Serializable{
}
//validate and store values
- for (Entry<String, Object> el : map.entrySet())
+ for (final Entry<String, Object> el : map.entrySet())
setRawDataToTransaction(el.getKey(), el.getValue());
}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java
new file mode 100644
index 00000000..0daa0eb7
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java
@@ -0,0 +1,188 @@
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Arrays;
+import java.util.Base64;
+
+import javax.annotation.PostConstruct;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.joda.time.DurationFieldType;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy;
+import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFIllegalStateException;
+import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;
+
+
+public class SecurePendingRequestIdGenerationStrategy implements IPendingRequestIdGenerationStrategy {
+ private static final Logger log = LoggerFactory.getLogger(SecurePendingRequestIdGenerationStrategy.class);
+
+ @Autowired(required=true) IConfiguration baseConfig;
+
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET = "core.pendingrequestid.digist.secret";
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM = "core.pendingrequestid.digist.algorithm";
+ public static final String CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME = "core.pendingrequestid.maxlifetime";
+
+ public static final String DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM = "HmacSHA256";
+ public static final String DEFAULT_PENDINGREQUESTID_MAX_LIFETIME = "300";
+
+ private static final int ENCODED_TOKEN_PARTS = 3;
+ private static final String TOKEN_SEPARATOR = "|";
+ private static final DateTimeFormatter TOKEN_TEXTUAL_DATE_FORMAT =
+ DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss SSS");
+
+ private int maxPendingRequestIdLifeTime = 300;
+ private final int maxPendingReqIdSize = 1024;
+ private String digistAlgorithm = null;
+ private SecretKey key = null;
+ private final byte[] salt = "notRequiredInThisScenario".getBytes();
+
+ @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);
+
+ }
+
+ }
+
+ @Override
+ public String validateAndGetPendingRequestId(String externalPendingReqId) throws PendingReqIdValidationException {
+ log.trace("RAW external pendingReqId: {}", externalPendingReqId);
+
+ try {
+ final byte[] externalPendingReqIdBytes = Base64.getUrlDecoder().decode(externalPendingReqId);
+
+ if (externalPendingReqIdBytes.length > maxPendingReqIdSize) {
+ log.warn("pendingReqId size exceeds {}", maxPendingReqIdSize);
+ throw new PendingReqIdValidationException(null, "pendingReqId exceeds max.size: " + maxPendingReqIdSize);
+
+ }
+
+ final String stringToken = new String(externalPendingReqIdBytes);
+ if (StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1) {
+ final String[] tokenElements = StringUtils.split(stringToken,
+ TOKEN_SEPARATOR, ENCODED_TOKEN_PARTS);
+
+ final String internalPendingReqId = tokenElements[1];
+ final DateTime timeStamp = TOKEN_TEXTUAL_DATE_FORMAT.parseDateTime(tokenElements[0]);
+
+ log.trace("Checking HMAC from externalPendingReqId ... ");
+ final byte[] tokenDigest = Base64.getDecoder().decode(tokenElements[2]);
+ final byte[] refDigist = calculateHMAC(buildInternalToken(internalPendingReqId, timeStamp));
+ 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");
+
+ }
+ log.debug("PendingRequestId HMAC digest check successful");
+
+ log.trace("Checking valid period ... ");
+ 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 );
+ throw new PendingReqIdValidationException(internalPendingReqId, "PendingRequestId exceeds the valid period");
+
+ }
+ log.debug("Token valid-period check successful");
+
+ return internalPendingReqId;
+
+ } else {
+ log.warn("PendingRequestId has an unvalid format");
+ log.debug("PendingRequestId: {}", stringToken);
+ throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format");
+
+ }
+
+ } 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);
+
+ }
+ }
+
+
+ @PostConstruct
+ private void initialize() throws EAAFConfigurationException {
+ log.debug("Initializing " + this.getClass().getName() + " ... ");
+
+ final String pendingReqIdDigistSecret = baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET);
+ if (StringUtils.isEmpty(pendingReqIdDigistSecret))
+ throw new EAAFConfigurationException("config.08", new Object[] {CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET});
+
+ digistAlgorithm = baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM, DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM);
+
+ maxPendingRequestIdLifeTime = Integer.valueOf(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME, DEFAULT_PENDINGREQUESTID_MAX_LIFETIME));
+
+ try {
+ final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256");
+ final KeySpec spec = new PBEKeySpec(pendingReqIdDigistSecret.toCharArray(), salt, 10000, 128);
+ key = keyFactory.generateSecret(spec);
+
+
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ log.error("Can NOT initialize TokenService with configuration object", e);
+ throw new EAAFConfigurationException("config.09",
+ new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET,
+ "Can NOT generate HMAC key"},
+ e);
+
+ }
+
+ log.info(this.getClass().getName() + " initialized with digistAlg: {} and maxLifeTime: {}", digistAlgorithm, maxPendingRequestIdLifeTime);
+
+ }
+
+ private String buildInternalToken(String internalPendingReqId, DateTime now) {
+ return new StringBuilder()
+ .append(TOKEN_TEXTUAL_DATE_FORMAT.print(now))
+ .append(TOKEN_SEPARATOR)
+ .append(internalPendingReqId).toString();
+ }
+
+ private byte[] calculateHMAC(String toSign) throws EAAFIllegalStateException {
+ try {
+ final Mac mac = Mac.getInstance(digistAlgorithm);
+ mac.init(key);
+ return mac.doFinal(toSign.getBytes("UTF-8"));
+
+ } catch (UnsupportedEncodingException | 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/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SimplePendingRequestIdGenerationStrategy.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SimplePendingRequestIdGenerationStrategy.java
new file mode 100644
index 00000000..59da3d06
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SimplePendingRequestIdGenerationStrategy.java
@@ -0,0 +1,25 @@
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy;
+import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;
+
+public class SimplePendingRequestIdGenerationStrategy implements IPendingRequestIdGenerationStrategy {
+
+ @Override
+ public String generateExternalPendingRequestId() {
+ return Random.nextLongRandom();
+
+ }
+
+ @Override
+ public String validateAndGetPendingRequestId(String pendingReqId) throws PendingReqIdValidationException {
+ if (StringUtils.isEmpty(pendingReqId))
+ throw new PendingReqIdValidationException(pendingReqId, "PendingRequestId is empty or null");
+
+ return pendingReqId;
+
+ }
+
+}