Spring Boot and Keycoak redirect loop, followed by 400 and "no state cookie" - spring-boot

This is driving me absolutely insane.
I'm trying to set up the most basic authentication with Spring Boot and Keycloak. Everything works fine until I actually log in through the realm login screen. I get redirected back to the secured location, and then back to keycloak auth page, and back to secured location (as I'm already authenticated). At the end I get to 400 page and see the following warning in my log:
2020-06-08 15:36:38.646 WARN 12028 --- [io-8080-exec-10] o.k.adapters.OAuthRequestAuthenticator : No state cookie
Sometimes I get err_to_many_redirects.
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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>sso-demo</groupId>
<artifactId>sso-demo-app1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.boot.version>2.3.0.RELEASE</spring.boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>10.0.1</version>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>10.0.1</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>
application.properties:
keycloak.auth-server-url=http://keycloakserver/auth
keycloak.realm=Realm Name
keycloak.public-client=true
keycloak.resource=demo-login-app
keycloak.ssl-required=external
keycloak.securityConstraints[0].authRoles[0]=test-user-role
keycloak.securityConstraints[0].securityCollections[0].patterns[0]=/secured
server.port=8080
Config:
#Configuration
public class KeycloakConfig {
#Bean
public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
Controller:
#Controller
#RequestMapping("/secured")
public class MainController {
#GetMapping
public String mainController(HttpServletRequest request, HttpServletResponse httpServletResponse, Model model) {
return "secured.html";
}
}

I was having this problem due to the realm name being configured incorrectly.
First I named my realm "Main Realm Name". I think the problem here were the spaces.
The second time when I tested on the master realm, I had specified "Master" as opposed to "master" in the application properties file.
configuring the realm name to "MainRealmName" fixed the issue

Related

Tomcat redirects all post request to get

I have issue with tomcat 9.0.50.
I have a basic Springboot application to deploy and all my post requests are actually redirected to GET request.
here is my Main class:
#SpringBootApplication
public class WsApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(WsApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WsApplication.class);
}
}
Here i simply extend my class with SpringBootServletInitializer and I added the configure method.
Second point: I created a GET and a POST request in a controller.
#RestController
#RequestMapping("/")
public class AppController {
#GetMapping
public String hello() {
return "Hello";
}
#PostMapping
public String helloName(#RequestBody String name) {
return "Hello " + name;
}
}
I also have my pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>ws-application</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ws-facturx</name>
<description>ws-facturx</description>
<packaging>war</packaging>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</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>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
In my application.prpperties I configured SQL and application name:
# ws-application
spring.application.name=ws-application
# postgresql
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL81Dialect
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL81Dialect
It should normally work correctly. I can send GET request to my base URL and do retrieve the expected response. When I send a POST request, i obtain a 302 response. I created a dummy application to check if issue was coming from the application.
I tried the call using postman and with a curl request:
curl -i -X POST -H "Content-Type: text/plain" -d "John" http://localhost:8080/ws-application
Is there any issue with tomcat or Springboot ? The java version used is provided in jdk-11.0.6
I don't really know "why" I have been able to solve this issue but here is the "how".
#Slf4j
#RestController
#RequestMapping("/api")
public class FacturxController {
#GetMapping
public String hello() {
return "Hello";
}
#PostMapping
public String helloName(#RequestBody String name) {
log.info("Hello Name");
return "Hello " + name;
}
}
this app has just one controller, but it seems that it required to set a path to the RequestMapping.

NotFound Failure in Spring Integration Test of Health Indicator

