1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.saml2.binding.decoding;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import javax.xml.namespace.QName;
23
24 import org.opensaml.common.SAMLObject;
25 import org.opensaml.common.binding.SAMLMessageContext;
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 BaseSAML2MessageDecoder {
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 }
58
59
60
61
62
63
64 public HTTPSOAP11Decoder(ParserPool pool) {
65 super(pool);
66 understoodHeaders = new LazyList<QName>();
67 }
68
69
70 public String getBindingURI() {
71 return SAMLConstants.SAML2_SOAP11_BINDING_URI;
72 }
73
74
75 protected boolean isIntendedDestinationEndpointURIRequired(SAMLMessageContext samlMsgCtx) {
76 return false;
77 }
78
79
80
81
82
83
84 public List<QName> getUnderstoodHeaders() {
85 return understoodHeaders;
86 }
87
88
89
90
91
92
93 public void setUnderstoodHeaders(List<QName> headerNames) {
94 understoodHeaders.clear();
95 if (headerNames != null) {
96 understoodHeaders.addAll(headerNames);
97 }
98 }
99
100
101 protected void doDecode(MessageContext messageContext) throws MessageDecodingException {
102 if (!(messageContext instanceof SAMLMessageContext)) {
103 log.error("Invalid message context type, this decoder only support SAMLMessageContext");
104 throw new MessageDecodingException(
105 "Invalid message context type, this decoder only support SAMLMessageContext");
106 }
107
108 if (!(messageContext.getInboundMessageTransport() instanceof HTTPInTransport)) {
109 log.error("Invalid inbound message transport type, this decoder only support HTTPInTransport");
110 throw new MessageDecodingException(
111 "Invalid inbound message transport type, this decoder only support HTTPInTransport");
112 }
113
114 SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext;
115
116 HTTPInTransport inTransport = (HTTPInTransport) samlMsgCtx.getInboundMessageTransport();
117 if (!inTransport.getHTTPMethod().equalsIgnoreCase("POST")) {
118 throw new MessageDecodingException("This message deocoder only supports the HTTP POST method");
119 }
120
121 log.debug("Unmarshalling SOAP message");
122 Envelope soapMessage = (Envelope) unmarshallMessage(inTransport.getIncomingStream());
123 samlMsgCtx.setInboundMessage(soapMessage);
124
125 Header messageHeader = soapMessage.getHeader();
126 if (messageHeader != null) {
127 checkUnderstoodSOAPHeaders(soapMessage.getHeader().getUnknownXMLObjects());
128 }
129
130 List<XMLObject> soapBodyChildren = soapMessage.getBody().getUnknownXMLObjects();
131 if (soapBodyChildren.size() < 1 || soapBodyChildren.size() > 1) {
132 log.error("Unexpected number of children in the SOAP body, " + soapBodyChildren.size()
133 + ". Unable to extract SAML message");
134 throw new MessageDecodingException(
135 "Unexpected number of children in the SOAP body, unable to extract SAML message");
136 }
137
138 XMLObject incommingMessage = soapBodyChildren.get(0);
139 if (!(incommingMessage instanceof SAMLObject)) {
140 log.error("Unexpected SOAP body content. Expected a SAML request but recieved {}", incommingMessage
141 .getElementQName());
142 throw new MessageDecodingException("Unexpected SOAP body content. Expected a SAML request but recieved "
143 + incommingMessage.getElementQName());
144 }
145
146 SAMLObject samlMessage = (SAMLObject) incommingMessage;
147 log.debug("Decoded SOAP messaged which included SAML message of type {}", samlMessage.getElementQName());
148 samlMsgCtx.setInboundSAMLMessage(samlMessage);
149
150 populateMessageContext(samlMsgCtx);
151 }
152
153
154
155
156
157
158
159
160
161 protected void checkUnderstoodSOAPHeaders(List<XMLObject> headers) throws MessageDecodingException {
162 if (headers == null || headers.isEmpty()) {
163 return;
164 }
165
166 AttributeExtensibleXMLObject attribExtensObject;
167 for (XMLObject header : headers) {
168 if (header instanceof AttributeExtensibleXMLObject) {
169 attribExtensObject = (AttributeExtensibleXMLObject) header;
170 if (DatatypeHelper.safeEquals("1", attribExtensObject.getUnknownAttributes().get(soapMustUnderstand))) {
171 if (!understoodHeaders.contains(header.getElementQName())) {
172 throw new MessageDecodingException("SOAP decoder encountered a header, "
173 + header.getElementQName()
174 + ", that requires undestanding however this decoder does not understand that header");
175 }
176 }
177 }
178 }
179 }
180 }