Skip to content
Snippets Groups Projects
Unverified Commit 7031be4a authored by Martin Weise's avatar Martin Weise
Browse files

Added test cases

parent 35e6e126
Branches
Tags
4 merge requests!129New module for citation as they occur multiple,!121Modified logging, modified logging level, modified flasgger endpoint,!113Resolve "Bugs related with Query Service",!111Resolve "Frontend errors and authorized dev keys"
Showing
with 210 additions and 36 deletions
package at.tuwien; package at.tuwien;
import at.tuwien.api.auth.SignupRequestDto; import at.tuwien.api.user.UserDetailsDto;
import at.tuwien.entities.user.RoleType;
import at.tuwien.entities.user.TimeSecret; import at.tuwien.entities.user.TimeSecret;
import at.tuwien.entities.user.Token; import at.tuwien.entities.user.Token;
import at.tuwien.entities.user.User; import at.tuwien.entities.user.User;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
import java.security.Principal;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.List;
@TestPropertySource(locations = "classpath:application.properties") @TestPropertySource(locations = "classpath:application.properties")
public abstract class BaseUnitTest { public abstract class BaseUnitTest {
...@@ -38,9 +44,21 @@ public abstract class BaseUnitTest { ...@@ -38,9 +44,21 @@ public abstract class BaseUnitTest {
.emailVerified(USER_1_VERIFIED) .emailVerified(USER_1_VERIFIED)
.themeDark(USER_1_THEME_DARK) .themeDark(USER_1_THEME_DARK)
.created(USER_1_CREATED) .created(USER_1_CREATED)
.roles(List.of(RoleType.ROLE_RESEARCHER))
.lastModified(USER_1_LAST_MODIFIED) .lastModified(USER_1_LAST_MODIFIED)
.build(); .build();
public final static UserDetails USER_1_DETAILS = UserDetailsDto.builder()
.username(USER_1_USERNAME)
.email(USER_1_EMAIL)
.password(USER_1_PASSWORD)
.authorities(List.of(new SimpleGrantedAuthority("ROLE_RESEARCHER")))
.build();
public final static Principal USER_1_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_1_DETAILS,
USER_1_PASSWORD, USER_1_DETAILS.getAuthorities());
public final static Long USER_2_ID = 2L; public final static Long USER_2_ID = 2L;
public final static String USER_2_EMAIL = "jane.doe@example.com"; public final static String USER_2_EMAIL = "jane.doe@example.com";
public final static String USER_2_USERNAME = "jdoe2"; public final static String USER_2_USERNAME = "jdoe2";
...@@ -59,37 +77,56 @@ public abstract class BaseUnitTest { ...@@ -59,37 +77,56 @@ public abstract class BaseUnitTest {
.emailVerified(USER_2_VERIFIED) .emailVerified(USER_2_VERIFIED)
.themeDark(USER_2_THEME_DARK) .themeDark(USER_2_THEME_DARK)
.created(USER_2_CREATED) .created(USER_2_CREATED)
.roles(List.of(RoleType.ROLE_RESEARCHER))
.lastModified(USER_2_LAST_MODIFIED) .lastModified(USER_2_LAST_MODIFIED)
.build(); .build();
public final static Long TOKEN_1_ID = 1L; public final static UserDetails USER_2_DETAILS = UserDetailsDto.builder()
public final static Boolean TOKEN_1_PROCESSED = false; .username(USER_2_USERNAME)
public final static String TOKEN_1_TOKEN = "mysecrettokenrandomlygenerated"; .email(USER_2_EMAIL)
public final static Instant TOKEN_1_VALID_TO = Instant.now() .password(USER_2_PASSWORD)
.authorities(List.of(new SimpleGrantedAuthority("ROLE_RESEARCHER")))
.build();
public final static Principal USER_2_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_2_DETAILS,
USER_2_PASSWORD, USER_2_DETAILS.getAuthorities());
public final static Long TIME_SECRET_1_ID = 1L;
public final static Boolean TIME_SECRET_1_PROCESSED = false;
public final static String TIME_SECRET_1_TOKEN = "mysecrettokenrandomlygenerated";
public final static Instant TIME_SECRET_1_VALID_TO = Instant.now()
.plus(1, ChronoUnit.DAYS); .plus(1, ChronoUnit.DAYS);
public final static Long TOKEN_2_ID = 2L; public final static Long TIME_SECRET_2_ID = 2L;
public final static Boolean TOKEN_2_PROCESSED = true; public final static Boolean TIME_SECRET_2_PROCESSED = true;
public final static String TOKEN_2_TOKEN = "blahblahblah"; public final static String TIME_SECRET_2_TOKEN = "blahblahblah";
public final static Instant TOKEN_2_VALID_TO = Instant.now() public final static Instant TIME_SECRET_2_VALID_TO = Instant.now()
.plus(1, ChronoUnit.DAYS); .plus(1, ChronoUnit.DAYS);
public final static TimeSecret TOKEN_1 = TimeSecret.builder() public final static TimeSecret TIME_SECRET_1 = TimeSecret.builder()
.id(TOKEN_1_ID) .id(TIME_SECRET_1_ID)
.uid(USER_1_ID) .uid(USER_1_ID)
.user(USER_1) .user(USER_1)
.token(TOKEN_1_TOKEN) .token(TIME_SECRET_1_TOKEN)
.processed(TOKEN_1_PROCESSED) .processed(TIME_SECRET_1_PROCESSED)
.validTo(TOKEN_1_VALID_TO) .validTo(TIME_SECRET_1_VALID_TO)
.build(); .build();
public final static TimeSecret TOKEN_2 = TimeSecret.builder() public final static TimeSecret TIME_SECRET_2 = TimeSecret.builder()
.id(TOKEN_2_ID) .id(TIME_SECRET_2_ID)
.uid(USER_2_ID) .uid(USER_2_ID)
.user(USER_2) .user(USER_2)
.token(TOKEN_2_TOKEN) .token(TIME_SECRET_2_TOKEN)
.processed(TOKEN_2_PROCESSED) .processed(TIME_SECRET_2_PROCESSED)
.validTo(TOKEN_2_VALID_TO) .validTo(TIME_SECRET_2_VALID_TO)
.build();
public final static Long TOKEN_1_ID = 1L;
public final static Instant TOKEN_1_EXPIRES = Instant.now().plus(100000000, ChronoUnit.MILLIS);
public final static Token TOKEN_1 = Token.builder()
.id(TOKEN_1_ID)
.expires(TOKEN_1_EXPIRES)
.build(); .build();
} }
...@@ -41,10 +41,10 @@ public class AuthenticationServiceIntegrationTest extends BaseUnitTest { ...@@ -41,10 +41,10 @@ public class AuthenticationServiceIntegrationTest extends BaseUnitTest {
public void beforeEach() { public void beforeEach() {
final User u1 = userRepository.save(USER_1); final User u1 = userRepository.save(USER_1);
final User u2 = userRepository.save(USER_2); final User u2 = userRepository.save(USER_2);
TOKEN_1.setUser(u1); TIME_SECRET_1.setUser(u1);
tokenRepository.save(TOKEN_1); tokenRepository.save(TIME_SECRET_1);
TOKEN_2.setUser(u2); TIME_SECRET_2.setUser(u2);
tokenRepository.save(TOKEN_2); tokenRepository.save(TIME_SECRET_2);
} }
@Test @Test
......
...@@ -20,31 +20,29 @@ import static org.junit.jupiter.api.Assertions.assertThrows; ...@@ -20,31 +20,29 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@SpringBootTest @SpringBootTest
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
public class TokenServiceIntegrationTest extends BaseUnitTest { public class TimeSecretUnitTest extends BaseUnitTest {
@MockBean @MockBean
private ReadyConfig readyConfig; private ReadyConfig readyConfig;
@Autowired @Autowired
private TimeSecretService tokenService; private TimeSecretService timeSecretService;
@Autowired @Autowired
private TimeSecretRepository tokenRepository; private TimeSecretRepository timeSecretRepository;
@BeforeEach @BeforeEach
public void beforeEach() { public void beforeEach() {
tokenRepository.save(TOKEN_1); timeSecretRepository.save(TIME_SECRET_1);
} }
@Test @Test
public void updateVerification_succeeds() throws SecretInvalidException { public void updateVerification_succeeds() throws SecretInvalidException {
/* mock */
/* test */ /* test */
tokenService.invalidate(TOKEN_1_TOKEN); timeSecretService.invalidate(TIME_SECRET_1_TOKEN);
assertThrows(SecretInvalidException.class, () -> { assertThrows(SecretInvalidException.class, () -> {
tokenService.invalidate(TOKEN_1_TOKEN); timeSecretService.invalidate(TIME_SECRET_1_TOKEN);
}); });
} }
......
package at.tuwien.service;
import at.tuwien.BaseUnitTest;
import at.tuwien.auth.JwtUtils;
import at.tuwien.config.ReadyConfig;
import at.tuwien.entities.user.Token;
import at.tuwien.exception.TokenNotEligableException;
import at.tuwien.exception.TokenNotFoundException;
import at.tuwien.exception.UserNotFoundException;
import at.tuwien.repositories.TokenRepository;
import at.tuwien.repositories.UserRepository;
import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.BeforeEach;
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.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import javax.servlet.ServletException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import static org.junit.jupiter.api.Assertions.assertThrows;
@Log4j2
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@SpringBootTest
@ExtendWith(SpringExtension.class)
public class TokenIntegrationTest extends BaseUnitTest {
@MockBean
private ReadyConfig readyConfig;
@Autowired
private TokenService tokenService;
@Autowired
private UserRepository userRepository;
@Autowired
private TokenRepository tokenRepository;
@Autowired
private JwtUtils jwtUtils;
@BeforeEach
public void beforeEach() {
userRepository.save(USER_1);
}
@Test
public void check_succeeds() throws ServletException {
/* mock */
final String jwt = jwtUtils.generateJwtToken(USER_1_USERNAME, TOKEN_1_EXPIRES);
final Token entity = Token.builder()
.token(jwt)
.tokenHash(JwtUtils.toHash(jwt))
.creator(USER_1_ID)
.expires(TOKEN_1_EXPIRES)
.build();
final Token token = tokenRepository.save(entity);
/* test */
tokenService.check(jwt);
}
@Test
public void check_revoked_fails() {
/* mock */
final String jwt = jwtUtils.generateJwtToken(USER_1_USERNAME, TOKEN_1_EXPIRES);
final Token entity = Token.builder()
.token(jwt)
.tokenHash(JwtUtils.toHash(jwt))
.creator(USER_1_ID)
.expires(TOKEN_1_EXPIRES)
.deleted(Instant.now().minus(1, ChronoUnit.SECONDS))
.build();
final Token token = tokenRepository.save(entity);
/* test */
assertThrows(ServletException.class, () -> {
tokenService.check(jwt);
});
}
@Test
public void create_userNotFound_fails() {
/* test */
assertThrows(UserNotFoundException.class, () -> {
tokenService.create(USER_2_PRINCIPAL);
});
}
}
package at.tuwien.auth; package at.tuwien.auth;
import at.tuwien.service.TokenService;
import at.tuwien.service.impl.UserDetailsServiceImpl; import at.tuwien.service.impl.UserDetailsServiceImpl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
...@@ -20,10 +21,12 @@ import java.io.IOException; ...@@ -20,10 +21,12 @@ import java.io.IOException;
public class AuthTokenFilter extends OncePerRequestFilter { public class AuthTokenFilter extends OncePerRequestFilter {
private final JwtUtils jwtUtils; private final JwtUtils jwtUtils;
private final TokenService tokenService;
private final UserDetailsServiceImpl userDetailsService; private final UserDetailsServiceImpl userDetailsService;
public AuthTokenFilter(JwtUtils jwtUtils, UserDetailsServiceImpl userDetailsService) { public AuthTokenFilter(JwtUtils jwtUtils, TokenService tokenService, UserDetailsServiceImpl userDetailsService) {
this.jwtUtils = jwtUtils; this.jwtUtils = jwtUtils;
this.tokenService = tokenService;
this.userDetailsService = userDetailsService; this.userDetailsService = userDetailsService;
} }
...@@ -32,6 +35,7 @@ public class AuthTokenFilter extends OncePerRequestFilter { ...@@ -32,6 +35,7 @@ public class AuthTokenFilter extends OncePerRequestFilter {
throws ServletException, IOException { throws ServletException, IOException {
final String jwt = parseJwt(request); final String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateJwtToken(jwt)) { if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
tokenService.check(jwt);
final String username = jwtUtils.getUserNameFromJwtToken(jwt); final String username = jwtUtils.getUserNameFromJwtToken(jwt);
final UserDetails userDetails; final UserDetails userDetails;
try { try {
......
...@@ -5,6 +5,7 @@ import com.auth0.jwt.algorithms.Algorithm; ...@@ -5,6 +5,7 @@ import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -40,6 +41,10 @@ public class JwtUtils { ...@@ -40,6 +41,10 @@ public class JwtUtils {
.getSubject(); .getSubject();
} }
public static String toHash(String token) {
return DigestUtils.sha256Hex(token);
}
public boolean validateJwtToken(String authToken) { public boolean validateJwtToken(String authToken) {
try { try {
final DecodedJWT jwt = JWT.decode(authToken); final DecodedJWT jwt = JWT.decode(authToken);
......
...@@ -2,6 +2,7 @@ package at.tuwien.config; ...@@ -2,6 +2,7 @@ package at.tuwien.config;
import at.tuwien.auth.AuthTokenFilter; import at.tuwien.auth.AuthTokenFilter;
import at.tuwien.auth.JwtUtils; import at.tuwien.auth.JwtUtils;
import at.tuwien.service.TokenService;
import at.tuwien.service.impl.UserDetailsServiceImpl; import at.tuwien.service.impl.UserDetailsServiceImpl;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme; import io.swagger.v3.oas.annotations.security.SecurityScheme;
...@@ -35,20 +36,22 @@ import javax.servlet.http.HttpServletResponse; ...@@ -35,20 +36,22 @@ import javax.servlet.http.HttpServletResponse;
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtUtils jwtUtils; private final JwtUtils jwtUtils;
private final TokenService tokenService;
private final SecurityConfig securityConfig; private final SecurityConfig securityConfig;
private final UserDetailsServiceImpl userDetailsService; private final UserDetailsServiceImpl userDetailsService;
@Autowired @Autowired
public WebSecurityConfig(JwtUtils jwtUtils, SecurityConfig securityConfig, public WebSecurityConfig(JwtUtils jwtUtils, TokenService tokenService, SecurityConfig securityConfig,
UserDetailsServiceImpl userDetailsService) { UserDetailsServiceImpl userDetailsService) {
this.jwtUtils = jwtUtils; this.jwtUtils = jwtUtils;
this.tokenService = tokenService;
this.securityConfig = securityConfig; this.securityConfig = securityConfig;
this.userDetailsService = userDetailsService; this.userDetailsService = userDetailsService;
} }
@Bean @Bean
public AuthTokenFilter authTokenFilter() { public AuthTokenFilter authTokenFilter() {
return new AuthTokenFilter(jwtUtils, userDetailsService); return new AuthTokenFilter(jwtUtils, tokenService, userDetailsService);
} }
@Override @Override
......
...@@ -5,7 +5,9 @@ import at.tuwien.exception.TokenNotEligableException; ...@@ -5,7 +5,9 @@ import at.tuwien.exception.TokenNotEligableException;
import at.tuwien.exception.TokenNotFoundException; import at.tuwien.exception.TokenNotFoundException;
import at.tuwien.exception.UserNotFoundException; import at.tuwien.exception.UserNotFoundException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.ServletException;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
...@@ -49,4 +51,11 @@ public interface TokenService { ...@@ -49,4 +51,11 @@ public interface TokenService {
* @throws UserNotFoundException The user does not exist in the metadata database. * @throws UserNotFoundException The user does not exist in the metadata database.
*/ */
void delete(String tokenHash, Principal principal) throws TokenNotFoundException, UserNotFoundException; void delete(String tokenHash, Principal principal) throws TokenNotFoundException, UserNotFoundException;
/**
* Checks if the developer token has not been marked as deleted
*
* @param jwt The token
*/
void check(String jwt) throws ServletException;
} }
...@@ -15,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -15,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.servlet.ServletException;
import java.security.Principal; import java.security.Principal;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
...@@ -94,4 +95,20 @@ public class TokenServiceImpl implements TokenService { ...@@ -94,4 +95,20 @@ public class TokenServiceImpl implements TokenService {
log.debug("deleted token {}", token); log.debug("deleted token {}", token);
} }
@Override
@Transactional
public void check(String jwt) throws ServletException {
final Optional<Token> optional = tokenRepository.findByTokenHash(JwtUtils.toHash(jwt));
if (optional.isEmpty()) {
return;
}
final Token token = optional.get();
if (token.getDeleted() != null) {
log.error("Token was marked as deleted on {}", token.getDeleted());
throw new ServletException("Token was marked as deleted");
}
token.setLastUsed(Instant.now());
tokenRepository.save(token);
}
} }
...@@ -51,10 +51,10 @@ public class Token { ...@@ -51,10 +51,10 @@ public class Token {
@Column(nullable = false, updatable = false) @Column(nullable = false, updatable = false)
private Instant expires; private Instant expires;
@Column(nullable = false, updatable = false) @Column
private Instant lastUsed; private Instant lastUsed;
@Column(nullable = false, updatable = false) @Column(updatable = false)
private Instant deleted; private Instant deleted;
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment