Skip to content

Commit

Permalink
Merge pull request #199 from kbss-cvut/development
Browse files Browse the repository at this point in the history
Release 2.14.1
  • Loading branch information
ledsoft authored Nov 27, 2022
2 parents 523ce1e + 7772be1 commit 3f1a520
Show file tree
Hide file tree
Showing 17 changed files with 364 additions and 402 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</parent>

<artifactId>termit</artifactId>
<version>2.14.0</version>
<version>2.14.1</version>
<name>TermIt</name>
<description>Terminology manager based on Semantic Web technologies.</description>
<packaging>${packaging}</packaging>
Expand All @@ -32,7 +32,7 @@
<org.springframework.data.version>2.7.5</org.springframework.data.version>
<org.hibernate.validator.version>6.2.3.Final</org.hibernate.validator.version>
<org.apache.tika.tika-core.version>2.5.0</org.apache.tika.tika-core.version>
<cz.cvut.kbss.jopa.version>0.19.0</cz.cvut.kbss.jopa.version>
<cz.cvut.kbss.jopa.version>0.19.2</cz.cvut.kbss.jopa.version>
<cz.cvut.kbss.jsonld.version>0.9.0</cz.cvut.kbss.jsonld.version>
<org.aspectj.version>1.9.7</org.aspectj.version>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ protected void configure(HttpSecurity http) throws Exception {
.and().exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and().cors().configurationSource(corsConfigurationSource()).and().csrf().disable()
.addFilter(authenticationFilter())
.addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtUtils, securityUtils, userDetailsService,
.addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtUtils, userDetailsService,
objectMapper));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,14 @@ public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

private final JwtUtils jwtUtils;

private final SecurityUtils securityUtils;

private final TermItUserDetailsService userDetailsService;

private final ObjectMapper objectMapper;

