I use spring security and axios to get data , but it seems that the get request can't pass the security check - spring

This is my axios, I use get method and add username&password into request. But I don't know why this can not pass backend check. By the way I'm pretty sure about the url is correct. 😁
axios({
method:'get',
url,
auth: {
username: 'From_Website',
password: 'aycfgz!'
}
}).then((response) =>{
console.log(response.data);
this.myblogs = response.data;
this.len = this.myblogs.length;
}).catch(err =>{
console.log(err);
});
And this is my backend configration code.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception{
authenticationManagerBuilder.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("From_Website")
.password(new BCryptPasswordEncoder().encode("aycfgz!"))
.roles("from_website");
}
}

What error are you getting and where? From the top of my head, you can try adding withCredentials: true config to your request.

Related

CORS header ‘Access-Control-Allow-Origin’ missing with Spring Data REST

I'm trying to solve a CORS issue with spring data rest but seems like the CORS headers are not attached. This is the config I have:
#Component
class DataRestConfig: RepositoryRestConfigurer {
override fun configureRepositoryRestConfiguration(config: RepositoryRestConfiguration?, cors: CorsRegistry?) {
cors?.addMapping("/*")
?.allowedOrigins("*")
?.allowedMethods("GET", "PUT", "DELETE","PATCH","POST","OPTIONS")
}
}
I also had the same issue with other API routes that are out of spring data rest. Here is my WebSecurityConfigurerAdapter
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
open class WebSecurityConfig(private val userDetailsServices: DatabaseUserDetailsServices, private val jwtService: JWTService): WebSecurityConfigurerAdapter() {
#Value("\${auth.jwt.secret}")
private var secret: String = ""
override fun configure(http: HttpSecurity) {
http
.cors().and()
.csrf().disable()
.addFilterAfter(JWTAuthorizationFilter(userDetailsServices, secret, jwtService),UsernamePasswordAuthenticationFilter::class.java)
.authorizeRequests()
.antMatchers(HttpMethod.POST,UserController.LOGIN_URL).permitAll()
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
.anyRequest().authenticated()
}
}
Edit:
Added the full WebSecurityConfigurerAdapter
I noticed that the OPTIONS request gets 403 this is why I've added the antMatchers for OPTIONS method but it did not help.
Here are the response and request headers. There is no response body:
If using Spring MVC you should configure the CORS behavior like so
#Configuration
public class CorsConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS");
}
}
I don't know why the other configs are not taken into account and I don't know if this is considered a good solution but since I only need this on the local environment it is not that important. This is how I got this working:
#Bean
#Profile("local")
open fun corsConfigurationSource(): CorsConfigurationSource{
val cors = UrlBasedCorsConfigurationSource()
val config = CorsConfiguration().applyPermitDefaultValues()
config.addAllowedMethod(HttpMethod.OPTIONS)
config.addAllowedMethod(HttpMethod.POST)
config.addAllowedMethod(HttpMethod.PATCH)
config.addAllowedMethod(HttpMethod.DELETE)
cors.registerCorsConfiguration("/**", config)
return cors
}
You can always have a CorsFilter to modify response headers. Here I have answered how we can have custom CorsFilter in Spring boot - https://stackoverflow.com/a/66882700/3709922. Kindly have a look.

Calls to webservices from Vue.js app are forbidden

