I am getting the following error when trying to test my controller. I know the error is being thrown by something in the security configuration, just not sure what it is exactly. org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'springSecurityFilterChain' is expected to be of type 'javax.servlet.Filter' but was actually of type 'org.springframework.beans.factory.support.NullBean'.
This is the test class
package com.chama.chamaservice.user;
import com.chama.chamaservice.auth.CustomAuthenticationFilter;
import com.chama.chamaservice.auth.CustomAuthorizationFilter;
import com.chama.chamaservice.config.SecurityConfig;
import org.junit.Before;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = UserController.class)
class UserControllerTest {
#MockBean
private WebSecurityConfiguration webSecurityConfiguration;
#MockBean
private UserService userService;
#MockBean
private UserDetailsService userDetailsService;
#MockBean
private SecurityConfig securityConfig;
#MockBean
private WebApplicationContext context;
#MockBean
private CustomAuthorizationFilter customAuthorizationFilter;
#Autowired
private MockMvc mockMvc;
#Before
public void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
#Test
#WithMockUser(username = "254704760842", roles = {"PLATFORM_SUPER_ADMIN"})
#DisplayName("Should list all users GET: /api/users/")
void shouldGetUsers() throws Exception {
mockMvc.perform(get("/api/users"))
.andExpect(status().is(200))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
}
}
Note that the test runner actually reaches the test class and the error is thrown at this line mockMvc.perform(get("/api/users"))
This is the controller under test
#GetMapping("")
#JsonView(Views.Public.class)
#PreAuthorize("hasAuthority('CAN_VIEW_ALL_PLATFORM_MEMBERS')")
public ResponseEntity<List<User>> getUsers() {
return ResponseEntity.ok().body(userService.getUsers());
}
This is my custom authorisation filter class.
package com.chama.chamaservice.auth;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.chama.chamaservice.config.ApplicationUserRole;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
#Slf4j
public class CustomAuthorizationFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getServletPath().equals("/api/login") || request.getServletPath().equals("/api/refresh/token")) {
filterChain.doFilter(request, response);
} else {
// Generate new access token from refresh token
String authorizationHeader = request.getHeader(AUTHORIZATION);
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
try {
String token = authorizationHeader.substring("Bearer ".length());
Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = verifier.verify(token);
String phoneNumber = decodedJWT.getSubject();
String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
Collection<SimpleGrantedAuthority> authorities = Arrays.stream(roles)
.map(ApplicationUserRole::valueOf) // <- parsing every String to ApplicationUserRole
.map(ApplicationUserRole::getGrantedAuthorities) // <- converting every ApplicationUserRole to a set of GrantedAuthority
.flatMap(Collection::stream) // <- converting stream of sets to a stream of GrantedAuthority
.collect(Collectors.toList());
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phoneNumber, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
} catch (Exception e) {
log.error("Error logging in: {}", e.getMessage());
response.setHeader("error", e.getMessage());
response.setStatus(FORBIDDEN.value());
Map<String, String> error = new HashMap<>();
error.put("message", e.getMessage());
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), error);
}
} else {
filterChain.doFilter(request, response);
}
}
}
}
And finally, this is my security config class
package com.chama.chamaservice.config;
import com.chama.chamaservice.auth.CustomAuthenticationFilter;
import com.chama.chamaservice.auth.CustomAuthorizationFilter;
import lombok.RequiredArgsConstructor;
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.method.configuration.EnableGlobalMethodSecurity;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
/*
* Setting custom login endpoint
* */
CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter(authenticationManagerBean());
customAuthenticationFilter.setFilterProcessesUrl("/api/login");
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.antMatchers("/api/login/**", "/api/token/refresh/**").permitAll()
.antMatchers("/api/users/save/**").permitAll()
.antMatchers("/api/daraja/register-url/validation/**").permitAll()
.antMatchers("/api/daraja/register-url/confirmation/**").permitAll()
.anyRequest()
.authenticated()
.and();
http.addFilter(customAuthenticationFilter);
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManager();
}
}
Related
I am using the HTTPBasic authentication scheme in my spring security, and I would like to log all failed and successful login attempts. It seems like the general way to do so is to call a method upon login failure, kind of like this...
.and().formLogin().failureHandler(//method to call upon failure);
However, this requires the form login, and I am using HTTPBasic. How would we set this up so that it would have a failurehandler on an HTTPBasic authentication scheme?
SecurityConfiguration.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import com.service.UserService;
#SuppressWarnings("deprecation")
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/welcome").permitAll().antMatchers("/secured")
.authenticated().and().formLogin()
.failureHandler(new SimpleUrlAuthenticationFailureHandler()).permitAll().and().httpBasic();
}
}
LoginFailureHandler.java
package com.config;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
#Component
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
String email = request.getParameter("email");
String redirectURL = "/login?error&email=" + email;
// if (exception.getMessage().contains("OTP")) {
// redirectURL = "/login?otp=true&email=" + email;
// } else {
// Customer customer = customerService.getCustomerByEmail(email);
// if (customer.isOTPRequired()) {
// redirectURL = "/login?otp=true&email=" + email;
// }
// }
super.setDefaultFailureUrl(redirectURL);
super.onAuthenticationFailure(request, response, exception);
}
}
I'm trying to set up JWT Authentication
I've been following this https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/
I can successfully create new user, problems start when I try to log in......
I keep getting response status 403 Forbidden
JWTAuthenticationFilter
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.web.authentication.UsernamePasswordAuthenticationFilter;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.flashcards.entities.UserEntity;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
setFilterProcessesUrl("/login");
}
u/Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
System.out.println(req);
try {
UserEntity creds = new ObjectMapper().readValue(req.getInputStream(), UserEntity.class);
System.out.println(creds);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(),
creds.getPassword(), new ArrayList<>()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
u/Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException {
String token = JWT.create().withSubject(((UserEntity) auth.getPrincipal()).getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
.sign(Algorithm.HMAC512(SecurityConstants.SECRET.getBytes()));
String body = ((UserEntity) auth.getPrincipal()).getUsername() + " " + token;
System.out.println(body);
res.getWriter().write(body);
res.getWriter().flush();
}
}
JWTAuthorizationFilter
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
public JWTAuthorizationFilter(AuthenticationManager authManager) {
super(authManager);
}
u/Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
String header = req.getHeader(SecurityConstants.HEADER_STRING);
if (header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
// Reads the JWT from the Authorization header, and then uses JWT to validate
// the token
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader(SecurityConstants.HEADER_STRING);
if (token != null) {
// parse the token.
String user = JWT.require(Algorithm.HMAC512(SecurityConstants.SECRET.getBytes())).build()
.verify(token.replace(SecurityConstants.TOKEN_PREFIX, "")).getSubject();
if (user != null) {
// new arraylist means authorities
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
}
return null;
}
return null;
}
}
WebSecurity
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
u/SuppressWarnings("deprecation")
u/EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(UserDetailsService userService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userDetailsService = userService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
u/Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().and().authorizeRequests().antMatchers( HttpMethod.POST, "/users/**").permitAll()
.anyRequest().authenticated().and().addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
u/Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
u/Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
UserController
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.flashcards.entities.UserEntity;
import com.example.flashcards.repositories.UserRepository;
u/CrossOrigin
u/RestController
u/RequestMapping("/users")
public class UserController {
u/Autowired
private UserRepository userRepo;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
// u/Transactional(rollbackFor = Exception.class)
u/PostMapping("/new")
public Long saveUser(#RequestBody UserEntity user) {
UserEntity newUser = user;
newUser.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepo.save(newUser).getUserId();
}
}
when I send POST request with JSON body with user info to http://localhost:8080/users/new everything is peachy, new user gets created and saved to database
when I send POST request with JSON body with username and password to http://localhost:8080/login I keep getting 403 Forbidden
If anyone could point me in the right direction it would be greatly appreciated!
I'm a beginner and this is my very first time dealing with Spring Security.
Thank you for the hint ;)
I got it to work now. The problem was that in JWTAuthenticationFilter, in successfulAuthentication method I was trying to use my UserEntity when it was supposed to be User from Spring's UserServiceDetail once I made that change it started working :)
I'm trying to create an application like this OAuth 2.0 Authorization Server Sample, but I'm having problems with CORS.
I already did what was suggested here CORS, but I'm getting this error:
Access to XMLHttpRequest at 'http://writer:secret#localhost:8081/oauth/token' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
My classes:
package br.com.sammubr.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class AuthApplication {
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.beans.factory.annotation.Value;
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.configuration.AuthenticationConfiguration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import java.security.KeyPair;
#EnableAuthorizationServer
#Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
AuthenticationManager authenticationManager;
KeyPair keyPair;
boolean jwtEnabled;
public AuthorizationServerConfiguration(
AuthenticationConfiguration authenticationConfiguration,
KeyPair keyPair,
#Value("${security.oauth2.authorizationserver.jwt.enabled:true}") boolean jwtEnabled) throws Exception {
this.authenticationManager = authenticationConfiguration.getAuthenticationManager();
this.keyPair = keyPair;
this.jwtEnabled = jwtEnabled;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("reader")
.authorizedGrantTypes("password")
.secret("{noop}secret")
.scopes("message:read")
.accessTokenValiditySeconds(600_000_000)
.and()
.withClient("writer")
.authorizedGrantTypes("password")
.secret("{noop}secret")
.scopes("message:write")
.accessTokenValiditySeconds(600_000_000)
.and()
.withClient("noscopes")
.authorizedGrantTypes("password")
.secret("{noop}secret")
.scopes("none")
.accessTokenValiditySeconds(600_000_000);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.authenticationManager(this.authenticationManager)
.tokenStore(tokenStore());
if (this.jwtEnabled) {
endpoints
.accessTokenConverter(accessTokenConverter());
}
}
#Bean
public TokenStore tokenStore() {
if (this.jwtEnabled) {
return new JwtTokenStore(accessTokenConverter());
} else {
return new InMemoryTokenStore();
}
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(this.keyPair);
DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
accessTokenConverter.setUserTokenConverter(new SubjectAttributeUserTokenConverter());
converter.setAccessTokenConverter(accessTokenConverter);
return converter;
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpoint;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
#FrameworkEndpoint
class IntrospectEndpoint {
TokenStore tokenStore;
IntrospectEndpoint(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
#PostMapping("/introspect")
#ResponseBody
public Map<String, Object> introspect(#RequestParam("token") String token) {
OAuth2AccessToken accessToken = this.tokenStore.readAccessToken(token);
Map<String, Object> attributes = new HashMap<>();
if (accessToken == null || accessToken.isExpired()) {
attributes.put("active", false);
return attributes;
}
OAuth2Authentication authentication = this.tokenStore.readAuthentication(token);
attributes.put("active", true);
attributes.put("exp", accessToken.getExpiration().getTime());
attributes.put("scope", accessToken.getScope().stream().collect(Collectors.joining(" ")));
attributes.put("sub", authentication.getName());
return attributes;
}
}
package br.com.sammubr.auth.configuration;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpoint;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.KeyPair;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
#FrameworkEndpoint
class JwkSetEndpoint {
KeyPair keyPair;
JwkSetEndpoint(KeyPair keyPair) {
this.keyPair = keyPair;
}
#GetMapping("/.well-known/jwks.json")
#ResponseBody
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
#Configuration
class KeyConfig {
#Bean
KeyPair keyPair() {
try {
String privateExponent = "3851612021791312596791631935569878540203393691253311342052463788814433805390794604753109719790052408607029530149004451377846406736413270923596916756321977922303381344613407820854322190592787335193581632323728135479679928871596911841005827348430783250026013354350760878678723915119966019947072651782000702927096735228356171563532131162414366310012554312756036441054404004920678199077822575051043273088621405687950081861819700809912238863867947415641838115425624808671834312114785499017269379478439158796130804789241476050832773822038351367878951389438751088021113551495469440016698505614123035099067172660197922333993";
String modulus = "18044398961479537755088511127417480155072543594514852056908450877656126120801808993616738273349107491806340290040410660515399239279742407357192875363433659810851147557504389760192273458065587503508596714389889971758652047927503525007076910925306186421971180013159326306810174367375596043267660331677530921991343349336096643043840224352451615452251387611820750171352353189973315443889352557807329336576421211370350554195530374360110583327093711721857129170040527236951522127488980970085401773781530555922385755722534685479501240842392531455355164896023070459024737908929308707435474197069199421373363801477026083786683";
String exponent = "65537";
RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent));
RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(new BigInteger(modulus), new BigInteger(privateExponent));
KeyFactory factory = KeyFactory.getInstance("RSA");
return new KeyPair(factory.generatePublic(publicSpec), factory.generatePrivate(privateSpec));
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import java.util.LinkedHashMap;
import java.util.Map;
class SubjectAttributeUserTokenConverter extends DefaultUserAuthenticationConverter {
#Override
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
Map<String, Object> response = new LinkedHashMap<>();
response.put("sub", authentication.getName());
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
}
return response;
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.Collections;
import static org.springframework.security.config.Customizer.withDefaults;
#Configuration
class UserConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.authorizeRequests()
.mvcMatchers("/.well-known/jwks.json").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().ignoringRequestMatchers(request -> "/introspect".equals(request.getRequestURI()));
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Bean
#Override
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withDefaultPasswordEncoder()
.username("subject")
.password("password")
.roles("USER")
.build());
}
}
And my request is simple like this:
import $ from 'jquery';
window.jQuery = $;
window.$ = $;
import axios from "axios";
let api = axios.create({
baseURL: 'http://writer:secret#localhost:8081',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
$(document).ready(function() {
$("input[type=submit]").on("click", function(ev) {
ev.preventDefault();
const params = new URLSearchParams();
params.append('username', 'subject');
params.append('password', 'password');
params.append('grant_type', 'password');
api.post('/oauth/token', params)
.then((resp) => {
console.log(resp.data)
}).catch(error => console.error(error));
});
});
I'm doing what you say in the Spring documentation, but it's not working. Can someone help me?
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 have a rest controller, which has simple CRUD operations. I am trying to write integration test.
Below is my RestController:
package com.gasx.corex.scheduler.controller;
import java.awt.*;
import java.util.List;
import com.gasx.corex.scheduler.service.SchedulerJobServiceI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.gasx.corex.ext.scheduler.domain.SchedulerJob;
import com.gasx.corex.scheduler.service.SchedulerJobService;
#RestController
#RequestMapping("/gasx/restscd")
public class SchedulerJobController {
#Autowired
private SchedulerJobServiceI schedulerJobService;
#RequestMapping(method = RequestMethod.GET , path="/getschedulerjobs" , produces= MediaType.APPLICATION_JSON_VALUE)
public List<SchedulerJob> getAllSchedulerJobs() {
return schedulerJobService.getAllSchedulerJobs();
}
#RequestMapping(method = RequestMethod.POST, value = "/addschedulerjob")
public void addSchedulerJob(#RequestBody SchedulerJob schedulerJob) {
schedulerJobService.addSchedulerJob(schedulerJob);
}
#RequestMapping(method = RequestMethod.POST, value = "/updateschedulerjob")
public void updateSchedulerJob(#RequestBody SchedulerJob schedulerJob) {
schedulerJobService.updateSchedulerJob(schedulerJob);
}
#RequestMapping(method = RequestMethod.POST, value = "/deleteschedulerjob")
public void deleteSchedulerJob(#RequestBody SchedulerJob schedulerJob) {
schedulerJobService.deleteSchedulerJob(schedulerJob);
}
}
I have written Integration test for all of the endpoints in RestController
Integration test class :-
package com.gasx.corex.ext.scheduler.integrationtest.domain;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gasx.corex.base.configuration.CoreConfiguration;
import com.gasx.corex.ext.scheduler.domain.SchedulerJob;
import com.gasx.corex.ext.scheduler.domain.utils.SchedulerJobType;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.http.HttpHeaders;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;
import sun.security.krb5.internal.Ticket;
import org.springframework.http.HttpMethod;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import java.io.IOException;
import java.util.Base64;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT , properties = {
"management.server.port=0", "management.context-path=/admin" ,"security.basic.enabled=false"} )
#EnableAutoConfiguration
#ContextConfiguration( classes = {CoreConfiguration.class } )
#AutoConfigureMockMvc
public class SchedulerJobTestInt {
#LocalServerPort
private int port ;
#Autowired
private TestRestTemplate testRestTemplate;
#Autowired
WebApplicationContext context;
#Autowired
private MockMvc mockMvc;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
}
#Test
public void getAllSchedulerJobsIntTest() throws Exception {
ResponseEntity<String> response = testRestTemplate.getForEntity("http://localhost:" + port +"/gasx/restscd/getschedulerjobs", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode responseJson = objectMapper.readTree(response.getBody());
assertThat(responseJson.isMissingNode()).isFalse();
assertThat(responseJson.toString()).isEqualTo("[]");
}
#Test
public void addSchedulerJobIntTest() throws Exception{
SchedulerJob schedulerJob = new SchedulerJob();
schedulerJob.setName("ALB Cleanup");
schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
schedulerJob.setType(SchedulerJobType.REST);
schedulerJob.setActive(true);
schedulerJob.setStartMissedRun(false);
schedulerJob.setCategory("SYSTEM");
schedulerJob.setCronExpression(null);
schedulerJob.setScheme("testScheme");
schedulerJob.setIdRegion(1);
schedulerJob.setAlbEndpoint("testAlbEndPoint");
schedulerJob.setAlbPayload("SCHED_ALB");
schedulerJob.setAlbPrio(1);
schedulerJob.setAlbJobUser("MKRAUS");
schedulerJob.setScriptParams("testScriptParams");
schedulerJob.setShellScriptParams("clear_tmp 15");
schedulerJob.setSoapEndpointAlias("");
schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
schedulerJob.setSoapExportPath("testExportPath");
schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
schedulerJob.setSoapAction("urn:readPartnersById");
schedulerJob.setRestEndpointAlias("testEndpointAlias");
schedulerJob.setRestUrl("testUrl");
schedulerJob.setRestEntityContent("");
schedulerJob.setRestExportPath("testRestExportPath");
schedulerJob.setHookScriptName("testHookScriptName");
schedulerJob.setMinutes("");
schedulerJob.setHours("");
String plainCredentials="gasx:gasx!";
String base64Credentials = Base64.getEncoder().encodeToString(plainCredentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
headers.add("Accept" , "application/json");
HttpEntity<String> entity = new HttpEntity<String>(asJsonString(schedulerJob), headers);
// ResponseEntity<Void> response = testRestTemplate.postForEntity("http://localhost:"+port +"/gasx/restscd/addschedulerjob", entity,Void.class);
ResponseEntity<Void> response = testRestTemplate.postForEntity("http://localhost:" + port +"/gasx/restscd/addschedulerjob", asJsonString(schedulerJob),Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
private String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
#Test
public void updateSchedulerJobTest(){
SchedulerJob schedulerJob = new SchedulerJob();
schedulerJob.setName("ALB Cleanup");
schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
schedulerJob.setType(SchedulerJobType.REST);
schedulerJob.setActive(true);
schedulerJob.setStartMissedRun(false);
schedulerJob.setCategory("SYSTEM");
schedulerJob.setCronExpression(null);
schedulerJob.setScheme("testScheme");
schedulerJob.setIdRegion(1);
schedulerJob.setAlbEndpoint("testAlbEndPoint");
schedulerJob.setAlbPayload("SCHED_ALB");
schedulerJob.setAlbPrio(1);
schedulerJob.setAlbJobUser("MKRAUS");
schedulerJob.setScriptParams("testScriptParams");
schedulerJob.setShellScriptParams("clear_tmp 15");
schedulerJob.setSoapEndpointAlias("");
schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
schedulerJob.setSoapExportPath("testExportPath");
schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
schedulerJob.setSoapAction("urn:readPartnersById");
schedulerJob.setRestEndpointAlias("testEndpointAlias");
schedulerJob.setRestUrl("testUrl");
schedulerJob.setRestEntityContent("");
schedulerJob.setRestExportPath("testRestExportPath");
schedulerJob.setHookScriptName("testHookScriptName");
schedulerJob.setMinutes("");
schedulerJob.setHours("");
ResponseEntity<Void> response = testRestTemplate.withBasicAuth("gasx" ,"gasx!").postForEntity("http://localhost:" + port +"/gasx/restscd/updateschedulerjob", schedulerJob,Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
#Test
public void deleteSchedulerJob(){
SchedulerJob schedulerJob = new SchedulerJob();
schedulerJob.setName("ALB Cleanup");
schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
schedulerJob.setType(SchedulerJobType.REST);
schedulerJob.setActive(true);
schedulerJob.setStartMissedRun(false);
schedulerJob.setCategory("SYSTEM");
schedulerJob.setCronExpression(null);
schedulerJob.setScheme("testScheme");
schedulerJob.setIdRegion(1);
schedulerJob.setAlbEndpoint("testAlbEndPoint");
schedulerJob.setAlbPayload("SCHED_ALB");
schedulerJob.setAlbPrio(1);
schedulerJob.setAlbJobUser("MKRAUS");
schedulerJob.setScriptParams("testScriptParams");
schedulerJob.setShellScriptParams("clear_tmp 15");
schedulerJob.setSoapEndpointAlias("");
schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
schedulerJob.setSoapExportPath("testExportPath");
schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
schedulerJob.setSoapAction("urn:readPartnersById");
schedulerJob.setRestEndpointAlias("testEndpointAlias");
schedulerJob.setRestUrl("testUrl");
schedulerJob.setRestEntityContent("");
schedulerJob.setRestExportPath("testRestExportPath");
schedulerJob.setHookScriptName("testHookScriptName");
schedulerJob.setMinutes("");
schedulerJob.setHours("");
ResponseEntity<Void> response = testRestTemplate.withBasicAuth("gasx" ,"gasx!").postForEntity("http://localhost:" + port +"/gasx/restscd/deleteschedulerjob", schedulerJob,Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
My problems:
1.)Wheneever I put breakpoint in Rest Controller, it doesnt' stop there, actually it is not getting invoked.
2.)When I run the test for GET it returns sign-in html page from response.getBody()
3.)When I run the test for POST it returns status 401 unauthorized
tried numerious possible solutions on google
even disabled spring security by commenting the the configuration still it doesn't work.
I can call the same Rest Controller from my Unit test and can stop the breakpoints.
My security configurations:-
package com.gasx.corex.scheduler.server;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.config.http.SessionCreationPolicy;
import com.gasx.corex.ext.user.domain.DefaultRoles;
#Configuration
#EnableWebSecurity
#Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.httpBasic().and()
.authorizeRequests()
.antMatchers("/gasx/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())
.antMatchers("/webjars/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())
.antMatchers("/monitor/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ACTUATOR.getName())
// dev urls
.antMatchers("/h2-console/**").hasAuthority(DefaultRoles.ROOT.getName())
.antMatchers("/swagger*/**","/v2/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName())
.anyRequest().denyAll();
// #formatter:on
httpSecurity.csrf().disable();
httpSecurity.headers().frameOptions().disable();
}
}
Tried one more thing, added below class to my package :-
package com.gasx.corex.ext.scheduler.integrationtest.domain;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
public class AllowAnonymousWebAccess extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity web) throws Exception {
web.antMatcher("**/*").anonymous();
}
}
and now it gives 404.
I don't know anything about this project's SecurityConfiguration (you should provide some more information about it), but I think that you should provide some authorization data (Like a JWT in the Authorization header, or so)
Could you give me some more information about the SecurityConfig? (look for org.springframework.security.config.something.something... imports )
EDIT
I took a look at your code, and actually this part
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.httpBasic().and()
.authorizeRequests()
.antMatchers("/gasx/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())
is protecting your API with an httpBasic type authorization. You shold provide the credentials in the header to test your application.