/** * Validates that the message context is a {@link SAMLMessageContext} and that its outbound transport is HTTP. * * @param messageContext current message context * * @throws MessageEncodingException thrown if the message context conditions are not met */ protected void validateMessageContent(MessageContext messageContext) throws MessageEncodingException { if (!(messageContext instanceof SAMLMessageContext)) { log.error("Invalid message context type, this encoder only support SAMLMessageContext"); throw new MessageEncodingException( "Invalid message context type, this encoder only support SAMLMessageContext"); } if (!(messageContext.getOutboundMessageTransport() instanceof HTTPOutTransport)) { log.error("Invalid outbound message transport type, this encoder only support HTTPOutTransport"); throw new MessageEncodingException( "Invalid outbound message transport type, this encoder only support HTTPOutTransport"); } } }
/** {@inheritDoc} */ public void encode(MessageContext messageContext) throws MessageEncodingException { log.debug("Beginning encode message to outbound transport of type: {}", messageContext .getOutboundMessageTransport().getClass().getName()); doEncode(messageContext); logEncodedMessage(messageContext); log.debug("Successfully encoded message."); }
/** * Log the encoded message to the protocol message logger. * * @param messageContext the message context to process */ protected void logEncodedMessage(MessageContext messageContext) { if(protocolMessageLog.isDebugEnabled() && messageContext.getOutboundMessage() != null){ if (messageContext.getOutboundMessage().getDOM() == null) { try { marshallMessage(messageContext.getOutboundMessage()); } catch (MessageEncodingException e) { log.error("Unable to marshall message for logging purposes: " + e.getMessage()); return; } } protocolMessageLog.debug("\n" + XMLHelper.prettyPrintXML(messageContext.getOutboundMessage().getDOM())); } }
/** * Custom serialization logic which transform XMLObject into String. * * @param out output stream * @throws java.io.IOException error performing XMLObject serialization */ private void writeObject(ObjectOutputStream out) throws IOException { try { if (serializedObject == null) { serializedObject = XMLHelper.nodeToString(SAMLUtil.marshallMessage(getObject())); } out.writeObject(serializedObject); } catch (MessageEncodingException e) { log.error("Error serializing SAML object", e); throw new IOException("Error serializing SAML object: " + e.getMessage()); } }
/** * Sends SAML message using the given binding. Context is expected to contain outboundMessageTransport. In case localEntityId or localEntityRole * is set, it is used, default SP is used otherwise. * * @param samlContext context * @param sign if true sent message is signed * @param binding binding to use * @return context * @throws SAMLException in case message can't be sent * @throws MessageEncodingException in case message encoding fails * @throws MetadataProviderException in case metadata for required entities is not found */ protected SAMLMessageContext sendMessage(SAMLMessageContext samlContext, boolean sign, SAMLBinding binding) throws SAMLException, MetadataProviderException, MessageEncodingException { verifyContext(samlContext); if (sign) { Assert.notNull(samlContext.getLocalSigningCredential(), "Cannot sign outgoing message as no signing credential is set in the context"); samlContext.setOutboundSAMLMessageSigningCredential(samlContext.getLocalSigningCredential()); } MessageEncoder encoder = binding.getMessageEncoder(); encoder.encode(samlContext); return samlContext; }
/** {@inheritDoc} */ protected void doEncode(MessageContext messageContext) throws MessageEncodingException { if (!(messageContext.getOutboundMessageTransport() instanceof HTTPOutTransport)) { log.error("Invalid outbound message transport type, this encoder only support HTTPOutTransport"); throw new MessageEncodingException( "Invalid outbound message transport type, this encoder only support HTTPOutTransport"); } super.doEncode(messageContext); }
/** * Custom serialization logic which transform List of XMLObject into List of Strings. * * @param out output stream * @throws java.io.IOException error performing XMLObject serialization */ private void writeObject(ObjectOutputStream out) throws IOException { try { if (serializedObject == null) { ArrayList<String> serializedItems = new ArrayList<String>(); for (T item : getObject()) { serializedItems.add(XMLHelper.nodeToString(SAMLUtil.marshallMessage(item))); } serializedObject = serializedItems; } out.writeObject(serializedObject); } catch (MessageEncodingException e) { log.error("Error serializing SAML object", e); throw new IOException("Error serializing SAML object: " + e.getMessage()); } }
/** {@inheritDoc} */ protected void doEncode(MessageContext messageContext) throws MessageEncodingException { if (!(messageContext instanceof SAMLMessageContext)) { log.error("Invalid message context type, this encoder only support SAMLMessageContext"); throw new MessageEncodingException( "Invalid message context type, this encoder only support SAMLMessageContext"); } if (!(messageContext.getOutboundMessageTransport() instanceof HTTPOutTransport)) { log.error("Invalid outbound message transport type, this encoder only support HTTPOutTransport"); throw new MessageEncodingException( "Invalid outbound message transport type, this encoder only support HTTPOutTransport"); } prepareMessageContext(messageContext); processOutboundHandlerChain(messageContext); encodeToTransport(messageContext); }
/** * Gets the signature algorithm URI to use with the given signing credential. * * @param credential the credential that will be used to sign the message * @param config the SecurityConfiguration to use (may be null) * * @return signature algorithm to use with the given signing credential * * @throws MessageEncodingException thrown if the algorithm URI could not be derived from the supplied credential */ protected String getSignatureAlgorithmURI(Credential credential, SecurityConfiguration config) throws MessageEncodingException { SecurityConfiguration secConfig; if (config != null) { secConfig = config; } else { secConfig = Configuration.getGlobalSecurityConfiguration(); } String signAlgo = secConfig.getSignatureAlgorithmURI(credential); if (signAlgo == null) { throw new MessageEncodingException("The signing credential's algorithm URI could not be derived"); } return signAlgo; }
/** * Gets the signature algorithm URI to use with the given signing credential. * * @param credential the credential that will be used to sign the message * @param config the SecurityConfiguration to use (may be null) * * @return signature algorithm to use with the given signing credential * * @throws MessageEncodingException thrown if the algorithm URI could not be derived from the supplied credential */ protected String getSignatureAlgorithmURI(Credential credential, SecurityConfiguration config) throws MessageEncodingException { SecurityConfiguration secConfig; if (config != null) { secConfig = config; } else { secConfig = Configuration.getGlobalSecurityConfiguration(); } String signAlgo = secConfig.getSignatureAlgorithmURI(credential); if (signAlgo == null) { throw new MessageEncodingException("The signing credential's algorithm URI could not be derived"); } return signAlgo; }
/** {@inheritDoc} */ protected void doEncode(MessageContext messageContext) throws MessageEncodingException { if (!(messageContext instanceof SAMLMessageContext)) { log.error("Invalid message context type, this encoder only support SAMLMessageContext"); throw new MessageEncodingException( "Invalid message context type, this encoder only support SAMLMessageContext"); } if (!(messageContext.getOutboundMessageTransport() instanceof HTTPOutTransport)) { log.error("Invalid outbound message transport type, this encoder only support HTTPOutTransport"); throw new MessageEncodingException( "Invalid outbound message transport type, this encoder only support HTTPOutTransport"); } SAMLMessageContext artifactContext = (SAMLMessageContext) messageContext; HTTPOutTransport outTransport = (HTTPOutTransport) artifactContext.getOutboundMessageTransport(); outTransport.setCharacterEncoding("UTF-8"); if (postEncoding) { postEncode(artifactContext, outTransport); } else { getEncode(artifactContext, outTransport); } }
/** {@inheritDoc} */ protected void encodeToTransport(MessageContext messageContext) throws MessageEncodingException { Element envelopeElem = marshallMessage(messageContext.getOutboundMessage()); preprocessTransport(messageContext); try { OutTransport outTransport = messageContext.getOutboundMessageTransport(); Writer out = new OutputStreamWriter(outTransport.getOutgoingStream(), "UTF-8"); XMLHelper.writeNode(envelopeElem, out); out.flush(); } catch (UnsupportedEncodingException e) { log.error("JVM does not support required UTF-8 encoding"); throw new MessageEncodingException("JVM does not support required UTF-8 encoding"); } catch (IOException e) { log.error("Unable to write message content to outbound stream", e); throw new MessageEncodingException("Unable to write message content to outbound stream", e); } }
/** * Process the outbound {@link HandlerChain} for the message context, if any. * * @param messageContext the message context to process * @throws MessageEncodingException thrown if a handler indicates a problem handling the message */ protected void processOutboundHandlerChain(MessageContext messageContext) throws MessageEncodingException { HandlerChainResolver outboundHandlerChainResolver = messageContext.getOutboundHandlerChainResolver(); if (outboundHandlerChainResolver != null) { log.debug("Invoking outbound handler chain on message context"); try { for (HandlerChain outboundHandlerChain : outboundHandlerChainResolver.resolve(messageContext)) { if (outboundHandlerChain != null) { invokeHandlerChain(outboundHandlerChain, messageContext); } } } catch (HandlerException e) { log.error("Encountered HandlerException when encoding message: {}", e.getMessage()); throw new MessageEncodingException("Handler exception while encoding message", e); } } }
} catch (SecurityException e) { log.error("Error during URL signing process", e); throw new MessageEncodingException("Unable to sign URL query string", e); } catch (UnsupportedEncodingException e) {
/** * Process the outbound {@link HandlerChain} for the message context, if any. * * @param messageContext the message context to process * @throws MessageEncodingException thrown if a handler indicates a problem handling the message */ protected void processOutboundHandlerChain(MessageContext messageContext) throws MessageEncodingException { HandlerChainResolver outboundHandlerChainResolver = messageContext.getOutboundHandlerChainResolver(); if (outboundHandlerChainResolver != null) { log.debug("Invoking outbound handler chain on message context"); try { for (HandlerChain outboundHandlerChain : outboundHandlerChainResolver.resolve(messageContext)) { if (outboundHandlerChain != null) { invokeHandlerChain(outboundHandlerChain, messageContext); } } } catch (HandlerException e) { log.error("Encountered HandlerException when encoding message: {}", e.getMessage()); throw new MessageEncodingException("Handler exception while encoding message", e); } } }
/** * Encode the message context to the transport. * * @param messageContext the message context to process * @throws MessageEncodingException thrown if there is a problem encoding the message context * to the transport */ protected void encodeToTransport(MessageContext messageContext) throws MessageEncodingException { Element envelopeElem = marshallMessage(messageContext.getOutboundMessage()); preprocessTransport(messageContext); try { OutTransport outTransport = messageContext.getOutboundMessageTransport(); Writer out = new OutputStreamWriter(outTransport.getOutgoingStream(), "UTF-8"); XMLHelper.writeNode(envelopeElem, out); out.flush(); } catch (UnsupportedEncodingException e) { log.error("JVM does not support required UTF-8 encoding"); throw new MessageEncodingException("JVM does not support required UTF-8 encoding"); } catch (IOException e) { log.error("Unable to write message content to outbound stream", e); throw new MessageEncodingException("Unable to write message content to outbound stream", e); } }
/** * Helper method that marshals the given message. * * @param message message the marshall and serialize * @return marshaled message * @throws org.opensaml.ws.message.encoder.MessageEncodingException * thrown if the give message can not be marshaled into its DOM representation */ public static Element marshallMessage(XMLObject message) throws MessageEncodingException { try { if (message.getDOM() != null) { log.debug("XMLObject already had cached DOM, returning that element"); return message.getDOM(); } Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(message); if (marshaller == null) { throw new MessageEncodingException("Unable to marshall message, no marshaller registered for message object: " + message.getElementQName()); } Element messageElem = marshaller.marshall(message); if (log.isTraceEnabled()) { log.trace("Marshalled message into DOM:\n{}", XMLHelper.nodeToString(messageElem)); } return messageElem; } catch (MarshallingException e) { log.error("Encountered error marshalling message to its DOM representation", e); throw new MessageEncodingException("Encountered error marshalling message into its DOM representation", e); } }
/** {@inheritDoc} */ protected void doEncode(MessageContext messageContext) throws MessageEncodingException { if (!(messageContext instanceof SAMLMessageContext)) { log.error("Invalid message context type, this encoder only support SAMLMessageContext"); throw new MessageEncodingException( "Invalid message context type, this encoder only support SAMLMessageContext"); } if (!(messageContext.getOutboundMessageTransport() instanceof HTTPOutTransport)) { log.error("Invalid outbound message transport type, this encoder only support HTTPOutTransport"); throw new MessageEncodingException( "Invalid outbound message transport type, this encoder only support HTTPOutTransport"); } SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; SAMLObject outboundMessage = samlMsgCtx.getOutboundSAMLMessage(); if (outboundMessage == null) { throw new MessageEncodingException("No outbound SAML message contained in message context"); } String endpointURL = getEndpointURL(samlMsgCtx).buildURL(); if (samlMsgCtx.getOutboundSAMLMessage() instanceof ResponseAbstractType) { ((ResponseAbstractType) samlMsgCtx.getOutboundSAMLMessage()).setRecipient(endpointURL); } signMessage(samlMsgCtx); samlMsgCtx.setOutboundMessage(outboundMessage); postEncode(samlMsgCtx, endpointURL); }
/** {@inheritDoc} */ protected void doEncode(MessageContext messageContext) throws MessageEncodingException { if (!(messageContext instanceof SAMLMessageContext)) { log.error("Invalid message context type, this encoder only support SAMLMessageContext"); throw new MessageEncodingException( "Invalid message context type, this encoder only support SAMLMessageContext"); } if (!(messageContext.getOutboundMessageTransport() instanceof HTTPOutTransport)) { log.error("Invalid outbound message transport type, this encoder only support HTTPOutTransport"); throw new MessageEncodingException( "Invalid outbound message transport type, this encoder only support HTTPOutTransport"); } SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; SAMLObject outboundMessage = samlMsgCtx.getOutboundSAMLMessage(); if (outboundMessage == null) { throw new MessageEncodingException("No outbound SAML message contained in message context"); } String endpointURL = getEndpointURL(samlMsgCtx).buildURL(); if (samlMsgCtx.getOutboundSAMLMessage() instanceof StatusResponseType) { ((StatusResponseType) samlMsgCtx.getOutboundSAMLMessage()).setDestination(endpointURL); } signMessage(samlMsgCtx); samlMsgCtx.setOutboundMessage(outboundMessage); postEncode(samlMsgCtx, endpointURL); }
/** {@inheritDoc} */ protected void doEncode(MessageContext messageContext) throws MessageEncodingException { if (!(messageContext instanceof SAMLMessageContext)) { log.error("Invalid message context type, this encoder only support SAMLMessageContext"); throw new MessageEncodingException( "Invalid message context type, this encoder only support SAMLMessageContext"); } if (!(messageContext.getOutboundMessageTransport() instanceof HTTPOutTransport)) { log.error("Invalid outbound message transport type, this encoder only support HTTPOutTransport"); throw new MessageEncodingException( "Invalid outbound message transport type, this encoder only support HTTPOutTransport"); } SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; String endpointURL = getEndpointURL(samlMsgCtx).buildURL(); setResponseDestination(samlMsgCtx.getOutboundSAMLMessage(), endpointURL); removeSignature(samlMsgCtx); String encodedMessage = deflateAndBase64Encode(samlMsgCtx.getOutboundSAMLMessage()); String redirectURL = buildRedirectURL(samlMsgCtx, endpointURL, encodedMessage); HTTPOutTransport out = (HTTPOutTransport) messageContext.getOutboundMessageTransport(); HTTPTransportUtils.addNoCacheHeaders(out); HTTPTransportUtils.setUTF8Encoding(out); out.sendRedirect(redirectURL); }