1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.saml2.binding.security;
18
19 import org.opensaml.common.SAMLObject;
20 import org.opensaml.common.SignableSAMLObject;
21 import org.opensaml.common.binding.SAMLMessageContext;
22 import org.opensaml.common.xml.SAMLConstants;
23 import org.opensaml.saml2.core.AuthnRequest;
24 import org.opensaml.saml2.metadata.SPSSODescriptor;
25 import org.opensaml.saml2.metadata.provider.MetadataProvider;
26 import org.opensaml.saml2.metadata.provider.MetadataProviderException;
27 import org.opensaml.ws.message.MessageContext;
28 import org.opensaml.ws.security.SecurityPolicyException;
29 import org.opensaml.ws.security.SecurityPolicyRule;
30 import org.opensaml.ws.transport.http.HTTPInTransport;
31 import org.opensaml.xml.util.DatatypeHelper;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35
36
37
38
39 public class SAML2AuthnRequestsSignedRule implements SecurityPolicyRule {
40
41
42 private final Logger log = LoggerFactory.getLogger(SAML2AuthnRequestsSignedRule.class);
43
44
45 public void evaluate(MessageContext messageContext) throws SecurityPolicyException {
46 if (!(messageContext instanceof SAMLMessageContext)) {
47 log.debug("Invalid message context type, this policy rule only supports SAMLMessageContext");
48 return;
49 }
50 SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext;
51
52 SAMLObject samlMessage = samlMsgCtx.getInboundSAMLMessage();
53 if (! (samlMessage instanceof AuthnRequest) ) {
54 log.debug("Inbound message is not an instance of AuthnRequest, skipping evaluation...");
55 return;
56 }
57
58 String messageIssuer = samlMsgCtx.getInboundMessageIssuer();
59 if (DatatypeHelper.isEmpty(messageIssuer)) {
60 log.warn("Inbound message issuer was empty, unable to evaluate rule");
61 return;
62 }
63
64 MetadataProvider metadataProvider = samlMsgCtx.getMetadataProvider();
65 if (metadataProvider == null) {
66 log.warn("Message context did not contain a metadata provider, unable to evaluate rule");
67 return;
68 }
69
70 SPSSODescriptor spssoRole;
71 try {
72 spssoRole = (SPSSODescriptor) metadataProvider
73 .getRole(messageIssuer, SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS);
74 } catch (MetadataProviderException e) {
75 log.warn("Error resolving SPSSODescriptor metadata for entityID '{}': {}", messageIssuer, e.getMessage());
76 throw new SecurityPolicyException("Error resolving metadata for entity ID", e);
77 }
78
79 if (spssoRole == null) {
80 log.warn("SPSSODescriptor role metadata for entityID '{}' could not be resolved", messageIssuer);
81 return;
82 }
83
84 if (spssoRole.isAuthnRequestsSigned() == Boolean.TRUE) {
85 if (! isMessageSigned(samlMsgCtx)) {
86 log.error("SPSSODescriptor for entity ID '{}' indicates AuthnRequests must be signed, "
87 + "but inbound message was not signed", messageIssuer);
88 throw new SecurityPolicyException("Inbound AuthnRequest was required to be signed but was not");
89 }
90 } else {
91 log.debug("SPSSODescriptor for entity ID '{}' does not require AuthnRequests to be signed", messageIssuer);
92 }
93
94 }
95
96
97
98
99
100
101
102 protected boolean isMessageSigned(SAMLMessageContext messageContext) {
103
104
105
106
107
108 SAMLObject samlMessage = messageContext.getInboundSAMLMessage();
109 if (samlMessage instanceof SignableSAMLObject) {
110 SignableSAMLObject signableMessage = (SignableSAMLObject) samlMessage;
111 if (signableMessage.isSigned()) {
112 return true;
113 }
114 }
115
116
117 HTTPInTransport inTransport = (HTTPInTransport) messageContext.getInboundMessageTransport();
118 String sigParam = inTransport.getParameterValue("Signature");
119 return !DatatypeHelper.isEmpty(sigParam);
120 }
121
122 }