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.wss10.EncodedString;
22 import org.apache.wss4j.binding.wss10.PasswordString;
23 import org.apache.wss4j.binding.wss10.UsernameTokenType;
24 import org.apache.wss4j.binding.wsu10.AttributedDateTime;
25 import org.apache.wss4j.common.bsp.BSPRule;
26 import org.apache.wss4j.common.cache.ReplayCache;
27 import org.apache.wss4j.common.ext.WSSecurityException;
28 import org.apache.wss4j.common.util.DateUtil;
29 import org.apache.wss4j.stax.ext.WSInboundSecurityContext;
30 import org.apache.wss4j.stax.ext.WSSConstants;
31 import org.apache.wss4j.stax.ext.WSSSecurityProperties;
32 import org.apache.wss4j.stax.securityToken.UsernameSecurityToken;
33 import org.apache.wss4j.stax.securityEvent.UsernameTokenSecurityEvent;
34 import org.apache.wss4j.stax.validate.TokenContext;
35 import org.apache.wss4j.stax.validate.UsernameTokenValidator;
36 import org.apache.wss4j.stax.validate.UsernameTokenValidatorImpl;
37 import org.apache.xml.security.exceptions.XMLSecurityException;
38 import org.apache.xml.security.stax.ext.*;
39 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
40 import org.apache.xml.security.stax.impl.util.IDGenerator;
41 import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
42 import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
43
44 import jakarta.xml.bind.JAXBElement;
45 import javax.xml.namespace.QName;
46 import javax.xml.stream.XMLStreamConstants;
47
48 import java.time.Instant;
49 import java.time.ZonedDateTime;
50 import java.time.format.DateTimeParseException;
51 import java.util.Deque;
52 import java.util.List;
53
54
55
56
57 public class UsernameTokenInputHandler extends AbstractInputSecurityHeaderHandler {
58
59 @Override
60 public void handle(final InputProcessorChain inputProcessorChain, final XMLSecurityProperties securityProperties,
61 Deque<XMLSecEvent> eventQueue, Integer index) throws XMLSecurityException {
62
63 @SuppressWarnings("unchecked")
64 final UsernameTokenType usernameTokenType =
65 ((JAXBElement<UsernameTokenType>) parseStructure(eventQueue, index, securityProperties)).getValue();
66
67 final List<XMLSecEvent> xmlSecEvents = getResponsibleXMLSecEvents(eventQueue, index);
68
69 checkBSPCompliance(inputProcessorChain, usernameTokenType, xmlSecEvents);
70
71 if (usernameTokenType.getId() == null) {
72 usernameTokenType.setId(IDGenerator.generateID(null));
73 }
74
75
76 final WSSSecurityProperties wssSecurityProperties = (WSSSecurityProperties) securityProperties;
77 Instant created = verifyCreated(wssSecurityProperties, usernameTokenType);
78
79 ReplayCache replayCache = wssSecurityProperties.getNonceReplayCache();
80 final EncodedString encodedNonce =
81 XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSSE_NONCE);
82 if (encodedNonce != null && replayCache != null) {
83
84 String nonce = encodedNonce.getValue();
85 if (replayCache.contains(nonce)) {
86 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
87 }
88
89
90
91
92 int utTTL = wssSecurityProperties.getUtTTL();
93 if (created == null || utTTL <= 0) {
94 replayCache.add(nonce);
95 } else {
96 replayCache.add(nonce, Instant.now().plusSeconds(utTTL));
97 }
98 }
99
100 final WSInboundSecurityContext wsInboundSecurityContext =
101 (WSInboundSecurityContext) inputProcessorChain.getSecurityContext();
102 final List<QName> elementPath = getElementPath(eventQueue);
103
104 final TokenContext tokenContext =
105 new TokenContext(wssSecurityProperties, wsInboundSecurityContext, xmlSecEvents, elementPath);
106
107 UsernameTokenValidator usernameTokenValidator =
108 wssSecurityProperties.getValidator(WSSConstants.TAG_WSSE_USERNAME_TOKEN);
109 if (usernameTokenValidator == null) {
110 usernameTokenValidator = new UsernameTokenValidatorImpl();
111 }
112 final UsernameSecurityToken usernameSecurityToken =
113 usernameTokenValidator.validate(usernameTokenType, tokenContext);
114
115 SecurityTokenProvider<InboundSecurityToken> securityTokenProvider =
116 new SecurityTokenProvider<InboundSecurityToken>() {
117
118 @Override
119 public InboundSecurityToken getSecurityToken() throws XMLSecurityException {
120 return (InboundSecurityToken)usernameSecurityToken;
121 }
122
123 @Override
124 public String getId() {
125 return usernameTokenType.getId();
126 }
127 };
128 inputProcessorChain.getSecurityContext().registerSecurityTokenProvider(usernameTokenType.getId(), securityTokenProvider);
129
130
131 UsernameTokenSecurityEvent usernameTokenSecurityEvent = new UsernameTokenSecurityEvent();
132 usernameTokenSecurityEvent.setSecurityToken((UsernameSecurityToken)securityTokenProvider.getSecurityToken());
133
134 usernameTokenSecurityEvent.setCorrelationID(usernameTokenType.getId());
135 inputProcessorChain.getSecurityContext().registerSecurityEvent(usernameTokenSecurityEvent);
136 }
137
138 private void checkBSPCompliance(InputProcessorChain inputProcessorChain, UsernameTokenType usernameTokenType,
139 List<XMLSecEvent> xmlSecEvents) throws WSSecurityException {
140
141 final WSInboundSecurityContext securityContext = (WSInboundSecurityContext) inputProcessorChain.getSecurityContext();
142 if (usernameTokenType.getAny() == null) {
143 securityContext.handleBSPRule(BSPRule.R3031);
144 }
145
146 int passwordIndex = -1;
147 int createdIndex = -1;
148 int nonceIndex = -1;
149 for (int i = 0; i < xmlSecEvents.size(); i++) {
150 XMLSecEvent xmlSecEvent = xmlSecEvents.get(i);
151 if (xmlSecEvent.getEventType() == XMLStreamConstants.START_ELEMENT) {
152 if (xmlSecEvent.asStartElement().getName().equals(WSSConstants.TAG_WSSE_USERNAME_TOKEN)) {
153 continue;
154 } else if (xmlSecEvent.asStartElement().getName().equals(WSSConstants.TAG_WSSE_PASSWORD)) {
155 if (passwordIndex != -1) {
156 securityContext.handleBSPRule(BSPRule.R4222);
157 }
158 passwordIndex = i;
159 } else if (xmlSecEvent.asStartElement().getName().equals(WSSConstants.TAG_WSU_CREATED)) {
160 if (createdIndex != -1) {
161 securityContext.handleBSPRule(BSPRule.R4223);
162 }
163 createdIndex = i;
164 } else if (xmlSecEvent.asStartElement().getName().equals(WSSConstants.TAG_WSSE_NONCE)) {
165 if (nonceIndex != -1) {
166 securityContext.handleBSPRule(BSPRule.R4225);
167 }
168 nonceIndex = i;
169 }
170 }
171 }
172
173 PasswordString passwordType =
174 XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSSE_PASSWORD);
175 if (passwordType != null && passwordType.getType() == null) {
176 securityContext.handleBSPRule(BSPRule.R4201);
177 }
178
179 EncodedString encodedNonce =
180 XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSSE_NONCE);
181 if (encodedNonce != null) {
182 if (encodedNonce.getEncodingType() == null) {
183 securityContext.handleBSPRule(BSPRule.R4220);
184 } else if (!WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING.equals(encodedNonce.getEncodingType())) {
185 securityContext.handleBSPRule(BSPRule.R4221);
186 }
187 }
188
189 }
190
191 private Instant verifyCreated(
192 WSSSecurityProperties wssSecurityProperties,
193 UsernameTokenType usernameTokenType
194 ) throws WSSecurityException {
195
196 int ttl = wssSecurityProperties.getUtTTL();
197 int futureTTL = wssSecurityProperties.getUtFutureTTL();
198
199 final AttributedDateTime attributedDateTimeCreated =
200 XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSU_CREATED);
201
202 if (attributedDateTimeCreated != null) {
203
204 ZonedDateTime created;
205 try {
206 created = ZonedDateTime.parse(attributedDateTimeCreated.getValue());
207 } catch (DateTimeParseException e) {
208 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
209 }
210
211
212 if (!DateUtil.verifyCreated(created.toInstant(), ttl, futureTTL)) {
213 throw new WSSecurityException(WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
214 }
215 return created.toInstant();
216 }
217 return null;
218 }
219 }