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.binding.artifact.SAMLArtifactMap.SAMLArtifactMapEntry;
27 import org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder;
28 import org.opensaml.common.xml.SAMLConstants;
29 import org.opensaml.saml1.core.Assertion;
30 import org.opensaml.saml1.core.AssertionArtifact;
31 import org.opensaml.saml1.core.AttributeQuery;
32 import org.opensaml.saml1.core.AuthorizationDecisionQuery;
33 import org.opensaml.saml1.core.Request;
34 import org.opensaml.saml1.core.RequestAbstractType;
35 import org.opensaml.saml1.core.Response;
36 import org.opensaml.saml1.core.ResponseAbstractType;
37 import org.opensaml.saml2.metadata.EntityDescriptor;
38 import org.opensaml.saml2.metadata.RoleDescriptor;
39 import org.opensaml.saml2.metadata.provider.MetadataProvider;
40 import org.opensaml.saml2.metadata.provider.MetadataProviderException;
41 import org.opensaml.ws.message.MessageContext;
42 import org.opensaml.ws.message.decoder.MessageDecodingException;
43 import org.opensaml.xml.parse.ParserPool;
44 import org.opensaml.xml.security.SecurityException;
45 import org.opensaml.xml.util.DatatypeHelper;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49
50
51
52 public abstract class BaseSAML1MessageDecoder extends BaseSAMLMessageDecoder {
53
54
55 private final Logger log = LoggerFactory.getLogger(BaseSAML1MessageDecoder.class);
56
57
58 private SAMLArtifactMap artifactMap;
59
60
61 private boolean useQueryResourceAsEntityId;
62
63
64 public BaseSAML1MessageDecoder() {
65 super();
66 useQueryResourceAsEntityId = true;
67 }
68
69
70
71
72
73
74 public BaseSAML1MessageDecoder(ParserPool pool) {
75 super(pool);
76 useQueryResourceAsEntityId = true;
77 }
78
79
80
81
82
83
84
85
86 public BaseSAML1MessageDecoder(SAMLArtifactMap map) {
87 super();
88 artifactMap = map;
89 useQueryResourceAsEntityId = true;
90 }
91
92
93
94
95
96
97
98
99
100 public BaseSAML1MessageDecoder(SAMLArtifactMap map, ParserPool pool) {
101 super(pool);
102 artifactMap = map;
103 useQueryResourceAsEntityId = true;
104 }
105
106
107 public void decode(MessageContext messageContext) throws MessageDecodingException, SecurityException {
108 super.decode(messageContext);
109
110 SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext;
111 if (samlMsgCtx.getInboundSAMLMessage() instanceof ResponseAbstractType) {
112 checkEndpointURI(samlMsgCtx);
113 }
114 }
115
116
117
118
119
120
121 public SAMLArtifactMap getArtifactMap() {
122 return artifactMap;
123 }
124
125
126
127
128
129
130
131 public boolean getUseQueryResourceAsEntityId() {
132 return useQueryResourceAsEntityId;
133 }
134
135
136
137
138
139
140
141 public void setUseQueryResourceAsEntityId(boolean useResource) {
142 useQueryResourceAsEntityId = useResource;
143 }
144
145
146
147
148
149
150
151
152
153
154 protected void populateMessageContext(SAMLMessageContext messageContext) throws MessageDecodingException {
155 populateMessageIdIssueInstantIssuer(messageContext);
156 populateRelyingPartyMetadata(messageContext);
157 }
158
159
160
161
162
163
164
165
166
167 protected void populateMessageIdIssueInstantIssuer(SAMLMessageContext messageContext)
168 throws MessageDecodingException {
169 SAMLObject samlMsg = messageContext.getInboundSAMLMessage();
170 if (samlMsg == null) {
171 return;
172 }
173
174 if (samlMsg instanceof RequestAbstractType) {
175 log.debug("Extracting ID, issuer and issue instant from request");
176 extractRequestInfo(messageContext, (RequestAbstractType) samlMsg);
177 } else if (samlMsg instanceof Response) {
178 log.debug("Extracting ID, issuer and issue instant from response");
179 extractResponseInfo(messageContext, (Response) samlMsg);
180 } else {
181 throw new MessageDecodingException("SAML 1.x message was not a request or a response");
182 }
183 }
184
185
186
187
188
189
190
191 protected void extractRequestInfo(SAMLMessageContext messageContext, RequestAbstractType abstractRequest) {
192 messageContext.setInboundSAMLMessageId(abstractRequest.getID());
193 messageContext.setInboundSAMLMessageIssueInstant(abstractRequest.getIssueInstant());
194
195 if (abstractRequest instanceof Request) {
196 Request request = (Request) abstractRequest;
197 if (request.getAttributeQuery() != null) {
198 extractAttributeQueryInfo(messageContext, request.getAttributeQuery());
199 }
200
201 if (request.getAuthorizationDecisionQuery() != null) {
202 extractAuthorizationDecisionQueryInfo(messageContext, request.getAuthorizationDecisionQuery());
203 }
204
205 if (request.getAssertionArtifacts() != null) {
206 extractAssertionArtifactInfo(messageContext, request.getAssertionArtifacts());
207 }
208 }
209 }
210
211
212
213
214
215
216
217
218 protected void extractAttributeQueryInfo(SAMLMessageContext messageContext, AttributeQuery query) {
219 if (useQueryResourceAsEntityId) {
220 log.debug("Attempting to extract issuer from SAML 1 AttributeQuery Resource attribute");
221 String resource = DatatypeHelper.safeTrimOrNullString(query.getResource());
222
223 if (resource != null) {
224 messageContext.setInboundMessageIssuer(resource);
225 log.debug("Extracted issuer from SAML 1.x AttributeQuery: {}", resource);
226 }
227 }
228 }
229
230
231
232
233
234
235
236
237 protected void extractAuthorizationDecisionQueryInfo(SAMLMessageContext messageContext,
238 AuthorizationDecisionQuery query) {
239 if (useQueryResourceAsEntityId) {
240 log.debug("Attempting to extract issuer from SAML 1 AuthorizationDecisionQuery Resource attribute");
241 String resource = DatatypeHelper.safeTrimOrNullString(query.getResource());
242
243 if (resource != null) {
244 messageContext.setInboundMessageIssuer(resource);
245 log.debug("Extracted issuer from SAML 1.x AuthorizationDecisionQuery: {}", resource);
246 }
247 }
248 }
249
250
251
252
253
254
255
256
257 protected void extractAssertionArtifactInfo(SAMLMessageContext messageContext, List<AssertionArtifact> artifacts) {
258 if (artifacts.size() == 0) {
259 return;
260 }
261
262 log.debug("Attempting to extract issuer based on first AssertionArtifact in request");
263 AssertionArtifact artifact = artifacts.get(0);
264 SAMLArtifactMapEntry artifactEntry = artifactMap.get(artifact.getAssertionArtifact());
265 messageContext.setInboundMessageIssuer(artifactEntry.getRelyingPartyId());
266
267 log.debug("Extracted issuer from SAML 1.x AssertionArtifact: {}", messageContext.getInboundMessageIssuer());
268 }
269
270
271
272
273
274
275
276
277
278 protected void extractResponseInfo(SAMLMessageContext messageContext, Response response)
279 throws MessageDecodingException {
280
281 messageContext.setInboundSAMLMessageId(response.getID());
282 messageContext.setInboundSAMLMessageIssueInstant(response.getIssueInstant());
283
284 String issuer = null;
285 List<Assertion> assertions = ((Response) response).getAssertions();
286 if (assertions != null && assertions.size() > 0) {
287 log.info("Attempting to extract issuer from enclosed SAML 1.x Assertion(s)");
288 for (Assertion assertion : assertions) {
289 if (assertion != null && assertion.getIssuer() != null) {
290 if (issuer != null && !issuer.equals(assertion.getIssuer())) {
291 throw new MessageDecodingException("SAML 1.x assertions, within response " + response.getID()
292 + " contain different issuer IDs");
293 }
294 issuer = assertion.getIssuer();
295 }
296 }
297 }
298
299 if (issuer == null) {
300 log.warn("Issuer could not be extracted from standard SAML 1.x response message");
301 }
302
303 messageContext.setInboundMessageIssuer(issuer);
304 }
305
306
307
308
309
310
311
312
313
314 protected void populateRelyingPartyMetadata(SAMLMessageContext messageContext) throws MessageDecodingException {
315 MetadataProvider metadataProvider = messageContext.getMetadataProvider();
316 try {
317 if (metadataProvider != null) {
318 EntityDescriptor relyingPartyMD = metadataProvider.getEntityDescriptor(messageContext
319 .getInboundMessageIssuer());
320 messageContext.setPeerEntityMetadata(relyingPartyMD);
321
322 QName relyingPartyRole = messageContext.getPeerEntityRole();
323 if (relyingPartyMD != null && relyingPartyRole != null) {
324 List<RoleDescriptor> roles = relyingPartyMD.getRoleDescriptors(relyingPartyRole,
325 SAMLConstants.SAML11P_NS);
326 if (roles != null && roles.size() > 0) {
327 messageContext.setPeerEntityRoleMetadata(roles.get(0));
328 }
329 }
330 }
331 } catch (MetadataProviderException e) {
332 log.error("Error retrieving metadata for relying party " + messageContext.getInboundMessageIssuer(), e);
333 throw new MessageDecodingException("Error retrieving metadata for relying party "
334 + messageContext.getInboundMessageIssuer(), e);
335 }
336 }
337
338
339
340
341
342
343
344
345 protected String getIntendedDestinationEndpointURI(SAMLMessageContext samlMsgCtx) throws MessageDecodingException {
346 SAMLObject samlMessage = samlMsgCtx.getInboundSAMLMessage();
347 String messageDestination = null;
348 if (samlMessage instanceof ResponseAbstractType) {
349 ResponseAbstractType response = (ResponseAbstractType) samlMessage;
350 messageDestination = DatatypeHelper.safeTrimOrNullString(response.getRecipient());
351 } else if (samlMessage instanceof RequestAbstractType) {
352
353 return null;
354 } else {
355 log.error("Invalid SAML message type encountered: {}", samlMessage.getElementQName().toString());
356 throw new MessageDecodingException("Invalid SAML message type encountered");
357 }
358 return messageDestination;
359 }
360
361 }