View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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   * Processor for the SecurityTokenReference XML Structure
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()) {   //NOPMD
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                         //we can now remove this processor from the chain
187                         inputProcessorChain.removeProcessor(this);
188                     }
189                     break;
190             }
191             if (refFound && !end) {
192                 xmlSecEventList.push(xmlSecEvent);
193             }
194             return xmlSecEvent;
195         }
196     }
197 }