I want to write a simple test for a custom HealthIndicator, which is defined in its own module separated from the module of the Spring application.
The HealthIndicator is pretty simple:
#Component
public class MyHealthIndicator implements HealthIndicator {
public Health health() {
return Health.up().withDetail("my-health", "okay").build();
}
}
This is the test:
#WebAppConfiguration
#ContextConfiguration(classes = {TestConfiguration.class, MyHealthIndicator.class})
#ExtendWith(SpringExtension.class)
class MyHealthIndicatorTests {
#Autowired
private MockMvc mockMvc;
#Test
public void healthTest() throws Exception {
mockMvc.perform(get("/management/health")).andExpect(status().isOk());
}
}
And this is the simple Test Configuration:
#Configuration
#EnableWebMvc
#ImportAutoConfiguration(classes = {HealthEndpointAutoConfiguration.class, MockMvcAutoConfiguration.class})
#TestPropertySource(properties = {"debug:true", "management.endpoints.enabled-by-default:true",
"management.endpoints.web.base-path:/management", "management.endpoints.web.exposure.include=health"})
public class TestConfiguration {
}
The test of the health endpoint returns a 404 - Not Found.
In the logs I see that the TestDispatcherServlet has no mapping for the health endpoint:
12:48:38.309 [main] WARN org.springframework.web.servlet.PageNotFound - No mapping for GET /management/health
but why?
In the logs I see also that the HealthEndpoint actually is created:
12:48:38.013 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'healthEndpoint'
But the mapping in the TestDispatcherServlet seems not to be configured. How can I enable the mapping?
Please note: I want to test my Health Indicator without a SpringBootApplication. Isn't that possible at all?
Edit:
Nothing special in the POM:
<?xml version="1.0" encoding="UTF-8"?>
<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.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Looks like a typo in defining the test property source.
Instead of
management.endpoints.web.base-path:/management
management.endpoints.enabled-by-default:true
it should be
management.endpoints.web.base-path=/management
management.endpoints.enabled-by-default=true

spring #controller vs #RestController error whitelabel error

I created a basic Spring MVC project in STS IDE.
When I try to add a controller I add the annotation #Controller and run the spring boot program, I get the following error:-(Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.), but when I add a #RestController the method returns the 'hello' string. Please help me out on how to fix it using #Controller and please let me know why this happened.
Sample code:
package com.adithya.spring.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#Controller
public class ApplicationController {
#RequestMapping("/")
public String Hello() {
return "Hello";
}
}
Also, my pom.xml file is as below:
<?xml version="1.0" encoding="UTF-8"?>
<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>com.adithya</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>MyApplication</name>
<description>Login & Reg</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Project directory structure .

Use RouterFunction with embedded Eureka server

I'm having an issue getting a simple web app using Spring Reactive's RouterFunction to work with an embedded Eureka server. I tried a couple of things, including using the old way of annotating #RestController which works fine. Furthermore, I tried to removing the Eureka dependency from the POM file after which the RouterFunction endpoint worked fine.
POM:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<groupId>com.test</groupId>
<artifactId>tds</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--SPRING-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
Router, that does not get hit:
#Configuration
public class Router {
#Bean
public RouterFunction<ServerResponse> route(Handler handler) {
return route(GET("/test"), Handler::handle);
}
}
Controller, that get's hit fine:
#RestController
#ResponseStatus(HttpStatus.OK)
public class controller {
#GetMapping("/discovery")
public String getApplication() {
return "test2222";
}
}
Main:
#SpringBootApplication
#EnableEurekaServer
public class DiscoveryApp {
public static void main(String[] args) {
SpringApplication.run(com.test.tds.DiscoveryApp.class, args);
}
}
As stated above, after removing the dependency to Eureka the RouterFunction endpoint works fine.
Does anyone have an idea how to make this work?
Apparently Webflux is currently not supported by Eureka server. It is suggested to use the old spring-boot-starter-web way.
As future reference:
https://github.com/spring-cloud/spring-cloud-netflix/issues/3108#issuecomment-408262981

Spring boot getting 401 unauthorized status code for simple get request

I am very new to Spring framework. I have created a new Spring Starter Project with following modules: web, mongo, security.
I have created a simple controller
#RestController
#RequestMapping("/users")
public class UserController {
private UserRepository userRepository;
#GetMapping("/all")
public List<User> getAllUsers(){
List<User> users = this.userRepository.findAll();
return users;
}
#PostMapping("/")
public void insert(#RequestBody User user){
this.userRepository.save(user);
}
}
And seeded some raw data to the database. When I make request to this route in Postman, I get the following response:
{
"timestamp": 1511113712858,
"status": 401,
"error": "Unauthorized",
"message": "Full authentication is required to access this resource",
"path": "/users/all"
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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>ngt</groupId>
<artifactId>someArtifact</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>dermaskin</name>
<description>Demo project for Spring Boot with mongodb</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
What is causing the unauthorized response and how to disable it for the /all route? Thanks!
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/users/all").permitAll();
}
}
You need to configure Spring Security, by default all routes all secured for authrorization.
The code above disables security only for "/users/all" URL.
I was getting this error as I included
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
in my pom.xml file.
Just remove it and try again.
You can keep your security dependency but then you have to setup a userid and a password. This can be done by adding the following into your application.properties file located under
src/main/resources
folder
security.user.name=user # Default user name.
security.user.password= # your password here

Resources