1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.wss4j.stax.impl.processor.input;
20
21 import org.apache.wss4j.binding.wsu10.TimestampType;
22 import org.apache.wss4j.common.bsp.BSPRule;
23 import org.apache.wss4j.common.ext.WSSecurityException;
24 import org.apache.wss4j.stax.ext.WSInboundSecurityContext;
25 import org.apache.wss4j.stax.ext.WSSConstants;
26 import org.apache.wss4j.stax.ext.WSSSecurityProperties;
27 import org.apache.wss4j.stax.securityEvent.TimestampSecurityEvent;
28 import org.apache.wss4j.stax.validate.TimestampValidator;
29 import org.apache.wss4j.stax.validate.TimestampValidatorImpl;
30 import org.apache.wss4j.stax.validate.TokenContext;
31 import org.apache.xml.security.exceptions.XMLSecurityException;
32 import org.apache.xml.security.stax.ext.AbstractInputSecurityHeaderHandler;
33 import org.apache.xml.security.stax.ext.InputProcessorChain;
34 import org.apache.xml.security.stax.ext.XMLSecurityProperties;
35 import org.apache.xml.security.stax.ext.XMLSecurityUtils;
36 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
37 import org.apache.xml.security.stax.impl.util.IDGenerator;
38
39 import jakarta.xml.bind.JAXBElement;
40 import javax.xml.namespace.QName;
41 import javax.xml.stream.XMLStreamConstants;
42
43 import java.time.ZoneOffset;
44 import java.time.ZonedDateTime;
45 import java.time.format.DateTimeParseException;
46 import java.time.temporal.ChronoField;
47 import java.util.Deque;
48 import java.util.List;
49
50 public class TimestampInputHandler extends AbstractInputSecurityHeaderHandler {
51
52 @Override
53 public void handle(final InputProcessorChain inputProcessorChain, final XMLSecurityProperties securityProperties,
54 Deque<XMLSecEvent> eventQueue, Integer index) throws XMLSecurityException {
55
56 final WSSSecurityProperties wssSecurityProperties = (WSSSecurityProperties) securityProperties;
57 final WSInboundSecurityContext wssecurityContextInbound =
58 (WSInboundSecurityContext) inputProcessorChain.getSecurityContext();
59
60
61 Boolean alreadyProcessed = wssecurityContextInbound.<Boolean>get(WSSConstants.TIMESTAMP_PROCESSED);
62 if (Boolean.TRUE.equals(alreadyProcessed)) {
63 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "invalidTimestamp",
64 new Object[] {"Message contains two or more timestamps"});
65 }
66 wssecurityContextInbound.put(WSSConstants.TIMESTAMP_PROCESSED, Boolean.TRUE);
67
68 @SuppressWarnings("unchecked")
69 final TimestampType timestampType =
70 ((JAXBElement<TimestampType>) parseStructure(eventQueue, index, securityProperties)).getValue();
71
72 final List<XMLSecEvent> xmlSecEvents = getResponsibleXMLSecEvents(eventQueue, index);
73 List<QName> elementPath = getElementPath(eventQueue);
74
75 checkBSPCompliance(inputProcessorChain, timestampType, xmlSecEvents);
76
77 if (timestampType.getId() == null) {
78 timestampType.setId(IDGenerator.generateID(null));
79 }
80
81 TimestampValidator timestampValidator = wssSecurityProperties.getValidator(WSSConstants.TAG_WSU_TIMESTAMP);
82 if (timestampValidator == null) {
83 timestampValidator = new TimestampValidatorImpl();
84 }
85 TokenContext tokenContext = new TokenContext(wssSecurityProperties, wssecurityContextInbound, xmlSecEvents, elementPath);
86 timestampValidator.validate(timestampType, tokenContext);
87
88 TimestampSecurityEvent timestampSecurityEvent = new TimestampSecurityEvent();
89 if (timestampType.getCreated() != null) {
90 try {
91 timestampSecurityEvent.setCreated(
92 timestampType.getCreated().getAsZonedDateTime().toInstant());
93 } catch (IllegalArgumentException e) {
94
95 }
96 }
97 if (timestampType.getExpires() != null) {
98 try {
99 timestampSecurityEvent.setExpires(
100 timestampType.getExpires().getAsZonedDateTime().toInstant());
101 } catch (IllegalArgumentException e) {
102
103 }
104 }
105 timestampSecurityEvent.setCorrelationID(timestampType.getId());
106 wssecurityContextInbound.registerSecurityEvent(timestampSecurityEvent);
107 wssecurityContextInbound.put(WSSConstants.PROP_TIMESTAMP_SECURITYEVENT, timestampSecurityEvent);
108 }
109
110 private void checkBSPCompliance(InputProcessorChain inputProcessorChain, TimestampType timestampType,
111 List<XMLSecEvent> xmlSecEvents) throws WSSecurityException {
112 final WSInboundSecurityContext securityContext = (WSInboundSecurityContext) inputProcessorChain.getSecurityContext();
113 if (timestampType.getCreated() == null) {
114 securityContext.handleBSPRule(BSPRule.R3203);
115 }
116
117 int createdIndex = -1;
118 int expiresIndex = -1;
119 for (int i = 0; i < xmlSecEvents.size(); i++) {
120 XMLSecEvent xmlSecEvent = xmlSecEvents.get(i);
121 if (xmlSecEvent.getEventType() == XMLStreamConstants.START_ELEMENT) {
122 QName name = xmlSecEvent.asStartElement().getName();
123
124 if (name.equals(WSSConstants.TAG_WSU_TIMESTAMP)) {
125 continue;
126 } else if (name.equals(WSSConstants.TAG_WSU_CREATED)) {
127 if (createdIndex != -1) {
128 securityContext.handleBSPRule(BSPRule.R3203);
129 }
130 if (expiresIndex != -1) {
131 securityContext.handleBSPRule(BSPRule.R3221);
132 }
133 createdIndex = i;
134 } else if (name.equals(WSSConstants.TAG_WSU_EXPIRES)) {
135 if (expiresIndex != -1) {
136 securityContext.handleBSPRule(BSPRule.R3224);
137 }
138 if (createdIndex == -1) {
139 securityContext.handleBSPRule(BSPRule.R3221);
140 }
141 expiresIndex = i;
142 } else {
143 securityContext.handleBSPRule(BSPRule.R3222);
144 }
145 }
146 }
147
148 if (timestampType.getCreated() != null) {
149 ZonedDateTime createdDate;
150 try {
151 createdDate = timestampType.getCreated().getAsZonedDateTime();
152 } catch (DateTimeParseException e) {
153 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
154 }
155
156 if (!ZoneOffset.UTC.equals(createdDate.getZone())) {
157 securityContext.handleBSPRule(BSPRule.R3217);
158 }
159
160 if (createdDate.getNano() > 0) {
161 int milliseconds = createdDate.get(ChronoField.MILLI_OF_SECOND);
162 if (milliseconds * 1000000 != createdDate.getNano()) {
163 securityContext.handleBSPRule(BSPRule.R3220);
164 }
165 }
166
167 String valueType = XMLSecurityUtils.getQNameAttribute(timestampType.getCreated().getOtherAttributes(),
168 WSSConstants.ATT_NULL_VALUE_TYPE);
169 if (valueType != null) {
170 securityContext.handleBSPRule(BSPRule.R3225);
171 }
172 } else {
173 securityContext.handleBSPRule(BSPRule.R3203);
174 }
175
176 if (timestampType.getExpires() != null) {
177 ZonedDateTime expiresDate;
178 try {
179 expiresDate = timestampType.getExpires().getAsZonedDateTime();
180 } catch (DateTimeParseException e) {
181 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
182 }
183
184 if (!ZoneOffset.UTC.equals(expiresDate.getZone())) {
185 securityContext.handleBSPRule(BSPRule.R3223);
186 }
187
188 if (expiresDate.getNano() > 0) {
189 int milliseconds = expiresDate.get(ChronoField.MILLI_OF_SECOND);
190 if (milliseconds * 1000000 != expiresDate.getNano()) {
191 securityContext.handleBSPRule(BSPRule.R3229);
192 }
193 }
194
195 String valueType = XMLSecurityUtils.getQNameAttribute(timestampType.getExpires().getOtherAttributes(),
196 WSSConstants.ATT_NULL_VALUE_TYPE);
197 if (valueType != null) {
198 securityContext.handleBSPRule(BSPRule.R3226);
199 }
200 }
201 }
202
203 }