Enabling CORS Spring issue with Spring Security - spring

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);
}
}

Related

Spring security login not showing

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>

Jersey #HeaderParam annotation in resource method paramenter not working with servlet filter

In the method in my resource class, I am accepting a request header value
#GET
#Path(value = "/identifiers")
#Produces(MediaType.APPLICATION_JSON)
public Response getXXX (#HeaderParam("Authorization") String authHeader){...}
I also have a servlet filter defined in web.xml for all incoming requests.
The way my application flow works is -
User requests my rest API and sends an Authorization header in request. My servlet filter will intercept the request and validate the Authorization header and for some users, it replaces this Authorization header with a new value.
The request then goes to the resource class and it uses this authorization header and does some action.
For the users whose Authorization header is changed by the filter, I noticed that the authHeader variable still has the original value.
E.g. - User makes a request containing Authorization header with a value "QwErTyUiOp". The servlet filter injects a new Authorization header in the request with a value "aSdFgHjKl". However, authHeader parameter still has "QwErTyUiOp".
When I iterated through the request object in my method, I could see that the request has the new Authorization header values ("aSdFgHjKl") so the filter is doing its job.
Can someone help me understand why is #HeaderParam capturing the header value before servlet filter has processed the request and if there is any way to alter this behavior?
Here is the web.xml from my application -
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>library-api</display-name>
<filter>
<filter-name>libUserFilter</filter-name>
<filter-class>org.rajiv.library.logic.filter.LibraryUserAuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>libUserFilter</filter-name>
<url-pattern>/v1/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Library API App</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>org.rajiv.library.resources</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>AdminServlet</servlet-name>
<servlet-class>org.rajiv.library.admin.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Library API App</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AdminServlet</servlet-name>
<url-pattern>/restricted/*</url-pattern>
</servlet-mapping>
</web-app>
and the filter class is -
public class LibraryUserAuthFilter implements Filter{
#Override
public void destroy() {
LOG.info("{} Destroyed", getClass());
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
IdsRequest idsRequest = IdsRequest.from(httpRequest);
try (LoggingContext context = LoggingContext.create()) {
TokenResolver.INSTANCE
.extractTokenFromHeaderOrCookie(idsRequest)
.map(TokenDigester.INSTANCE::computeTokenDigest)
.ifPresent(digestedToken -> context.put(CustomLoggingContext.SESSION.toString(), digestedToken));
Optional<HttpServletRequest> modifiedRequest = Optional.empty();
try (LoggingContext libAuthContext = LoggingContext.create()) {
libAuthContext.put(CustomLoggingContext.COMPONENT.toString(), SdkComponents.SDK_LIB_AUTH.toString());
LOG.info("Validation started for request to path:{}", httpRequest.getRequestURI().toString());
modifiedRequest = Optional.of(validate(idsRequest));
} catch (IdentityServicesSdkException ex) {
context.put(CustomLoggingContext.INCIDENT_ID.toString(), ex.getIncidentId());
ProblemResponseWriter.INSTANCE.writeStatusAndProblem(idsRequest, httpResponse, ex);
LOG.warn("Validation failed: {}", ex.getErrorCode());
}
if(modifiedRequest.isPresent()) {
chain.doFilter(modifiedRequest.get(), servletResponse);
}
}
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
initializeScheme(filterConfig);
initializeHost(filterConfig);
initializePort(filterConfig);
String serviceName = filterConfig.getServletContext().getContextPath().replaceAll("/", "").trim();
if(serviceName.isEmpty()) {
serviceName = Optional
.ofNullable(System.getenv("SERVICE_NAME"))
.orElseGet(() -> "service-name-unavailable");
}
LOG.info("{} Initialized", getClass());
}
private void initializeScheme(FilterConfig filterConfig) {
String initParam = filterConfig.getInitParameter(PROXY_SCHEME_ENVIRONMENT_VARIABLE);
if(Strings.isNullOrEmpty(initParam)) {
initParam = loadAuthNSchemeFromEnvVar();
}
scheme = initParam;
LOG.info("HOST_SCHEME: {}", scheme);
}
private void initializeHost(FilterConfig filterConfig) {
String initParam = filterConfig.getInitParameter(PROXY_HOST_ENVIRONMENT_VARIABLE);
if(Strings.isNullOrEmpty(initParam)) {
initParam = loadAuthNHostFromEnvVar();
}
host = initParam;
LOG.info("HOST: {}", host);
}
private void initializePort(FilterConfig filterConfig) {
String initParam = filterConfig.getInitParameter(PROXY_PORT_ENVIRONMENT_VARIABLE);
Integer parsedInitParam = null;
if(!Strings.isNullOrEmpty(initParam)) {
parsedInitParam = Integer.valueOf(initParam);
}
if(parsedInitParam == null) {
parsedInitParam = loadAuthNPortFromEnvVar();
}
port = parsedInitParam;
LOG.info("HOST_PORT: {}", port);
}
}

Custom spring filter not getting called when web application is accessed or url is hit

Below is my configuration in web.xml and I have one JwtFilter but it is not getting access when rest urls are been called.
web.xml
<web-app
<display-name>Portal Web</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet-spring-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>jwtFilter</filter-name>
<filter-class>com.pingle.lola.authentication.JwtFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>jwtFilter</filter-name>
<url-pattern>/portal/lola/*</url-pattern>
</filter-mapping>
This is my JwtFilter
public class JwtFilter extends GenericFilterBean {
#Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
System.out.println("came here");
final String authHeader = request.getHeader("Authorization");
System.out.println("came here - " + authHeader);
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
System.out.println("should throw");
throw new ServletException("Missing or invalid Authorization header.");
}
final String token = authHeader.substring(7); // The part after "Bearer "
System.out.println("came here" + token);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (final SignatureException e) {
throw new ServletException("Invalid token.");
}
chain.doFilter(req, res);
}
}
and I have controller where basic rest API are confugured. I am trying to check if any URL is hit like localhost:8080/portal/lola/getData .. it should go to JwtFilter and check for authentication token in header of request and if valid pass it on the controller other wise throw error message. Logic is written properly but filter is not called and when I hit above URL, it goes to controller directly without reaching filter.
my spring config.xml
<context:component-scan base-package="com.pingle.lola.controller"/>
<mvc:annotation-driven/>
//Dont know why I created it when its not mapped to any controller :(
<mvc:default-servlet-handler/>
It seems like /portal is name of application context. Filter url-pattern should not contain name of context. This means, that filter url-pattern should be /lola/* without /portal. Try to change filter mapping to:
<filter-mapping>
<filter-name>jwtFilter</filter-name>
<url-pattern>/lola/*</url-pattern>
</filter-mapping>

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