javax.servlet.ServletException: Circular view path [login] - spring

I am new to Spring Boot and want to add the Spring Security module to my previous project. I followed this link. My Spring Boot version is 1.5.6.RELEASE.
Here is the security configuration
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
Here is the MVC configuration:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
I can ensure that home.html, hello.html and login.html are located in resources/templates/. As I added the Spring Security part to a previous project, I also has an controller that handles jpa request
#Controller
#RequestMapping("/test/pgsql")
public class TestPostgreSQLController {
#Autowired
private CustomerRepository customerRepository;
#RequestMapping("/save")
public #ResponseBody
String process() {
customerRepository.save(new Customer("Neo", "Chan"));
customerRepository.save(new Customer("Luke", "Liu"));
customerRepository.save(new Customer("Ran", "Guo"));
customerRepository.save(new Customer("Joey", "Chen"));
customerRepository.save(new Customer("Larry", "Huang"));
return "Done";
}
#RequestMapping("/findbyid")
public #ResponseBody String findById(#RequestParam("id") long id) {
String result = "";
result = customerRepository.findOne(id).toString();
return result;
}
#RequestMapping("/find")
public #ResponseBody String find(#RequestParam("lastname") String lastName) {
String results = "";
for (Customer bauer : customerRepository.findCustomersByLastName(lastName)) {
System.out.println(bauer.toString());
results = results + bauer.toString() + "<br>";
}
return results;
}
}
the pom.xml is like this
<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.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
I build the project as jar package. When I visit the localhost:8080/home or localhost:8080/login address. It throws the following exception:
javax.servlet.ServletException: Circular view path [login]: would dispatch back to the current handler URL [/login] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
Any suggestion? Thanks in advance.

I had the same problem. Problem is related with pom file, you should add Thymeleaf dependency and code will start works.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

It's long time after this question been asked but I found the answer here]
try to add registry.addViewController("/login").setViewName("login.html");
that work for me hope it helps1

Related

new Authorization Server Custom Login Page

I am using new Spring Authorization Server
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.2.3</version>
</dependency>
I wan to configure custom login page. I have two beans configured
AuthorizationServerConfig.java
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.cors(Customizer.withDefaults())
.formLogin()
.and().build();
}
SecurityConfig.java
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.authorizeRequests(authorizeRequests ->
authorizeRequests.mvcMatchers("/custom-login", "/css/**", "/js**", "/image/**").permitAll().anyRequest().authenticated()
)
.formLogin()
.loginPage("/custom-login").failureForwardUrl("/custom-login?error");
return http.build();
}
Whenever User enter incorrect credentials is not being directed to /custom-login?error
He is directed to /custom-login
I seems .failureForwardUrl("/custom-login?error"); is not working
If don't use custom login page user is being directed to /login?error=some-error
Can someone help to solve this problem?
I solved the problem.
I changed the configuration to
AuthorizationServerCOnfig.java
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http
.cors(Customizer.withDefaults())
.formLogin().loginPage("/custom-login").failureForwardUrl("/custom-login?error=true")
.and()
.build();
}
SecurityConfig.java
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.formLogin().failureForwardUrl("/custom-login")
return http.build();
}
I added LoginController.java to handle custom-login redirects.
#Controller
public class LoginController {
#GetMapping("/custom-login")
public String login() {
return "login";
}
#PostMapping("/custom-login")
public String loginFailed() {
return "redirect:/authenticate?error=invalid username or password";
}
}
If you don't specify those end points. you will be redirected to /login
Also I had both
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
And
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.2.3</version>
</dependency>
My service was both authorization server and resource server at the same time.
So I removed
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
And every thing works expectedly

Unable to make swagger doc ui/api public in spring boot security

