/** {@inheritDoc} */ protected void doDecode(MessageContext messageContext) throws MessageDecodingException { if (!(messageContext instanceof SAMLMessageContext)) { log.error("Invalid message context type, this decoder only support SAMLMessageContext"); throw new MessageDecodingException( "Invalid message context type, this decoder only support SAMLMessageContext"); } if (!(messageContext.getInboundMessageTransport() instanceof HTTPInTransport)) { log.error("Invalid inbound message transport type, this decoder only support HTTPInTransport"); throw new MessageDecodingException( "Invalid inbound message transport type, this decoder only support HTTPInTransport"); } SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; HTTPInTransport inTransport = (HTTPInTransport) samlMsgCtx.getInboundMessageTransport(); if (!inTransport.getHTTPMethod().equalsIgnoreCase("POST")) { throw new MessageDecodingException("This message decoder only supports the HTTP POST method"); } String relayState = inTransport.getParameterValue("RelayState"); samlMsgCtx.setRelayState(relayState); log.debug("Decoded SAML relay state of: {}", relayState); InputStream base64DecodedMessage = getBase64DecodedMessage(inTransport); Assertion inboundMessage = (Assertion) unmarshallMessage(base64DecodedMessage); Response response = SamlRedirectUtils.wrapAssertionIntoResponse(inboundMessage, inboundMessage.getIssuer().getValue()); samlMsgCtx.setInboundMessage(response); samlMsgCtx.setInboundSAMLMessage(response); log.debug("Decoded SAML message"); populateMessageContext(samlMsgCtx); }
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; } }
/** * Gets the source location used to for the artifacts created by this encoder. * * @param requestContext current request context * * @return source location used to for the artifacts created by this encoder */ protected Endpoint getAcsEndpoint(SAMLMessageContext<SAMLObject, SAMLObject, NameID> requestContext) { BasicEndpointSelector selector = new BasicEndpointSelector(); selector.setEndpointType(ArtifactResolutionService.DEFAULT_ELEMENT_NAME); selector.getSupportedIssuerBindings().add(SAMLConstants.SAML2_SOAP11_BINDING_URI); selector.setMetadataProvider(requestContext.getMetadataProvider()); selector.setEntityMetadata(requestContext.getLocalEntityMetadata()); selector.setEntityRoleMetadata(requestContext.getLocalEntityRoleMetadata()); Endpoint acsEndpoint = selector.selectEndpoint(); if (acsEndpoint == null) { log.error("No artifact resolution service endpoint defined for the entity " + requestContext.getOutboundMessageIssuer()); return null; } return acsEndpoint; } }
/** * Decodes the TARGET parameter and adds it to the message context. * * @param samlMsgCtx current message context * * @throws MessageDecodingException thrown if there is a problem decoding the TARGET parameter. */ protected void decodeTarget(SAMLMessageContext samlMsgCtx) throws MessageDecodingException { HTTPInTransport inTransport = (HTTPInTransport) samlMsgCtx.getInboundMessageTransport(); String target = DatatypeHelper.safeTrim(inTransport.getParameterValue("TARGET")); if (target == null) { log.error("URL TARGET parameter was missing or did not contain a value."); throw new MessageDecodingException("URL TARGET parameter was missing or did not contain a value."); } samlMsgCtx.setRelayState(target); }
@Override protected String getActualReceiverEndpointURI(SAMLMessageContext messageContext) throws MessageDecodingException { InTransport inTransport = messageContext.getInboundMessageTransport(); if (inTransport instanceof LocationAwareInTransport) { return ((LocationAwareInTransport)inTransport).getLocalAddress(); } else { return super.getActualReceiverEndpointURI(messageContext); } }
/** {@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); }
/** {@inheritDoc} */ public void decode(MessageContext messageContext) throws MessageDecodingException, SecurityException { super.decode(messageContext); SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; if (samlMsgCtx.getInboundSAMLMessage() instanceof ResponseAbstractType) { checkEndpointURI(samlMsgCtx); } }
/** * Extract information from a SAML RequestAbstractType message. * * @param messageContext current message context * @param request the SAML message to process * * @throws MessageDecodingException thrown if the request issuer has a format other than {@link NameIDType#ENTITY} */ protected void extractRequestInfo(SAMLMessageContext messageContext, RequestAbstractType request) throws MessageDecodingException { messageContext.setInboundSAMLMessageId(request.getID()); messageContext.setInboundSAMLMessageIssueInstant(request.getIssueInstant()); messageContext.setInboundMessageIssuer(extractEntityId(request.getIssuer())); }
/** * Removes the signature from the protocol message. * * @param messageContext current message context */ protected void removeSignature(SAMLMessageContext messageContext) { SignableSAMLObject message = (SignableSAMLObject) messageContext.getOutboundSAMLMessage(); if (message.isSigned()) { log.debug("Removing SAML protocol message signature"); message.setSignature(null); } }
/** * Extract information from a SAML RequestAbstractType message. * * @param messageContext current message context * @param abstractRequest the SAML message to process */ protected void extractRequestInfo(SAMLMessageContext messageContext, RequestAbstractType abstractRequest) { messageContext.setInboundSAMLMessageId(abstractRequest.getID()); messageContext.setInboundSAMLMessageIssueInstant(abstractRequest.getIssueInstant()); if (abstractRequest instanceof Request) { Request request = (Request) abstractRequest; if (request.getAttributeQuery() != null) { extractAttributeQueryInfo(messageContext, request.getAttributeQuery()); } if (request.getAuthorizationDecisionQuery() != null) { extractAuthorizationDecisionQueryInfo(messageContext, request.getAuthorizationDecisionQuery()); } if (request.getAssertionArtifacts() != null) { extractAssertionArtifactInfo(messageContext, request.getAssertionArtifacts()); } } }
/** * Extract the issuer, and populate message context, from the Resource attribute of the AuthorizationDecisionQuery * query if {@link #useQueryResourceAsEntityId} is true. * * @param messageContext current message context * @param query query to extract resource name from */ protected void extractAuthorizationDecisionQueryInfo(SAMLMessageContext messageContext, AuthorizationDecisionQuery query) { if (useQueryResourceAsEntityId) { log.debug("Attempting to extract issuer from SAML 1 AuthorizationDecisionQuery Resource attribute"); String resource = DatatypeHelper.safeTrimOrNullString(query.getResource()); if (resource != null) { messageContext.setInboundMessageIssuer(resource); log.debug("Extracted issuer from SAML 1.x AuthorizationDecisionQuery: {}", resource); } } }
/** {@inheritDoc} */ public boolean isIssuerAuthenticated() { return isInboundSAMLMessageAuthenticated() || super.isIssuerAuthenticated(); } }
/** * Validate the decoded SAML2 response message. * * Performs basic message verification: * <dl> * <dd>{@link #validateSignature(SAMLMessageContext)} * </dd> * <dt>Validate signature</dt> * <dd>Mandatory signing verification</dd> * <dt>Verify if request MUST be signed</dt> * <dl> * * @param context The message context containing decoded message * @throws SAML2SecurityException If message should be rejected. * @throws OAException If an internal error occurs */ public void validateResponse(SAMLMessageContext<SignableSAMLObject, SignableSAMLObject, SAMLObject> context) throws Exception { context.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); validateMessage(context); }
protected void verifyIssuer(Issuer issuer, BasicSAMLMessageContext context) throws SAMLException { // Validat format of issuer if (issuer.getFormat() != null && !issuer.getFormat().equals(NameIDType.ENTITY)) { System.out.println("Assertion invalidated by issuer type"+issuer.getFormat()); throw new SAMLException("SAML Assertion is invalid"); } // Validate that issuer is expected peer entity if (!context.getPeerEntityMetadata().getEntityID().equals(issuer.getValue())) { System.out.println("Assertion invalidated by unexpected issuer value"+ issuer.getValue()); throw new SAMLException("SAML Assertion is invalid"); } }
/** * Gets the source location used to for the artifacts created by this encoder. * * @param requestContext current request context * * @return source location used to for the artifacts created by this encoder */ protected String getSourceLocation(SAMLMessageContext<RequestAbstractType, Response, NameIdentifier> requestContext) { BasicEndpointSelector selector = new BasicEndpointSelector(); selector.setEndpointType(ArtifactResolutionService.DEFAULT_ELEMENT_NAME); selector.getSupportedIssuerBindings().add(SAMLConstants.SAML1_SOAP11_BINDING_URI); selector.setMetadataProvider(requestContext.getMetadataProvider()); selector.setEntityMetadata(requestContext.getLocalEntityMetadata()); selector.setEntityRoleMetadata(requestContext.getLocalEntityRoleMetadata()); Endpoint acsEndpoint = selector.selectEndpoint(); if (acsEndpoint == null) { log.error("Unable to select source location for artifact. No artifact resolution service defined for issuer."); return null; } return acsEndpoint.getLocation(); } }
/** {@inheritDoc} */ protected boolean isMessageSigned(SAMLMessageContext messageContext) { HTTPInTransport inTransport = (HTTPInTransport) messageContext.getInboundMessageTransport(); String sigParam = inTransport.getParameterValue("Signature"); return (!DatatypeHelper.isEmpty(sigParam)) || super.isMessageSigned(messageContext); }
/** * 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; } }
/** * Extract the issuer, and populate message context, from the Resource attribute of the Attribute query if * {@link #useQueryResourceAsEntityId} is true. * * @param messageContext current message context * @param query query to extract resource name from */ protected void extractAttributeQueryInfo(SAMLMessageContext messageContext, AttributeQuery query) { if (useQueryResourceAsEntityId) { log.debug("Attempting to extract issuer from SAML 1 AttributeQuery Resource attribute"); String resource = DatatypeHelper.safeTrimOrNullString(query.getResource()); if (resource != null) { messageContext.setInboundMessageIssuer(resource); log.debug("Extracted issuer from SAML 1.x AttributeQuery: {}", resource); } } }
/** {@inheritDoc} */ protected boolean isMessageSigned(SAMLMessageContext messageContext) { HTTPInTransport inTransport = (HTTPInTransport) messageContext.getInboundMessageTransport(); String sigParam = inTransport.getParameterValue("Signature"); return (!DatatypeHelper.isEmpty(sigParam)) || super.isMessageSigned(messageContext); }