Achieving CORS in Mule ESB
Achieving CORS means you have a defense mechanism that restricts resources from being requested from another domain outside the domain from which the resource originated.
Join the DZone community and get the full member experience.
Join For FreeSo, you or your company has decided to write some APIs for your business or a product you are working on, and you used Mule ESB to write your HTTP endpoints (which can be called from others and consume your API). However, if you are not using Anypoint Manager to manage your APIs, then you might run into a problem.
After spending many tough hours on it, you are ready to test your first API. You get ready to call it using some client — maybe a SOAP or REST client. You press the button… and nothing happens. You start debugging your code, start checking all the connections and whatnot, and finally, you find that whatever endpoint you designed to expect a POST
or GET
or PUT
or some other commonly used HTTP method is actually expecting “OPTIONS.” Now, what is this OPTIONS? Why is it being sent in spite of the fact that the AJAX call you made is clearly set up to send a POST
or PUT
request?
Welcome to CORS.
Cross-origin resource sharing (CORS) is a defense mechanism that restricts the resources (i.e., fonts, AJAX calls, etc.) from being requested from another domain outside the domain from which the resource originated.
A web page may freely embed images, stylesheets, scripts, iframes, videos, and some plugin content (such as Adobe Flash) from any other domain. However, embedded web fonts and AJAX (XMLHttpRequest
) requests have traditionally been limited to accessing the same domain as the parent web page (as per the same-origin security policy). Cross-domain AJAX requests are forbidden by default because of their ability to perform advanced requests (POST
, PUT
, DELETE
, and other types of HTTP requests, along with specifying custom HTTP headers) that introduce many cross-site scripting security issues.
CORS defines a way in which a browser and server can interact to determine safely whether or not to allow the cross-origin request. It allows for more freedom and functionality than purely same-origin requests, but it’s more secure than simply allowing all cross-origin requests. It is a recommended standard of the W3C. For a complete explanation, please click here.
Let’s Make the API Accessible to All
Today, I will show you how you can configure CORS on your APIs in Mule ESB, which is very simple. All we have to do is follow the few steps below.
Create a cors:config
in your global elements in a mule-config file as follows.
<cors:config name="Cors_Configuration" doc:name="Cors Configuration">
<cors:origins>
<cors:origin url="*" accessControlMaxAge="30">
<cors:methods>
<cors:method>GET</cors:method>
<cors:method>POST</cors:method>
<cors:method>OPTIONS</cors:method>
</cors:methods>
<cors:headers>
<cors:header>X-Allow-Origin</cors:header>
</cors:headers>
</cors:origin>
</cors:origins>
</cors:config>
Add an XML namespace for cors:config
in your Mule config file. I could not find an online resource, so I got the XSD and placed it in my Mule project’s resources folder, then added the namespace.
< mulexmlns: context = "http://www.springframework.org/schema/context"
xmlns: encryption = "http://www.mulesoft.org/schema/mule/encryption"
xmlns = "http://www.mulesoft.org/schema/mule/core"
xmlns: doc = "http://www.mulesoft.org/schema/mule/documentation"
xmlns: spring = "http://www.springframework.org/schema/beans"
xmlns: http = "http://www.mulesoft.org/schema/mule/http"
xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns: cors = "http://www.mulesoft.org/schema/mule/cors"
xsi: schemaLocation = "http://www.mulesoft.org/schema/mule/encryptionhttp://www.mulesof
Here is the complete mule-cors.xsd that you can keep in your resources folder:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.mulesoft.org/schema/mule/cors"
attributeFormDefault="unqualified" elementFormDefault="qualified">
<xs:import namespace="http://www.w3.org/XML/1998/namespace"></xs:import>
<xs:import namespace="http://www.springframework.org/schema/beans"
schemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"></xs:import>
<xs:import namespace="http://www.mulesoft.org/schema/mule/core"
schemaLocation="http://www.mulesoft.org/schema/mule/core/current/mule.xsd"></xs:import>
<xs:element
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
substitutionGroup="mule:abstract-extension" name="config">
<xs:complexType>
<xs:complexContent>
<xs:extension base="mule:abstractExtensionType">
<xs:annotation>
<xs:documentation>Cors Module</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="origins">
<xs:annotation>
<xs:documentation></xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded"
name="origin">
<xs:complexType>
<xs:complexContent>
<xs:extension
xmlns="http://www.mulesoft.org/schema/mule/cors"
base="OriginObjectType">
<xs:attribute type="xs:string" use="optional"
name="value-ref"></xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" use="optional" name="ref">
<xs:annotation>
<xs:documentation>The reference object for this parameter</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" use="optional" name="name">
<xs:annotation>
<xs:documentation>Give a name to this configuration so it can be
later referenced by config-ref.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute type="xs:string" use="optional" name="storePrefix">
<xs:annotation>
<xs:documentation>Prefix used to differentiate the object store
used as the backend of the configured origins.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute type="xs:string" use="optional" name="originsStore-ref">
<xs:annotation>
<xs:documentation>The object store used for storing the origins.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:complexType name="OriginObjectType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="methods">
<xs:annotation>
<xs:documentation></xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="method">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" use="optional"
name="value-ref"></xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" use="optional" name="ref">
<xs:annotation>
<xs:documentation>The reference object for this parameter</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="headers">
<xs:annotation>
<xs:documentation></xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="header">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" use="optional"
name="value-ref"></xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" use="optional" name="ref">
<xs:annotation>
<xs:documentation>The reference object for this parameter</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="expose-headers">
<xs:annotation>
<xs:documentation></xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="expose-header">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" use="optional"
name="value-ref"></xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" use="optional" name="ref">
<xs:annotation>
<xs:documentation>The reference object for this parameter</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" use="optional" name="url">
<xs:annotation>
<xs:documentation></xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute
xmlns="http://www.mulesoft.org/schema/mule/cors"
type="longType" use="optional" name="accessControlMaxAge">
<xs:annotation>
<xs:documentation></xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute type="xs:string" use="optional" name="ref">
<xs:annotation>
<xs:documentation>The reference object for this parameter</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:element
xmlns="http://www.mulesoft.org/schema/mule/cors"
xmlns:mule="http://www.mulesoft.org/schema/mule/core" type="ValidateType"
substitutionGroup="mule:abstract-intercepting-message-processor" name="validate">
<xs:annotation>
<xs:documentation>Perform CORS validation. This operation will add
the necessary CORS headers to the response. If the request method is
OPTIONS it will not perform further processing of the message. If
this request is not a CORS request, then the processing will
continue without altering the message.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:complexType name="ValidateType">
<xs:complexContent>
<xs:extension
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:abstractInterceptingMessageProcessorType">
<xs:attribute type="xs:string" use="optional" name="config-ref">
<xs:annotation>
<xs:documentation>Specify which configuration to use for this
invocation.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute
xmlns="http://www.mulesoft.org/schema/mule/cors"
type="booleanType" use="optional" default="false" name="publicResource">
<xs:annotation>
<xs:documentation>specifies if this resource should be publicly
available regardless the origin.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute
xmlns="http://www.mulesoft.org/schema/mule/cors"
type="booleanType" use="optional" default="false" name="acceptsCredentials">
<xs:annotation>
<xs:documentation>specifies whether the resource accepts
credentials or not.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:simpleType name="integerType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:integer"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="decimalType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:decimal"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="floatType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:float"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="doubleType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:double"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="dateTimeType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:dateTime"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="longType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:long"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="byteType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:byte"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="booleanType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:boolean"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="anyUriType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:anyURI"></xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="charType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"></xs:minLength>
<xs:maxLength value="1"></xs:maxLength>
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction
xmlns:mule="http://www.mulesoft.org/schema/mule/core"
base="mule:propertyPlaceholderType">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:schema>
Now add cors:validate to your Mule flow:
<cors:validate config-ref="Cors_Configuration"
publicResource="true" acceptsCredentials="false" doc:name="CORS Validate" />
That’s it! You are done! This is how we configure CORS in a Mule ESB on-premise API. If you use Anypoint API Manager, then configuring CORS is as easy as just clicking a button and applying the CORS policy on your API endpoint.
For more information, check out Mule’s documentation on CORS.
I hope I was able to give some concise steps that may help you to implement CORS in Mule ESB. Let me know if it helped you and if you found any problems with your implementation of CORS.
Opinions expressed by DZone contributors are their own.
Comments