2016-12-02 7 views
0

私は現在の全体システムをマイクロサービスアーキテクチャに移行するソリューションを模索しています。私はSpring IntegrationとSpring Securityを使ってサービスを統合して保護したいと思っています。私の理解によれば、バックエンドサービスを保護することは、シングルサインオン(SSO)に似ています。私は、ユーザを一元的に認証するために、Jasig CAS 4.2.7(Spring Securityでうまく動作しているようです)、Spring Integration 4.2.11.RELEASE、Spring Security 4.0.4.RELEASEを使用します。CASとのSpring Integrationを使用する場合のセキュリティ保護されたバックエンドサービスへのアクセス方法は?

Webアプリケーションとサービスという2つのモジュールを持つMavenプロジェクトを作成しました。どちらもWebアプリケーションです。 3つのwarファイルを同じローカルのTomcat(バージョン7.0.36)にデプロイし、jimiとbobをCASプロパティファイルに追加して、CASの認証に合格するようにします。 URL​​にアクセスしようとすると、フロントエンドアプリケーションで認証されましたが、バックエンドサービスではアクセスが禁止されています。

POMファイルは以下のようになります。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>prototype.integration.security</groupId> 
    <artifactId>prototype-integration-security</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>pom</packaging> 

    <name>prototype-integration-security</name> 

    <properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    </properties> 

    <build> 
    <plugins> 
     <plugin> 
     <groupId>org.apache.maven.plugins</groupId> 
     <artifactId>maven-compiler-plugin</artifactId> 
     <version>3.5.1</version> 
     <configuration> 
      <source>1.7</source> 
      <target>1.7</target> 
     </configuration> 
     </plugin> 
     <plugin> 
     <groupId>org.apache.maven.plugins</groupId> 
     <artifactId>maven-war-plugin</artifactId> 
     <version>2.6</version> 
     <configuration> 
      <warName>${project.name}</warName> 
     </configuration> 
     </plugin> 
    </plugins> 
    </build> 

    <dependencies> 
    <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
     <version>4.12</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.integration</groupId> 
     <artifactId>spring-integration-http</artifactId> 
     <version>4.2.11.RELEASE</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-web</artifactId> 
     <version>4.0.4.RELEASE</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-test</artifactId> 
     <version>4.2.7.RELEASE</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.logging.log4j</groupId> 
     <artifactId>log4j-slf4j-impl</artifactId> 
     <version>2.7</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.logging.log4j</groupId> 
     <artifactId>log4j-jcl</artifactId> 
     <version>2.7</version> 
    </dependency> 
    <dependency> 
     <groupId>javax</groupId> 
     <artifactId>javaee-api</artifactId> 
     <version>7.0</version> 
     <scope>provided</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.integration</groupId> 
     <artifactId>spring-integration-security</artifactId> 
     <version>4.2.11.RELEASE</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.logging.log4j</groupId> 
     <artifactId>log4j-core</artifactId> 
     <version>2.7</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-config</artifactId> 
     <version>4.0.4.RELEASE</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-cas</artifactId> 
     <version>4.0.4.RELEASE</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.httpcomponents</groupId> 
     <artifactId>httpclient</artifactId> 
     <version>4.5.1</version> 
    </dependency> 
    <dependency> 
     <groupId>com.fasterxml.jackson.core</groupId> 
     <artifactId>jackson-databind</artifactId> 
     <version>2.6.4</version> 
    </dependency> 
    </dependencies> 
    <modules> 
    <module>prototype-integration-security-web</module> 
    <module>prototype-integration-security-service</module> 
    </modules> 
</project> 

は、2つのモジュールの展開記述ファイルのweb.xmlが以下のように表示名を除いて同じに見えます。

