How to override default Spring Boot Login page? - spring-boot

I'm totally new with Spring Boot 2 and I have this simple application that I'm trying to run. Unfortunately, each time I run my service, I end up with this login form from Spring Boot. Is there any way I can override this?
I've already tried the solution from this question but it didn't work for me:
How to override Spring Security default configuration in Spring Boot
Here is what I have so far for the code:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Defines the application, supports service registry, circuit breaker
* for Spring Boot application.
*
* #EnableJpaRepositories - add this to enable
*
* #author himanshu sharma
* #since June 2017
*/
#EnableDiscoveryClient
#EnableCircuitBreaker
#EnableHystrixDashboard
#EnableSwagger2
#EnableCaching
#SpringBootApplication
#ImportResource("classpath:service-config.xml")
#ComponentScan(basePackages = "com.manulife.ap.*, io.swagger")
public class Application{
#Autowired
DiscoveryClient discoveryClient;
/**
* Application start point.
* #param args
*/
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
#RequestMapping(value="/greeting", method=RequestMethod.GET)
public String sayHello () {
return "Hello from Spring Boot!";
}
}
--EDIT:#devshawn--
I tried the solution of excluding the SecurityAutoConfiguration.class but I somehow got this error message when I tried to access my endpoint:

I'm assuming you're using Spring Boot 2, as you did not mention which version of Spring you are using. In spring boot 2, you cannot disable the default login via properties files as you could in spring boot 1. There's a few ways of doing this depending on what you're trying to achieve.
Permit All Access, Secure Endpoints Later
Add a class titled SecurityConfig that looks like this:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").permitAll();
}
}
This removes authentication on all endpoints in your service. Later on, you can configure security further via this class.
Remove Security Auto Configuration
When Spring Security is found on the classpath, Spring Boot automatically configures security. You can remove it all together if you don't want it auto configured by changing your #SpringBootApplication annotation.
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class})

Related

Spring Boot Starter GraphQL OPTIONS Pre-Flight request rejected with HTTP 403

I've recently converted a GraphQL API from SpringBoot Web to WebFlux. In the previous version, the #RequestMapping was annotated with #CrossOrigin, which seemed to cover the OPTIONS HTTP verb.
In the new version, I am using the #MutationMapping / #QueryMapping annotations to map the schema to my methods, and responding to them reactively.
The problem is that for some of our frontend's, an OPTIONS preflight is sent and rejected with a 403 by this new implementation.
Is there an annotation or configuration I can enable where this preflight will not be rejected?
I've attempted to use the GraphQlWebFluxAutoConfiguration.GraphQlEndpointCorsConfiguration object however I can't seem to get it configured correctly. Any advice would be much appreciated, as I'm relatively new to the WebFlux stack.
Here's how I solved it - the issue was caused by my local dev environment having tomcat9, and the staging/qa environment I was deploying to having tomcat7 (not supporting WebFlux properly).
Please note that the app.enable-cors is a property defined in my application.properties file - you will need to add this if you are just copying+pasting this code.
I created two configuration classes, overriding both the Mvc and WebFlux Configurer.addCorsMapping(CorsRegistry registry) method. Depending on which auto configuration is loaded, the correct overriden method will be run. Code as follows:
First, the WebFlux version
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
#Configuration
#ConditionalOnProperty(name = "app.enable-cors", havingValue = "true")
public class GraphQLWebFluxConfiguration implements WebFluxConfigurer {
#Override
public void addCorsMappings(CorsRegistry corsRegistry){
corsRegistry.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("*");
}
}
Secondly the MVC version
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
#ConditionalOnProperty(name = "app.enable-cors", havingValue = "true")
public class GraphQLWebMvcConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry corsRegistry){
corsRegistry.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("*");
}
}
I obviously have this disabled for the prod environment, but as a workaround for your QA/local environment it works well.

How to automatically add all Converters to a FormatterRegistry in Spring?

