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

Popular posts from this blog

java - Suppress Jboss version details from HTTP error response -

gridview - Yii2 DataPorivider $totalSum for a column -

Sass watch command compiles .scss files before full sftp upload -