1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.common.binding.decoding;
18
19 import java.net.MalformedURLException;
20 import java.net.URL;
21
22 import javax.servlet.http.HttpServletRequest;
23
24 import org.opensaml.common.SAMLObject;
25 import org.opensaml.common.SignableSAMLObject;
26 import org.opensaml.common.binding.SAMLMessageContext;
27 import org.opensaml.ws.message.decoder.BaseMessageDecoder;
28 import org.opensaml.ws.message.decoder.MessageDecodingException;
29 import org.opensaml.ws.transport.InTransport;
30 import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
31 import org.opensaml.xml.parse.ParserPool;
32 import org.opensaml.xml.security.SecurityException;
33 import org.opensaml.xml.util.DatatypeHelper;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37
38
39
40 public abstract class BaseSAMLMessageDecoder extends BaseMessageDecoder implements SAMLMessageDecoder {
41
42
43 private final Logger log = LoggerFactory.getLogger(BaseSAMLMessageDecoder.class);
44
45
46 public BaseSAMLMessageDecoder() {
47 super();
48 }
49
50
51
52
53
54
55 public BaseSAMLMessageDecoder(ParserPool pool) {
56 super(pool);
57 }
58
59
60
61
62
63
64
65
66
67
68 protected boolean isMessageSigned(SAMLMessageContext messageContext) {
69 SAMLObject samlMessage = messageContext.getInboundSAMLMessage();
70 if (samlMessage instanceof SignableSAMLObject) {
71 return ((SignableSAMLObject)samlMessage).isSigned();
72 } else {
73 return false;
74 }
75 }
76
77
78
79
80
81
82
83
84
85 protected abstract boolean isIntendedDestinationEndpointURIRequired(SAMLMessageContext samlMsgCtx);
86
87
88
89
90
91
92
93
94
95
96 protected abstract String getIntendedDestinationEndpointURI(SAMLMessageContext samlMsgCtx)
97 throws MessageDecodingException;
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 protected String getActualReceiverEndpointURI(SAMLMessageContext messageContext) throws MessageDecodingException {
116 InTransport inTransport = messageContext.getInboundMessageTransport();
117 if (! (inTransport instanceof HttpServletRequestAdapter)) {
118 log.error("Message context InTransport instance was an unsupported type: {}",
119 inTransport.getClass().getName());
120 throw new MessageDecodingException("Message context InTransport instance was an unsupported type");
121 }
122 HttpServletRequest httpRequest = ((HttpServletRequestAdapter)inTransport).getWrappedRequest();
123
124 StringBuffer urlBuilder = httpRequest.getRequestURL();
125
126 return urlBuilder.toString();
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 protected boolean compareEndpointURIs(String messageDestination, String receiverEndpoint)
144 throws MessageDecodingException {
145
146 URL messageURL = null;
147 try {
148 messageURL = new URL(messageDestination);
149 } catch (MalformedURLException e) {
150 log.error("Message destination URL was malformed in destination check: {}", e.getMessage());
151 throw new MessageDecodingException("Message destination URL was malformed in destination check");
152 }
153
154 URL endpointURL = null;
155 try {
156 endpointURL = new URL(receiverEndpoint);
157 } catch (MalformedURLException e) {
158 log.error("Recipient endpoint URL was malformed in destination check: {}", e.getMessage());
159 throw new MessageDecodingException("Recipient endpoint URL was malformed in destination check");
160 }
161
162 return messageURL.equals(endpointURL);
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176
177 protected void checkEndpointURI(SAMLMessageContext messageContext)
178 throws SecurityException, MessageDecodingException {
179
180 log.debug("Checking SAML message intended destination endpoint against receiver endpoint");
181
182 String messageDestination =
183 DatatypeHelper.safeTrimOrNullString(getIntendedDestinationEndpointURI(messageContext));
184
185 boolean bindingRequires = isIntendedDestinationEndpointURIRequired(messageContext);
186
187 if (messageDestination == null) {
188 if (bindingRequires) {
189 log.error("SAML message intended destination endpoint URI required by binding was empty");
190 throw new SecurityException("SAML message intended destination (required by binding) was not present");
191 } else {
192 log.debug("SAML message intended destination endpoint in message was empty, not required by binding, skipping");
193 return;
194 }
195 }
196
197 String receiverEndpoint = getActualReceiverEndpointURI(messageContext);
198
199 log.debug("Intended message destination endpoint: {}", messageDestination);
200 log.debug("Actual message receiver endpoint: {}", receiverEndpoint);
201
202 boolean matched = compareEndpointURIs(messageDestination, receiverEndpoint);
203 if (!matched) {
204 log.error("SAML message intended destination endpoint '{}' did not match the recipient endpoint '{}'",
205 messageDestination, receiverEndpoint);
206 throw new SecurityException("SAML message intended destination endpoint did not match recipient endpoint");
207 } else {
208 log.debug("SAML message intended destination endpoint matched recipient endpoint");
209 }
210 }
211
212 }