Unable to send Post Request with SpringBoot - java

I´m tring to make a post request, according the code below:
String url = new StringBuilder().append("https://...").toString();
Map<String, Map<String, String>> body = buildBotBody(email,message);
restTemplate.postForEntity(url, body, Void.class);
This request don´t needs authentication, it don´t needs login and password. At the Postman I can make the request with success, but when I try to execute the code above, I got:
401 Unauthorized
I got simulate the error at the Postman and it gave me the message below:
"message": "The request has both SAS authentication scheme and 'Basic' authorization scheme. Only one scheme should be used."
When I changed the authentication method to "No Auth" at Postman, the request worked fine.
I think I have to set this option "No Auth" at the code, but I don´t know how.
I made this way:
private HttpEntity<?> builderHeadersToBuildBotBody(String email, StringBuilder message) {
Map<String, String> map = new HashMap<String, String>();
map.put("emailadress", email);
map.put("emailSubject", "Pendência para lançamento de horas do Jira");
map.put("emailBody", message.toString());
return builderHeaders(map);
}
private HttpEntity<?> builderHeaders(Map<String, String> map) {
HttpHeaders requestHeaders = new HttpHeaders();
//requestHeaders.setAccept(Collections.singletonList(new MediaType("application", "json")));
requestHeaders.setContentType(new MediaType("application", "json"));
//requestHeaders.set(HttpHeaders.USER_AGENT, "");
return new HttpEntity<>(requestHeaders);
}
private void sendBotMessage(StringBuilder message, String nome, String email) throws Exception{
try {
String url = new StringBuilder().append("https://prod-12.westeurope.logic.azure.com:443/workflows/fbf4c29cbcad4679b1a1159fff7b07f9/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=zxm46aQnBj3ZTKPOddnnwUgtQZoQcQfixNtXVxAJjPg").toString();
HttpEntity<?> requestEntity = builderHeadersToBuildBotBody(email,message);
restTemplate.exchange(url, HttpMethod.POST, requestEntity, Void.class);
logger.info("Bot enviado com sucesso! " + nome);
} catch (Exception e) {
logger.error("Erro ao enviar Bot.", e);
throw e;
}
}
But the error continues.

If Spring Security is on your classpath you may need to disable authentication. This is done by creating a #Configuration class which extends the WebSecurityConfigurerAdaptor
#Configuration
public class NoSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests().anyRequest().permitAll()
.and()
.csrf().disable();
}
}
Obviously this is something you would not want to do in production but can be useful in dev environments.

<?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.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>br.com.oss.jira.quality</groupId>
<artifactId>jira-quality</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jira-quality</name>
<description>Gerenciador de inconsistências no Jira</description>
<properties>
<java.version>1.8</java.version>
<lombok.version>1.18.6</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- <dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- Exclude the default Jackson dependency -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>desenv</id>
<properties>
<activatedProperties>desenv</activatedProperties>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<activatedProperties>prod</activatedProperties>
</properties>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>

The endpoint requires authorization and you should provide it with the request (credentials, token, etc.). Clean the cookies on Postman and I guess it’ll stop working too.

Related

java.lang.NoSuchMethodError when using spring-social-twitter