public JwtAuthorizationFilter(AuthenticationManager authenticationManager, JwtUtils jwtUtils,
SecurityUtils securityUtils, TermItUserDetailsService userDetailsService,
ObjectMapper objectMapper) {
TermItUserDetailsService userDetailsService, ObjectMapper objectMapper) {
super(authenticationManager);
this.jwtUtils = jwtUtils;
this.securityUtils = securityUtils;
this.userDetailsService = userDetailsService;
this.objectMapper = objectMapper;
}
Expand All @@ -83,7 +79,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
final TermItUserDetails userDetails = jwtUtils.extractUserInfo(authToken);
final TermItUserDetails existingDetails = userDetailsService.loadUserByUsername(userDetails.getUsername());
SecurityUtils.verifyAccountStatus(existingDetails.getUser());
securityUtils.setCurrentUser(existingDetails);
SecurityUtils.setCurrentUser(existingDetails);
refreshToken(authToken, response);
chain.doFilter(request, response);
} catch (JwtException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,14 @@ public class OntologicalAuthenticationProvider implements AuthenticationProvider

private static final Logger LOG = LoggerFactory.getLogger(OntologicalAuthenticationProvider.class);

private final SecurityUtils securityUtils;

private final TermItUserDetailsService userDetailsService;

private final PasswordEncoder passwordEncoder;

private ApplicationEventPublisher eventPublisher;

@Autowired
public OntologicalAuthenticationProvider(SecurityUtils securityUtils, TermItUserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
this.securityUtils = securityUtils;
public OntologicalAuthenticationProvider(TermItUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
this.userDetailsService = userDetailsService;
this.passwordEncoder = passwordEncoder;
}
Expand All @@ -69,7 +65,7 @@ public Authentication authenticate(Authentication authentication) {
throw new BadCredentialsException("Provided credentials don't match.");
}
onLoginSuccess(userDetails.getUser());
return securityUtils.setCurrentUser(userDetails);
return SecurityUtils.setCurrentUser(userDetails);
}

private static void verifyUsernameNotEmpty(String username) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,12 @@ public CommentChangeNotifier(CommentService commentService, TermService termServ
* @param to Interval end
* @return Notification message ready for sending via email
*/
public Message createCommentChangesMessage(Instant from, Instant to) {
public Optional<Message> createCommentChangesMessage(Instant from, Instant to) {
final Map<Asset<?>, List<Comment>> comments = findChangedComments(from, to);
if (comments.isEmpty()) {
LOG.debug("No new or updated comments found for the specified interval.");
return Optional.empty();
}
final Map<String, Object> variables = new HashMap<>();
final List<AssetWithComments> assetsWithComments = comments.entrySet().stream()
.map(e -> new AssetWithComments(
Expand All @@ -74,10 +78,10 @@ public Message createCommentChangesMessage(Instant from, Instant to) {
variables.put("from", LocalDate.ofInstant(from, ZoneId.systemDefault()));
variables.put("to", LocalDate.ofInstant(to, ZoneId.systemDefault()));
variables.put("commentedAssets", assetsWithComments);
return Message.to(resolveNotificationRecipients(comments).stream().map(
return Optional.of(Message.to(resolveNotificationRecipients(comments).stream().map(
AbstractUser::getUsername).toArray(String[]::new))
.content(messageComposer.composeMessage(COMMENT_CHANGES_TEMPLATE, variables))
.subject("TermIt News").build();
.subject("TermIt News").build());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.stereotype.Service;

import java.time.*;
import java.util.Optional;

@Service
public class NotificationService {
Expand Down Expand Up @@ -39,8 +40,8 @@ public void notifyOfCommentChanges() {
LOG.debug("Running comment change notification.");
final Instant now = Utils.timestamp();
final Instant previous = resolvePreviousRun(now, scheduleConfig.getCron().getNotification().getComments());
final Message changeNotificationMessage = commentChangeNotifier.createCommentChangesMessage(previous, now);
postman.sendMessage(changeNotificationMessage);
final Optional<Message> changeNotificationMessage = commentChangeNotifier.createCommentChangesMessage(previous, now);
changeNotificationMessage.ifPresent(postman::sendMessage);
}

private static Instant resolvePreviousRun(Instant now, String cronExpression) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public boolean isAuthenticated() {
* @param userDetails Details of the user to set as current
* @return The generated authentication token
*/
public AuthenticationToken setCurrentUser(TermItUserDetails userDetails) {
public static AuthenticationToken setCurrentUser(TermItUserDetails userDetails) {
final AuthenticationToken token = new AuthenticationToken(userDetails.getAuthorities(), userDetails);
token.setAuthenticated(true);

Expand Down
12 changes: 0 additions & 12 deletions src/test/java/cz/cvut/kbss/termit/environment/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Environment {
Expand Down Expand Up @@ -87,16 +85,6 @@ public static void setCurrentUser(User user) {
setCurrentUser(ua);
}

/**
* Gets current user as security principal.
*
* @return Current user authentication as principal or {@code null} if there is no current user
*/
public static Optional<Principal> getCurrentUserPrincipal() {
return SecurityContextHolder.getContext() != null ?
Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()) : Optional.empty();
}

public static UserAccount getCurrentUser() {
return currentUser;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;

import java.io.IOException;
import java.net.URI;
Expand All @@ -50,7 +49,6 @@

import static org.junit.jupiter.api.Assertions.*;

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class DataDaoTest extends BaseDaoTestRunner {

private static final String FIRST_NAME_LABEL = "First name";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
import cz.cvut.kbss.termit.model.resource.File;
import cz.cvut.kbss.termit.model.resource.Resource;
import cz.cvut.kbss.termit.persistence.context.DescriptorFactory;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -321,4 +325,74 @@ void updateRefreshesLastModifiedValue() throws Exception {
final long after = sut.getLastModified();
assertThat(after, greaterThan(before));
}

@Test
void removeFileUpdatesParentDocumentInVocabularyContext() {
final Document document = Generator.generateDocumentWithId();
final cz.cvut.kbss.termit.model.Vocabulary vocabulary = new cz.cvut.kbss.termit.model.Vocabulary();
vocabulary.setUri(Generator.generateUri());
vocabulary.setLabel("Vocabulary");
vocabulary.setGlossary(new Glossary());
vocabulary.setModel(new Model());
vocabulary.setDocument(document);
document.setVocabulary(vocabulary.getUri());
final File file = new File();
file.setLabel("test.html");
file.setUri(Generator.generateUri());
file.setDocument(document);
final File fileTwo = new File();
fileTwo.setLabel("test-two.html");
fileTwo.setUri(Generator.generateUri());
fileTwo.setDocument(document);
document.addFile(fileTwo);
transactional(() -> {
em.persist(vocabulary, descriptorFactory.vocabularyDescriptor(vocabulary));
em.persist(document, descriptorFactory.documentDescriptor(vocabulary));
em.persist(file, descriptorFactory.fileDescriptor(vocabulary));
em.persist(fileTwo, descriptorFactory.fileDescriptor(vocabulary));
});

transactional(() -> {
final Resource toRemove = sut.getReference(file.getUri()).get();
sut.remove(toRemove);
});

final cz.cvut.kbss.termit.model.Vocabulary
result = em.find(cz.cvut.kbss.termit.model.Vocabulary.class, vocabulary.getUri(),
descriptorFactory.vocabularyDescriptor(vocabulary));
assertEquals(1, result.getDocument().getFiles().size());
assertTrue(result.getDocument().getFiles().contains(fileTwo));
}

@Test
void updateSupportsSubclassesOfResource() {
final Document doc = Generator.generateDocumentWithId();
final File fileOne = Generator.generateFileWithId("test.html");
doc.addFile(fileOne);
final File fileTwo = Generator.generateFileWithId("testTwo.html");
transactional(() -> {
// Ensure correct RDFS class hierarchy interpretation
final Repository repository = em.unwrap(Repository.class);
try (final RepositoryConnection conn = repository.getConnection()) {
final ValueFactory vf = conn.getValueFactory();
conn.add(vf.createIRI(cz.cvut.kbss.termit.util.Vocabulary.s_c_dokument), RDFS.SUBCLASSOF, vf.createIRI(
cz.cvut.kbss.termit.util.Vocabulary.s_c_zdroj));
}
em.persist(doc);
em.persist(fileOne);
em.persist(fileTwo);
});

final String newName = "Updated name";
doc.setLabel(newName);
final String newDescription = "Document description.";
doc.setDescription(newDescription);
doc.addFile(fileTwo);
transactional(() -> sut.update(doc));
final Document result = em.find(Document.class, doc.getUri());
assertEquals(newName, result.getLabel());
assertEquals(newDescription, result.getDescription());
assertEquals(2, result.getFiles().size());
assertTrue(result.getFiles().contains(fileTwo));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
import cz.cvut.kbss.termit.util.Configuration;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -41,6 +41,7 @@
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
Expand Down Expand Up @@ -81,9 +82,6 @@ class JwtAuthorizationFilterTest {
@Mock
private TermItUserDetailsService detailsServiceMock;

@Mock
private SecurityUtils securityUtilsMock;

private JwtUtils jwtUtilsSpy;

private ObjectMapper objectMapper;
Expand All @@ -100,20 +98,22 @@ void setUp() {
this.objectMapper = Environment.getObjectMapper();
this.signingKey = Keys.hmacShaKeyFor(config.getJwt().getSecretKey().getBytes(StandardCharsets.UTF_8));
this.jwtUtilsSpy = spy(new JwtUtils(objectMapper, config));
this.sut = new JwtAuthorizationFilter(authManagerMock, jwtUtilsSpy, securityUtilsMock, detailsServiceMock,
this.sut = new JwtAuthorizationFilter(authManagerMock, jwtUtilsSpy, detailsServiceMock,
objectMapper);
}

@AfterEach
void tearDown() {
Environment.resetCurrentUser();
}

@Test
void doFilterInternalExtractsUserInfoFromJwtAndSetsUpSecurityContext() throws Exception {
when(detailsServiceMock.loadUserByUsername(user.getUsername())).thenReturn(new TermItUserDetails(user));
generateJwtIntoRequest();

sut.doFilterInternal(mockRequest, mockResponse, chainMock);
final ArgumentCaptor<TermItUserDetails> captor = ArgumentCaptor.forClass(TermItUserDetails.class);
verify(securityUtilsMock).setCurrentUser(captor.capture());
final TermItUserDetails userDetails = captor.getValue();
assertEquals(user, userDetails.getUser());
assertEquals(user, SecurityUtils.currentUser());
}

private void generateJwtIntoRequest() {
Expand Down Expand Up @@ -141,18 +141,20 @@ void doFilterInternalInvokesFilterChainAfterSuccessfulExtractionOfUserInfo() thr
@Test
void doFilterInternalLeavesEmptySecurityContextAndPassesRequestDownChainWhenAuthenticationIsMissing()
throws Exception {
Environment.resetCurrentUser();
sut.doFilterInternal(mockRequest, mockResponse, chainMock);
verify(chainMock).doFilter(mockRequest, mockResponse);
verify(securityUtilsMock, never()).setCurrentUser(any());
assertNull(SecurityContextHolder.getContext().getAuthentication());
}

@Test
void doFilterInternalLeavesEmptySecurityContextAndPassesRequestDownChainWhenAuthenticationHasIncorrectFormat()
throws Exception {
Environment.resetCurrentUser();
mockRequest.addHeader(HttpHeaders.AUTHORIZATION, generateJwt());
sut.doFilterInternal(mockRequest, mockResponse, chainMock);
verify(chainMock).doFilter(mockRequest, mockResponse);
verify(securityUtilsMock, never()).setCurrentUser(any());
assertNull(SecurityContextHolder.getContext().getAuthentication());
}

@Test
Expand Down
Loading

0 comments on commit 3f1a520

Please sign in to comment.