blob: c2d13dfbb8622486d9dc482b594b8d9be9443aef [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.swssf.wss.impl.processor.input;
import org.swssf.binding.wsu10.TimestampType;
import org.swssf.wss.ext.WSSConstants;
import org.swssf.wss.ext.WSSSecurityProperties;
import org.swssf.wss.ext.WSSecurityContext;
import org.swssf.wss.ext.WSSecurityException;
import org.swssf.wss.securityEvent.TimestampSecurityEvent;
import org.apache.xml.security.stax.ext.*;
import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.stream.XMLStreamConstants;
import java.util.Calendar;
import java.util.Deque;
import java.util.GregorianCalendar;
import java.util.Iterator;
/**
* @author $Author$
* @version $Revision$ $Date$
*/
public class TimestampInputHandler extends AbstractInputSecurityHeaderHandler {
//Chapter 10 Security Timestamps: ...may only be present at most once per header (that is, per SOAP actor/role)
@Override
public void handle(final InputProcessorChain inputProcessorChain, final XMLSecurityProperties securityProperties,
Deque<XMLSecEvent> eventQueue, Integer index) throws XMLSecurityException {
final WSSSecurityProperties wssSecurityProperties = (WSSSecurityProperties) securityProperties;
Boolean alreadyProcessed = inputProcessorChain.getSecurityContext().<Boolean>get(WSSConstants.TIMESTAMP_PROCESSED);
if (Boolean.TRUE.equals(alreadyProcessed)) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "invalidTimestamp",
"Message contains two or more timestamps");
}
inputProcessorChain.getSecurityContext().put(WSSConstants.TIMESTAMP_PROCESSED, Boolean.TRUE);
@SuppressWarnings("unchecked")
final TimestampType timestampType =
((JAXBElement<TimestampType>) parseStructure(eventQueue, index, securityProperties)).getValue();
checkBSPCompliance(inputProcessorChain, timestampType, eventQueue, index);
if (timestampType.getCreated() == null) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "missingCreated");
}
try {
// Validate whether the security semantics have expired
//created and expires is optional per spec. But we enforce the created element in the validation
Calendar crea = null;
if (timestampType.getCreated() != null) {
XMLGregorianCalendar created;
try {
created = WSSConstants.datatypeFactory.newXMLGregorianCalendar(timestampType.getCreated().getValue());
} catch (IllegalArgumentException e) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
}
logger.debug("Timestamp created: " + created);
crea = created.toGregorianCalendar();
}
Calendar exp = null;
if (timestampType.getExpires() != null) {
XMLGregorianCalendar expires;
try {
expires = WSSConstants.datatypeFactory.newXMLGregorianCalendar(timestampType.getExpires().getValue());
} catch (IllegalArgumentException e) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
}
logger.debug("Timestamp expires: " + expires);
exp = expires.toGregorianCalendar();
}
Calendar rightNow = Calendar.getInstance();
Calendar ttl = Calendar.getInstance();
ttl.add(Calendar.SECOND, -wssSecurityProperties.getTimestampTTL());
if (exp != null && wssSecurityProperties.isStrictTimestampCheck() && exp.before(rightNow)) {
logger.debug("Time now: " + WSSConstants.datatypeFactory.newXMLGregorianCalendar(new GregorianCalendar()).toXMLFormat());
throw new WSSecurityException(WSSecurityException.ErrorCode.MESSAGE_EXPIRED, "invalidTimestamp",
"The security semantics of the message have expired");
}
if (crea != null && wssSecurityProperties.isStrictTimestampCheck() && crea.before(ttl)) {
logger.debug("Time now: " + WSSConstants.datatypeFactory.newXMLGregorianCalendar(new GregorianCalendar()).toXMLFormat());
throw new WSSecurityException(WSSecurityException.ErrorCode.MESSAGE_EXPIRED, "invalidTimestamp",
"The security semantics of the message have expired");
}
if (crea != null && crea.after(rightNow)) {
logger.debug("Time now: " + WSSConstants.datatypeFactory.newXMLGregorianCalendar(new GregorianCalendar()).toXMLFormat());
throw new WSSecurityException(WSSecurityException.ErrorCode.MESSAGE_EXPIRED, "invalidTimestamp",
"The security semantics of the message is invalid");
}
TimestampSecurityEvent timestampSecurityEvent = new TimestampSecurityEvent();
timestampSecurityEvent.setCreated(crea);
timestampSecurityEvent.setExpires(exp);
((WSSecurityContext) inputProcessorChain.getSecurityContext()).registerSecurityEvent(timestampSecurityEvent);
inputProcessorChain.getSecurityContext().put(WSSConstants.PROP_TIMESTAMP_SECURITYEVENT, timestampSecurityEvent);
} catch (IllegalArgumentException e) {
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
}
}
private void checkBSPCompliance(InputProcessorChain inputProcessorChain, TimestampType timestampType,
Deque<XMLSecEvent> eventDeque, int index) throws WSSecurityException {
final WSSecurityContext securityContext = (WSSecurityContext) inputProcessorChain.getSecurityContext();
if (timestampType.getCreated() == null) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3203);
}
Iterator<XMLSecEvent> xmlSecEventIterator = eventDeque.descendingIterator();
int curIdx = 0;
//forward to first timestamp child element
while (curIdx++ <= index) {
xmlSecEventIterator.next();
}
int createdIndex = -1;
int expiresIndex = -1;
while (xmlSecEventIterator.hasNext()) {
XMLSecEvent xmlSecEvent = xmlSecEventIterator.next();
if (xmlSecEvent.getEventType() == XMLStreamConstants.START_ELEMENT) {
if (xmlSecEvent.asStartElement().getName().equals(WSSConstants.TAG_wsu_Created)) {
if (createdIndex != -1) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3203);
}
if (expiresIndex != -1) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3221);
}
createdIndex = curIdx;
} else if (xmlSecEvent.asStartElement().getName().equals(WSSConstants.TAG_wsu_Expires)) {
if (expiresIndex != -1) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3224);
}
if (createdIndex == -1) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3221);
}
expiresIndex = curIdx;
} else {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3222);
}
}
curIdx++;
}
if (timestampType.getCreated() != null) {
XMLGregorianCalendar createdCalendar;
try {
createdCalendar = WSSConstants.datatypeFactory.newXMLGregorianCalendar(timestampType.getCreated().getValue());
} catch (IllegalArgumentException e) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
}
if (createdCalendar.getFractionalSecond().scale() > 3) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3220);
}
if (createdCalendar.getSecond() > 59) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3213);
}
String valueType = XMLSecurityUtils.getQNameAttribute(timestampType.getCreated().getOtherAttributes(), WSSConstants.ATT_NULL_ValueType);
if (valueType != null) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3225);
}
if (createdCalendar.getTimezone() == DatatypeConstants.FIELD_UNDEFINED) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3217);
}
}
if (timestampType.getExpires() != null) {
XMLGregorianCalendar expiresCalendar;
try {
expiresCalendar = WSSConstants.datatypeFactory.newXMLGregorianCalendar(timestampType.getExpires().getValue());
} catch (IllegalArgumentException e) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
}
if (expiresCalendar.getFractionalSecond().scale() > 3) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3229);
}
if (expiresCalendar.getSecond() > 59) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3215);
}
String valueType = XMLSecurityUtils.getQNameAttribute(timestampType.getExpires().getOtherAttributes(), WSSConstants.ATT_NULL_ValueType);
if (valueType != null) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3226);
}
if (expiresCalendar.getTimezone() == DatatypeConstants.FIELD_UNDEFINED) {
securityContext.handleBSPRule(WSSConstants.BSPRule.R3223);
}
}
}
/*
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-1106985890">
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2009-11-18T10:11:28.358Z</wsu:Created>
<wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2009-11-18T10:26:28.358Z</wsu:Expires>
</wsu:Timestamp>
*/
}