<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
     id="IntegrationSecurityWeb" version="3.0"> 
    <display-name>Integration Security Web Prototype</display-name> 

    <servlet> 
    <servlet-name>dispatcher</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <load-on-startup>1</load-on-startup> 
    </servlet> 
    <servlet-mapping> 
    <servlet-name>dispatcher</servlet-name> 
    <url-pattern>/*</url-pattern> 
    </servlet-mapping> 

    <filter> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
    </filter> 
    <filter-mapping> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <url-pattern>/*</url-pattern> 
    </filter-mapping> 
</web-app> 

WebモジュールのSpringアプリケーションコンテキスト構成ファイルでは、dispatcher-servlet.xmlは次のようになります。

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:task="http://www.springframework.org/schema/task" 
     xmlns:security="http://www.springframework.org/schema/security" 
     xmlns:int="http://www.springframework.org/schema/integration" 
     xmlns:int-http="http://www.springframework.org/schema/integration/http" 
     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/task 
          http://www.springframework.org/schema/task/spring-task.xsd 
          http://www.springframework.org/schema/security 
          http://www.springframework.org/schema/security/spring-security.xsd 
          http://www.springframework.org/schema/integration 
          http://www.springframework.org/schema/integration/spring-integration-4.2.xsd 
          http://www.springframework.org/schema/integration/http 
          http://www.springframework.org/schema/integration/http/spring-integration-http-4.2.xsd 
          http://www.springframework.org/schema/integration/security 
          http://www.springframework.org/schema/integration/security/spring-integration-security-4.2.xsd"> 

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> 
    <constructor-arg> 
     <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"> 
     <constructor-arg> 
      <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
      <property name="targetClass" value="org.apache.http.impl.client.HttpClients"/> 
      <property name="targetMethod" value="createMinimal"/> 
      </bean> 
     </constructor-arg> 
     </bean> 
    </constructor-arg> 
    <property name="messageConverters"> 
     <list> 
     <bean class="org.springframework.http.converter.StringHttpMessageConverter" /> 
     <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /> 
     <bean class="org.springframework.http.converter.FormHttpMessageConverter"> 
     </bean> 
     </list> 
    </property> 
    </bean> 

    <bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties"> 
    <property name="service" value="http://localhost:8080/prototype-integration-security-web/login/cas" /> 
    <property name="sendRenew" value="false" /> 
    </bean> 

    <!-- Access voters --> 
    <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> 
    <constructor-arg name="decisionVoters"> 
     <list> 
     <bean class="org.springframework.security.access.vote.RoleHierarchyVoter"> 
      <constructor-arg> 
      <bean class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl"> 
       <property name="hierarchy"> 
       <value> 
        ROLE_ADMIN > ROLE_USER 
       </value> 
       </property> 
      </bean> 
      </constructor-arg> 
     </bean> 
     <bean class="org.springframework.security.access.vote.AuthenticatedVoter" /> 
     </list> 
    </constructor-arg> 
    </bean> 

    <bean id="casEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"> 
    <property name="loginUrl" value="https://localhost:8443/cas/login" /> 
    <property name="serviceProperties" ref="serviceProperties" /> 
    </bean> 

    <bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter"> 
    <property name="authenticationManager" ref="authenticationManager" /> 
    </bean> 

    <!-- This filter handles a Single Logout Request from the CAS Server --> 
    <bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" /> 

    <!-- This filter redirects to the CAS Server to signal Single Logout should be performed --> 
    <bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> 
    <constructor-arg value="http://localhost:8080/cas/logout" /> 
    <constructor-arg> 
     <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" /> 
    </constructor-arg> 
    <property name="filterProcessesUrl" value="/logout/cas" /> 
    </bean> 

    <security:http entry-point-ref="casEntryPoint" access-decision-manager-ref="accessDecisionManager" use-expressions="false"> 
    <security:intercept-url pattern="/admin/**" access="ROLE_ADMIN" /> 
    <security:intercept-url pattern="/**" access="ROLE_USER" /> 
    <security:form-login /> 
    <security:logout /> 
    <security:custom-filter before="LOGOUT_FILTER" ref="requestSingleLogoutFilter"/> 
    <security:custom-filter before="CAS_FILTER" ref="singleLogoutFilter"/> 
    <security:custom-filter position="CAS_FILTER" ref="casFilter" /> 
    </security:http> 

    <security:user-service id="userService"> 
    <security:user name="jimi" password="jimi" authorities="ROLE_ADMIN" /> 
    <security:user name="bob" password="bob" authorities="ROLE_USER" /> 
    </security:user-service> 

    <bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"> 
    <property name="authenticationUserDetailsService"> 
     <bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"> 
     <constructor-arg index="0" ref="userService" /> 
     </bean> 
    </property> 
    <property name="serviceProperties" ref="serviceProperties" /> 
    <property name="ticketValidator"> 
     <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator"> 
     <constructor-arg index="0" value="https://localhost:8443/cas" /> 
     </bean> 
    </property> 
    <property name="key" value="localCAS" /> 
    </bean> 

    <security:authentication-manager alias="authenticationManager"> 
    <security:authentication-provider ref="casAuthenticationProvider" /> 
    </security:authentication-manager> 

    <int:channel-interceptor order="99"> 
    <bean class="org.springframework.integration.security.channel.SecurityContextPropagationChannelInterceptor"/> 
    </int:channel-interceptor> 

    <task:executor id="pool" pool-size="5"/> 

    <int:poller id="poller" default="true" fixed-rate="1000"/> 

    <int-security:secured-channels> 
    <int-security:access-policy pattern="user*" send-access="ROLE_USER" /> 
    <int-security:access-policy pattern="admin*" send-access="ROLE_ADMIN" /> 
    </int-security:secured-channels> 

    <int-http:inbound-channel-adapter path="/user*" supported-methods="GET, POST" channel="userRequestChannel" /> 

    <int:channel id="userRequestChannel"> 
    <int:queue/> 
    </int:channel> 

    <int-http:outbound-channel-adapter url="http://localhost:8080/prototype-integration-security-service/query?ticket={ticket}" 
            http-method="GET" 
            rest-template="restTemplate" 
            channel="userRequestChannel"> 
    <int-http:uri-variable name="ticket" expression="T(org.springframework.security.core.context.SecurityContextHolder).context.authentication.credentials"/> 
    </int-http:outbound-channel-adapter> 

    <int-http:inbound-channel-adapter path="/admin/callback*" 
            supported-methods="GET, POST" 
            channel="adminRequestChannel" /> 

    <int:channel id="adminRequestChannel"> 
    <int:queue/> 
    </int:channel> 

    <int:logging-channel-adapter id="logging" channel="adminRequestChannel" level="DEBUG" /> 
</beans> 

サービスモジュールのコンテキスト構成ファイルでは、dispatcher-servlet.xmlは次のようになります。

追加のコードは必要ありません。このため、私はSpring Integrationが好きです。私は間違ったことをしたのか、いくつかの構成を逃したのかあなたのアイデア、意見、提案を共有してください。前もって感謝します。

答えて

0

私は以前はCASを使ったことがありませんでしたが、どうすればheaders.serviceTicketが得られるかを分かち合っているようです。

私はあなたのURLのparam経由 ticketを伝播するアイデアは良いが、私たちが入ってくるURLからそれを抽出する必要があり、すべての最初のだと思う

ログインに成功すると、CASはバックに、ユーザーのブラウザをリダイレクトします元のサービス。また、「サービスチケット」を表す不透明な文字列であるチケットパラメータも含まれます。前述の例を続けると、ブラウザがリダイレクトされるURLはhttps://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZとなる可能性があります。我々はこのように行うことができます。この目的のために

http://docs.spring.io/spring-security/site/docs/4.2.0.RELEASE/reference/htmlsingle/#cas

<int-http:inbound-channel-adapter path="/user*" supported-methods="GET, POST" channel="userRequestChannel"> 
     <int-http:header name="serviceTicket" expression="#requestParams.ticket"/> 
</int-http:inbound-channel-adapter> 

そうでない場合は、問題の共有例外とはギャップを決定するために、ネットワークトラフィックをトレースしてみてください。

UPDATE

CASのためにその春のセキュリティページの説明によると、私たちは持っている:

を...我々は<int-http:inbound-channel-adapter>で要求のparamを心配する必要があり、ちょうどSecurityContextに依存しないように元本の資格情報は、サービスチケット不透明値になりながら、CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIERに等しくなります...

だから、見えます<int-http:outbound-gateway>

<int-http:uri-variable name="ticket" 
     expression="T(org.springframework.security.core.context.SecurityContextHolder).context.authentication.credentials"/> 
+0

ありがとうございます。私は以下のようにしてみましたが、運がなければチケットはMultipleValueMapの公開ではないとの例外がありました。これはチケットのキーと値のペアがないことを意味します。

+0

私の答えで更新を見つけてください。 –

+0

こんにちは、Artem、あなたの提案に感謝し、SecurityContextHolderからService Ticketを入手できるようになりました。しかしそれはまだ動作しません、私のアクセスは403エラーによって拒否されます。バックエンドサービスは、Webモジュールの元のoutbound-channel-adapterを置き換えるoutbound-gatewayの 'transfer-cookie =" true "'を設定することによって、cookieを転送しようとしていますが、チケットをまったく検証しないようです。 –

関連する問題