diff options
| author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2019-04-23 15:00:13 +0200 | 
|---|---|---|
| committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2019-04-23 15:00:13 +0200 | 
| commit | 5c1b5b863fe8d6c08cfe0749fed7ce9594827f8a (patch) | |
| tree | e96cf3ae1f3ed011b0588fd7a341038484c55017 /eaaf_core | |
| parent | f689c1e404b5cf22d17346da75a296c825a3ba03 (diff) | |
| download | EAAF-Components-5c1b5b863fe8d6c08cfe0749fed7ce9594827f8a.tar.gz EAAF-Components-5c1b5b863fe8d6c08cfe0749fed7ce9594827f8a.tar.bz2 EAAF-Components-5c1b5b863fe8d6c08cfe0749fed7ce9594827f8a.zip | |
add different strategies for pendingRequestId generation
Diffstat (limited to 'eaaf_core')
9 files changed, 488 insertions, 66 deletions
| diff --git a/eaaf_core/pom.xml b/eaaf_core/pom.xml index 21d6c338..34b0d69e 100644 --- a/eaaf_core/pom.xml +++ b/eaaf_core/pom.xml @@ -96,6 +96,11 @@  	</dependency>  	<dependency> +	    <groupId>joda-time</groupId> +    	<artifactId>joda-time</artifactId> +	</dependency> +	 +	<dependency>  		<groupId>junit</groupId>        	<artifactId>junit</artifactId>        	<scope>test</scope> 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; +				 +	} + +} | 
