/* * Copyright 2005-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.ws.soap.security.xwss.callback; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import com.sun.xml.wss.impl.callback.TimestampValidationCallback; /** * A default implementation of a {@code TimestampValidationCallback.TimestampValidator}. Based on a version found * in the JWSDP samples. * * @author Arjen Poutsma * @since 1.0.0 */ public class DefaultTimestampValidator implements TimestampValidationCallback.TimestampValidator { @Override public void validate(TimestampValidationCallback.Request request) throws TimestampValidationCallback.TimestampValidationException { if (request instanceof TimestampValidationCallback.UTCTimestampRequest) { TimestampValidationCallback.UTCTimestampRequest utcRequest = (TimestampValidationCallback.UTCTimestampRequest) request; Date created = parseDate(utcRequest.getCreated()); validateCreationTime(created, utcRequest.getMaxClockSkew(), utcRequest.getTimestampFreshnessLimit()); if (utcRequest.getExpired() != null) { Date expired = parseDate(utcRequest.getExpired()); validateExpirationTime(expired, utcRequest.getMaxClockSkew()); } } else { throw new TimestampValidationCallback.TimestampValidationException("Unsupport request: [" + request + "]"); } } private Date getFreshnessAndSkewAdjustedDate(long maxClockSkew, long timestampFreshnessLimit) { Calendar c = new GregorianCalendar(); long offset = c.get(Calendar.ZONE_OFFSET); if (c.getTimeZone().inDaylightTime(c.getTime())) { offset += c.getTimeZone().getDSTSavings(); } long beforeTime = c.getTimeInMillis(); long currentTime = beforeTime - offset; long adjustedTime = currentTime - maxClockSkew - timestampFreshnessLimit; c.setTimeInMillis(adjustedTime); return c.getTime(); } private Date getGMTDateWithSkewAdjusted(Calendar calendar, long maxClockSkew, boolean addSkew) { long offset = calendar.get(Calendar.ZONE_OFFSET); if (calendar.getTimeZone().inDaylightTime(calendar.getTime())) { offset += calendar.getTimeZone().getDSTSavings(); } long beforeTime = calendar.getTimeInMillis(); long currentTime = beforeTime - offset; if (addSkew) { currentTime = currentTime + maxClockSkew; } else { currentTime = currentTime - maxClockSkew; } calendar.setTimeInMillis(currentTime); return calendar.getTime(); } private Date parseDate(String date) throws TimestampValidationCallback.TimestampValidationException { SimpleDateFormat calendarFormatter1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); SimpleDateFormat calendarFormatter2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSS'Z'"); try { try { return calendarFormatter1.parse(date); } catch (ParseException ignored) { return calendarFormatter2.parse(date); } } catch (ParseException ex) { throw new TimestampValidationCallback.TimestampValidationException("Could not parse request date: " + date, ex); } } private void validateCreationTime(Date created, long maxClockSkew, long timestampFreshnessLimit) throws TimestampValidationCallback.TimestampValidationException { Date current = getFreshnessAndSkewAdjustedDate(maxClockSkew, timestampFreshnessLimit); if (created.before(current)) { throw new TimestampValidationCallback.TimestampValidationException( "The creation time is older than currenttime - timestamp-freshness-limit - max-clock-skew"); } Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(), maxClockSkew, true); if (currentTime.before(created)) { throw new TimestampValidationCallback.TimestampValidationException( "The creation time is ahead of the current time."); } } private void validateExpirationTime(Date expires, long maxClockSkew) throws TimestampValidationCallback.TimestampValidationException { Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(), maxClockSkew, false); if (expires.before(currentTime)) { throw new TimestampValidationCallback.TimestampValidationException( "The current time is ahead of the expiration time in Timestamp"); } } }