Mule 3.5 - Google OAuth2 Example - google-api

I'm trying to connect Mule 3.5 to the Google API (Tasks, Calender etc) but I'm having all sorts of problems with the OAuth2 authentication.
Could anybody give me an example .xml file of a Mule project with a working Google OAuth2 Example (and maybe the settings in Google's API Console), please.
A link would do too.

You need to create an application in your Google Developer account (https://console.developers.google.com/) using the create project button. Take note of your project ID you will need this in the Google connector configuration.
You then need to click on the application and go to APIs & Auth. Make sure the API that you need is set to status 'ON'. In this case you probably want to turn Calendar on and anything else you don't need off. Be aware that significant numbers of calls to the Calendar service might incur costs or quota limits.
Also under the APIs & Auth section of the left side of the Google developer console you need to select credentials. Then click the red button Create new client ID. This will give you two critical pieces of information:
Client ID - This goes into your 'consumerKey' in the Google connector in Mule
Client Secret - This goes into your 'consumerSecret' in the Mule
connector
The other important thing to set up is the redirect URI. This will need to be something like:
http://localhost:8081/oauth2callback
This needs to match what you put into your connector configuration. If you're running your Mule server behind a firewall you will need to configure things such as your proxy so this callback can reach your server.
Here is a crude example that I've managed to get working. Be sure to replace the clientID clientSecret and application name as appropriate.
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:json="http://www.mulesoft.org/schema/mule/json"
xmlns:https="http://www.mulesoft.org/schema/mule/https"
xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking"
xmlns:objectstore="http://www.mulesoft.org/schema/mule/objectstore"
xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:google-calendars="http://www.mulesoft.org/schema/mule/google-calendars"
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" version="EE-3.4.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core
http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http
http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/google-calendars
http://www.mulesoft.org/schema/mule/google-calendars/1.0/mule-google-calendars.xsd
http://www.mulesoft.org/schema/mule/objectstore
http://www.mulesoft.org/schema/mule/objectstore/1.0/mule-objectstore.xsd
http://www.mulesoft.org/schema/mule/ee/tracking
http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd
http://www.mulesoft.org/schema/mule/https
http://www.mulesoft.org/schema/mule/https/current/mule-https.xsd
http://www.mulesoft.org/schema/mule/json
http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd">
<!-- The 'consumerKey' is Client ID of you google application
The 'consumerSecret' is the Client Secret of the google application
The 'applicationName' is the application name you supplied (or Google created for you) when you created your application
on the google developer console
-->
<google-calendars:config-with-oauth
name="Google_Calendars"
consumerKey="replace-with-client-ID"
consumerSecret="replace-with-client-secret" doc:name="Google Calendars"
applicationName="replace-with-application-name">
<!-- The values here need to match the redirect URL you authorized for your Google Application
In this case the callback URL would be http://localhost:8081/ouath2callback
-->
<google-calendars:oauth-callback-config
domain="localhost" localPort="8081" path="oauth2callback" remotePort="8081" />
</google-calendars:config-with-oauth>
<!-- This is the objectstore that stores your Auth key which is used in the second flow -->
<objectstore:config name="ObjectStore" doc:name="ObjectStore" />
<!-- The first flow is executed when you go to http://localhost:8080/oauth-authorize
It initiates the Google authentication and if successful gets the auth key and puts it into the object store -->
<flow name="authorizationAndAuthenticationFlow" doc:name="authorizationAndAuthenticationFlow">
<http:inbound-endpoint exchange-pattern="request-response"
host="localhost" port="8080" path="oauth-authorize" doc:name="HTTP" />
<google-calendars:authorize config-ref="Google_Calendars"
doc:name="Google Calendars" />
<!-- Your Auth token is store in the key 'accessTokenId' -->
<objectstore:store config-ref="ObjectStore" key="accessTokenId"
value-ref="#[flowVars['OAuthAccessTokenId']]" overwrite="true"
doc:name="ObjectStore" />
</flow>
<!-- This flow can be called after the authentication is complete. It uses the previously stored token and to retreive your
Calendars and return them as JSON -->
<flow name="getInformationFromCalendar" doc:name="getInformationFromCalendar">
<http:inbound-endpoint exchange-pattern="request-response"
host="localhost" port="8081" doc:name="HTTP" />
<!-- The enricher adds the access token to your message -->
<enricher target="#[flowVars['accessTokenId']]" doc:name="Message Enricher">
<objectstore:retrieve config-ref="ObjectStore"
key="accessTokenId" defaultValue-ref="#['']" doc:name="Get AccessToken" />
</enricher>
<expression-filter expression="#[flowVars['accessTokenId'] != '']"
doc:name="Is Access Token Set" />
<!-- gets your first 200 calendars using the accessToken that you enriched the message with-->
<google-calendars:get-calendar-list
config-ref="Google_Calendars" maxResults="200"
pageToken="#[flowVars['GoogleCalendar_NEXT_PAGE_TOKEN']]" doc:name="Google Calendars"
accessTokenId="#[flowVars['accessTokenId']]" />
<json:object-to-json-transformer
doc:name="Object to JSON" />
</flow>
</mule>

The Google Connectors Suite for Mule has a complete example, including a Mule XML configuration.

We've since published documentation on how to use OAuth connectors. Let us know if it's helpful.

Related

How to set up server.xml in WebSphere Liberty with LDAP to match global security active similar to WAS 7.0 for spring apps

I have a spring app.
It is consistently giving me this error in websphere liberty. This is my login settings .
in web.xml for spring security.
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<!-- ===== SECURITY CONFIGURATION ===== -->
<!-- All requests matching pattern below will bypass the security filter chain completely -->
<security:http pattern="/image/**" security="none"/>
<!-- security:http pattern="/login.jsp*" security="none" / -->
<!-- Defines who can access each URL. -->
<!--
Spring Security 3.0 introduced the ability to use Spring EL expressions as an authorization mechanism in addition to the simple use
of configuration attributes and access-decision voters which have seen before. Expression-based access control is built on the same
architecture but allows complicated boolean logic to be encapsulated in a single expression.
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html
-->
<security:http auto-config="true" use-expressions="true">
<!-- URL restrictions (order is important!) Most specific matches should be at top -->
<!-- Don't set any role restrictions on login.jsp. Any requests for the login page should be available for anonymous users -->
<security:intercept-url pattern="/login.jsp*" access="isAuthenticated()" />
...
Anonymous access to the login page doesn't appear to be enabled. This is almost certainly an error. Please check your configuration allows unauthenticated access to the configured login page. (Simulated access was rejected: org.springframework.security.access.AccessDeniedException: Access is denied)
I have configured LDAP but I do not know how to tie LDAP settings to server authentication as similar to WAS 7.0 global security activation so the application is not able to authenticate .
Can someone give me further infomation as how the access-id in security settings relates to LDAP Realm.
<jaasLoginContextEntry id="system.WEB_INBOUND" loginModuleRef="HashLogin, certificate, hashtable, token, userNameAndPassword" name="system.WEB_INBOUND"/>
<jaasLoginContextEntry id="WSLogin" loginModuleRef="WSLoginId, certificate, hashtable, token, userNameAndPassword" name="WSLoginId" />
<jaasLoginModule id="WSLoginId" className="com.ibm.ws.security.common.auth.module.WSLoginModuleImpl" libraryRef="${com.ibm.ws.security.wim.*}"></jaasLoginModule>
</server>
I have looked at the Liberty profile documents so I would appreciate a more detailed information then linking me to IBM documents because I have read those and several information out in internet a lot and have exhausted all resources that I can do look up on so I would really appreciate a more detailed explanation which would explain how to implement global security and application security enablement as WAS 7.0 does when we configure LDAP repository in WAS . My LDAP is Microsoft Active Directory. And my application security is handled by spring container.
As resource I looked at this but this did not seem to help.
How to map security role to ldap group in websphere liberty profile
Here is how access-id in the Liberty profile can be defined assuming the LDAP server definition has realm name as ldapRealm in server.xml.
<!- Sample LDAP definition -->
<ldapRegistry id="TivoliLdap" host="myHost.rtp.raleigh.ibm.com" realm="ldapRealm" port="389" ldapType="IBM Tivoli Directory Server" ignoreCase="false" baseDN="o=mycompany,c=us">
</ldapRegistry>
<!-- Application binding sample for using access-id attribute for user or group element -->
<application-bnd>
<security-role name="Employee">
<user name="Bob" access-id="user:ldapRealm/Bob"/>
<group ame="developers" access-id="group:ldapRealm/developers"/>
</security-role>
</application-bnd>

Using Gateway from another application

I am using spring-boot, spring-integration and hornetq.
I have a central messaging bridge project "app-bridge" and a number of other projects that request information from the bridge. All projects are deployed as "war" files to a tomcat server.
I need to create a synchronous request from "app-1" to the "app-bridge" application ("app-bridge" makes an MQ request to a remote application for the response and I don't want to expose the way it gets the data to each individual application. ie only "app-bridge" should know how to get the response).
In "app-bridge" I have the following gateway defined.
<int:gateway service-interface="org.company.SendAndReceive"
default-request-channel="synchronousOutChannel"
default-reply-channel="synchronousInChannel"
default-reply-timeout="30000"
default-request-timeout="30000">
</int:gateway>
This works fine when run from the "app-bridge" project.
#Autowired
private final SendAndReceive sendAndReceive;
...
#Scheduled(fixedDelay = 30000L)
public void testing() {
sendAndReceive.send("HELLO");
String resposne = sendAndReceive.receive();
System.out.println(resposne); //prints the response or null if a timeout occurred
}
The problem is that I need to run this from the "app-1" project.
How can I achieve this?
UPDATE for #Gary
integration xml file in the app-bridge project.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-file="http://www.springframework.org/schema/integration/file"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-4.1.xsd
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
<!--************************* SENDING ********************************-->
<!-- handle errors -->
<int:channel id="as400SynchronousOutFailedChannel" />
<int-jms:outbound-channel-adapter
id="as400SynchronousOutFailed"
destination-name="as400.synchronous.out.failed"
channel="as400SynchronousOutFailedChannel"
connection-factory="jmsConnectionFactory"/>
<!-- Read local messages from hornet -->
<int:channel id="as400SynchronousOutChannel" />
<int-jms:message-driven-channel-adapter
id="jmsSynchronousAS400Out"
acknowledge="transacted"
destination-name="as400.synchronous.out"
channel="as400SynchronousOutChannel"
connection-factory="jmsConnectionFactory"
error-channel="as400SynchronousOutFailedChannel"
concurrent-consumers="1"
pub-sub-domain="false" />
<!-- Send messages to AS/400 -->
<int-jms:outbound-channel-adapter
id="jmsSynchronousOut"
destination="as400SynchronousOutQueue"
channel="as400SynchronousOutChannel"
jms-template="as400JmsTemplate">
<int-jms:request-handler-advice-chain>
<int:retry-advice max-attempts="3">
<int:exponential-back-off initial="2000" multiplier="2" />
</int:retry-advice>
</int-jms:request-handler-advice-chain>
</int-jms:outbound-channel-adapter>
<!-- Connection to remote AS/400 Queue -->
<bean id="as400SynchronousOutQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="AS400.SYNCHRONOUS.IN" />
<property name="targetClient">
<bean id="com.ibm.mq.jms.JMSC.MQJMS_CLIENT_NONJMS_MQ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>
</property>
</bean>
<!-- Place to put messages that have failed -->
<int-jms:outbound-channel-adapter
id="jmsAS400SynchronousOutFailed"
destination-name="as400.synchronous.out.failed"
channel="as400SynchronousOutFailedChannel"
connection-factory="jmsConnectionFactory"/>
<!--************************* RECEIVING ********************************-->
<!-- handle errors -->
<int:channel id="as400SynchronousInFailedChannel" />
<int-jms:outbound-channel-adapter
id="as400SynchronousInFailed"
destination-name="as400.synchronous.in.failed"
channel="as400SynchronousInFailedChannel"
connection-factory="jmsConnectionFactory"/>
<!-- Receive messages from AS/400 -->
<int:channel id="as400SynchronousInChannel">
<int:rendezvous-queue/>
</int:channel>
<int-jms:message-driven-channel-adapter
id="jmsAS400SynchronousIn"
acknowledge="transacted"
destination="as400SynchronousInQueue"
channel="as400SynchronousInChannel"
connection-factory="as400ConnectionFactory"
error-channel="as400SynchronousInFailedChannel"/>
<!-- Connection to remote AS/400 Queue -->
<bean id="as400SynchronousInQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="AS400.SYNCHRONOUS.OUT" />
</bean>
<int:gateway service-interface="com.example.bridge.as400.As400SendAndReceive"
default-request-channel="as400SynchronousOutChannel"
default-reply-channel="as400SynchronousInChannel"
default-reply-timeout="30000"
default-request-timeout="30000">
</int:gateway>
</beans>
com.example.bridge.as400.As400SendAndReceive java class.
public interface As400SendAndReceive {
public void send(final String message);
public String receive();
}
So I want all my other war applications (app-1, app-2, app-3) to be able to call the "com.example.bridge.as400.As400SendAndReceive" gateway somehow that is defined in the "app-bridge" war. It is also important that if say both "app-1" and "app-2" request a message, it is sent back to the correct requestor. The As400 message does not support HEADERS so it is being sent as a plain MQSTR.
The <int:gateway/> generates a local java API; you can't use it alone for requests to a remote system.
Your app-bridge should have a <int-jms:inbound-gateway/> to service requests over JMS.
The other apps would use an <int:gateway/> wired to send requests to an <int-jms:outbound-gateway/> configured to send messages to the same destination the app-1 inbound gateway is listening on.
EDIT:
The remote apps can't "call" the gateway in app-bridge; it's a simple java object that's only visible within app-bridge.
You need some kind of external communication between app-n and app-bridge. You can choose the technology of your choice, JMS, RMI, RabbitMQ, HTTP, etc, etc.
You need an <int-x:outbound-gateway/> in app-n and an <int-x:inbound-gateway/> in app-bridge.
Where x is whatever you choose to use for the communication. Explore the documentation to make your choice. Given you are already using JMS to talk to the AS/400, maybe JMS would be the best choice (but you need different queues).

Spring Security for RESTful API

I'm building a restful API using Spring 4.1.6 and spring-boot-starter-data-rest.
To make the rest api fully functional I need the last piece of the puzzle: security. Now I noticed spring has it's own spring-security-* packages that can aid with that task.
I tried using spring-security-config and spring-security-web and it works like a charm, with the exception that if the user is not authenticated, spring will redirect the user to login, thus giving a HTML login form.
Because it's a Restful API, I just need an error to be returned in a JSON object if the user lacks the credentials or does not have enough permissions to read a particular resource.
I'm sure I'm not the first to ask this question and searched all over the web for people asking the same thing, but couldn't quite find was I was looking for. So.. should I continue my research in this direction with spring-security, or should I find something?
Any advice is welcome,
thank you
To change the Login Form response to a custom Http Response you need to configure a custom http response handler for Http Security config. If you are using xml for your security configuration use the configuration shown below, failureHandler used is the one available in Spring Security package. Update the URL to match yours.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- Rest authentication entry point configuration -->
<http use-expressions="true" entry-point-ref="restAuthenticationEntryPoint">
<intercept-url pattern="/api/**" />
<sec:form-login authentication-failure-handler-ref="myFailureHandler" />
<logout />
</http>
<!-- Using default failure handler -->
<beans:bean id="myFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler" />
</beans:beans>

jax-rs only authentication no authorization

I have a JAX-RS web service deployed on IBM WebSphere and I want to secure this WS when it receives the requests (delegated from other server).
So I use the basic auth and set the username and password on BasicAuthSecurityHandler object and delegate the request to other server.
Now when the other server receives the request I use Federated repository in WAS under Global security and do the authentication.
If I comment out the auth-constraint in the deployment descriptor, the authentication is not taking place.
I want to do only authentication and no authorization.
I tried using #PermitAll annotation on the Jax-WS method but the authorization is also happening before the Jax-WS method is executed.
So is there any way I can skip the authorization and still do the authentication?
I dont have any rules associated to my users, so I want to skip the authorization.
<security-constraint id="SecurityConstraint_1">
<display-name>RESTSecurity</display-name>
<web-resource-collection id="WebResourceCollection_1">
<web-resource-name>DelegateReqComApp</web-resource-name>
<description>
Protection area for Rest resource /addresses
</description>
<url-pattern>/rest/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<!-- Authorization Constraint commented out -->
<auth-constraint id="AuthConstraint_1">
<description>
Used to guard resources under this url-pattern
</description>
<role-name>iapawas012</role-name>
</auth-constraint>
</security-constraint>
Create the auth-constraint and map iapawas012 role to the special subject ALL_AUTHENTICATED. It basically says that any user, which successfully authenticates is authorized to invoke your service.
You can do it either in the web admin console on the Enterprise Application > yourApplication > Security role to user/group mapping or via binding file ibm-application-bnd.xml in the EAR in META-INF folder:
<?xml version="1.0" encoding="UTF-8"?>
<application-bnd
xmlns="http://websphere.ibm.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-application-bnd_1_2.xsd"
version="1.2">
<security-role name="iapawas012">
<special-subject type="ALL_AUTHENTICATED_USERS" />
</security-role>
</application-bnd>

WS-Security Websphere Configuration

I'm trying to develop a web service that uses WS-Security using Websphere 7 and JAX-WS. Looking through some guides, it appears that I MUST create a application server user registry and maintain username/passwords inside of that server. Is there anyway to avoid having to create usernames in the server itself and somehow capture the header and do validation based upon another a custom security configuration like a single sign-on?
I'm able to create a handler to get the header, but when mustUnderstands is set to 1 in the request (which is mandatory), it gets rejected before my handler sees the message.
I'm only looking to use the UsernameToken part of WS-Security.
Any help is appreciated.
An example of my request
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" Id="unt_20">
<wsse:Username>some_username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">some_password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
...body...
</soapenv:Body>
</soapenv:Envelope>
Is it possible to create a custom security implementation so I can use my existing user validation scheme?
It would appear that I can implement a custom user registry that can interact with the security implementation of my choice. A link to the IBM article:
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.base.doc/info/aes/ae/tsec_useregistry.html
Another possible answer is to create a Trust Association Interceptor (TAI). This basically extends your current security.
Here is a useful link to get started:
http://www.ibm.com/developerworks/websphere/techjournal/0508_benantar/0508_benantar.html
You can use the out-of-box WS-Security runtime with policy/bindings to achieve this, but you must write custom code to override the default behavior of checking the user registry for UsernameTokens.
See this article for using your own authentication mechanism when consuming the UsernameToken:
Configuring a UsernameToken caller configuration with no registry interaction
See this article if you want to also create WebSphere credentials based on the user name in that token:
Replacing the authentication method of the UsernameToken consumer using a stacked JAAS login module
Can you elaborate on what you want to achieve?
The WAS Server needs to validate the username and password that comes in the header against its user registry (which could an LDAP, File based registry etc).
LTPA tokens (which are used by WebSphere and related products for SSO) can be used too.
If you spell out your requirements, folks here will be able to help you out.
HTH
Manglu
JAX-WS should allow you to have a custom interceptor.
Take a look at this spring config to see how I have added an interceptor to the service endpoint.
<jaxws:endpoint id="pqdws"
implementor="#Atypon"
address="/pqdws"
publishedEndpointUrl="#ws_webapp_url_ext#">
<jaxws:properties>
<entry key="exceptionMessageCauseEnabled" value="true"/>
<entry key="Content-length"
</jaxws:properties>
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackRef">
<ref bean="passwordCallback"/>
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
<bean id="passwordCallback"
class="access.ws.ServerPasswordCallback">
<property name="username" value="#ws_sec_username#"/>
<property name="password" value="#ws_sec_password#"/>
</bean>
The interceptor can then do whatever you wish including calling out to an external service for authentication.

Resources