diff options
Diffstat (limited to 'eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java')
-rw-r--r-- | eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java | 214 |
1 files changed, 0 insertions, 214 deletions
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 deleted file mode 100644 index f0ef9b38..00000000 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java +++ /dev/null @@ -1,214 +0,0 @@ -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 org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; - -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; - -/** - * PendingRequestId generation strategy based on signed tokens that facilitates extended token validation - * - * @author tlenz - * - */ -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 getPendingRequestIdWithOutChecks(String externalPendingReqId) throws PendingReqIdValidationException { - final String[] tokenElements = extractTokens(externalPendingReqId); - return tokenElements[1]; - - } - - @Override - public String validateAndGetPendingRequestId(String externalPendingReqId) throws PendingReqIdValidationException { - try { - final String[] tokenElements = extractTokens(externalPendingReqId); - 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; - - - } 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); - - } - } - - @NonNull - private String[] extractTokens(@Nullable String externalPendingReqId) throws PendingReqIdValidationException { - if (StringUtils.isEmpty(externalPendingReqId)) { - log.info("PendingReqId is 'null' or empty"); - throw new PendingReqIdValidationException(null, "PendingReqId is 'null' or empty"); - - } - - log.trace("RAW external pendingReqId: {}", externalPendingReqId); - 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); - return tokenElements; - - } else { - log.warn("PendingRequestId has an unvalid format"); - log.debug("PendingRequestId: {}", stringToken); - throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format"); - - } - - } - - - @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); - - } - - } - -} |