Declare and use RabbitMQ with Spring 4 Websockets - spring-4

in our current app, we are using Spring AMQP this way:
<rabbit:connection-factory id="cachingConnectionFactory"
username="${rabbitmq.connection.username}"
password="${rabbitmq.connection.password}"
host="${rabbitmq.connection.host}"
port="${rabbitmq.connection.port}"
executor="rabbitmqPoolTaskExecutor"
requested-heartbeat="${rabbitmq.connection.requested-heartbeat}"
channel-cache-size="${rabbitmq.connection.channel-cache-size}"
virtual-host="${rabbitmq.connection.virtual-host}" />
<rabbit:admin id="adminRabbit"
connection-factory="cachingConnectionFactory"
auto-startup="true" />
<rabbit:template id="rabbitTemplate"
connection-factory="cachingConnectionFactory"
exchange="v1.general.exchange"
message-converter="jsonMessageConverter"
encoding="${rabbitmq.template.encoding}"
channel-transacted="${rabbitmq.template.channel-transacted}" />
<rabbit:queue id="v1.queue.1" name="v1.queue.1" />
<rabbit:queue id="v1.queue.2" name="v1.queue.2" />
<rabbit:queue id="v1.queue.3" name="v1.queue.3" />
<fanout-exchange name="v1.general.exchange" xmlns="http://www.springframework.org/schema/rabbit" >
<bindings>
<binding queue="v1.queue.1" />
<binding queue="v1.queue.2" />
<binding queue="v1.queue.3" />
</bindings>
</fanout-exchange>
<listener-container xmlns="http://www.springframework.org/schema/rabbit"
connection-factory="cachingConnectionFactory"
message-converter="jsonMessageConverter"
task-executor="rabbitmqPoolTaskExecutor"
auto-startup="${rabbitmq.listener-container.auto-startup}"
concurrency="${rabbitmq.listener-container.concurrency}"
channel-transacted="${rabbitmq.listener-container.channel-transacted}"
prefetch="${rabbitmq.listener-container.prefetch}"
transaction-size="${rabbitmq.listener-container.transaction-size}" >
<listener id="v1.listener.queue.1" ref="listener1" method="handleMessage" queues="v1.queue.1" />
<listener id="v1.listener.queue.2" ref="listener2" method="handleMessage" queues="v1.queue.2" />
<listener id="v1.listener.queue.3" ref="listener3" method="handleMessage" queues="v1.queue.3" />
</listener-container>
<bean id="amqpServerConnection" class="com.sub1.sub2.RabbitGatewayConnectionImpl">
<property name="rabbitTemplate" ref="rabbitTemplate" />
</bean>
When I am configuring the websocket in the new Spring 4-based app I don't know how/where declare exchanges, queues, etc...
registry.enableStompBrokerRelay("/example1/", "/example2/")
.setApplicationLogin("guest")
.setApplicationPasscode("guest")
.setAutoStartup(true)
.setRelayHost("localhost")
.setRelayPort(5672)
.setSystemHeartbeatReceiveInterval(10000)
.setSystemHeartbeatSendInterval(10000);
This stuff must be implement with AMPQ yet?

Essentially clients establish a WebSocket session and use STOMP for messaging (STOMP over WebSocket), not AMQP. In STOMP everything is driven by the destination header and it's up to message brokers to define what it means. For example, check the RabbitMQ STOMP plugin page to see how Rabbit maps STOMP destinations to queues and exchanges.
So if you think of RabbitMQ as your message broker where you already manage queues, exchanges, etc. On the web application side, the messaging protocol is STOMP, clients can send messages to STOMP destinations mapped to #MessageMapping controller methods or to destinations supported by RabbitMQ. Furthermore, controllers, or any other component injected with a SimpMessagingTemplate can send messages to the broker (Rabbit) which will then broadcast to connected web clients.
Hope this helps.

Related

int-http:outbound-gateway reply-channel 'stalls'

