Uploaded image for project: 'Spring Data Redis'
  1. Spring Data Redis
  2. DATAREDIS-1142

"CROSSSLOT Keys in request don't hash to the same slot" error using Spring Data along with Spring Session while OAuth2 login process

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.2.7 (Moore SR7)
    • Component/s: Lettuce Driver
    • Labels:
      None
    • Environment:
      JVM: openjdk-11.0.1
      Spring Boot 2.2.6.RELEASE
      Spring Cloud Hoxton.SR4

      Description

      Hi,

      I'm trying to implement an OAuth2 login (authorization code grant type) on my Spring Cloud Gateway and Spring Security based application, storing Http Sessions on Redis.

      Since Spring Cloud Gateway is based on Reactor, I use

      @EnableRedisWebSession

       

      to enable all default configurations.

      If I use a standalone Redis service, everything work fine: I can login and see my session on Redis.

       

      When I switch to a Redis Cluster (3 masters, 3 slaves, no Sentinel), I'm facing this error:

      CROSSSLOT Keys in request don't hash to the same slot

      when I receive the callback from the Identity Provider, exactly when authentication was successfully and Spring Session tries to store session on Redis.

      This is my configuration:

      application.yml (fragment)

       

      spring:
        application:
          name: @project.artifactId@
      
        session:
          store-type: redis
      
        redis:
          cluster:
            nodes: localhost:7000

       

       

      pom.xml

       

      <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
         <modelVersion>4.0.0</modelVersion>
         <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.6.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
         </parent>
         <groupId>com.myapp</groupId>
         <artifactId>website-api-gateway</artifactId>
         <version>0.0.1-SNAPSHOT</version>
         <name>website-api-gateway</name>
         <description>API Gateway for Ducati.com website APIs</description>
      
         <properties>
            <java.version>11</java.version>
            <spring-cloud.version>Hoxton.SR4</spring-cloud.version>
         </properties>
      
         <dependencies>
            <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
               <groupId>org.springframework.cloud</groupId>
               <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
            <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
               <groupId>org.springframework.session</groupId>
               <artifactId>spring-session-data-redis</artifactId>
            </dependency>
            <dependency>
               <groupId>org.springframework.security</groupId>
               <artifactId>spring-security-oauth2-client</artifactId>
            </dependency>
            <dependency>
               <groupId>org.springframework.security</groupId>
               <artifactId>spring-security-oauth2-jose</artifactId>
            </dependency>
      
            <dependency>
               <groupId>org.projectlombok</groupId>
               <artifactId>lombok</artifactId>
               <optional>true</optional>
            </dependency>
            <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-test</artifactId>
               <scope>test</scope>
               <exclusions>
                  <exclusion>
                     <groupId>org.junit.vintage</groupId>
                     <artifactId>junit-vintage-engine</artifactId>
                  </exclusion>
               </exclusions>
            </dependency>
            <dependency>
               <groupId>io.projectreactor</groupId>
               <artifactId>reactor-test</artifactId>
               <scope>test</scope>
            </dependency>
         </dependencies>
      
         <dependencyManagement>
            <dependencies>
               <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-dependencies</artifactId>
                  <version>${spring-cloud.version}</version>
                  <type>pom</type>
                  <scope>import</scope>
               </dependency>
            </dependencies>
         </dependencyManagement>
      
         <build>
            <plugins>
               <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
               </plugin>
            </plugins>
         </build>
      
      </project>

       

      Googling the error, it looks like that this happens when you use a standalone connection interacting with a cluster. Deep debugging the code, it looks like this is the case: ReactiveRedisTemplate is using the standalone connection agains the cluster, despite the factory (LettuceConnectionFactory) contains a cluster connection configured properly.

       

      Do I miss something in the configuration?

       

      I found a dirty workaround so far. ReactiveRedisTemplate class (which is used by the framework as implementation of ReactiveRedisOperations interface), use the connection in the method

      private <T> Publisher<T> doInConnection(ReactiveRedisCallback<T> action, boolean exposeConnection)
      

      at line 191.

      Here the connection is taken by LettuceConnectionFactory at line 198:

       

      ReactiveRedisConnection conn = factory.getReactiveConnection();
      

      The actual implementation of LettuceConnectionFactory#getReactiveConnection returns always a standalone connection and, as far as I can tell, LettuceConnectionFactory#getReactiveClusterConnection is never called.

      The non-reactive implementation LettuceConnectionFactory#getConnection fallbacks to LettuceConnectionFactory#get*Cluster*Connection if isClusterAware() is true: _ I think that _LettuceConnectionFactory#getReactiveConnection should do the same_._

      Since both LettuceConnectionFactory#getReactiveConnection and __ LettuceConnectionFactory#getReactiveClusterConnection return a class that is package private I cannot override that methods.

      As workaround, I reimplemented the factory changing getReactiveConnection implementation with fallback to getReactiveClusterConnection (as the non-reactive counterpart):

      @Override public LettuceReactiveRedisConnection getReactiveConnection() { 
           if (isClusterAware()) { 
               return getReactiveClusterConnection(); 
           } 
           return getShareNativeConnection() ? 
                new LettuceReactiveRedisConnection(getSharedReactiveConnection(),          reactiveConnectionProvider) : 
                new LettuceReactiveRedisConnection(reactiveConnectionProvider); 
      }
      

      This solved my issue: is this the correct fix to the problem? If this is ok, I can try to create a pull request.

       

      Thanks.

       

       

        Attachments

          Activity

            People

            Assignee:
            cstrobl Christoph Strobl
            Reporter:
            acomo Andrea Como
            Last updater:
            Sunny Dhindsa
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: