I'm am trying to set up an application that has an Angular front-end and a Maven/Spring Boot backend and have set up my first REST controller. My issue is that when I send a GET HTTP request to the backend from my Angular IDE it returns an error stating:
"Access to XMLHttpRequest at 'http://localhost:8080/api/getData' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
I'm confused as I have set up the "doFilter" to accept all requests from any origin so it shouldn't be throwing this error. My code follows:
My APIController:
package com.SSCCoursework.controller;
import com.SSCCoursework.Model.SharePrice;
import com.SSCCoursework.Model.Shares;
import com.SSCCoursework.Model.SharesList;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#CrossOrigin (origins = "http://localhost:4200", maxAge = 3600)
#RestController
public class ApiController
{
File Shares_File = new File("Shares_Data.xml");
ArrayList<Shares> shareList = new ArrayList<Shares>();
#RequestMapping(value="/api/getData", produces="application/JSON")
public Object getData()
{
Shares share1 = new Shares();
SharePrice share1_2 = new SharePrice();
share1.setCompanyName("test");
share1.setCompanySymbol("test");
share1.setNumOfShares(123);
Date date = new Date();
share1.setLastShareUpdate(date);
share1_2.setCurrency("dollar");
share1_2.setValue(12345f);
share1.setSharePrice(share1_2);
shareList.add(share1);
SharesList sharelist = new SharesList();
sharelist.setBookList(shareList);
return share1;
}
}
My SimpleCORSFilter:
package com.SSCCoursework.Security;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
#Component
public class SimpleCORSFilter implements Filter
{
#Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, Connection, User-Agent, authorization, sw-useragent, sw-version");
if (req.getMethod().equals("OPTIONS"))
{
res.setStatus(HttpServletResponse.SC_OK);
return;
}
filterChain.doFilter(request, response);
}
#Override
public void destroy()
{
}
}
My Angular code is just trying to use a GET method (this.httpClient.get('http://localhost:8080/api/getData') to print the data to the browser console but the error is preventing it from working. Am I missing a step in my backend?
you can easily define a global cors config just by adding in your main application class where you start your spring boot app
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:8080")
.allowedMethods("PUT", "DELETE", "GET", "POST");
}
};
}
for more details take a look here
Related
I am currently working on a spring boot application, and I've got a handler which takes the HttpServletRequest as an argument.
I was wondering, is it possible to invoke a bean that - provided the session cookie - can return the information of who made the request? (e.g. username)
In the end I found this way to make the code work in the desired way.
package org.my.package;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.csrf.InvalidCsrfTokenException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static org.springframework.security.web.context.HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
#Slf4j
#Configuration
public class CsrfDeniedHandlerConfig {
#AllArgsConstructor
static class CsrfDeniedHandler implements AccessDeniedHandler {
private final AccessDeniedHandler accessDeniedHandler;
#Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
if (accessDeniedException.getClass().equals(InvalidCsrfTokenException.class)) {
SecurityContextImpl securityContext = (SecurityContextImpl) request.getSession().getAttribute(SPRING_SECURITY_CONTEXT_KEY);
User user = (User) securityContext.getAuthentication().getPrincipal();
log.error("Invalid CSRF token request from {}: {}", user.getUsername().toUpperCase(), accessDeniedException.getMessage());
}
accessDeniedHandler.handle(request, response, accessDeniedException);
}
}
#Bean
public AccessDeniedHandler csrfDeniedHandler() {
return new CsrfDeniedHandler(new AccessDeniedHandlerImpl());
}
}
I have a problem with the config about spring-security. So I have made some configuration so far, and I am able to use all API with **GET. But none of the rest API like Delete-PUT-Post.
And for this I am getting an error like below:
The error is 403.
So my configuration is in two classes :
CorsFilter.java
package com.example.rest.webservices.restfulwebservices.basic.auth;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CorsFilter implements Filter
{
#Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException
{
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
// if (request.getMethod().equals("OPTIONS"))
// {
response.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"Content-Type, Authorization, Content-Length, X-Requested-With");
response.addHeader("Access-Control-Allow-Credentials", "true");
// }
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy()
{
}
}
and the second class is :
SpringSecurityConfigurationBasicAuth
package com.example.rest.webservices.restfulwebservices.basic.auth;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.session.SessionManagementFilter;
#Configuration
#EnableWebSecurity
public class SpringSecurityConfigurationBasicAuth extends WebSecurityConfigurerAdapter {
#Bean
CorsFilter corsFilter() {
CorsFilter filter = new CorsFilter();
return filter;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(corsFilter(), SessionManagementFilter.class);
//http.cors();
http .csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
http.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
// .formLogin().and()
.httpBasic();
}
}
My controller is as below:
ItemController
package com.example.rest.webservices.restfulwebservices.todo;
import java.net.URI;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
#CrossOrigin(origins="http://localhost:4200")
#RestController
public class ItemController {
#Autowired
private ItemService itemService;
#GetMapping(path = "/users/{username}/items")
public List<Item> getAllToDosList(#PathVariable String username){
return itemService.findAll(username);
}
#GetMapping(path = "/users/{username}/item/{id}")
public Item getItem(#PathVariable String username, #PathVariable Integer id){
return itemService.findById(id);
}
#PutMapping("/users/{username}/item/{id}")
public ResponseEntity<Item> updateItem(#PathVariable String username,
#PathVariable Integer id, #RequestBody Item item ){
Item updateditem = itemService.saveItem(item);
return new ResponseEntity<Item>(updateditem, HttpStatus.OK);
}
#PostMapping("/users/{username}/item")
public ResponseEntity<Void> addItem(#PathVariable String username, #RequestBody Item item ){
Item createdItem = itemService.saveItem(item);
URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(createdItem.getId()).toUri();
return ResponseEntity.created(uri).build();
}
#DeleteMapping(path = "/users/{username}/item/{id}")
public ResponseEntity<Void> removeToDosFromList(#PathVariable String username,
#PathVariable Integer id){
Item todo = itemService.deleteToDoById(id);
if (todo != null)
{
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
}
And so far this work only for the GET API, Please have a look in the classes, maybe you have more ideas than me, as I have a lack of experience.
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
You are passing OPTIONS method in the argument which is for specifying which method to allow, only OPTIONS type request will be allowed, use GET if you want to allow get requests. If you want to allow all request types just pass "/**" as the argument, with out specifying any method type.
I think the question here is:
do you want to autenticate the user to call some of the paths?
If the answer is no, you should remove this line .anyRequest().authenticated()
if the answer is yes you should specify the urls you want to be authenticated and define the authentication method and make the call with a proper Authorization header
I have edited the question to make more sense. The original was:
How can I fix Angular and Spring Boot configuration with Spring JDBC authentication so that I am able to logout even with CSRF protection enabled?
With CSRF disabled for /logout:
I am able to login (receiving CSRF and JSESSIONID cookies) and logout (200 OK is received) using Postman.
I am able to login (receiving CSRF and JSESSIONID cookies) and logout (200 OK is received) using Firefox and the Angular frontend.
With CSRF enabled for /logout:
I am able to login (receiving CSRF and JSESSIONID cookies) and logout (200 OK is received) using Postman.
I am able to login using Firefox and the Angular frontend.
When trying to log out, however...
There is first a preflight request that succeeds:
Then, I see a request to /logout:
I debugged the backend and it seems Spring is unable to find a matching CSRF token in its TokenRepository. So I end up with a MissingCsrfTokenException and a 403 Forbidden. How can I fix that?
Backend:
SecurityConfiguration:
package org.adventure.configuration;
import org.adventure.security.RESTAuthenticationEntryPoint;
import org.adventure.security.RESTAuthenticationFailureHandler;
import org.adventure.security.RESTAuthenticationSuccessHandler;
import org.adventure.security.RESTLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.JdbcUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
#Autowired
private RESTLogoutSuccessHandler restLogoutSuccessHandler;
#Autowired
private DataSource dataSource;
#Autowired
private AccountsProperties accountsProperties;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests().antMatchers("/h2-console/**")
.permitAll();
httpSecurity.authorizeRequests().antMatchers("/secure/**").authenticated();
httpSecurity.cors().configurationSource(corsConfigurationSource());
httpSecurity.csrf()
.ignoringAntMatchers("/h2-console/**")
.ignoringAntMatchers("/login")
//.ignoringAntMatchers("/logout")
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
httpSecurity.headers()
.frameOptions()
.sameOrigin();
httpSecurity.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
httpSecurity.formLogin().successHandler(authenticationSuccessHandler);
httpSecurity.formLogin().failureHandler(authenticationFailureHandler);
httpSecurity.logout().logoutSuccessHandler(restLogoutSuccessHandler);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
JdbcUserDetailsManagerConfigurer jdbcUserDetailsManagerConfigurer = auth.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema();
if (Objects.nonNull(accountsProperties)) {
FirstUser firstUser = accountsProperties.getFirstUser();
if (Objects.nonNull(firstUser)) {
String name = firstUser.getName();
String password = firstUser.getPassword();
if (Objects.nonNull(name) && Objects.nonNull(password) &&
!("".equals(name) || "".equals(password))) {
jdbcUserDetailsManagerConfigurer.withUser(User.withUsername(name)
.password(passwordEncoder().encode(password))
.roles("USER"));
}
}
FirstAdmin firstAdmin = accountsProperties.getFirstAdmin();
if (Objects.nonNull(firstAdmin)) {
String name = firstAdmin.getName();
String password = firstAdmin.getPassword();
if (Objects.nonNull(name) && Objects.nonNull(password) &&
!("".equals(name) || "".equals(password))) {
jdbcUserDetailsManagerConfigurer.withUser(User.withUsername(name)
.password(passwordEncoder().encode(password))
.roles("ADMIN"));
}
}
}
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // Strength increased as per OWASP Password Storage Cheat Sheet
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
configuration.setAllowedHeaders(List.of("X-XSRF-TOKEN", "Content-Type"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
source.registerCorsConfiguration("/secure/classifieds", configuration);
source.registerCorsConfiguration("/login", configuration);
source.registerCorsConfiguration("/logout", configuration);
return source;
}
}
RESTAuthenticationEntryPoint:
package org.adventure.security;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class RESTAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
RESTAuthenticationFailureHandler
package org.adventure.security;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class RESTAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
super.onAuthenticationFailure(request, response, exception);
}
}
RESTAuthenticationSuccessHandler
package org.adventure.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#Component
public class RESTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
clearAuthenticationAttributes(request);
}
}
RESTLogoutSuccessHandler
package org.adventure.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#Component
public class RESTLogoutSuccessHandler implements LogoutSuccessHandler {
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
response.setStatus(HttpServletResponse.SC_OK);
}
}
Frontend:
To /login and /logout I make POST requests with withCredentials: true, and have a HttpInterceptor configured:
import { Injectable } from '#angular/core';
import { HttpInterceptor, HttpXsrfTokenExtractor, HttpRequest, HttpHandler, HttpEvent } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable()
export class XsrfInterceptor implements HttpInterceptor {
constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let requestToForward = req;
let token = this.tokenExtractor.getToken() as string;
if (token !== null) {
requestToForward = req.clone({ setHeaders: { "X-XSRF-TOKEN": token } });
}
return next.handle(requestToForward);
}
}
LogoutService:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class LogoutService {
private url = 'http://localhost:8080/logout';
constructor(private http: HttpClient) { }
public logout(): Observable<any> {
return this.http.post(
this.url, { withCredentials: true }).pipe(
map(response => {
console.log(response)
})
);
}
}
In HttpClient, the POST method has a little bit different signature than a GET: https://github.com/angular/angular/blob/master/packages/http/src/http.ts
The second parameter is any request body we want to send, not the options, which are the third parameter. So withCredentials: true was simply never set correctly on the actual request.
Changing the call to:
this.http.post(
this.url, null, { withCredentials: true })
fixed the problem.
I need to create "Remember me"-provided REST service. My app should receive JSON with login data, authenticate user and make it possible for app to remember the user. I've written some code snippet with few mocked #RequestMapping's and simple Spring security config, and, however, application authenticates user (because of successfulAuthentication() Filter's method invocation). But when I'm trying to send request to the secured url even after login action, it returns 401 code. I know, this is quite obvious that new request creates a new session, but is there any way to perform "remember me" behaviour without sending login info in each Request's body? Here is some of my code:
package com.checkpoint.aimer.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
public class RestSecurityFilter extends AbstractAuthenticationProcessingFilter{
public RestSecurityFilter(String url, AuthenticationManager m) {
super(url);
this.setAuthenticationManager(m);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException,
IOException, ServletException {
HttpSession session = request.getSession();
Authentication auth = this.getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken("roman", "sawawluha"));
SecurityContextHolder.getContext().setAuthentication(auth);
return auth;
}
}
Security configuration:
package com.checkpoint.aimer.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public RestSecurityFilter restSecurity() throws Exception {
RestSecurityFilter filter = new RestSecurityFilter("/auth/login_test", authenticationManagerBean());
return filter;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public UserDetailsService usr() {
return new UserSecurityService();
}
#Override
public void configure(HttpSecurity http) throws Exception{
http
.httpBasic().authenticationEntryPoint(new AuthenticationEntryPoint() {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException arg2) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Oops");
}
}).and()
.addFilterBefore(restSecurity(),BasicAuthenticationFilter.class )
.rememberMe().rememberMeServices(new TokenBasedRememberMeServices("key",usr()) ).and()
.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.antMatchers("/auth/**").anonymous()
.and()
.csrf().disable()
.logout().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth
.userDetailsService(usr());
}
}
Do you have any ideas?
Remember me features are mostly implemented based on cookies. You can store some authentication token into cookie. I believe you can even use Session Cookies for this.
BUT REMEMBER:
You have to use HTTPS all the time
Use HttpOnly cookie attribute all the time
Use Secure cookie attribute all the time
Because cookie is send to client with every request, you need to make sure it's send via secure channel, and not accessible to cross site attacks.
I have this service that I published on my local machine:
http://joediego.dtdns.net:3000/jcsistemas/rest/cliente/all
If I hit afromentioned URL endpoint, I can get a response with my JSON feed. But when I use another host name such as http://localhost:8081, the service responds with below message:
XMLHttpRequest can not load http: // localhost: 8081 / jcsistemas / rest / customer / all. In the 'Access-Control-Allow-Origin "header is present on the requested resource. Origin 'http: // localhost: 9000' is not allowed Therefore access.
Here is what I tried so far to overcome the same origin policy issue:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
//filter
#Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
#Configuration
#EnableWebMvc
#ComponentScan("my..package...... ")
public class WebAppConfig extends WebMvcConfigurerAdapter {
//configureContentNegotiation
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(true).
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("html", MediaType.TEXT_HTML).
mediaType("xml", MediaType.APPLICATION_XML);
}
}
AngualarJS Module configuration:
angular.module('my_module').config(['$routeProvider','$httpProvider',function($routeProvider,$httpProvider) {
//how configure headers here??
}]);
}());
I managed to solve my problem by removing #Component SimpleCorsFilter and adding getServletFilters() method in a WebApplicationInitializer subclass. For to those who use a Java-based application configuration, here down the component declaration:
public MyWebApplicationInitializer implements WebApplicationInitializer
{
# Override
protected Filter[] getServletFilters()
{
return new Filter[] {new MyFilter()}; // MyFilter refers to the filter needed class
}
}