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 java.util.ArrayDeque;
22 import java.util.Deque;
23 import java.util.List;
24
25 import jakarta.xml.bind.JAXBElement;
26 import javax.xml.namespace.QName;
27 import javax.xml.stream.XMLStreamConstants;
28 import javax.xml.stream.XMLStreamException;
29 import javax.xml.stream.events.Attribute;
30
31 import org.apache.wss4j.binding.wss10.KeyIdentifierType;
32 import org.apache.wss4j.binding.wss10.ReferenceType;
33 import org.apache.wss4j.binding.wss10.SecurityTokenReferenceType;
34 import org.apache.wss4j.common.ext.WSSecurityException;
35 import org.apache.wss4j.stax.ext.WSInboundSecurityContext;
36 import org.apache.wss4j.stax.ext.WSSConstants;
37 import org.apache.wss4j.stax.ext.WSSSecurityProperties;
38 import org.apache.wss4j.stax.impl.securityToken.SecurityTokenReferenceImpl;
39 import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
40 import org.apache.wss4j.stax.utils.WSSUtils;
41 import org.apache.xml.security.exceptions.XMLSecurityException;
42 import org.apache.xml.security.stax.ext.AbstractInputProcessor;
43 import org.apache.xml.security.stax.ext.AbstractInputSecurityHeaderHandler;
44 import org.apache.xml.security.stax.ext.InputProcessorChain;
45 import org.apache.xml.security.stax.ext.XMLSecurityProperties;
46 import org.apache.xml.security.stax.ext.XMLSecurityUtils;
47 import org.apache.xml.security.stax.ext.stax.XMLSecEndElement;
48 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
49 import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
50 import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
51 import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
52
53
54
55
56 public class SecurityTokenReferenceInputHandler extends AbstractInputSecurityHeaderHandler {
57
58 @Override
59 public void handle(final InputProcessorChain inputProcessorChain, final XMLSecurityProperties securityProperties,
60 Deque<XMLSecEvent> eventQueue, Integer index) throws XMLSecurityException {
61
62 @SuppressWarnings("unchecked")
63 final SecurityTokenReferenceType securityTokenReferenceType =
64 ((JAXBElement<SecurityTokenReferenceType>) parseStructure(eventQueue, index, securityProperties)).getValue();
65
66 QName attributeName = null;
67 String attributeValue = null;
68
69 final KeyIdentifierType keyIdentifierType = XMLSecurityUtils.getQNameType(
70 securityTokenReferenceType.getAny(), WSSConstants.TAG_WSSE_KEY_IDENTIFIER);
71 if (keyIdentifierType != null) {
72 attributeValue = keyIdentifierType.getValue().trim();
73 if (WSSConstants.NS_SAML10_TYPE.equals(keyIdentifierType.getValueType())) {
74 attributeName = WSSConstants.ATT_NULL_ASSERTION_ID;
75 } else if (WSSConstants.NS_SAML20_TYPE.equals(keyIdentifierType.getValueType())) {
76 attributeName = WSSConstants.ATT_NULL_ID;
77 }
78 }
79 final ReferenceType referenceType = XMLSecurityUtils.getQNameType(
80 securityTokenReferenceType.getAny(), WSSConstants.TAG_WSSE_REFERENCE);
81 if (referenceType != null) {
82 attributeValue = WSSUtils.dropReferenceMarker(referenceType.getURI());
83 if (WSSConstants.NS_SAML10_TYPE.equals(referenceType.getValueType())) {
84 attributeName = WSSConstants.ATT_NULL_ASSERTION_ID;
85 } else if (WSSConstants.NS_SAML20_TYPE.equals(referenceType.getValueType())) {
86 attributeName = WSSConstants.ATT_NULL_ID;
87 }
88 }
89
90 if (attributeName != null) {
91 InternalSecurityTokenReferenceInputProcessor internalSecurityTokenReferenceInputHandler
92 = new InternalSecurityTokenReferenceInputProcessor(
93 securityTokenReferenceType.getId(), attributeName,
94 attributeValue, (WSSSecurityProperties) securityProperties);
95 inputProcessorChain.addProcessor(internalSecurityTokenReferenceInputHandler);
96 } else {
97 throw new WSSecurityException(WSSecurityException.ErrorCode.UNSUPPORTED_SECURITY_TOKEN);
98 }
99 }
100
101 static class InternalSecurityTokenReferenceInputProcessor extends AbstractInputProcessor {
102
103 private final String securityTokenReferenceId;
104 private final QName attribute;
105 private final String attributeValue;
106 private boolean refFound = false;
107 private boolean end = false;
108 private QName startElementName;
109 private int startElementLevel;
110
111 private final ArrayDeque<XMLSecEvent> xmlSecEventList = new ArrayDeque<>();
112
113 InternalSecurityTokenReferenceInputProcessor(String securityTokenReferenceId, QName attribute,
114 String attributeValue, WSSSecurityProperties securityProperties) {
115 super(securityProperties);
116 this.securityTokenReferenceId = securityTokenReferenceId;
117 this.attribute = attribute;
118 this.attributeValue = attributeValue;
119 }
120
121 @Override
122 public XMLSecEvent processHeaderEvent(InputProcessorChain inputProcessorChain)
123 throws XMLStreamException, XMLSecurityException {
124 return inputProcessorChain.processHeaderEvent();
125 }
126
127 @Override
128 public XMLSecEvent processEvent(final InputProcessorChain inputProcessorChain)
129 throws XMLStreamException, XMLSecurityException {
130 XMLSecEvent xmlSecEvent = inputProcessorChain.processEvent();
131 switch (xmlSecEvent.getEventType()) {
132 case XMLStreamConstants.START_ELEMENT:
133 XMLSecStartElement xmlSecStartElement = xmlSecEvent.asStartElement();
134 Attribute attribute = xmlSecStartElement.getAttributeByName(this.attribute);
135 if (attribute != null && this.attributeValue.equals(attribute.getValue())) {
136 if (refFound) {
137 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "duplicateId");
138 }
139 refFound = true;
140 startElementName = xmlSecStartElement.getName();
141 List<QName> elementPath = xmlSecStartElement.getElementPath();
142 startElementLevel = elementPath.size();
143 }
144 break;
145 case XMLStreamConstants.END_ELEMENT:
146 XMLSecEndElement xmlSecEndElement = xmlSecEvent.asEndElement();
147 if (xmlSecEndElement.getName().equals(startElementName)
148 && xmlSecEndElement.getDocumentLevel() == startElementLevel) {
149 end = true;
150 xmlSecEventList.push(xmlSecEvent);
151
152 SecurityTokenProvider<InboundSecurityToken> securityTokenProvider =
153 new SecurityTokenProvider<InboundSecurityToken>() {
154
155 private InboundSecurityToken securityToken;
156
157 @Override
158 public InboundSecurityToken getSecurityToken() throws XMLSecurityException {
159 if (this.securityToken != null) {
160 return this.securityToken;
161 }
162
163 SecurityTokenProvider<? extends InboundSecurityToken> securityTokenProvider =
164 inputProcessorChain.getSecurityContext().getSecurityTokenProvider(attributeValue);
165 return this.securityToken = new SecurityTokenReferenceImpl(
166 securityTokenProvider.getSecurityToken(),
167 xmlSecEventList,
168 (WSInboundSecurityContext) inputProcessorChain.getSecurityContext(),
169 securityTokenReferenceId,
170 WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE);
171 }
172
173 @Override
174 public String getId() {
175 return securityTokenReferenceId;
176 }
177 };
178 inputProcessorChain.getSecurityContext().registerSecurityTokenProvider(securityTokenReferenceId,
179 securityTokenProvider);
180
181 return xmlSecEvent;
182 } else if (xmlSecEndElement.getDocumentLevel() == 3
183 && xmlSecEndElement.getName().equals(WSSConstants.TAG_WSSE_SECURITY)
184 && WSSUtils.isInSecurityHeader(xmlSecEndElement,
185 ((WSSSecurityProperties) getSecurityProperties()).getActor())) {
186
187 inputProcessorChain.removeProcessor(this);
188 }
189 break;
190 }
191 if (refFound && !end) {
192 xmlSecEventList.push(xmlSecEvent);
193 }
194 return xmlSecEvent;
195 }
196 }
197 }