I have a Spring Boot 2.1.6 project that uses Spring's Converters a lot (24 of them). All are annotated as #Component. Now I've added a #EnableWebMvc and have to add them to the FormatterRegistry via registry.addConverter in a WebMvcConfigurer.addFormatters
Can I have Spring find all of them automatically (they are all in the same separate package) and add them or do I have to manually add all 24 of them and change my WebMvcConfigurer every time I add a converter?
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
List<Formatter> formatters;
#Override
public void addFormatters(FormatterRegistry registry) {
formatters.forEach(registry::addFormatter);
}
}
Since you have implemented the Converter interface and also annotated them with #Component, you can get them all by injecting them as a collection. #Autowired List<Converter> converters;

How to serve static resources in Spring boot with #EnableWebMvc

Cracking head over this. The documentation says:
By default Spring Boot will serve static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext.
Minimal example:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#SpringBootApplication
#EnableWebMvc
public class Main {
public static void main(final String[] args) {
SpringApplication.run(Main.class, args);
}
}
And create one directory /src/main/resources/public placing static resources there. When I run the application I only get 404. When I remove #EnableWebMvc resources are served as expected.
Attempted (and failed) remedies
/**
* #see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#addResourceHandlers(org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry)
*/
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/public/**").addResourceLocations("/public/");
}
In the application.properties added:
spring.mvc.static-path-pattern=/**
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
The question
So my question: What do I need to configure to serve static resource when I want to use the #EnableWebMvc annotation?
In the documentation you mentionned, it says :
If you want to take complete control of Spring MVC, you can add your
own #Configuration annotated with #EnableWebMvc.
You should try to use #EnableWebMvc with your configuration instead of your Spring boot application.
There's an example of this in this documentation.
Enabling the MVC Java Config or the MVC XML Namespace
To enable MVC Java config add the annotation #EnableWebMvc to one of
your #Configuration classes:
#Configuration
#EnableWebMvc
public class WebConfig {
}
Also in these examples :
Customizing the Provided Configuration
Conversion and Formatting
I hope this will help you.
You should configure a ViewResolver something like below along with your ResourceHandlers. Check this
#Bean
public InternalResourceViewResolver defaultViewResolver() {
return new InternalResourceViewResolver();
}

Hystrix Dashboard Issue in Spring Boot

I am new to Hystrix Dashboard. I have written sample application with Hystrix.
I want to see the Hystrix chart (command metric stream). But I am getting the below error:
Circuit: Unable to connect to Command Metric Stream
Thread Pools: Loading...
I am using STS with Maven.
Below is the code used:
Simple server microservice application (Spring boot web running in port 8085)
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
#RestController
#SpringBootApplication
public class BookstoreApplication {
#RequestMapping(value = "/recommended")
public String readingList(){
return "Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)";
}
public static void main(String[] args) {
SpringApplication.run(BookstoreApplication.class, args);
}
}
Simple client microservice application (Spring boot web running in port 8095) I have included the dependency of Hystrix and Hystrix Dashboard along with Web, so all the Hystrix dependencies are in classpath
package hello;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
#Service
public class BookService {
private final RestTemplate restTemplate;
public BookService(RestTemplate rest) {
this.restTemplate = rest;
}
#HystrixCommand(fallbackMethod = "reliable")
public String readingList() {
URI uri = URI.create("http://localhost:8090/recommended");
return this.restTemplate.getForObject(uri, String.class);
}
public String reliable() {
return "Cloud Native Java (O'Reilly)";
}
}
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.web.client.RestTemplate;
#EnableHystrixDashboard
#EnableHystrix
#EnableCircuitBreaker
#RestController
#SpringBootApplication
public class ReadingApplication {
#Autowired
private BookService bookService;
#Bean
public RestTemplate rest(RestTemplateBuilder builder) {
return builder.build();
}
#RequestMapping("/to-read")
public String toRead() {
return bookService.readingList();
}
public static void main(String[] args) {
SpringApplication.run(ReadingApplication.class, args);
}
}
By running the above code, the hystrix is working fine, when the BooKStoreApplication is down, it is going to fallback method.
Both the urls are working fine.
Normal Case:
http://localhost:8085/recommended
Output: Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)
http://localhost:8095/to-read
Output: Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)
When BookStoreApplication is down (http://localhost:8085/recommended) accessing http://localhost:8095/to-read returns "Cloud Native Java (O'Reilly)" as expected.
But when I tried to invoke this url http://localhost:8095/hystrix, I am getting the Hystrix DashBoard Page and asking for the stream value.
I have tried given http://localhost:8095/ or http://localhost:8095/to-read, and clicked "Monitor Stream" and it is going to next page with error:
Circuit: Unable to connect to Command Metric Stream
Thread Pools: Loading...
I've experienced the same. The main problem was, that I didn't have the actuator dependency in my maven pom. So I could not get the hystrix stream.
Include the spring-boot-actuator.
Check if localhost:8085/health is running.
Try to enter localhost:8085/hystrix.stream to stream value in Hystrix Dashboard.
Execute the service few times -> the dashboard should show the monitored method/command.

Spring Security LDAP Authentication does not work with Java 8

I am trying to use LDAP Authentication provided by Spring Security. Everything compiles fine. I get the following error on deploying the application.
Caused by: java.lang.RuntimeException: Could not postProcess org.springframework.security.ldap.server.ApacheDSContainer#54a76efa of type class org.springframework.security.ldap.server.ApacheDSContainer
at org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor.postProcess(AutowireBeanFactoryObjectPostProcessor.java:70)
at org.springframework.security.config.annotation.SecurityConfigurerAdapter$CompositeObjectPostProcessor.postProcess(SecurityConfigurerAdapter.java:123)
at org.springframework.security.config.annotation.SecurityConfigurerAdapter.postProcess(SecurityConfigurerAdapter.java:82)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer.access$400(LdapAuthenticationProviderConfigurer.java:58)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer$ContextSourceBuilder.build(LdapAuthenticationProviderConfigurer.java:555)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer$ContextSourceBuilder.access$500(LdapAuthenticationProviderConfigurer.java:446)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer.getContextSource(LdapAuthenticationProviderConfigurer.java:606)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer.build(LdapAuthenticationProviderConfigurer.java:76)
Spring Core version is 4.3.2. Spring Security LDAP version is 4.1.1.
My Google research listed a 2013 post which says that the issue is because of incompatibility between Spring Security LDAP and Java 8. The same article said it has been fixed in some Spring Boot version. It does not talk about any fix for non-Spring boot libraries.
Has anybody tried Spring Security LDAP Authentication using Java 8? Please help.
Here's my working config using Java 8 and Spring Security LDAP. We're connecting our Spring Web app to an Active Directory instance to secure access by URL.
If I recall correctly, it took longer than I expected to get this working.
You'll need to change the "Base" for the LDAP context path, and note that the ldap.user is the full LDAP CN, not just a username. You can use and LDAP browser like JXplorer (http://jxplorer.org/) to get the LDAP settings correct.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(SecurityConfig.class);
#Value("ldap://${ldap.host}:${ldap.port:389}")
private String url;
#Value("${ldap.user}")
private String user;
#Value("${ldap.password}")
private String password;
#Override
protected void configure(HttpSecurity http) throws Exception {
LOGGER.info("Configuring security...");
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/index.html").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userSearchFilter("(&(objectClass=user)(sAMAccountName={0}))")
.contextSource(ldapContextSource());
}
#Bean
public BaseLdapPathContextSource ldapContextSource() {
LOGGER.info("LDAP: {}", url);
LdapContextSource bean = new LdapContextSource();
bean.setUrl(url);
bean.setBase("DC=CORP,DC=MyCompany,DC=com");
bean.setUserDn(user);
bean.setPassword(password);
bean.setPooled(true);
bean.setReferral("follow");
return bean;
}
}
This assumes you have your LDAP settings in a configuration file that looks something like this
ldap.host=ldap.mycompany.com
ldap.user=CN=MyUser,OU=Service Accounts,OU=New-York,DC=CORP,DC=MyCompany,DC=com
# Encrypt using Jasypt or something
ldap.password=B1gS3cr3t

Resources