I am trying to call some webservices from a Vue.js instance, and I'm facing some issues.
Webservices are made with springboot. After having some CORS troubles, it seemed to work well so far. But now, my POST and PATCH won't work when other (GET, DELETE) work fine.
When calling a POST or PATCH request, I receive a 403 (forbidden) response.
This is the configuration on the server side:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtTokenDecoder jwtTokenDecoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic().disable()
.formLogin().disable()
.logout().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Install the JWT authentication filter
http.addFilterBefore(new JwtAuthenticationFilter(jwtTokenDecoder), BasicAuthenticationFilter.class);
// Authorize only authenticated requests
http.authorizeRequests()
.anyRequest().authenticated();
http.cors();
}
}
And the WebConfig where I accept all calls, whatever the origin or the method
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*");
}
}
And the controller :
#RestController
#RequestMapping("/admin")
#Api("Administration API")
#CrossOrigin(origins = "*")
class AdminController {
#PostMapping("/user")
#PreAuthorize("hasRole('Administrator')")
public User createUser(#RequestBody String userJson,
Authentication authentication) {
EvidenzAuthentication evidenzAuthentication = (EvidenzAuthentication) authentication;
JsonObject dataAsJSON = new JsonParser().parse(userJson).getAsJsonObject();
User u = new User();
u.setFirstName((dataAsJSON.has("firstName") ? dataAsJSON.get("firstName").getAsString() : ""));
u.setLastName((dataAsJSON.has("lastName") ? dataAsJSON.get("lastName").getAsString() : ""));
u.setEmail((dataAsJSON.has("email") ? dataAsJSON.get("email").getAsString() : ""));
u.setProfileId((dataAsJSON.has("profile") ? dataAsJSON.get("profile").getAsString() : ""));
u.setIssuerId(evidenzAuthentication.getIssuerId());
if (userDao.createUser(u).isPresent()) {
return userDao.createUser(u).get();
} else {
return null;
}
}
}
This is an exemple of call on the client side :
axios.post('/admin/user',
{data: "firstName":"Peter","lastName":"Sellers","email":"peter.sellers#party.com","profile":"Reader"},
crossDomain: true,
headers: { 'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
'Authorization': 'Bearer ' + localStorage.getItem('auth_token') }})
.then(response => {
self.submitStatus = "OK";
})
.catch(function (error) {
console.log(error)
});;
I don't understand what is wrong. As I said, only POST and PATCH won't work. GET and DELETE work just fine.
When testing my webservices with PostMan, I don't have any problem either....
The problem came from the call to axios.post.
The second argument for post, put and patch is the data, and the third is the options.
The options were send as data, which wasn't correct, obviously.
The correct way to do it is to create a set of data (either by creating a json string, or by using URLSearchParams) and place it as second argument of post call.
const params = new URLSearchParams();
params.append('firstName', this.currentUser.firstName);
params.append('lastName', this.currentUser.lastName);
params.append('email', this.currentUser.email);
params.append('profile', this.currentUser.profileId);
axios.post('/admin/user',
params,
{headers: {'Authorization': 'Bearer ' + localStorage.getItem('auth_token')}});

Can't access response header (x-auth-token sent by spring session)

I'm using
spring-session-1.3.1
spring-boot-1.5.9
jax-rs for my REST API
I did the following to enable SpringSession
aplication.properties
### Spring Session
spring.session.store-type=jdbc
HttpSessionConfig.java
#Configuration
public class HttpSessionConfig
{
#Bean
public HttpSessionStrategy httpSessionStrategy() {
return new HeaderHttpSessionStrategy();
}
}
Database tables are being created and everything works fine. Now I want to login through my API by calling /login. What I don't understand now is, how do I access the x-auth-token sent by spring session in the response. In the chrome dev tools I can clearly see that the x-auth-token is included in the response header.
But when I try to access the header using angulars httpclient I cant even see it.
this.http.post(this.apiBaseURL + "api/session/login", {
username: username,
password: password,
platform: 'webapp',
platformVersion: '0.1',
apiLevel: 1
}, { observe: 'response' })
.subscribe(data => {
console.log(data.headers.keys());
});
Console output:
This can be resolved by allowing Access-Control-Expose-Headers in header. x-auth-token is a custom header, which need to expose to outside world by allowing above tag. You can use below code to get this resolve.
#Configuration
public class WebSecurityCorsFilter extends OncePerRequestFilter {
#Override
public void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
res.setHeader("Access-Control-Allow-Credentials", "x-auth-token");
}
}

