Spring security login not showing - spring

I'm adding Spring Security on a Spring MVC app; however, when I run the application, the Spring Security default login does not show up (not even when I browse to a link which is supposed to be "secured").
Configuration class (forgive the indentation):
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConf extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("**/secured/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin().permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
}
private PasswordEncoder getPasswordEncoder() {
return new PasswordEncoder() {
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encode(rawPassword).equals(encodedPassword);
}
#Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
};
} }
I also tried adding a custom login, but it does not seem to find the page (which is otherwise reachable):
http.authorizeRequests()
.antMatchers("**/secured/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin().loginPage('/login').permitAll();
Summing up, I need the default Spring Security login page to be displayed first, so I can test the authentication, then I need to be able to add a new login form to be displayed instead. What should I do?
EDIT: I figured out the configuration problem which prevented the Spring login to be displayed. The following tags had to be added in the web.xml file in order to integrate Spring Security with Spring MVC. Now the login is succesfully displayed.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

I figured out the configuration problem which prevented the Spring login to be displayed. The following tags had to be added in the web.xml file in order to integrate Spring Security with Spring MVC. Now the login is succesfully displayed.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Related

Enabling CORS Spring issue with Spring Security

I need to enable CORS for Spring application that uses Spring Security and it is not working. I am making GET request from http://localhost:3000 (which is node.js server) to http://localhost:8080 (which is Tomcat server).
I tried the following approaches but can not make any of them work:
https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
Spring Data Rest and Cors
https://gist.github.com/zeroows/80bbe076d15cb8a4f0ad
Enabling CORS using Spring Boot 1.3.3-RELEASE
Spring CORS controller annotation not working
Currently I have a #Controller:
#Controller
#RequestMapping("/views")
public class LoginController{
#Autowired
private EventService eventService;
#RequestMapping(value = "/companies", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public String listCompanies(Model model) {
String companiesList = eventService.getCompanies();
return companiesList;
}
}
And AppConfig file where I have been unsuccessfully trying to allow CORS:
#EnableWebMvc
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
I want to somehow get the json from the listCompanies method in my Angular2 app. I am getting No 'Access-Control-Allow-Origin' header is present error, so I suppose it is CORS issue.
I had similar problem and fixed it with custom filter as described in documentation: 27.5 Filter based CORS support
Basically, you need to create filter:
public class MyCorsFilter extends CorsFilter {
public MyCorsFilter() {
super(configurationSource());
}
private static UrlBasedCorsConfigurationSource configurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
and then add it in web.xml (or corresponding java based config) before springSecurityFilterChain like this:
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>com.example.configuration.cors.MyCorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I also have dispatchOptionsRequest (which is not necessary according to the new documentation):
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
...
<!-- "OPTIONS" method support -->
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
...
</servlet>
Did you defined somewhere the allowed origines in spring configuration? http://localhost:8080
#EnableWebMvc
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true);
}
}
Look at chapter 27.3 of official docs to enable global CORS configuration :
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html
If you don't need to include cookies on cross-origin request, replace .allowCredentials(true) by .allowCredentials(false)
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Enabling CORS support - Access-Control-Allow-Origin
*
*
* <code>
<!-- Add this to your web.xml to enable "CORS" -->
<filter>
<filter-name>cors</filter-name>
<filter-class>com.elm.mb.rest.filters.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
* </code>
*/
public class CORSFilter extends OncePerRequestFilter {
private static final Log LOG = LogFactory.getLog(CORSFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
LOG.trace("Sending Header....");
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
// response.addHeader("Access-Control-Allow-Headers", "Authorization");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Max-Age", "1");
}
filterChain.doFilter(request, response);
}
}

Spring web security 4 not working on the existing spring project with java based config

