ProcessTimestampedMessage.java

  1. /*
  2.  * AdroitLogic UltraESB Enterprise Service Bus
  3.  *
  4.  * Copyright (c) 2010-2012 AdroitLogic Private Ltd. (http://adroitlogic.org). All Rights Reserved.
  5.  *
  6.  * GNU Affero General Public License Usage
  7.  *
  8.  * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
  9.  * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
  10.  * any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  13.  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
  14.  * more details.
  15.  *
  16.  * You should have received a copy of the GNU Affero General Public License along with this program (See LICENSE-AGPL.TXT).
  17.  * If not, see http://www.gnu.org/licenses/agpl-3.0.html
  18.  *
  19.  * Commercial Usage
  20.  *
  21.  * Licensees holding valid UltraESB Commercial licenses may use this file in accordance with the UltraESB Commercial
  22.  * License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written
  23.  * agreement between you and AdroitLogic.
  24.  *
  25.  * If you are unsure which license is appropriate for your use, or have questions regarding the use of this file,
  26.  * please contact AdroitLogic at info@adroitlogic.com
  27.  */
  28. /*
  29.  * Modificato da Link.it (https://link.it) per supportare le seguenti funzionalità:
  30.  * - firma e cifratura degli attachments
  31.  * - cifratura con chiave simmetrica
  32.  * - supporto CRL
  33.  *
  34.  * Copyright (c) 2011-2025 Link.it srl (https://link.it).
  35.  *
  36.  */

  37. package org.openspcoop2.security.message.soapbox;

  38. import java.text.ParseException;
  39. import java.text.SimpleDateFormat;
  40. import java.util.Calendar;
  41. import java.util.Date;
  42. import java.util.GregorianCalendar;
  43. import java.util.TimeZone;

  44. import org.adroitlogic.soapbox.CryptoUtil;
  45. import org.adroitlogic.soapbox.InvalidMessageDataException;
  46. import org.adroitlogic.soapbox.MessageSecurityContext;
  47. import org.adroitlogic.soapbox.Processor;
  48. import org.adroitlogic.soapbox.SBConstants;
  49. import org.adroitlogic.soapbox.SecurityConfig;
  50. import org.adroitlogic.soapbox.SecurityFailureException;
  51. import org.slf4j.Logger;
  52. import org.openspcoop2.security.message.constants.SecurityConstants;
  53. import org.openspcoop2.utils.LoggerWrapperFactory;
  54. import org.openspcoop2.utils.UtilsException;
  55. import org.openspcoop2.utils.date.DateManager;
  56. import org.w3c.dom.Element;

  57. /**
  58.  * ProcessTimestampedMessage
  59.  *
  60.  * Author of the original AdroitLogic code:
  61.  * @author asankha
  62.  *
  63.  * Authors of the Link.it modification to the code:
  64.  * @author Andrea Poli (apoli@link.it)
  65.  * @author Giovanni Bussu (bussu@link.it)
  66.  * @author $Author$
  67.  * @version $Rev$, $Date$
  68.  */
  69. public class ProcessTimestampedMessage implements Processor {
  70.    
  71.     private static final Logger logger = LoggerWrapperFactory.getLogger(ProcessTimestampedMessage.class);
  72.    
  73.     private final SimpleDateFormat zuluMillisecondsPrecision = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // SimpleDateFormat non e' thread-safe
  74.     private final SimpleDateFormat zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); // SimpleDateFormat non e' thread-safe

  75.     public ProcessTimestampedMessage() {
  76.         this.zuluMillisecondsPrecision.setTimeZone(TimeZone.getTimeZone("UTC"));
  77.         this.zulu.setTimeZone(TimeZone.getTimeZone("UTC"));
  78.     }

  79.     @Override
  80.     public void process(SecurityConfig secConfig, MessageSecurityContext msgSecCtx) {

  81.         Element elem = CryptoUtil.getSecurityProcessorElement(
  82.             msgSecCtx.getDocument().getDocumentElement(), SBConstants.WSU, "Timestamp");

  83.         if (elem == null) {
  84.             if (ProcessTimestampedMessage.logger.isDebugEnabled()) {
  85.                 ProcessTimestampedMessage.logger.debug("Message is not timestamped - skipping ProcessTimestampedMessage");
  86.             }
  87.             throw new SecurityFailureException("WS-Security failure - Message is not timestamped");
  88.         }

  89.         String createdTime = CryptoUtil.getFirstChild(elem, SBConstants.WSU, "Created").getTextContent();
  90.         String expiryTime  = CryptoUtil.getFirstChild(elem, SBConstants.WSU, "Expires").getTextContent();

  91.         Long futureTimeToLive = (Long) msgSecCtx.getProperty(SecurityConstants.TIMESTAMP_FUTURE_TTL);
  92.         boolean isStrict = (Boolean) msgSecCtx.getProperty(SecurityConstants.TIMESTAMP_STRICT);
  93.        
  94.         Calendar created, expiry, valid = null;
  95.         boolean precisionInSeconds = false;
  96.         created = new GregorianCalendar();
  97.         expiry = new GregorianCalendar();
  98.         valid = new GregorianCalendar();
  99.        
  100.         try {

  101.             synchronized(this.zuluMillisecondsPrecision) {
  102.                 created.setTime(this.zuluMillisecondsPrecision.parse(createdTime));
  103.             }
  104.            
  105.         } catch (ParseException e) {
  106.             try {

  107.                 synchronized(this.zulu) {
  108.                     created.setTime(this.zulu.parse(createdTime));
  109.                 }
  110.                
  111.                 precisionInSeconds = true;
  112.             } catch (ParseException e1) {
  113.                 throw new InvalidMessageDataException("Invalid timestamp data. Created : " + createdTime + " Expected in Zulu format : " + e1.getMessage());
  114.             }
  115.         }

  116.         valid.setTimeInMillis(created.getTime().getTime()-futureTimeToLive.longValue());
  117.         SimpleDateFormat format = (precisionInSeconds) ? this.zulu : this.zuluMillisecondsPrecision;

  118.         try {
  119.             synchronized (format) {
  120.                 expiry.setTime(format.parse(expiryTime));
  121.             }
  122.         } catch (ParseException e) {
  123.             throw new InvalidMessageDataException("Invalid timestamp data. " +
  124.                 " Expiry : " + expiryTime + " Expected in Zulu format : " + e.getMessage());
  125.         }

  126.         Calendar rightNow;
  127.         try {
  128.             rightNow = DateManager.getCalendar();
  129.         } catch (UtilsException e) {
  130.             rightNow = new GregorianCalendar();
  131.             rightNow.setTimeInMillis(new Date().getTime());
  132.         }
  133.        
  134.         if (expiry.before(created)) {
  135.             if(isStrict) {
  136.                 throw new SecurityFailureException("Message expiry : " + expiryTime + " before created time : " + createdTime);
  137.             } else {
  138.                 if (ProcessTimestampedMessage.logger.isInfoEnabled()) {
  139.                     ProcessTimestampedMessage.logger.warn("Message expiry : " + expiryTime + " before created time : " + createdTime);
  140.                 }
  141.             }
  142.         } else if (rightNow.before(valid)) {
  143.             synchronized (format) {
  144.                 String msg = "Message is not yet valid. Created timestamp is : " + createdTime + " " +
  145.                             " Current system time : " + format.format(rightNow.getTime()) +
  146.                             " Future time to live set to "+futureTimeToLive/1000l+" seconds";
  147.                 if(isStrict) {
  148.                     throw new SecurityFailureException(msg);
  149.                 } else {
  150.                     if (ProcessTimestampedMessage.logger.isInfoEnabled()) {
  151.                         ProcessTimestampedMessage.logger.warn(msg);
  152.                     }
  153.                 }
  154.             }
  155.         } else if (rightNow.after(expiry)) {
  156.             synchronized (format) {
  157.                 String msg = "Message has expired at : " + expiryTime +
  158.                         " Current system time : " + format.format(rightNow.getTime());
  159.                 if(isStrict) {
  160.                     throw new SecurityFailureException(msg);
  161.                 } else {
  162.                     if (ProcessTimestampedMessage.logger.isInfoEnabled()) {
  163.                         ProcessTimestampedMessage.logger.warn(msg);
  164.                     }
  165.                 }
  166.             }
  167.         } else {
  168.             if (ProcessTimestampedMessage.logger.isDebugEnabled()) {
  169.                 synchronized (format) {
  170.                     ProcessTimestampedMessage.logger.debug("Timestamp verified and valid at : " + format.format(rightNow.getTime()));
  171.                 }
  172.             }
  173.         }
  174.     }
  175. }