ProcessTimestampedMessage.java
/*
* AdroitLogic UltraESB Enterprise Service Bus
*
* Copyright (c) 2010-2012 AdroitLogic Private Ltd. (http://adroitlogic.org). All Rights Reserved.
*
* GNU Affero General Public License Usage
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
* Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program (See LICENSE-AGPL.TXT).
* If not, see http://www.gnu.org/licenses/agpl-3.0.html
*
* Commercial Usage
*
* Licensees holding valid UltraESB Commercial licenses may use this file in accordance with the UltraESB Commercial
* License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written
* agreement between you and AdroitLogic.
*
* If you are unsure which license is appropriate for your use, or have questions regarding the use of this file,
* please contact AdroitLogic at info@adroitlogic.com
*/
/*
* Modificato da Link.it (https://link.it) per supportare le seguenti funzionalità:
* - firma e cifratura degli attachments
* - cifratura con chiave simmetrica
* - supporto CRL
*
* Copyright (c) 2011-2024 Link.it srl (https://link.it).
*
*/
package org.openspcoop2.security.message.soapbox;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.adroitlogic.soapbox.CryptoUtil;
import org.adroitlogic.soapbox.InvalidMessageDataException;
import org.adroitlogic.soapbox.MessageSecurityContext;
import org.adroitlogic.soapbox.Processor;
import org.adroitlogic.soapbox.SBConstants;
import org.adroitlogic.soapbox.SecurityConfig;
import org.adroitlogic.soapbox.SecurityFailureException;
import org.slf4j.Logger;
import org.openspcoop2.security.message.constants.SecurityConstants;
import org.openspcoop2.utils.LoggerWrapperFactory;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.date.DateManager;
import org.w3c.dom.Element;
/**
* ProcessTimestampedMessage
*
* Author of the original AdroitLogic code:
* @author asankha
*
* Authors of the Link.it modification to the code:
* @author Andrea Poli (apoli@link.it)
* @author Giovanni Bussu (bussu@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class ProcessTimestampedMessage implements Processor {
private static final Logger logger = LoggerWrapperFactory.getLogger(ProcessTimestampedMessage.class);
private final SimpleDateFormat zuluMillisecondsPrecision = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // SimpleDateFormat non e' thread-safe
private final SimpleDateFormat zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); // SimpleDateFormat non e' thread-safe
public ProcessTimestampedMessage() {
this.zuluMillisecondsPrecision.setTimeZone(TimeZone.getTimeZone("UTC"));
this.zulu.setTimeZone(TimeZone.getTimeZone("UTC"));
}
@Override
public void process(SecurityConfig secConfig, MessageSecurityContext msgSecCtx) {
Element elem = CryptoUtil.getSecurityProcessorElement(
msgSecCtx.getDocument().getDocumentElement(), SBConstants.WSU, "Timestamp");
if (elem == null) {
if (ProcessTimestampedMessage.logger.isDebugEnabled()) {
ProcessTimestampedMessage.logger.debug("Message is not timestamped - skipping ProcessTimestampedMessage");
}
throw new SecurityFailureException("WS-Security failure - Message is not timestamped");
}
String createdTime = CryptoUtil.getFirstChild(elem, SBConstants.WSU, "Created").getTextContent();
String expiryTime = CryptoUtil.getFirstChild(elem, SBConstants.WSU, "Expires").getTextContent();
Long futureTimeToLive = (Long) msgSecCtx.getProperty(SecurityConstants.TIMESTAMP_FUTURE_TTL);
boolean isStrict = (Boolean) msgSecCtx.getProperty(SecurityConstants.TIMESTAMP_STRICT);
Calendar created, expiry, valid = null;
boolean precisionInSeconds = false;
created = new GregorianCalendar();
expiry = new GregorianCalendar();
valid = new GregorianCalendar();
try {
synchronized(this.zuluMillisecondsPrecision) {
created.setTime(this.zuluMillisecondsPrecision.parse(createdTime));
}
} catch (ParseException e) {
try {
synchronized(this.zulu) {
created.setTime(this.zulu.parse(createdTime));
}
precisionInSeconds = true;
} catch (ParseException e1) {
throw new InvalidMessageDataException("Invalid timestamp data. Created : " + createdTime + " Expected in Zulu format : " + e1.getMessage());
}
}
valid.setTimeInMillis(created.getTime().getTime()-futureTimeToLive.longValue());
SimpleDateFormat format = (precisionInSeconds) ? this.zulu : this.zuluMillisecondsPrecision;
try {
synchronized (format) {
expiry.setTime(format.parse(expiryTime));
}
} catch (ParseException e) {
throw new InvalidMessageDataException("Invalid timestamp data. " +
" Expiry : " + expiryTime + " Expected in Zulu format : " + e.getMessage());
}
Calendar rightNow;
try {
rightNow = DateManager.getCalendar();
} catch (UtilsException e) {
rightNow = new GregorianCalendar();
rightNow.setTimeInMillis(new Date().getTime());
}
if (expiry.before(created)) {
if(isStrict) {
throw new SecurityFailureException("Message expiry : " + expiryTime + " before created time : " + createdTime);
} else {
if (ProcessTimestampedMessage.logger.isInfoEnabled()) {
ProcessTimestampedMessage.logger.warn("Message expiry : " + expiryTime + " before created time : " + createdTime);
}
}
} else if (rightNow.before(valid)) {
synchronized (format) {
String msg = "Message is not yet valid. Created timestamp is : " + createdTime + " " +
" Current system time : " + format.format(rightNow.getTime()) +
" Future time to live set to "+futureTimeToLive/1000l+" seconds";
if(isStrict) {
throw new SecurityFailureException(msg);
} else {
if (ProcessTimestampedMessage.logger.isInfoEnabled()) {
ProcessTimestampedMessage.logger.warn(msg);
}
}
}
} else if (rightNow.after(expiry)) {
synchronized (format) {
String msg = "Message has expired at : " + expiryTime +
" Current system time : " + format.format(rightNow.getTime());
if(isStrict) {
throw new SecurityFailureException(msg);
} else {
if (ProcessTimestampedMessage.logger.isInfoEnabled()) {
ProcessTimestampedMessage.logger.warn(msg);
}
}
}
} else {
if (ProcessTimestampedMessage.logger.isDebugEnabled()) {
synchronized (format) {
ProcessTimestampedMessage.logger.debug("Timestamp verified and valid at : " + format.format(rightNow.getTime()));
}
}
}
}
}