private Response extractSamlResponse(HttpServletRequest request) { SAMLMessageContext messageContext; final SAMLMessageHandler samlMessageHandler = openSAMLContext.samlMessageHandler(); try { messageContext = samlMessageHandler.extractSAMLMessageContext(request); } catch (MessageDecodingException me) { throw new ServiceProviderAuthenticationException("Could not decode SAML Response", me); } catch (org.opensaml.xml.security.SecurityException se) { throw new ServiceProviderAuthenticationException("Could not decode SAML Response", se); } LOG.debug("Message received from issuer: " + messageContext.getInboundMessageIssuer()); if (!(messageContext.getInboundSAMLMessage() instanceof Response)) { throw new ServiceProviderAuthenticationException("SAML Message was not a Response."); } final Response inboundSAMLMessage = (Response) messageContext.getInboundSAMLMessage(); try { openSAMLContext.validatorSuite().validate(inboundSAMLMessage); return inboundSAMLMessage; } catch (ValidationException ve) { LOG.warn("Response Message failed Validation", ve); throw new RuntimeException("Invalid SAML Response Message", ve); } }
/** {@inheritDoc} */ protected boolean isIntendedDestinationEndpointURIRequired(SAMLMessageContext samlMsgCtx) { return samlMsgCtx.getInboundSAMLMessage() instanceof ResponseAbstractType; } }
/** * Determine whether the SAML message represented by the message context is digitally signed. * * <p>The default behavior is to examine whether an XML signature is present on the * SAML protocol message. Subclasses may augment or replace with binding-specific behavior.</p> * * @param messageContext current message context * @return true if the message is considered to be digitially signed, false otherwise */ protected boolean isMessageSigned(SAMLMessageContext messageContext) { SAMLObject samlMessage = messageContext.getInboundSAMLMessage(); if (samlMessage instanceof SignableSAMLObject) { return ((SignableSAMLObject)samlMessage).isSigned(); } else { return false; } }
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String servletPath = request.getServletPath(); if (servletPath == null || !servletPath.endsWith("SingleSignOnService") || request.getMethod().equalsIgnoreCase("GET")) { chain.doFilter(request, response); return; } SAMLMessageContext messageContext; try { messageContext = samlMessageHandler.extractSAMLMessageContext(request, response, request.getMethod().equalsIgnoreCase("POST")); } catch (Exception e) { throw new IllegalArgumentException(e); } AuthnRequest authnRequest = (AuthnRequest) messageContext.getInboundSAMLMessage(); if (authnRequest.isForceAuthn()) { SecurityContextHolder.getContext().setAuthentication(null); } chain.doFilter(request, response); } }
/** {@inheritDoc} */ public void decode(MessageContext messageContext) throws MessageDecodingException, SecurityException { super.decode(messageContext); SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; if (samlMsgCtx.getInboundSAMLMessage() instanceof ResponseAbstractType) { checkEndpointURI(samlMsgCtx); } }
/** {@inheritDoc} */ public void evaluate(MessageContext messageContext) throws SecurityPolicyException { if (!(messageContext instanceof SAMLMessageContext)) { log.debug("Invalid message context type, this policy rule only supports SAMLMessageContext"); return; } SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; SAMLObject samlMsg = samlMsgCtx.getInboundSAMLMessage(); if (!(samlMsg instanceof SignableSAMLObject)) { log.debug("Extracted SAML message was not a SignableSAMLObject, can not process signature"); return; } SignableSAMLObject signableObject = (SignableSAMLObject) samlMsg; if (!signableObject.isSigned()) { log.info("SAML protocol message was not signed, skipping XML signature processing"); return; } Signature signature = signableObject.getSignature(); performPreValidation(signature); doEvaluate(signature, signableObject, samlMsgCtx); }
/** * Extracts the message ID, issue instant, and issuer from the incoming SAML message and populates the message * context with it. * * @param messageContext current message context * * @throws MessageDecodingException thrown if there is a problem populating the message context */ protected void populateMessageIdIssueInstantIssuer(SAMLMessageContext messageContext) throws MessageDecodingException { SAMLObject samlMsg = messageContext.getInboundSAMLMessage(); if (samlMsg == null) { return; } if (samlMsg instanceof RequestAbstractType) { log.debug("Extracting ID, issuer and issue instant from request"); extractRequestInfo(messageContext, (RequestAbstractType) samlMsg); } else if (samlMsg instanceof Response) { log.debug("Extracting ID, issuer and issue instant from response"); extractResponseInfo(messageContext, (Response) samlMsg); } else { throw new MessageDecodingException("SAML 1.x message was not a request or a response"); } }
SAMLObject samlMsg = samlMsgCtx.getInboundSAMLMessage(); if (samlMsg == null) { log.error("Message context did not contain inbound SAML message");
/** * {@inheritDoc} * * <p>This SAML 1-specific implementation extracts the value of the ResponseAbstractType * protocol message Recipient attribute.</p> * * */ protected String getIntendedDestinationEndpointURI(SAMLMessageContext samlMsgCtx) throws MessageDecodingException { SAMLObject samlMessage = samlMsgCtx.getInboundSAMLMessage(); String messageDestination = null; if (samlMessage instanceof ResponseAbstractType) { ResponseAbstractType response = (ResponseAbstractType) samlMessage; messageDestination = DatatypeHelper.safeTrimOrNullString(response.getRecipient()); } else if (samlMessage instanceof RequestAbstractType) { // don't treat as an error, just return null return null; } else { log.error("Invalid SAML message type encountered: {}", samlMessage.getElementQName().toString()); throw new MessageDecodingException("Invalid SAML message type encountered"); } return messageDestination; }
/** * {@inheritDoc} * * <p>This SAML 2-specific implementation extracts the value of the protocol message Destination attribute.</p> * * */ protected String getIntendedDestinationEndpointURI(SAMLMessageContext samlMsgCtx) throws MessageDecodingException { SAMLObject samlMessage = samlMsgCtx.getInboundSAMLMessage(); String messageDestination = null; if (samlMessage instanceof RequestAbstractType) { RequestAbstractType request = (RequestAbstractType) samlMessage; messageDestination = DatatypeHelper.safeTrimOrNullString(request.getDestination()); } else if (samlMessage instanceof StatusResponseType) { StatusResponseType response = (StatusResponseType) samlMessage; messageDestination = DatatypeHelper.safeTrimOrNullString(response.getDestination()); } else { log.error("Invalid SAML message type encountered: {}", samlMessage.getElementQName().toString()); throw new MessageDecodingException("Invalid SAML message type encountered"); } return messageDestination; }
@SuppressWarnings("unchecked") private void doSSO(HttpServletRequest request, HttpServletResponse response, Authentication authentication, boolean postRequest) throws ValidationException, SecurityException, MessageDecodingException, MarshallingException, SignatureException, MessageEncodingException, MetadataProviderException, IOException, ServletException { SAMLMessageContext messageContext = samlMessageHandler.extractSAMLMessageContext(request, response, postRequest); AuthnRequest authnRequest = (AuthnRequest) messageContext.getInboundSAMLMessage(); String assertionConsumerServiceURL = idpConfiguration.getAcsEndpoint() != null ? idpConfiguration.getAcsEndpoint() : authnRequest.getAssertionConsumerServiceURL(); List<SAMLAttribute> attributes = attributes(authentication); SAMLPrincipal principal = new SAMLPrincipal( authentication.getName(), attributes.stream().filter(attr -> "urn:oasis:names:tc:SAML:1.1:nameid-format".equals(attr.getName())) .findFirst().map(attr -> attr.getValue()).orElse(NameIDType.UNSPECIFIED), attributes, authnRequest.getIssuer().getValue(), authnRequest.getID(), assertionConsumerServiceURL, messageContext.getRelayState()); samlMessageHandler.sendAuthnResponse(principal, response); }
SignableSAMLObject message = context.getInboundSAMLMessage();
SAMLObject samlMessage = samlMsgCtx.getInboundSAMLMessage(); if (! (samlMessage instanceof AuthnRequest) ) { log.debug("Inbound message is not an instance of AuthnRequest, skipping evaluation...");
/** * Determine whether the inbound message is signed. * * @param messageContext the message context being evaluated * @return true if the inbound message is signed, otherwise false */ protected boolean isMessageSigned(SAMLMessageContext messageContext) { // TODO this really should be determined by the decoders and supplied to the rule // in some fashion, to handle binding-specific signature mechanisms. See JIRA issue JOWS-4. // // For now evaluate here inline for XML Signature and HTTP-Redirect and HTTP-Post-SimpleSign. SAMLObject samlMessage = messageContext.getInboundSAMLMessage(); if (samlMessage instanceof SignableSAMLObject) { SignableSAMLObject signableMessage = (SignableSAMLObject) samlMessage; if (signableMessage.isSigned()) { return true; } } // This handles HTTP-Redirect and HTTP-POST-SimpleSign bindings. HTTPInTransport inTransport = (HTTPInTransport) messageContext.getInboundMessageTransport(); String sigParam = inTransport.getParameterValue("Signature"); return !DatatypeHelper.isEmpty(sigParam); }
SignableSAMLObject message = context.getInboundSAMLMessage();