I developing spring 4 web project and angularjs app on front-end. I use java based spring security configuration. Now I try implement the Spring web security 4 for the user authorization. I created SecurityConfig class :
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
...
and added import annotation to main spring config class:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.gepick.*")
#EnableTransactionManagement
#Import({ SecurityConfig.class })
public class WebAppConfig extends WebMvcConfigurerAdapter{
...
If I understand well, now when open project on browser spring should redirect me to default spring security login form for authorization (.anyRequest().authenticated()), but in my situation not redirecting, but open web app without authorization form. Why?
Have you added the springSecurityFilterChain in your web.xml?
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

#PreAuthorize annotation in Spring Security doesn't work. Might be misconfigured .xml file

I'm using Spring Security (Spring Boot app) with AngularJS, and I'm trying to allow/deny access to specific mappings based on user's granted authorities.
User.java
public class User implements UserDetails {
...
private String username;
private String password;
private boolean enabled;
private List<GrantedAuthority> grantedAuthorities;
public User(...) {...}
private class Permission implements GrantedAuthority {
String permission;
public Permission(String permission) {
this.permission = permission;
}
#Override
public String getAuthority() {
return permission;
}
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return grantedAuthorities;
}
...
}
Also, I have my own implementation of UserDetailsService (method loadUserByUsername(String username)) which populates user data with data from database.
Previously mentioned mappings are:
#RequestMapping("yes")
public void doesHaveAuthority() {yes();}
#PreAuthorize("hasAuthority('10001')")
private void yes() {}
#RequestMapping("no")
public void doesntHaveAuthority() {no();}
#PreAuthorize("hasAuthority('00000')")
private void no() {}
Where user does have authority "10001", but doesn't have authority "00000", and access to /yes should be allowed, but access to /no shouldn't. Unfortunately, both paths are allowed.
I have spring-security-config as maven dependency as mentioned here.
My WEB-INF/web.xml
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
and WEB-INF/security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<context:component-scan base-package="com.mycompany.project" />
<global-method-security pre-post-annotations="enabled" />
</beans:beans>
So, to summarize: UserDetailsService implementation works (I can login with user credentials and logger prints granted authorities so I know they're there), but user can access both yes and /no paths when in reality he/she shouldn't be able to access /no since he/she doesn't have authority (permission) "00000".
Maybe my xml config is not correct or isn't being read at all.
Thanks for your time
UPDATE As M. Deinum said in comments Spring Boot disregards web.xml and security.xml files. Solution was to modify SecurityConfiguration which extends WebSecurityConfigurerAdapter and add corresponding antMatchers with corresponding authorities.
Example:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and()
.authorizeRequests()
.antMatchers("/login.html", "/index.html", "/").permitAll()
.antMatchers("/yes").hasAuthority("10001")
.antMatchers("/no").hasAuthority("00000")
.anyRequest()
.authenticated().and()
.addFilterAfter(new CSRFHeaderFilter(), CsrfFilter.class)
.csrf().csrfTokenRepository(csrfTokenRepository());
}
User "We are Borg" asked me to post solution as an answer so here it goes:
Basically, since my app is Spring Boot app, it disregarded (ignored my .xml config files). Solution was quite simple: extend WebSecurityConfigurerAdapter and override configure(HttpSecurity) method. When overriding it, make sure that user has authority and/or permission to access path (antMatchers). It should look something like this:
SecurityConfiguration.java
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and()
.authorizeRequests()
.antMatchers("/login.html", "/index.html", "/").permitAll()
.antMatchers("/yes").hasAuthority("10001")
.antMatchers("/no").hasAuthority("00000")
.anyRequest().authenticated();
}
}
And you won't be needing #PreAuthorize annotation anymore, nor will you need .xml config files (security.xml, web.xml, etc...)
Good luck ;)

How to set order for SessionRepositoryFilter?

I am evaluating spring-session with my web application. During the very first request to the web app, multiple httpsession is being created for a single client. After debugging I found that the problem is, the response is committed earlier in the filter chain by ShallowEtagHeaderFilter before reaching SessionRepositoryFilter, so the cookie added to the response is not sent to the client. so, every further ajax request creates a new session, but the session id is not set in the cookie.
I'm trying to move SessionRepositoryFilter after ShallowEtagHeaderFilter. is there a way to do it?
filter config:
#Bean
public SessionRepositoryFilter sessionFilter(RedisOperationsSessionRepository sessionRepository) {
HttpSessionStrategy cookieStrategy = new CookieHttpSessionStrategy();
((CookieHttpSessionStrategy) cookieStrategy).setCookieName("JSESSIONID");
SessionRepositoryFilter sessionRepositoryFilter = new SessionRepositoryFilter(sessionRepository);
sessionRepositoryFilter.setHttpSessionStrategy(cookieStrategy);
return sessionRepositoryFilter;
}
filter is registered by:
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addFilter("sessionFilter", DelegatingFilterProxy.class)
.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
}
As you mentioned in the comment, you can register a filter for any url-pattern using web.xml:
<filter>
<filter-name>sessionFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>sessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Or in a spring way you can do it in the application configuration class, like this:
#Configuration
public class WebAppConfig implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) {
servletContext
.addFilter("sessionFilter", DelegatingFilterProxy.class)
.addMappingForUrlPatterns(null, false, "/*");
}
}

how to configure my application with spring security?

I am new with spring security I tried to read and there is alot of information and I don't know if I am in the right direction.
I have html file that the html element create with JS
lets assume that I have two input fields with ID ( html input fields )
emailInput and passwordInput
and button with ID ( html button )
loginLabel
I added the configuration to pring-security-config
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
</beans>
I added to web.xml
filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
I created Servlet Filer
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.configuration.*;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
How i connect between the fields in the input ( the element are not from tag ) to the SecurityConfig ?
Do I need to create from element or I can do it without it ?
Do I need to create JSP file or is it ok to use html files ?
Step 1: Enable HTTP security.
Step 2: Turn on form login.
Step 3: Set the names of the username and password parameters expected in the login request.
Sample below:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.usernameParameter("emailInput")
.passwordParameter("passwordInput");
}
}

Resources