spring security + oauth2 + reactjs + restful http client

I am doing spring boot 1.5+ security with auth2 authentication and reactjs. for http calls using restful http client. Authentication is working perfectly and I am successfully accessing data from resource server. The issue is logout code is not working and I am getting this error on console:
POST http://localhost:8080/logout 403 ()
error: "Forbidden"
message: "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'.
I am sharing my code also.
1) ReactJs code
handleLogout = (e) => {
client({
method: 'POST',
path: '/logout',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}}).then(response => {
console.log(response);
});
}
2) restful http client
'use strict';
// client is custom code that configures rest.js to include support for HAL, URI Templates,
// and other things. It also sets the default Accept request header to application/hal+json.
// get the rest client
var rest = require('rest');
// provides default values for the request object. default values can be provided for the method, path, params, headers, entity
// If the value does not exist in the request already than the default value utilized
var defaultRequest = require('rest/interceptor/defaultRequest');
// Converts request and response entities using MIME converter registry
// Converters are looked up by the Content-Type header value. Content types without a converter default to plain text.
var mime = require('rest/interceptor/mime');
// define the request URI by expanding the path as a URI template
var uriTemplateInterceptor = require('./uriTemplateInterceptor');
// Marks the response as an error based on the status code
// The errorCode interceptor will mark a request in error if the status code is equal or greater than the configured value.
var errorCode = require('rest/interceptor/errorCode');
var csrf = require('rest/interceptor/csrf');
// A registry of converters for MIME types is provided. Each time a request or response entity needs to be encoded or
// decoded, the 'Content-Type' is used to lookup a converter from the registry.
// The converter is then used to serialize/deserialize the entity across the wire.
var baseRegistry = require('rest/mime/registry');
var registry = baseRegistry.child();
registry.register('text/uri-list', require('./uriListConverter'));
registry.register('application/hal+json', require('rest/mime/type/application/hal'));
// wrap all the above interceptors in rest client
// default interceptor provide Accept header value 'application/hal+json' if there is not accept header in request
module.exports = rest
.wrap(mime, { registry: registry })
.wrap(uriTemplateInterceptor)
.wrap(errorCode)
.wrap(csrf)
.wrap(defaultRequest, { headers: { 'Accept': 'application/hal+json' }});
3) application.yml of client application
debug: true
spring:
aop:
proxy-target-class: true
security:
user:
password: none
oauth2:
client:
access-token-uri: http://localhost:9999/uaa/oauth/token
user-authorization-uri: http://localhost:9999/uaa/oauth/authorize
client-id: acme
client-secret: acmesecret
resource:
user-info-uri: http://localhost:9999/uaa/user
jwt:
key-value: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgnBn+WU3i6KarB6gYlg40ckBiWmtVEpYkggvHxow74T19oDyO2VRqyY9oaJ/cvnlsZgTOYAUjTECjL8Ww7F7NJZpxMPFviqbx/ZeIEoOvd7DOqK3P5RBtLsV5A8tjtfqYw/Th4YEmzY/XkxjHH+KMyhmkPO+/tp3eGmcMDJgH+LwA6yhDgCI4ztLqJYY73gX0pEDTPwVmo6g1+MW8x6Ctry3AWBZyULGt+I82xv+snqEriF4uzO6CP2ixPCnMfF1k4dqnRZ/V98hnSLclfMkchEnfKYg1CWgD+oCJo+kBuCiMqmeQBFFw908OyFKxL7Yw0KEkkySxpa4Ndu978yxEwIDAQAB
-----END PUBLIC KEY-----
zuul:
routes:
resource:
path: /resource/**
url: http://localhost:9000/resource
user:
path: /user/**
url: http://localhost:9999/uaa/user
logging:
level:
org.springframework.security: DEBUG
4) CorsFilter configuration in authorization server
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
System.out.println("*********** running doFilter method of CorsFilter of auth-server***********");
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.addHeader("Access-Control-Allow-Headers", "x-auth-token, x-requested-with");
response.addHeader("Access-Control-Max-Age", "3600");
if (request.getMethod()!="OPTIONS") {
try {
chain.doFilter(req, res);
} catch (IOException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
} else {
}
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
5) AuthrorizationServerConfigurerAdapter of authentication server
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Bean
public #Autowired JwtAccessTokenConverter jwtAccessTokenConverter() throws Exception {
System.out.println("*********** running jwtAccessTokenConverter ***********");
// Setting up a JWT token using JwtAccessTokenConverter.
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// JWT token signing key
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "suleman123".toCharArray())
.getKeyPair("resourcekey");
converter.setKeyPair(keyPair);
return converter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
System.out.println("*********** running configure(ClientDetailsServiceConfigurer clients) ***********");
clients.inMemory()
.withClient("acme") // registers a client with client Id 'acme'
.secret("acmesecret") // registers a client with password 'acmesecret'
.authorizedGrantTypes("authorization_code", "refresh_token",
"password") // We registered the client and authorized the “password“, “authorization_code” and “refresh_token” grant types
.scopes("openid") // scope to which the client is limited
.autoApprove(true);
}
/**
*
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
System.out.println("*********** running configure(AuthorizationServerEndpointsConfigurer endpoints) ***********");
// we choose to inject an existing authentication manager from the spring container
// With this step we can share the authentication manager with the Basic authentication filter
endpoints.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
System.out.println("*********** running configure(AuthorizationServerSecurityConfigurer oauthServer) ***********");
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
"isAuthenticated()");
}
}
Finally got this working. What I have done to make it work:
1) I have installed 'react-cookie' library
npm install react-cookie --save
2) In my reactjs code I have imported react-cookie library and in method where I am using restful http client to generate logout request I am fetching Csrf-Token from cookie and sending it as request header.
handleLogout = (e) => {
client({
method: 'POST',
path: 'logout',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf8',
'X-Requested-With': 'XMLHttpRequest',
'X-Csrf-Token': Cookie.load('XSRF-TOKEN')
}
}).then(response => {
this.setState({authenticated: false});
console.log(response);
});
}
3) In authorization server instead of using my custom Cors Filter class which I have mentioned in my question, now I am using Spring Cors Filter code
#Configuration
public class CorsFilterConfig {
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
4) In application.properties file of Authorization Server I have added this property, so CorsFilter will run before SpringSecurityFilterChain
security.filter-order=50

how to do Authentication in Spring security using custom user detail service and angular js 2 as front end

this is my security configuration file
package com.data.topic;
#EnableWebSecurity
#ComponentScan(basePackageClasses = CustomUserDetailService.class)
public class Security extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/css/**", "/index").permitAll()
.antMatchers("/js/**").permitAll()
.antMatchers("/node_modules").permitAll()
.antMatchers("/topic/**").hasRole("user")
.and()
.formLogin().loginPage("/sch_signin")
.usernameParameter("username")
.passwordParameter("password")
.successForwardUrl("/")
.failureUrl("/login-error")
.and().csrf().disable();
}
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsServiceBean());
}
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return new CustomUserDetailService();
}
}
i want to know how should i send username and password using angular2 i tried this method on submit
onSubmit(){
let url="http://localhost:8080/sch_signin";
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
console.log(this.user);
this.http.post(url,JSON.stringify(this.user),options);
console.log('data submited');
}
i don't get any error and neither i get authenticated
please help me understand how spring intercept the authentication request
I got the solution after some research. I was posting the form in wrong way the right way to post a form in Angular2.
let url="http://localhost:8080/sch_signin";
let headers = new Headers({'Content-Type':'application/x-www-form-urlencoded'});
let options = new RequestOptions({ headers: headers });
this.http.post(url,body.toString(),options).subscribe((data)=>console.log(data));
First the content type should be application/x-www-form-urlencoded and second you have to send the data in request body so Spring Security can read it.

Resources