I try using Twitter API via Spring library spring-social-twitter. However I'm when calling sendDirectMessage(String toScreenName, String text) function I get the following exception:
java.lang.NoSuchMethodError: 'org.springframework.http.HttpStatus org.springframework.http.client.ClientHttpResponse.getStatusCode()'
at org.springframework.social.twitter.api.impl.TwitterErrorHandler.handleError(TwitterErrorHandler.java:56) ~[spring-social-twitter-1.1.0.RELEASE.jar:1.1.0.RELEASE]
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) ~[spring-web-6.0.4.jar:6.0.4]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:915) ~[spring-web-6.0.4.jar:6.0.4]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:864) ~[spring-web-6.0.4.jar:6.0.4]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:804) ~[spring-web-6.0.4.jar:6.0.4]
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:503) ~[spring-web-6.0.4.jar:6.0.4]
at org.springframework.social.twitter.api.impl.DirectMessageTemplate.sendDirectMessage(DirectMessageTemplate.java:77) ~[spring-social-twitter-1.1.0.RELEASE.jar:1.1.0.RELEASE]
at com.example.twittertest.TwitterController.send(TwitterController.java:17) ~[classes/:na]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) ~[tomcat-embed-core-10.1.5.jar:6.0]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) ~[tomcat-embed-core-10.1.5.jar:6.0]
I have the my TwitterTemplate configured as following:
#Component
public class TwitterTemplateCreator {
public Twitter getTwitterTemplate() {
return new TwitterTemplate(
"<cosumerKey>",
"<consumerSecret>",
"<accessToken>",
"<accessTokenSecret>");
}
}
TwitterController:
#RestController
#RequestMapping(("/api"))
public class TwitterController {
#Autowired
private TwitterTemplateCreator twitterTemplateCreator;
#PostMapping(value = "/send")
public void send(#RequestParam("name") String name, #RequestParam("text") String text) {
twitterTemplateCreator.getTwitterTemplate().directMessageOperations().sendDirectMessage(name, text);
}
}
And finally 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>3.0.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>twitter-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>twitter-test</name>
<description>twitter-test</description>
<properties>
<java.version>17</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-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-twitter</artifactId>
<version>1.1.0.RELEASE</version>
</dependency>
</dependencies>
<build>
<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>
My guess is that there is inconsistency with dependencies versions but after trying different Spring Boot versions I still can't figure out what causes this issue.
Your guess is correct. Spring Social Twitter is no longer maintained. The last release, 1.1.2.RELEASE, was made in October 2015 and it depends on Spring Framework 4. Spring Boot 1.x is based on Spring Framework 4.x but it has been out of support since 2019.
I would recommend that you find an alternative to Spring Social Twitter. The alternative would be to use it with Spring Boot 1.x but then you will be using unsupported software for which bug fixes won't be available. Even if you're happy to take that risk, there's also a good chance that Spring Social Twitter isn't compatible with the current version of Twitter's API.
Solved by defining my own OAuth1 Rest Template using spring-social.
First included following dependencies:
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-core</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-web</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-security</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
Then create new temlate which extends AbstractOAuth1ApiBinding:
public class TwitterTemplate extends AbstractOAuth1ApiBinding {
public static final String TWITTER_API = "https://api.twitter.com/1.1";
public TwitterTemplate(String consumerKey, String consumerSecret, String accessToken,
String accessTokenSecret) {
super(consumerKey, consumerSecret, accessToken, accessTokenSecret);
}
public TwitterUserResponse getUser(String name) {
return getRestTemplate().getForObject(
TWITTER_API + "/users/show.json?screen_name={name}", TwitterUserResponse.class, name);
}
}
Then just instantiate TwitterTemplate and call needed method.

Spring rest template post xml - error No HttpMessageConverter

I have a Spring Boot(2.7.6) rest application that should call a POST endpoint which contains the following request:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<folder>
<created>2022-12-02T10:30:18.673Z</created>
<path>/okm:root/test3</path>
</folder>
In order to call the endpoints I have created the following method:
#SneakyThrows
#GetMapping("/create")
public void post() {
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
body.add("path", "/okm:root/test4");
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT, MediaType.ALL.getType());
headers.setBasicAuth("dummy", "admin");
headers.setContentType(MediaType.APPLICATION_XML);
// Note the body object as first parameter!
HttpEntity<?> httpEntity = new HttpEntity<Object>(body, headers);
ResponseEntity<Folder> response = restTemplate.exchange("http://localhost:8080/OpenKM/services/rest/folder/create", HttpMethod.POST, httpEntity, Folder.class);
System.out.println(response);
}
The pom.xml is as follows:
<?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.7.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.service.openmk</groupId>
<artifactId>openmk-service-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>openmk-service-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<repositories>
<repository>
<id>openkm.com</id>
<name>OpenKM Maven Repository</name>
<url>https://maven.openkm.com</url>
</repository>
</repositories>
<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.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<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>
<dependency>
<groupId>com.openkm</groupId>
<artifactId>sdk4j</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
However when i call the method above the following exception is triggered:
2022-12-02 15:19:37.906 ERROR 14044 --- [nio-8082-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.RestClientException: No HttpMessageConverter for org.springframework.util.LinkedMultiValueMap and content type "application/xml"] with root cause
org.springframework.web.client.RestClientException: No HttpMessageConverter for org.springframework.util.LinkedMultiValueMap and content type "application/xml"
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:1006) ~[spring-web-5.3.24.jar:5.3.24]
Can someone please help me out to fix the above error?
Solution is:
ensure that spring.xml.ignore is true (by default it is true)
you can check in you controller by calling
SpringProperties.getFlag("spring.xml.ignore")
The main problem: there are no any built in impl of HttpMessageConverter for application/xml in spring-web (without additional dependencies). However Spring can parse and build xml body/response using JAXB or jackson lib. For this purpose Spring check 2 classes for availability from ClassLoader:
javax.xml.bind.Binder (impl in jaxb-api) and
com.fasterxml.jackson.databind.ObjectMapper (part of jackson-dataformat-xml)
I prefer to use jackson-dataformat-xml, due to huge developers community of jackson libs. Shortly said solution is to add dependency to pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