I'm creating a Spring Integration prototype using Spring Boot.
I have a 'hub' that accepts console input and sends that to an separate socket/tcp application.
The tcp application echos what it was sent in its reply to the hub.
The hub then takes the tcp response & sends it to a separate restful/http application.
The http application echos what is was sent back to the hub.
I'm stuck on the hub's int-http:outbound-gateway which send a request to http. When i omit the 'reply-channel', i can enter more than one bit of text and send to the tcp application. That reply is forwarded to the http application & printed in the console.
However, when i include a reply-channel, i can send one message to the tcp application (the http app receives it) and then the hub application 'stalls'; i type messages in console, hit 'enter' but nothing happens.
Here's my config:
<!-- TO tcp application/server -->
<int:channel id="input" />
<int:gateway id="simple.gateway"
service-interface="com.foo.SimpleGateway"
default-request-channel="input"/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="4444"
single-use="true"
so-timeout="10000"/>
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="input"
reply-channel="clientBytes2StringChannel"
connection-factory="client"
request-timeout="10000"
reply-timeout="10000"/>
<int:object-to-string-transformer id="clientBytes2String"
input-channel="clientBytes2StringChannel"
output-channel="broadcast.channel" />
<int:channel id="broadcast.channel" />
<int:recipient-list-router id="tcp.broadcast.list"
input-channel="broadcast.channel">
<int:recipient channel="to.http" />
<!-- other channels to broadcast to -->
</int:recipient-list-router>
<!-- TO HTTP restful endpoint -->
<!-- this sends the requests -->
<int:channel id="to.http" />
<!-- <int-http:outbound-gateway id="http-outbound-gateway" -->
<!-- request-channel="to.http" -->
<!-- url="http://localhost:8080/howdy?message={msg}" -->
<!-- http-method="GET" -->
<!-- expected-response-type="java.lang.String" -->
<!-- charset="UTF-8"> -->
<!-- <int-http:uri-variable name="msg" expression="payload"/> -->
<!-- </int-http:outbound-gateway> -->
<int-http:outbound-gateway id="http-outbound-gateway"
request-channel="to.http"
url="http://localhost:8080/howdy?message={msg}"
http-method="GET"
expected-response-type="java.lang.String"
charset="UTF-8"
reply-channel="from.http.pubsub.channel">
<int-http:uri-variable name="msg" expression="payload"/>
</int-http:outbound-gateway>
<!-- http://docs.spring.io/spring-integration/reference/html/messaging-endpoints-chapter.html -->
<int:publish-subscribe-channel id="from.http.pubsub.channel" />
<bean id="inboundHTTPPrinterService"
class="com.foo.service.InboundHTTPPrinterService"/>
<int:service-activator id="inboutdHttpPrintServiceActivator"
ref="inboundHTTPPrinterService"
input-channel="from.http.pubsub.channel"
method="printFromHttp"/>
</beans>
In its final form, i want the HTTP response to be printed somewhere AND forwarded to a separate AMQP application.
Your description isn't clear, however, I guess, you mean some issue in here:
<int:service-activator id="inboutdHttpPrintServiceActivator"
ref="inboundHTTPPrinterService"
input-channel="from.http.pubsub.channel"
method="printFromHttp"/>
It would be great to see the printFromHttp() source code, but according your fears it seems for that the method is void.
To send message back to the replyChannel in the headers you should return something from your service method. Looks like in your case it is just enough the same payload or message if that.

Spring OAuth 2 Call /oauth/token Resulted in 401 (Unauthorized)

Greeting everyone, I try to configure simple authorization code flow via Spring Security OAuth.
I tested my authorisation and resource server configuration via following approaches:
Create a web application as client and use its page to fire http post call to /oauth/authorize.
After getting code, I use the same page to
fire another http post with code and get token.
At the end, I use
curl -H to place token inside header and get response from protected
resource.
But when I try to use rest template. It throw error message 401 Unauthorised error.
Server side - security configure:
<http auto-config="true" pattern="/protected/**"
authentication-manager-ref="authenticationManager">
<custom-filter ref="resourceFilter" before="PRE_AUTH_FILTER" />
<csrf disabled="true" />
</http>
<http auto-config="true">
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login default-target-url="/admin.html" />
<logout logout-success-url="/welcome.html" logout-url="/logout"/>
<csrf disabled="true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="admin" password="123456" authorities="ROLE_USER,ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
Server side - authorisation and resource configure:
<oauth:authorization-server
client-details-service-ref="clientDetails" error-page="error">
<oauth:authorization-code />
</oauth:authorization-server>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="admin" secret="fooSecret" />
</oauth:client-details-service>
<oauth:resource-server id="resourceFilter" />
Client Side:
<oauth:client id="oauth2ClientContextFilter" />
<oauth:resource id="sso" client-id="admin"
access-token-uri="http://localhost:8080/tough/oauth/token"
user-authorization-uri="http://localhost:8080/tough/oauth/authorize"
use-current-uri="true" client-secret="secret"
client-authentication-scheme="header" type="authorization_code"
scope="trust" />
<oauth:rest-template id="template" resource="sso"/>
If anyone knows where goes wrong, please do let me know.
There were two issues with my configuration above.
I noticed my client used wrong secret to communicate with authorization server.
Token endpoint at authorization server use authentication manager which
serve user authentication. It result
client are rejected all times until I create new security realm for
token endpoint and configure it to use a authentication manger designed for
client.
Note client is different from user. Client is third party want to access resource belong to your user (also called resource owner).
I had the same problem. It helped to add a
org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService
to spring securities authentication-manager, glueing the clientDetailsService to the authentication manager. So
<authentication-manager alias="authenticationManager">
...
<authentication-provider user-service-ref="clientDetailsUserDetailsService"/>
...
</authentication-manager>
nearly solved the problem for me. I had one more Issue: Since ClientDetailsUserDetailsService has no default constructor, spring threw Exceptions of the form
org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class
[class org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService]:
Common causes of this problem include using a final class or a non-visible class;
nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
Which I could not solve without using a copy of that class receiving the clientDetailsService as property instead of a constructor arg.