I am trying to add swagger to my existing application. I have added the following dependencies :
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Now the API /swagger-ui/ and /v2/api-docs is working fine. I am developing the application in REST API. The API's are working fine from POST man when i am sending JWT Token with them. They are not working in browser.
To make them working in browser, i have added the URL's in spring security permit all. But it is still not working in browser.
Spring Security Config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(
.............
"/v2/api-docs",
"/swagger-ui.html")
.permitAll().anyRequest().authenticated().and().addFilter(getAuthenticationFilter())
.addFilter(new AuthorizationFilter(authenticationManager())).sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().cors();
}
How can i make those API's public?
try using security config
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] AUTH_WHITELIST = {
"/healthz"
};
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(AUTH_WHITELIST);
}
}
You need to make public more urls than just those two.
Springfox documentation states to allow the following urls
.antMatchers(
HttpMethod.GET,
"/v2/api-docs",
"/swagger-resources/**",
"/swagger-ui.html**",
"/webjars/**",
"favicon.ico"
).permitAll()
or to ignore them:
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/v2/api-docs",
"/swagger-resources/**",
"/swagger-ui.html**",
"/webjars/**");
}
}
source: https://springfox.github.io/springfox/docs/current/

Spring security doest not restrict access

I have Spring MVC project and try to add security. My problem is that spring doesn't deny access to pages. I mean if I go to /product page, it will open. I have the following security config:
#Configuration
#EnableWebSecurity
public class SecureConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("a").password("1")
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated();
http.csrf().disable();
}
}
At first, I thought, these methods are not executed by spring context, but then I found that they are executed.
if I understand correctly, this configuration should deny access to all pages, but the opposite happens, I can go to any page (/, /product, /test pages)
My security dependencies:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.4.0</version>
</dependency>
Application class:
public class Application implements WebApplicationInitializer {
Logger logger = LoggerFactory.getLogger(Application.class);
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebConf.class, SecureConfig.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
dispatcher.addMapping("/*");
dispatcher.setLoadOnStartup(1);
}
}
I solved this problem by adding the following class:
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
SpringSecurityFilterChain did not work without this class, that's why security didn't work.

Spring Keycloak Bearer only

Iam developing a angular webapp which is connected to a java (spring framework) backend. Authentication is done via a keycloak server.
On my local machine with the embedded tomcat server the angular application and the spring application runs without errors.
For deployment i need to use the old fashioned way by using an existing tomcat server.
The angular frontend is available in the ROOT directory via http://myurl/
The spring backend is placed as war file and reachable via http://myurl/api/
Everything works on the server except the authentication part.
Angular app is able to login via redirect etc. and gets an access token.
This token is transmitted on a request to the spring backend.
But the backend return a not authorized message.
Any help is apriciated!
Message is:
Unable to authenticate using the Authorization header
I have created a SecurityConfig class:
#Configuration
#EnableWebSecurity
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(
AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider
= keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/*")
.authenticated()
.anyRequest()
.permitAll();
}
}
Added this line to the application properties
keycloak
keycloak.auth-server-url=https://authserver.net/auth
keycloak.realm=myRealm keycloak.bearer-only=true
keycloak.resource=myclient
keycloak.cors=true
And added this dependancies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>3.3.0.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Disabling the csrf token solved this issue.
Example:
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/*")
.authenticated()
.anyRequest()

Vaadin 7 + Spring security configuration

I'm trying to configure Spring Security + Vaadin4Spring together with my Vaadin 7 application.
I have following code:
pom.xml security related dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.vaadin.spring</groupId>
<artifactId>spring-vaadin-security</artifactId>
<version>0.0.3-SNAPSHOT</version>
</dependency>
My MainUI class definition:
#VaadinUI
public class MainUI extends UI {
and Application class
#PropertySource(value = "classpath:application.properties")
#EnableAutoConfiguration
#ComponentScan
#EnableGlobalMethodSecurity
public class Application extends GlobalMethodSecurityConfiguration {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("password").roles("ADMIN");
}
}
Right now when I'm trying to access http://localhost:8080/ I have following error message:
HTTP ERROR 404
Problem accessing /error. Reason:Request was not handled by any registered handler.Powered by Jetty://
What I'm doing wrong ? Please help me, I'm stuck on this the second day Without Spring security my application works perfectly, but without security it's doesn't have a big sense.. Thanks!
Solved at the vaadin4spring github: https://github.com/peholmst/vaadin4spring/issues/78

Resources