Swagger #OpenAPIDefinition not doing anything

so I have a simple Spring Boot REST API that works fine, now I have added some swagger dependencies, both for ui and core, and have done some testing with some tags like #ApiIgnore or #Operation and they both work fine and both are updated in the http://localhost:8080/swagger-ui/#/
Now I am trying to update the API info through the #OpenAPIDefinition tag, something like this in my application class:
#OpenAPIDefinition(
info = #Info(
title = "the title",
version = "0.0",
description = "My API",
license = #License(name = "Apache 2.0", url = "http://foo.bar"),
contact = #Contact(url = "http://gigantic-server.com", name = "Fred", email = "Fred#gigagantic-server.com")))
Now I have read here that the spring boot app should do a class scan and recognize the #OpenAPIDefinition bean and update the generated json in http://localhost:8080/v3/api-docs. But this is not the case, I have also tried setting that info with openapi.yaml files but also no luck.
I suspect this might have to do with my dependencies, as I am new to swagger and still a bit lost and might have mixed something up, I leave my pom.xml here:
<?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.5.4</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>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I am at a bit of a loss on how to continue and don't understand how swagger can recognize the #ApiIgnore tag for example but ignore the #OpenAPIDefinition one. As I said I am new to this whole thing and stackoverflow in general, so please forgive me if I forgot to add any relevant code, thank you!
Try removing some unnecessary dependencies:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
<version>2.1.2</version>
</dependency>
springfox-boot-starter should bring them in already.
If this does not work you can always do the following:
#Configuration
public class SwaggerConfiguration {
#Bean
public OpenAPI openAPI() {
return new OpenAPI()
.info(new Info().title("the title").version("0.0").description("My API")
.contact(new Contact().name("Fred").url("http://gigantic-server.com").email("Fred#gigagantic-server.com")));
}
}
So after a lot of different things I found this guide where it explains how to alter API info, in a nutshell, I added a #Api(tags = "Employee") to my EmployeeController class, then in my Application class added:
#Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(new ApiInfoBuilder()
.title("Employee API")
.description("A CRUD API to demonstrate Springfox 3 integration")
.version("0.0.1-SNAPSHOT")
.license("MIT")
.licenseUrl("https://opensource.org/licenses/MIT")
.build())
.tags(new Tag("Employee", "Endpoints for CRUD operations on employees"))
.select().apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.build();
}
And this appears to solve the issue, I now wonder what would happen if I had multiple controllers, I hope this helps anyone that was in my predicament, the overall issue seemed to be that this is a springfox related way of altering API documentation and the previous ways are swagger-core related? As I said I am new to this world so if anyone could point me out to why it wasn't working it would be amazing, thanks!

Problem hitting REST endpoint in Spring Boot 2.2.0 application

