Spring Integration: how to make the SecurityContext propagation working? -
i'm trying integrate 2 simple spring web applications spring integration, , want propagate spring securitycontext between 2 applications, i've not yet found working solution.
the 2 applications similar between each other, there few differences in configuration: 1 of them has "caller", other 1 has "receiver".
in order getting expected result, i'm using spring security , i've configured both applications following spring security configuration:
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" 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-4.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.1.xsd"> <http auto-config="true"> <intercept-url pattern="/" access="permitall" /> <intercept-url pattern="/service/**" access="permitall" /> <intercept-url pattern="/home" access="permitall" /> <intercept-url pattern="/admin**" access="hasrole('admin')" /> <intercept-url pattern="/dba**" access="hasrole('admin') , hasrole('dba')" /> <form-login authentication-failure-url="/accessdenied" /> </http> <authentication-manager id="authenticationmanager"> <authentication-provider> <user-service> <user name="user" password="user" authorities="role_user" /> <user name="admin" password="admin" authorities="role_admin" /> <user name="dba" password="dba" authorities="role_admin,role_dba" /> </user-service> </authentication-provider> </authentication-manager> <beans:bean id="accessdecisionmanager" class="org.springframework.security.access.vote.affirmativebased"> <beans:constructor-arg> <beans:list> <beans:bean class="org.springframework.security.access.vote.rolevoter" /> <beans:bean class="org.springframework.security.access.vote.authenticatedvoter" /> </beans:list> </beans:constructor-arg> </beans:bean> </beans:beans>
this working: if go url http://localhost:8080/caller/login
, login process correctly managed spring security layer.
so i'm trying configure spring integration module in order "integrate" 2 applications; idea (wrong?) use http:outbound-gateway
"caller", invoke "receiver" @ specific url. on other side, there http:inbound-gateway
manage requests.
here configuration of "caller" side:
<?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-http="http://www.springframework.org/schema/integration/http" xmlns:task="http://www.springframework.org/schema/task" xmlns:int-security="http://www.springframework.org/schema/integration/security" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-4.3.xsd http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http-4.3.xsd http://www.springframework.org/schema/integration/security http://www.springframework.org/schema/integration/security/spring-integration-security-4.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd"> <int:channel id="requestchannel"> <int:dispatcher task-executor="executor"/> </int:channel> <int:channel-interceptor ref="requestchannelinterceptor" pattern="requestchannel"> </int:channel-interceptor> <task:executor id="executor" pool-size="5"/> <bean id="requestchannelinterceptor" class="org.springframework.integration.security.channel.securitycontextpropagationchannelinterceptor"></bean> <bean id="requestchannelbean" class="test.spring.webapp.client.messagingchannel"> <property name="requestchannel" ref="requestchannel"></property> </bean> <int-http:outbound-gateway id="gateway" request-channel="requestchannel" encode-uri="true" url="http://localhost:8080/receiver/service/{request}" http-method="get" > <int-http:uri-variable name="request" expression="payload"/> </int-http:outbound-gateway> <int-security:secured-channels access-decision-manager="accessdecisionmanager"> <int-security:access-policy pattern="requestchannel" send-access="role_admin,role_user,role_dba,role_anonymous"/> </int-security:secured-channels> </beans>
here configuration of "receiver" side instead:
<?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-http="http://www.springframework.org/schema/integration/http" xmlns:task="http://www.springframework.org/schema/task" xmlns:int-security="http://www.springframework.org/schema/integration/security" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-4.3.xsd http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http-4.3.xsd http://www.springframework.org/schema/integration/security http://www.springframework.org/schema/integration/security/spring-integration-security-4.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd"> <int:channel id="requestchannel"> <int:dispatcher task-executor="executor"/> </int:channel> <int:channel-interceptor ref="requestchannelinterceptor" pattern="requestchannel"> </int:channel-interceptor> <task:executor id="executor" pool-size="5"/> <bean id="requestchannelinterceptor" class="org.springframework.integration.security.channel.securitycontextpropagationchannelinterceptor"></bean> <int-http:inbound-gateway id="gateway" request-channel="requestchannel" path="/service/**" supported-methods="get"> </int-http:inbound-gateway> <int-security:secured-channels access-decision-manager="accessdecisionmanager"> <int-security:access-policy pattern="requestchannel" send-access="role_admin,role_user,role_dba,role_anonymous"/> </int-security:secured-channels> <bean id="channelservice" class="test.spring.webapp.server.channelservice"/> <int:service-activator id="channelserviceactivator" ref="channelservice" input-channel="requestchannel" method="manage"/> </beans>
as can see, i'm using component securitycontextpropagationchannelinterceptor of spring integration, intended make "propagation" of security context.
i'm using int-security:secured-channels
in configuration, illustrated in documentation.
but configuration doesn't work: when call url http://localhost:8080/caller/service/hello
(logged or not logged same), i'm getting following exception:
org.springframework.messaging.messagehandlingexception: http request execution failed uri [http://localhost:8080/receiver/service/hello]; nested exception org.springframework.web.client.httpservererrorexception: 500 internal server error
furthermore, class org.springframework.integration.channel.interceptor.threadstatepropagationchannelinterceptor has following method:
@override @suppresswarnings("unchecked") public final message<?> postreceive(message<?> message, messagechannel channel) { if (message instanceof messagewiththreadstate) { messagewiththreadstate<s> messagewiththreadstate = (messagewiththreadstate<s>) message; message<?> messagetohandle = messagewiththreadstate.message; populatepropagatedcontext(messagewiththreadstate.state, messagetohandle, channel); return messagetohandle; } return message; }
the message instance contains logged principal. debugging method, noticed logged principal (for example "admin") obtained on "caller" side, not in "receiver" side (where there "anonymoususer"): why propagation of securitycontext not working?
i believe totally wrong or missing in configuration...
it can't propagated process (application) premise. see implementation of securitycontextpropagationchannelinterceptor
. based on threadstatepropagationchannelinterceptor
. 1 more time thread state, not 1 process via network.
since there no 1 common solution inter-process securitycontext
transfer, there no out-of-the-box.
as answered in question (spring integration: securitycontext propagation), should transfer credential
via http headers. think better using standard apache httpclient
credentialprovider
(or basicauthorizationinterceptor
spring framework 4.3.1) approach send request basic authentication
header. achieve security via network base64 encoding credentials.
on receiver side should similar in https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/authentication/www/basicauthenticationfilter.java#l224:
byte[] base64token = header.substring(6).getbytes("utf-8"); byte[] decoded; try { decoded = base64.decode(base64token); } catch (illegalargumentexception e) { throw new badcredentialsexception( "failed decode basic authentication token"); } string token = new string(decoded, getcredentialscharset(request)); int delim = token.indexof(":"); if (delim == -1) { throw new badcredentialsexception("invalid basic authentication token"); } return new string[] { token.substring(0, delim), token.substring(delim + 1) };
Comments
Post a Comment