I am using mockito to test a resttemplate exchange method, but I am getting a BadRequest 400 : "{"timestamp":"2022-06-09T20:27:37.950+00:00","status":400. I am using junit 5 as well.
This is my code:
import com.fasterxml.jackson.core.JsonProcessingException;
import exception.HmacExeption;
import model.Payload;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
#ExtendWith(MockitoExtension.class)
class GithubWebHookServiceTest {
#Mock
private RestTemplate restTemplate;
#InjectMocks
private CarService carService;
#Test
public void test() throws HmacExeption, NoSuchAlgorithmException, InvalidKeyException, JsonProcessingException {
ResponseEntity<String> responseEntity = new ResponseEntity<String>("sampleBodyString", HttpStatus.ACCEPTED);
Mockito.
when(restTemplate.exchange(
Matchers.anyString(),
Matchers.any(HttpMethod.class),
Matchers.<HttpEntity<?>> any(),
Matchers.<Class<String>> any()
)
).thenReturn(responseEntity);
carService.executeRestCall(new Payload());
}
}
Not sure, what am I missing.
Thanks!!
Related
I'm trying to make a login/registration in Spring Boot but I'm facing some problems.
Registration and login works just fine, but I want to check and verify the token at every request sent.
This is the JwtUsernameAndPasswordAuthenticationFilter:
package com.example.springsecurityproject.jwt;
import com.example.springsecurityproject.entity.UserEntity;
import com.example.springsecurityproject.repository.UserRepository;
import com.example.springsecurityproject.service.TokenService;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.apache.catalina.User;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.crypto.SecretKey;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Date;
import java.time.LocalDate;
#AllArgsConstructor
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private TokenService tokenService;
private AuthenticationManager authenticationManager;
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
UsernameAndPasswordAuthenticationRequest authenticationRequest =
new ObjectMapper().readValue(request.getInputStream(), UsernameAndPasswordAuthenticationRequest.class);
Authentication authentication = new UsernamePasswordAuthenticationToken(
authenticationRequest.getUsername(),
authenticationRequest.getPassword()
);
Authentication authenticate = authenticationManager.authenticate(authentication);
return authenticate;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
String secretKey = Encoders.BASE64.encode(key.getEncoded());
tokenService.addToken(secretKey, (UserEntity) authResult.getPrincipal());
String JWTtoken = Jwts.builder()
.setSubject(authResult.getName())
.claim("authorities", authResult.getAuthorities())
.setIssuedAt(new java.util.Date())
.setExpiration(Date.valueOf(LocalDate.now().plusWeeks(2)))
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
.compact();
response.addHeader("Authorization", "Bearer" + JWTtoken);
}
}
In this when the Key is created I'm saving it into a database where there is the encrypted key and the UserEntity (as foreign key).
In the JwtVerifierToken I'm usign a function getKeyByUser that just take the key when I pass the UserEntity, but the method request.getUserPrincipal() returns null, that means I can't have the key and also cannot verify.
package com.example.springsecurityproject.jwt;
import com.example.springsecurityproject.entity.TokenEntity;
import com.example.springsecurityproject.entity.UserEntity;
import com.example.springsecurityproject.repository.TokenRepository;
import com.example.springsecurityproject.service.UserService;
import com.google.common.base.Strings;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Autowired;
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.security.Key;
public class JwtTokenVerifier extends OncePerRequestFilter {
private final TokenRepository tokenRepository;
private UserService userService;
public JwtTokenVerifier(TokenRepository tokenRepository) {
this.tokenRepository = tokenRepository;
}
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader("Authorization");
if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith("Bearer")){
filterChain.doFilter(request,response);
return;
}
try {
TokenEntity key = tokenRepository.getKeyByUser((UserEntity) request.getUserPrincipal());
String token = authorizationHeader.replace("Bearer", "");
Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey((Key) key).build().parseClaimsJws(token);
Claims body = claimsJws.getBody();
String username = body.getSubject();
}
catch (JwtException e){
throw new IllegalStateException("Token non verificato");
}
}
}
This is the ApplicationSecurityConfig
package com.example.springsecurityproject.security;
import com.example.springsecurityproject.jwt.JwtTokenVerifier;
import com.example.springsecurityproject.jwt.JwtUsernameAndPasswordAuthenticationFilter;
import com.example.springsecurityproject.repository.TokenRepository;
import com.example.springsecurityproject.repository.UserRepository;
import com.example.springsecurityproject.service.TokenService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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 static org.springframework.security.config.http.SessionCreationPolicy.*;
#Slf4j
#Configuration
#EnableWebSecurity
#AllArgsConstructor
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
private final TokenService tokenService;
private final TokenRepository tokenRepository;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(STATELESS)
.and()
//.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) (per averlo abilitato)
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(tokenService,authenticationManager()))
.addFilterAfter(new JwtTokenVerifier(tokenRepository),JwtUsernameAndPasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/register").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
/*
Form Based Login
.formLogin()
.loginPage("/login")
.permitAll()
.defaultSuccessUrl("/courses", true)
.passwordParameter("password")
.usernameParameter("username")
.and()
.rememberMe()
.tokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(31))//default 2 weeks
.key("verysecurekey")
.rememberMeParameter("remember-me")
.and()
.logout()
.logoutUrl("/logout")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID", "remember-me")
.logoutSuccessUrl("/login");
*/
}
/*
#Override
#Bean
protected UserDetailsService userDetailsService() {
UserDetails vitoUser = User.builder()
.username("vito")
.password(passwordEncoder.encode("password"))
//.roles(STUDENT.name())
.authorities(STUDENT.getGrantedAuthorities())
.build();
UserDetails ddbdevUser = User.builder()
.username("ddbdev")
.password(passwordEncoder.encode("password"))
//.roles(ADMIN.name())
.authorities(ADMIN.getGrantedAuthorities())
.build();
UserDetails marioUser = User.builder()
.username("benmar")
.password(passwordEncoder.encode("password"))
//.roles(MODERATOR.name())
.authorities(MODERATOR.getGrantedAuthorities())
.build();
return new InMemoryUserDetailsManager(
ddbdevUser,
vitoUser,
marioUser
);
}
*/
}
Can someone help? I'm stuck :(
For some reason I cannot add a filter that will take over the authorization phase of the filter chain. The defaultChain is reading out on start: "Will not secure any request", but it seems like my request are secured when I test, however It will not trigger my filter. If I could get some help on this matter it would be greatly appreciated!
WEBCONFIG
package com.legacybanking.legacyBankingAPI.security.securityConfig;
import com.legacybanking.legacyBankingAPI.security.jwt.JwtPasswordValidator;
import com.legacybanking.legacyBankingAPI.services.CustomerService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.util.List;
#Configuration
#AllArgsConstructor
#EnableWebSecurity
#Slf4j
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final CustomerService customerService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customerService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
#Bean
protected UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
log.info("ITS NOT WORKING");
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.addFilter(new JwtPasswordValidator(authenticationManager()))
.authorizeRequests()
// ANT MACHERS = WHITELISTING
.antMatchers("/api/**")
.permitAll()
.anyRequest()
.authenticated();
}
}
JWTCONFIG
package com.legacybanking.legacyBankingAPI.security.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.legacybanking.legacyBankingAPI.models.Customer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.stream.Collectors;
#Slf4j
public class JwtPasswordValidator extends UsernamePasswordAuthenticationFilter {
#Autowired
private final AuthenticationManager authenticationManager;
public JwtPasswordValidator(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
System.out.println("request = " + request.getParameter("email"));
System.out.println("request = " + request.getParameter("password"));
String email = request.getParameter("email");
String password = request.getParameter("password");
log.info("Test Loging -> {}, {}",email,password);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(email,password);
return authenticationManager.authenticate(authenticationToken);
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
System.out.println(authResult);
User user = (User) authResult.getPrincipal();
String key = "secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret";
Algorithm algorithm = Algorithm.HMAC256(key.getBytes());
String access_token = JWT.create()
.withSubject(user.getUsername())
.withIssuedAt(new Date())
.withExpiresAt(new Date(System.currentTimeMillis() + 60 * 60 * 1000))
.withIssuer(request.getRequestURI())
.withClaim("roles", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.sign(algorithm);
String refresh_token = JWT.create()
.withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 60 * 60 * 1000))
.withIssuer(request.getRequestURI())
.sign(algorithm);
System.out.println(access_token);
log.info("This is the access token: {}", access_token);
response.addHeader("Authorization", "Bearer " + access_token);
response.setHeader("access_token", "token" + access_token);
}
}
You have to register the JwtPasswordValidator class inside the AppSecurityConfig cofig() method as follows:
http.addFilter(JwtPasswordValidator);
also you may need to create a CustomAuthorizationFilter which extends OncePerRequestFilter class and register it inside the config method as follows:
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
if need more help do not hesitate to ask.
I am attempting to write a #SpringBootTest which will both issue REST requests and mock responses. I want to do this because my spring application receives REST requests and in response it fetches information from another source using REST. I would like to trigger my application by initiating a REST GET (MockMvc), but would also like to mock the other source's response (MockRestServiceServer).
Here is a sanitized version of the test, with my application removed:
import lombok.extern.slf4j.Slf4j;
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.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.client.RestTemplate;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
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;
#Slf4j
#ExtendWith(SpringExtension.class)
#SpringBootTest
#AutoConfigureMockMvc
class RestTest {
private static final String URI = "/my-test-uri";
private static final String RESPONSE = "my-response";
#Autowired
private MockMvc mockMvc;
#Test
void testRest() throws Exception {
log.info("Initiating request for GET {}", URI);
mockMvc.perform(get(URI))
.andExpect(status().isOk())
.andExpect(content().string(containsString(RESPONSE)));
}
#TestConfiguration
static class TestConfig {
#Primary
#Bean
public RestTemplateBuilder restTemplateBuilder() {
RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate);
server.expect(requestTo(URI))
.andRespond(withSuccess(RESPONSE, MediaType.APPLICATION_JSON));
log.info("Mocking response to GET {}: {}", URI, RESPONSE);
RestTemplateBuilder mockBuilder = mock(RestTemplateBuilder.class);
when(mockBuilder.build()).thenReturn(restTemplate);
return mockBuilder;
}
}
}
The test fails because it does not receive the response defined in TestConfig.restTemplateBuilder. I am providing both the REST requestor (testRest() method) and the REST responder (TestConfig.restTemplateBuilder). What am I doing wrong?
Here's the failure:
Status expected:<200> but was:<404>
Expected :200
Actual :404
<Click to see difference>
java.lang.AssertionError: Status expected:<200> but was:<404>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:59)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:122)
at org.springframework.test.web.servlet.result.StatusResultMatchers.lambda$matcher$9(StatusResultMatchers.java:627)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:196)
at com.mycompany.RestTest.testRest(RestTest.java:54)
...
at java.base/java.lang.Thread.run(Thread.java:830)
I am trying to use the addProvider method and seems it undefined even though it is imported import java.security.Security;
package com.example.fingerprient2;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.security.Security;
import org.bouncycastle.jcajce.BCFKSLoadStoreParameter;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import android.security.keystore.KeyProperties;
import javax.crypto.KeyGenerator;
public class EnCryptor {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
KeyGenerator keyGenerator =KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC ,"AndroidKeyStore");
}
any help to know why addProvider doesn't appear?
Because you're not in a scope where you can call a method. It needs to be called from a function or an initializer:
public class Encryptor {
public void initialize() {
Security.addProvider(new BouncyCastleProvider());
}
}
So I am attempting to write a basic Rest Controller in Spring Tool Suite with Spring annotations where I hit the endpoint "/health" and I receive the following message upon hitting the endpoint "Kafka Streaming App is healthy".
The only error I receive is the 404 status error when I check on the browser and I have already tried logging please help. I think the problem might be how I am calling the Controller in the Main Application class in Spring.
Main Application Class
package com.eds.kafka.streaming.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
//#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
//#Configuration
//#EntityScan(basePackages = {"com.eds.kafka.streaming.model"})
//#ComponentScan(basePackages = { "com.eds.kafka.streaming.service", "com.eds.kafka.streaming.util", "com.eds.kafka.streaming.config", "com.eds.kafka.streaming.controller"}) //"com.tmobile.eds.infosec.volt.encr",
#ComponentScan(basePackages = {"com.eds.kafka.streaming"})
#SpringBootApplication
public class KafkaStreamingAppContainerApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(KafkaStreamingAppContainerApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(KafkaStreamingAppContainerApplication.class);
}
}
Controller Class
package com.eds.kafka.streaming.controller;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
#EnableAutoConfiguration
#PropertySource("classpath:application-${spring.profiles.active}.properties")
#RestController
public class MainController {
#RequestMapping(method = RequestMethod.GET, value = "/health", produces = "application/json")
#ResponseBody
public ResponseEntity home() {
System.out.println("Controller being configured!");
return new ResponseEntity("Kafka Streaming App is Healthy", HttpStatus.OK);
}
}
Please let me know if you have any advice and if needed I can provide a zipped version of the project if that is needed just message me.