I'm trying to call a REST service that is protected by basic authentication and I can't get this work. Basically, I need to setup the authorization header as
"Authorization: Basic [base64 encoded user name and password]".
My flow looks like this:
<flow name="testjsonFlow1" doc:name="testjsonFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="testjson" doc:name="HTTP"/>
<set-property propertyName="Authorization" doc:name="Set Authentication Header" value="#["Basic " + Base64.encodeBase64String("username:password")]"/>
<http:outbound-endpoint exchange-pattern="request-response" host="<url>" port="80" path="Services/V1/testservices" method="POST" contentType="text/plain" doc:name="HTTP"/>
<echo-component doc:name="Echo"/>
</flow>
Invoking this flow results in the following error:
[Error: unresolvable property or identifier: Base64]
[Near : {... "Basic " + Base64.encodeBase64String("com ....}]
I see that the MuleStudio ships with commons-codec-1.3-osgi.jar while the Base64 API is not included and only comes with later version.
So my questions are:
Is this the right way to call a REST service that is protected with basic auth?
How can I resolve this issue?
How can I make the Mulestudio reference the commons-codec-1.9 jar instead of the commons-codec-1.3-osgi.jar?
Environment details: Windows 7 64 bit, Mule CE 3.4.
Any help is appreciated.
Update 1:
I made some updates to the script and it works now. Here is the updated script:
<flow name="testjsonFlow1" doc:name="testjsonFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="testjson" doc:name="HTTP" />
<set-variable variableName="uName" doc:name="Variable" value="domain\user"/>
<set-variable variableName="pwd" doc:name="Variable" value="P#ssword"/>
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy">
<scripting:text><![CDATA[
def cred = message.getInvocationProperty("uName") + ":" + message.getInvocationProperty("pwd")
def credBytes = cred.bytes
def encodedCred = credBytes.encodeBase64().toString()
message.setProperty("credential",encodedCred)
return null;]]></scripting:text>
</scripting:script>
</scripting:component>
<set-property propertyName="Authorization" doc:name="Set Authentication Header" value="Basic #[header:OUTBOUND:credential]"/>
<logger level="INFO" doc:name="Logger"/>
<logger message="#[message.outboundProperties['Authorization']]" level="INFO" doc:name="Logger"/>
<http:outbound-endpoint exchange-pattern="request-response" host="myserver.com" port="80" path="Services/V1/service1/" method="POST" contentType="text/plain" doc:name="HTTP" />
</flow>
Answering your question to david in the comments above but hate pasting code into the comment editor.
You can add the user and pw to the endpoint and it'll base64 encode it like above.
<http:outbound-endpoint exchange-pattern="request-response"
host="foo.bar.com" port="80"
path="getFoo" method="GET"
user="username" password="password">
</http:outbound-endpoint>
<configuration>
<expression-language>
<import class="org.apache.commons.codec.binary.Base64" />
</expression-language>
</configuration>
or use the fully qualified class name in your expression.
But...
No, configure the username and password on the endpoint. See: http://www.mulesoft.org/documentation/display/current/Mule+Endpoint+URIs
Ditto.
Don't. Stick to the version provided by Mule. If you insist on using a most recent version, you'll need to package it with your application and use classloader override to ensure your application will use the packaged Commons Codec. See: http://www.mulesoft.org/documentation/display/current/Classloader+Control+in+Mule#ClassloaderControlinMule-Fine-GrainedClassloadingControl
Embedding user name and password on the http:outbound-endpoint didn't work as the password had a special character ('#') which was throwing a different exception. I made it work with a different approach and updated it in the question.
Related
I'm trying to call an API Rest from a flow in mule. This API has a basic auth protocol, so I need to send the header "Authorization: Basic XXXXXXX".
The issue that I encounterd is that on the Anypoint Studio, when I'm cofiguring the HTTP Request, I don't get the option of Basic Auth on the Authentication tab, I only see NTLM.
I already tried to set the header manualy, But it gets ignored.
Already tried to include this:
< http:basic-authentication username="${ofsc.clientId}#${ofsc.instance}" password="${ofsc.clientKey}"/>
on the http:request-config, and it didn't work either.
This is the Mule config:
< http:listener-config name="Gateway" host="localhost" port="8281" basePath="/base" doc:name="HTTP Listener Configuration"/>
< http:request-config name="OFSC" host="api.etadirect.com" basePath="/rest/ofscCore/v1" doc:name="HTTP Request Configuration" port="443" protocol="HTTPS">
< http:basic-authentication username="${ofsc.clientId}#${ofsc.instance}" password="${ofsc.clientKey}"/>
< /http:request-config>
< spring:beans>
< spring:bean id="Bean" name="BasicAuthEncode" class="tools.BasicAuthEncode" />
< /spring:beans>
< context:property-placeholder location="env.properties"/>
<flow name="TestFlow">
<http:listener config-ref="Gateway" path="/test" doc:name="HTTP">
<http:response-builder disablePropertiesAsHeaders="true"/>
<http:error-response-builder disablePropertiesAsHeaders="true"/>
</http:listener>
<invoke object-ref="BasicAuthEncode" method="encodeCredentials" doc:name="LPM" methodArgumentTypes="java.lang.String" methodArguments="${ofsc.clientId}#${ofsc.instance}:${ofsc.clientKey}" name="LPM2"/>
<set-variable variableName="credentials" value="Basic #[message.payloadAs(java.lang.String)]" doc:name="Creds"/>
<http:request config-ref="OFSC" path="/activities/3818" method="GET" doc:name="HTTP">
<http:request-builder>
<http:header headerName="Content-Type" value="application/json"/>
</http:request-builder>
<http:success-status-code-validator values="200,400,401,404,403"/>
</http:request>
<logger message="#[message.payloadAs(java.lang.String)]" level="INFO" doc:name="Logger"/>
</flow>
I'm probably doing something relly wrong, but couldn't find the answer. Hope you guys can help me
Thanks
uncheck the "enable cookie" in the http configuration resolved the issue.
The issue was on my properties file.
The values where wrapped in quotes, and the base64 encoding was giving me a wrong string.
Using mulesoft twitter connector an dynamically setting values for the twitter config parameters as shown below,
<twitter:config name="Twitter__Configuration" accessKey="#[flowVars.accessToken]" consumerKey="#[flowVars.consumerKey]" consumerSecret="#[flowVars.consumerSecret]" doc:name="Twitter: Configuration" accessSecret="#[flowVars.accessTokenSecret]"/>
<flow name="twitterFlow1">
<db:select config-ref="MySQL_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[select * from twittercredentials;]]></db:parameterized-query>
</db:select>
<set-variable variableName="consumerKey" value="#[message.payload[0]['consumerkey']]" doc:name="Variable" />
<set-variable variableName="consumerSecret" value="#[message.payload[0]['consumersecret']]" doc:name="Variable" />
<set-variable variableName="accessToken" value="#[message.payload[0]['accesstoken']]" doc:name="Variable" />
<set-variable variableName="accessTokenSecret" value="#[message.payload[0]['accesstokensecret']]" doc:name="Variable" />
</flow>
<flow name="twitterFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/twitterconnect" doc:name="HTTP"/>
<flow-ref name="twitterFlow1" />
<twitter:show-user config-ref="Twitter__Configuration" doc:name="Twitter"/>
<json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>
But I get an exception when invoking /twitterconnect,
Failed to connect/reconnect: Work Descriptor. Root Exception was: 401 response received, but no WWW-Authenticate header was p
resent. Type: class java.lang.IllegalStateException
Works fine with hard coded values in the twitter config. Any help please?
I think that won't work because you instance the twitter:config only one time and is empty.
You should find the way to create a new configuration and inject it to the twitter component.
Try This:
Create a properties file and write the AccessKey, AccessSecret, ConsumerKey, ConsumerSecret values in the properties file with references, and enter the details in the twitter connector as ${} and place the references inside the braces.
I have a case where I need to poll a directory on my file system. Each file that is added to that directory needs to be posted to an HTTP endpoint.
The HTTP endpoint is available on "/rest/latest/file". Using postman, I've verified that the REST call works with the following settings:
POST
basic auth
form-data:
key = file
value = Selected a file from my file system (using a dialog)
My mule flow currently looks like this:
<file:connector name="File" autoDelete="true" streaming="true" validateConnections="true" moveToPattern="#[message.inboundProperties['originalFilename']].backup" moveToDirectory="src/main/resources/output" doc:name="File"/>
<flow name="importdataqualityresultsFlow1" doc:name="importdataqualityresultsFlow1">
<file:inbound-endpoint path="src/main/resources/input" responseTimeout="10000" doc:name="File"/>
<set-payload value="#[['file' :#[message.inboundAttachments['text.txt']]]]" doc:name="Set Payload"/>
<http:outbound-endpoint exchange-pattern="request-response" host="localhost" port="80" path="rest/latest/file" method="POST" user="Admin" password="admin" contentType="application/form-data" doc:name="HTTP"/>
</flow>
I can tell in my application logs that the user logs in using basic auth, after which I get a stack trace.
Any help / pointers would be greatly appreciated.
You need to create a map payload with the form fields:
<flow name="importdataqualityresultsFlow1">
<file:inbound-endpoint path="src/main/resources/input" />
<object-to-string-transformer />
<set-payload value="#[['file': message.payload]]" />
<http:outbound-endpoint exchange-pattern="request-response" host="localhost" port="80" path="rest/latest/file" method="POST" user="Admin" password="admin" contentType="application/form-data" />
</flow>
Is there a way to send the JSON response to another server as a request asynchronously (for example to monitor, etc...)
here is my mule flow
<flow name="loggingFlow1" doc:name="loggingFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="${source.http.host}" port="${source.http.port}" doc:name="HTTP" responseTimeout="10000" />
<http:outbound-endpoint exchange-pattern="request-response" method="GET" address="http://${dest.http.host}:${dest.http.port}#[header:INBOUND:http.request]" contentType="application/json" doc:name="HTTP_GET" responseTimeout="10000" />
<async processingStrategy="Asynchronous_Processing_Strategy" doc:name="Async">
<http:outbound-endpoint exchange-pattern="one-way" address="http://localhost:8080/Monitor/response" doc:name="HTTP"/>
</async>
</flow>
For any reason, it seems the InputStream produced by the first http:outbound-endpoint is read more than once.
Serializing this InputStream to a String with an object-to-string-transformer or a byte[] with an object-to-byte-array-transformer is the best option, the echo-component is a legacy one that is not very much used anymore.
I am attempting to consume a wsdl service using cfx:proxy-client in Mule ESB 3.3 but keep getting this error
org.apache.cxf.service.factory.ServiceConstructionException: Could not find definition for service {http://support.cxf.module.mule.org/}ProxyService.
at org.apache.cxf.wsdl11.WSDLServiceFactory.create(WSDLServiceFactory.java:139)
at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.buildServiceFromWSDL(ReflectionServiceFactoryBean.java:383)
at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.initializeServiceModel(ReflectionServiceFactoryBean.java:506)
Below is my simple flow:
<flow name="spider-middleware" doc:name="spider-middleware">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="salesforce" doc:name="HTTP"/>
<cxf:proxy-client operation="getCustomerByID"
payload="body"
wsdlLocation="http://localhost:4546/eplus-ws-fake/services/EplusCustomer/v1?wsdl"
enableMuleSoapHeaders="true"
doc:name="SOAP"/>
</flow>
The service is hardcoded to return a customer for getCustomerByID(1).
Please shed some lights on how do I get around the issue?
Thanks.
I got it working but only by providing a full SOAP envelope and not just the body, ie. using payload="envelope".
Also I removed the operation and wsdlLocation attributes, which are useless for the proxy-client. I also had to add SOAPAction and Content-Type properties, otherwise the test webservice I'm using chokes on the request.
This gives (using a test service from WebServiceX.net):
<flow name="pureCxfProxyClient">
<vm:inbound-endpoint path="test.in"
exchange-pattern="request-response" />
<set-property propertyName="SOAPAction"
value="http://www.webservicex.net/getACHByZipCode" />
<set-property propertyName="Content-Type" value="text/xml" />
<http:outbound-endpoint address="http://www.webservicex.net/FedACH.asmx"
exchange-pattern="request-response" >
<cxf:proxy-client payload="envelope" />
</http:outbound-endpoint>
</flow>
Note I used a VM endpoint, which allowed me to deal with the XMLStreamReader returned by the cxf:proxy-client.
In particular, I needed to do the following:
final XMLStreamReader xsr = (XMLStreamReader) result.getPayload();
xsr.nextTag();
to avoid crazy NPEs in org.mule.module.xml.stax.ReversibleXMLStreamReader.
All in all this is pretty intense... plus the cxf:proxy-client doesn't deliver much value when used standalone. You could actually just go with:
<flow name="pureCxfProxyClient">
<vm:inbound-endpoint path="test.in"
exchange-pattern="request-response" />
<set-property propertyName="SOAPAction"
value="http://www.webservicex.net/getACHByZipCode" />
<set-property propertyName="Content-Type" value="text/xml" />
<http:outbound-endpoint address="http://www.webservicex.net/FedACH.asmx"
exchange-pattern="request-response" />
</flow>
... and be freed of the XMLStreamReader part.