WCF Service Authentication + Sitecore

We are currently implementing WCF services in Sitecore to execute certain tasks. However we want to secure and authenticate these interactions to keep the Sitecore security model intact.
We use following configuration for the authentication (only relevant config and anonymised):
<service name="Services.MailService" behaviorConfiguration="serviceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="Interfaces.IMailService"/>
</service>
<behavior name="serviceBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Services.Authentication.CustomServiceAuthentication, MyLibrary" />
</serviceCredentials>
</behavior>
<wsHttpBinding>
<binding>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
<transport clientCredentialType="None">
</transport>
</security>
</binding>
</wsHttpBinding>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
The custom validator inherits from UserNamePasswordValidator and logs the user in using the standard Sitecore.Security.Authentication.AuthenticationManager.Login() method. On this exact moment the user is indeed logged in and appears as Sitecore.Context.User. But when arriving in the WCF method itself this authentication is gone. (resulting in access exceptions from Sitecore as anonymous user does not have add item rights)
After a few tests and studying the interactions I noticed that the issue would be that WCF uses multiple messages and thus multiple HttpContext are being used. The cookies and login are not being retained between the requests. Looking deeper I noticed that the System.ServiceModel.ServiceSecurityContext.Current does retain the security login however it only shows up once entering the WCF method (ea it's not possible to use this in the Sitecore httpBeginRequest pipeline to identify and login the user at the UserResolver)
How can I ensure both asp.net and wcf are properly authenticated throughout the call?
In the end we ended up resolving this by including the following in the constructor of the service since our InstanceContextMode was set to PerCall:
// Handle login for Sitecore to sync with the WCF security context
if (ServiceSecurityContext.Current != null)
{
AuthenticationManager.Login(
string.Format("{0}\\{1}", "yoursitecoredomain", ServiceSecurityContext.Current.PrimaryIdentity.Name));
}

Consume SOAP based web service with https

I'm integrating af ASP.NET application, which must consume a 3rd party SOAP web service, which can only be accessed by HTTPS. I add a service reference i VS2012 with the HTTPS URL and VS find the service just fine. But when I use the proxy that VS create to use the web service, it uses regular HTTP.
I suspect that I should alter the binding in the web.config, but I can't seem to figure out what to do. How do I set up the web service to use HTTPS?
You need to make sure that the binding the client uses has security mode="Transport" set up (and that the client binding matches the server binding), something like this for example:
<binding name="yourClientSecureBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
and that the client indeed accesses the httpS:// address of the web service:
<client>
<endpoint bindingConfiguration="yourClientSecureBinding"
address="https://..."
... />
</client>
You are not providing any code, so for starters have a look at these posts: here (Microsoft developer network - Transport Security with an Anonymous Client) and here (Https with BasicHTTPBinding).

Spring AsyncServlet with ActiveMQ, Camel and Jetty

I'm trying to use Spring AsyncServlet with Camel and ActiveMQ. I'm using the following versions.
<spring.version>3.2.0.M1</spring.version>
<camel.version>2.10.0</camel.version>
<jetty.version>8.1.3.v20120416</jetty.version>
<activemq.version>5.6.0</activemq.version>
I want to push messages to clients that are connected to the server (Jetty).
My Camel routes looks like the following.
from("mina:udp://source_machine:9998").to("activemq:myqueue");
I've the following in my Spring/Camel configuration based on this.
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost:61616" />
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="maxConnections" value="8" />
<property name="maximumActive" value="500" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory" />
<property name="transacted" value="false" />
<property name="concurrentConsumers" value="10" />
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig" />
</bean>
Using the above configuration I'm able to input messages into my queue (at least I don't get any errors.) However, I've no idea how to read from this queue.
Is this the correct way of configuring ActiveMQ when using Spring, Camel and Jetty ?
How do I add/register a MessageListener javax.jms.MessageListener so that I can read from my queue.
How can I control the queue size and make the queue non-persistent?
It it possible to add multiple listeners
Thanks.
Your config looks good for activemq. No idea about jetty. There is no jetty config in the snippet you provided.
In a camel route you can simply use a from activemq endpoint to listen on the queue.
from("activemq:myqueue").to("log:test");
Btw. I typically use the jms ednpoint instead of the ActiveMQ one. This has the advantage that it is easier to switch to another jms provider if you have to at some point.
You can also use the connectionfactory and use you own DefaultMessageListenerContainer in a bean. See the spring configs for how to do this but this has nothing to do with camel then.
You can control the queue size in the activemq config. Using the http://activemq.apache.org/producer-flow-control.html.
You can not make a queue no persistent but you can define the messages you send to be non persistent. http://activemq.apache.org/how-do-i-disable-persistence.html
You can define many listeners and you can even define the number of threads for one listener using the option maxConcurrentConsumers on the from endpoint above.

Resources