1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.saml1.binding.decoding;
18
19 import java.util.List;
20
21 import javax.xml.namespace.QName;
22
23 import org.opensaml.common.SAMLObject;
24 import org.opensaml.common.binding.SAMLMessageContext;
25 import org.opensaml.common.binding.artifact.SAMLArtifactMap;
26 import org.opensaml.common.xml.SAMLConstants;
27 import org.opensaml.ws.message.MessageContext;
28 import org.opensaml.ws.message.decoder.MessageDecodingException;
29 import org.opensaml.ws.soap.soap11.Envelope;
30 import org.opensaml.ws.soap.soap11.Header;
31 import org.opensaml.ws.transport.http.HTTPInTransport;
32 import org.opensaml.xml.AttributeExtensibleXMLObject;
33 import org.opensaml.xml.XMLObject;
34 import org.opensaml.xml.parse.ParserPool;
35 import org.opensaml.xml.util.DatatypeHelper;
36 import org.opensaml.xml.util.LazyList;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41
42
43 public class HTTPSOAP11Decoder extends BaseSAML1MessageDecoder {
44
45
46 private final Logger log = LoggerFactory.getLogger(HTTPSOAP11Decoder.class);
47
48
49 private List<QName> understoodHeaders;
50
51
52 private final QName soapMustUnderstand = new QName(SAMLConstants.SOAP11ENV_NS, "mustUnderstand");
53
54
55 public HTTPSOAP11Decoder() {
56 super();
57 understoodHeaders = new LazyList<QName>();
58 }
59
60
61
62
63
64
65 public HTTPSOAP11Decoder(ParserPool pool) {
66 super(pool);
67 understoodHeaders = new LazyList<QName>();
68 }
69
70
71
72
73
74
75
76
77 public HTTPSOAP11Decoder(SAMLArtifactMap map) {
78 super(map);
79 understoodHeaders = new LazyList<QName>();
80 }
81
82
83
84
85
86
87
88
89
90 public HTTPSOAP11Decoder(SAMLArtifactMap map, ParserPool pool) {
91 super(map, pool);
92 understoodHeaders = new LazyList<QName>();
93 }
94
95
96 public String getBindingURI() {
97 return SAMLConstants.SAML1_SOAP11_BINDING_URI;
98 }
99
100
101
102
103
104
105 public List<QName> getUnderstoodHeaders() {
106 return understoodHeaders;
107 }
108
109
110
111
112
113
114 public void setUnderstoodHeaders(List<QName> headerNames) {
115 understoodHeaders.clear();
116 if (headerNames != null) {
117 understoodHeaders.addAll(headerNames);
118 }
119 }
120
121
122 protected void doDecode(MessageContext messageContext) throws MessageDecodingException {
123 if (!(messageContext instanceof SAMLMessageContext)) {
124 log.error("Invalid message context type, this decoder only support SAMLMessageContext");
125 throw new MessageDecodingException(
126 "Invalid message context type, this decoder only support SAMLMessageContext");
127 }
128
129 if (!(messageContext.getInboundMessageTransport() instanceof HTTPInTransport)) {
130 log.error("Invalid inbound message transport type, this decoder only support HTTPInTransport");
131 throw new MessageDecodingException(
132 "Invalid inbound message transport type, this decoder only support HTTPInTransport");
133 }
134
135 SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext;
136
137 HTTPInTransport inTransport = (HTTPInTransport) samlMsgCtx.getInboundMessageTransport();
138 if (!inTransport.getHTTPMethod().equalsIgnoreCase("POST")) {
139 throw new MessageDecodingException("This message deocoder only supports the HTTP POST method");
140 }
141
142 log.debug("Unmarshalling SOAP message");
143 Envelope soapMessage = (Envelope) unmarshallMessage(inTransport.getIncomingStream());
144 samlMsgCtx.setInboundMessage(soapMessage);
145
146 Header messageHeader = soapMessage.getHeader();
147 if (messageHeader != null) {
148 checkUnderstoodSOAPHeaders(soapMessage.getHeader().getUnknownXMLObjects());
149 }
150
151 List<XMLObject> soapBodyChildren = soapMessage.getBody().getUnknownXMLObjects();
152 if (soapBodyChildren.size() < 1 || soapBodyChildren.size() > 1) {
153 log.error("Unexpected number of children in the SOAP body, " + soapBodyChildren.size()
154 + ". Unable to extract SAML message");
155 throw new MessageDecodingException(
156 "Unexpected number of children in the SOAP body, unable to extract SAML message");
157 }
158
159 XMLObject incommingMessage = soapBodyChildren.get(0);
160 if (!(incommingMessage instanceof SAMLObject)) {
161 log.error("Unexpected SOAP body content. Expected a SAML request but recieved {}", incommingMessage
162 .getElementQName());
163 throw new MessageDecodingException("Unexpected SOAP body content. Expected a SAML request but recieved "
164 + incommingMessage.getElementQName());
165 }
166
167 SAMLObject samlMessage = (SAMLObject) incommingMessage;
168 log.debug("Decoded SOAP messaged which included SAML message of type {}", samlMessage.getElementQName());
169 samlMsgCtx.setInboundSAMLMessage(samlMessage);
170
171 populateMessageContext(samlMsgCtx);
172 }
173
174
175
176
177
178
179
180
181
182 protected void checkUnderstoodSOAPHeaders(List<XMLObject> headers) throws MessageDecodingException {
183 if (headers == null || headers.isEmpty()) {
184 return;
185 }
186
187 AttributeExtensibleXMLObject attribExtensObject;
188 for (XMLObject header : headers) {
189 if (header instanceof AttributeExtensibleXMLObject) {
190 attribExtensObject = (AttributeExtensibleXMLObject) header;
191 if (DatatypeHelper.safeEquals("1", attribExtensObject.getUnknownAttributes().get(soapMustUnderstand))) {
192 if (!understoodHeaders.contains(header.getElementQName())) {
193 throw new MessageDecodingException("SOAP decoder encountered a header, "
194 + header.getElementQName()
195 + ", that requires undestanding however this decoder does not understand that header");
196 }
197 }
198 }
199 }
200 }
201
202
203 protected boolean isIntendedDestinationEndpointURIRequired(SAMLMessageContext samlMsgCtx) {
204 return false;
205 }
206 }