I try to create a Spring Boot REST application with GraphQL and MongoeDB (I start from that article https://medium.com/oril/spring-boot-graphql-mongodb-8733002b728a). The application start but I got 404 error when I try to post something to a endpoint.
I read also that #PostConstruct is not supported anymore with 2.2.0 (it's another problem I'll try to figure out later, I try to preload the database during startup).
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.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tsoai-api</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>
<lombok.version>1.18.10</lombok.version>
<commons-io.version>2.5</commons-io.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-data-mongodb</artifactId>
</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>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphiql-spring-boot-starter</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
My main application file look like this (nothing very special!):
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
MainController.java
#RestController
#RequestMapping(path = "/query")
public class MainController {
private GraphQL graphQL;
private GraphQlUtility graphQlUtility;
#Autowired
MainController(GraphQlUtility graphQlUtility) throws IOException {
this.graphQlUtility = graphQlUtility;
graphQL = graphQlUtility.createGraphQlObject();
}
#PostMapping(path= "/")
public ResponseEntity query(#RequestBody String query){
ExecutionResult result = graphQL.execute(query);
System.out.println("errors: "+result.getErrors());
return ResponseEntity.ok(result.getData());
}
}
When I post on http://localhost:8080/query, I got this error:
{
"timestamp": "2019-10-19T16:10:19.136+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/query"
}
It will match /query/ only but not /query . If you want to match both /query and /query/ , you can just leave path of the #PostMapping in the query method as the default.
#RestController
#RequestMapping(path = "/query")
public class MainController {
#PostMapping
public ResponseEntity query(#RequestBody String query){
}
}
There could be a reason for this error that Spring boot is not scanning this class. Please try to add ComponentScan annotation on Spring boot main class with the package where you keep your controllers as given below.
#ComponentScan(basePackages= {"com.example"})
Check the port on which your Spring Server is running, According to the medium post they have configured it to run on :8000 while you're hitting on :8080.
The error states the same that it cannot find any controller mapped to this api-endpoint.
http://localhost:8000/query/
`

REST end point of Spring Boot application as WAR on tomcat with keycloak is no more secure

I have a spring - boot application with tomcat embedded and I configures my application with keycloak-spring-boot-adapter according to the below link
Spring boot adapter
I packaged my application as Jar and every thing works perfectly. My context root was
localhost:8080/service/api/*
and there was no problem, All end points was secure. Without authentication no one can access the API. Here is the Properties
server.contextPath=/service
keycloak.realm = demo
keycloak.resource = client-apps
keycloak.auth-server-url = http://localhost:8180/auth
keycloak.ssl-required = external
keycloak-bearer-only = true
keycloak.credentials.secret = client-apps
keycloak.public-client = true
keycloak.enabled = true
keycloak.use-resource-role-mappings = true
keycloak.securityConstraints[0].authRoles[0] = admin
keycloak.securityConstraints[0].securityCollections[0].name = Secure Mappings
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /api/*
keycloak.securityConstraints[0].securityCollections[0].patterns[1] = /service/api/*
keycloak.securityConstraints[0].securityCollections[0].patterns[1] = /*/api/*
Now Requirement Changes and we need to deploy the Jar as War on Tomcat. Here is the 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>group</groupId>
<artifactId>service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>${packaging.type}</packaging>
<name>Loan Service</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<junit.version>4.12</junit.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
<!-- <dependency> <groupId>io.github.benas</groupId> <artifactId>random-beans</artifactId>
<version>3.7.0</version> </dependency> -->
<dependency>
<groupId>org.jsondoc</groupId>
<artifactId>jsondoc-core</artifactId>
<version>1.2.19</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>3.4.3.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>
<profile>
<id>jar</id>
<properties>
<packaging.type>jar</packaging.type>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>war</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<packaging.type>war</packaging.type>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- <configuration>
<webResources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
<targetPath>WEB-INF/classes</targetPath>
</resource>
</webResources>
</configuration> -->
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
War is successfully made and After deploying on the tomcat webapps directory , my REST end points are no longer secure. Now the Root context path is same as before
localhost:8080/service/api/*
AS you can see in properties file that which paths needs to be secure. Now I have tried but can't figure out what is the root cause of this?
Can anybody expert in keycloak and spring boot help me that what i ma missing or where i am doing wrong.
Project Structure:
Spring Boot Config:
#SpringBootApplication
public class Application extends SpringBootServletInitializer{
#Autowired
private MessageSource messageSource;
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class)
.properties("spring.config.name=application,master-data")
.run(args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class).properties("spring.config.name=application,master-data");
}
#Bean
#Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public AccessToken getAccessToken() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
return ((KeycloakPrincipal<?>) request.getUserPrincipal()).getKeycloakSecurityContext().getToken();
}
#Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource);
return bean;
}
}
the problem is that your new Root context: host:port/service/api/* doesn't match up with your Rest Endpoints being in /api/ . Does that make sense? You have that extra path [port] in your context. that's what's throwing it off.
My suggestion is to switch to the Spring Security Adapter instead. With this adapter, you can do everything the Spring Boot Adapter does (and much more), in a more flexible way. You only need to write some configuration code.
Related to your question, here you've got one thread that discusses a problem similar to the one of yours, which was brought to a JIRA issue (I can't find the link, though). It is couple of years old, but the KC team member states they haven't even tried that scenario (Spring Boot Adapter + War deployment).

Categories

Resources