0.1 #1
10 changed files with 186 additions and 39 deletions
|
@ -2,6 +2,7 @@ package net.friedl.fling.controller;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -56,12 +57,17 @@ public class FlingController {
|
||||||
return flingService.create(flingDto);
|
return flingService.create(flingDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/artifact")
|
@PostMapping("/{id}/artifacts")
|
||||||
public ArtifactDto postArtifact(@PathVariable UUID id,
|
public ArtifactDto postArtifact(@PathVariable UUID id,
|
||||||
@RequestBody @Valid ArtifactDto artifactDto) {
|
@RequestBody @Valid ArtifactDto artifactDto) {
|
||||||
return artifactService.create(id, artifactDto);
|
return artifactService.create(id, artifactDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}/artifacts")
|
||||||
|
public Set<ArtifactDto> getArtifacts(@PathVariable UUID id) {
|
||||||
|
return flingService.getArtifacts(id);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping(path = "/{id}")
|
@GetMapping(path = "/{id}")
|
||||||
public FlingDto getFling(@PathVariable UUID id) {
|
public FlingDto getFling(@PathVariable UUID id) {
|
||||||
return flingService.getById(id);
|
return flingService.getById(id);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.friedl.fling.model.mapper;
|
package net.friedl.fling.model.mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import net.friedl.fling.model.dto.ArtifactDto;
|
import net.friedl.fling.model.dto.ArtifactDto;
|
||||||
import net.friedl.fling.persistence.entities.ArtifactEntity;
|
import net.friedl.fling.persistence.entities.ArtifactEntity;
|
||||||
|
@ -13,5 +14,7 @@ public interface ArtifactMapper {
|
||||||
|
|
||||||
List<ArtifactDto> mapEntities(List<ArtifactEntity> artifactEntities);
|
List<ArtifactDto> mapEntities(List<ArtifactEntity> artifactEntities);
|
||||||
|
|
||||||
|
Set<ArtifactDto> mapEntities(Set<ArtifactEntity> artifactEntities);
|
||||||
|
|
||||||
List<ArtifactEntity> mapDtos(List<ArtifactDto> artifactDtos);
|
List<ArtifactEntity> mapDtos(List<ArtifactDto> artifactDtos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@ public interface FlingRepository extends JpaRepository<FlingEntity, UUID> {
|
||||||
|
|
||||||
FlingEntity findByShareId(String shareId);
|
FlingEntity findByShareId(String shareId);
|
||||||
|
|
||||||
@Query("SELECT COUNT(*) FROM ArtifactEntity a, FlingEntity f where a.fling=f.id and f.id=:flingId")
|
@Query("SELECT fe FROM FlingEntity fe JOIN ArtifactEntity ae ON fe.id=ae.id WHERE ae.id=:artifactId")
|
||||||
Long countArtifactsById(Long flingId);
|
FlingEntity findByArtifactId(UUID artifactId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.friedl.fling.security;
|
package net.friedl.fling.security;
|
||||||
|
|
||||||
|
import static net.friedl.fling.security.FlingAuthorities.FLING_ADMIN;
|
||||||
import static org.springframework.security.config.Customizer.withDefaults;
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -10,6 +11,7 @@ import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
|
@ -48,54 +50,76 @@ public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
|
||||||
http
|
http
|
||||||
.csrf().disable()
|
.csrf().disable()
|
||||||
.cors(withDefaults())
|
.cors(withDefaults())
|
||||||
|
|
||||||
|
/**********************************************/
|
||||||
|
/** Authentication Interceptor Configuration **/
|
||||||
|
/**********************************************/
|
||||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
|
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
|
||||||
// Everybody can try to authenticate
|
// Do not keep authorization token in session. This would interfere with bearer authentication
|
||||||
|
// in that it is possible to authenticate without a bearer token if the session is kept.
|
||||||
|
// Turn off this confusing and non-obvious behavior.
|
||||||
|
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************/
|
||||||
|
/** API Authorization Configuration **/
|
||||||
|
/*************************************/
|
||||||
|
//! Go from most specific to more !//
|
||||||
|
//! general, as first hit counts !//
|
||||||
|
|
||||||
|
/**********************************/
|
||||||
|
/** Authorization for: /api/auth **/
|
||||||
|
/**********************************/
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers("/api/auth/**")
|
.antMatchers("/api/auth/**")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.and()
|
.and()
|
||||||
// We need to go from most specific to more general.
|
|
||||||
// Hence, first define user permissions
|
|
||||||
.authorizeRequests()
|
/***********************************/
|
||||||
// TODO: This is still insecure since URLs are not encrypted
|
/** Authorization for: /api/fling **/
|
||||||
// TODO: iframe requests don't send the bearer, use cookie instead
|
/***********************************/
|
||||||
.antMatchers(HttpMethod.GET, "/api/fling/{flingId}/download/{downloadId}")
|
|
||||||
.permitAll()
|
|
||||||
.and()
|
|
||||||
.authorizeRequests()
|
|
||||||
.antMatchers(HttpMethod.POST, "/api/artifacts/{flingId}/**")
|
|
||||||
.access("@authorizationService.allowUpload(#flingId, authentication)")
|
|
||||||
.and()
|
|
||||||
.authorizeRequests()
|
|
||||||
.antMatchers(HttpMethod.PATCH, "/api/artifacts/{artifactId}")
|
|
||||||
.access("@authorizationService.allowPatchingArtifact(#artifactId, authentication)")
|
|
||||||
.and()
|
|
||||||
.authorizeRequests()
|
|
||||||
// TODO: This is still insecure since URLs are not encrypted
|
|
||||||
// TODO: iframe requests don't send the bearer, use cookie instead
|
|
||||||
.antMatchers("/api/artifacts/{artifactId}/{downloadId}/download")
|
|
||||||
.permitAll()
|
|
||||||
.and()
|
|
||||||
.authorizeRequests()
|
|
||||||
// TODO: Security by request parameters is just not well supported with spring security
|
|
||||||
// TODO: Change API
|
|
||||||
.regexMatchers(HttpMethod.GET, "\\/api\\/fling\\?(shareId=|flingId=)[a-zA-Z0-9]+")
|
|
||||||
.access("@authorizationService.allowFlingAccess(authentication, request)")
|
|
||||||
.and()
|
|
||||||
.authorizeRequests()
|
|
||||||
// TODO: Security by request parameters is just not well supported with spring security
|
|
||||||
// TODO: Change API
|
|
||||||
.regexMatchers(HttpMethod.GET, "\\/api\\/artifacts\\?(shareId=|flingId=)[a-zA-Z0-9]+")
|
|
||||||
.access("@authorizationService.allowFlingAccess(authentication, request)")
|
|
||||||
.and()
|
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers(HttpMethod.GET, "/api/fling/{flingId}/**")
|
.antMatchers(HttpMethod.GET, "/api/fling/{flingId}/**")
|
||||||
.access("@authorizationService.allowFlingAccess(#flingId, authentication)")
|
.access("@authorizationService.allowFlingAccess(#flingId, authentication)")
|
||||||
.and()
|
.and()
|
||||||
// And lastly, the owner is allowed everything
|
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers("/api/**")
|
.antMatchers(HttpMethod.GET, "/api/fling/share/{shareId}")
|
||||||
.hasAuthority(FlingAuthorities.FLING_ADMIN.getAuthority());
|
.access("@authorizationService.allowFlingAccessByShareId(#shareId, authentication)")
|
||||||
|
.and()
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.POST, "/api/fling/{flingId}/artifact")
|
||||||
|
.access("@authorizationService.allowUpload(#flingId, authentication)")
|
||||||
|
.and()
|
||||||
|
// only admin can create, delete and list flings
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.DELETE, "/api/fling/{flingId}")
|
||||||
|
.hasAnyAuthority(FLING_ADMIN.getAuthority())
|
||||||
|
.and()
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.POST, "/api/fling")
|
||||||
|
.hasAuthority(FLING_ADMIN.getAuthority())
|
||||||
|
.and()
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.GET, "/api/fling")
|
||||||
|
.hasAuthority(FLING_ADMIN.getAuthority())
|
||||||
|
.and()
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************/
|
||||||
|
/** Authorization for: /api/artifacts **/
|
||||||
|
/***************************************/
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.GET, "/api/artifacts/{artifactId}/**")
|
||||||
|
.access("@authorizationService.allowArtifactAccess(#artifactId, token)")
|
||||||
|
.and()
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.POST, "/api/artifacts/{artifactId}/data")
|
||||||
|
.access("@authorizationService.allowArtifactUpload(#artifactId, token)")
|
||||||
|
.and()
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.DELETE, "/api/artifacts/{artifactId}")
|
||||||
|
.access("@authorizationService.allowArtifactUpload(#artifactId, token)");
|
||||||
|
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class AuthenticationService {
|
||||||
Claims claims = jwtParser.parseClaimsJws(token).getBody();
|
Claims claims = jwtParser.parseClaimsJws(token).getBody();
|
||||||
|
|
||||||
switch (claims.getSubject()) {
|
switch (claims.getSubject()) {
|
||||||
case "owner":
|
case "admin":
|
||||||
return new FlingToken(new FlingAdminAuthority(), token);
|
return new FlingToken(new FlingAdminAuthority(), token);
|
||||||
case "user":
|
case "user":
|
||||||
UUID grantedFlingId = UUID.fromString(claims.get("id", String.class));
|
UUID grantedFlingId = UUID.fromString(claims.get("id", String.class));
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.friedl.fling.persistence.entities.FlingEntity;
|
||||||
import net.friedl.fling.persistence.repositories.FlingRepository;
|
import net.friedl.fling.persistence.repositories.FlingRepository;
|
||||||
import net.friedl.fling.security.FlingAuthorities;
|
import net.friedl.fling.security.FlingAuthorities;
|
||||||
import net.friedl.fling.security.authentication.FlingToken;
|
import net.friedl.fling.security.authentication.FlingToken;
|
||||||
|
@ -65,4 +66,20 @@ public class AuthorizationService {
|
||||||
log.info("User not authorized to access fling[.id={}]", flingId);
|
log.info("User not authorized to access fling[.id={}]", flingId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean allowFlingAccessByShareId(String shareId, AbstractAuthenticationToken token) {
|
||||||
|
FlingEntity flingEntity = flingRepository.findByShareId(shareId);
|
||||||
|
return allowFlingAccess(flingEntity.getId(), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allowArtifactAccess(UUID artifactId, AbstractAuthenticationToken token) {
|
||||||
|
FlingEntity flingEntity = flingRepository.findByArtifactId(artifactId);
|
||||||
|
return allowFlingAccess(flingEntity.getId(), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allowArtifactUpload(UUID artifactId, AbstractAuthenticationToken token) {
|
||||||
|
FlingEntity flingEntity = flingRepository.findByArtifactId(artifactId);
|
||||||
|
return allowUpload(flingEntity.getId(), token);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package net.friedl.fling.service;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -11,7 +12,9 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.friedl.fling.model.dto.ArtifactDto;
|
||||||
import net.friedl.fling.model.dto.FlingDto;
|
import net.friedl.fling.model.dto.FlingDto;
|
||||||
|
import net.friedl.fling.model.mapper.ArtifactMapper;
|
||||||
import net.friedl.fling.model.mapper.FlingMapper;
|
import net.friedl.fling.model.mapper.FlingMapper;
|
||||||
import net.friedl.fling.persistence.entities.FlingEntity;
|
import net.friedl.fling.persistence.entities.FlingEntity;
|
||||||
import net.friedl.fling.persistence.repositories.FlingRepository;
|
import net.friedl.fling.persistence.repositories.FlingRepository;
|
||||||
|
@ -24,15 +27,18 @@ public class FlingService {
|
||||||
|
|
||||||
private FlingRepository flingRepository;
|
private FlingRepository flingRepository;
|
||||||
private FlingMapper flingMapper;
|
private FlingMapper flingMapper;
|
||||||
|
private ArtifactMapper artifactMapper;
|
||||||
private ArchiveService archiveService;
|
private ArchiveService archiveService;
|
||||||
private PasswordEncoder passwordEncoder;
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public FlingService(FlingRepository flingRepository, FlingMapper flingMapper,
|
public FlingService(FlingRepository flingRepository, FlingMapper flingMapper,
|
||||||
|
ArtifactMapper artifactMapper,
|
||||||
ArchiveService archiveService, PasswordEncoder passwordEcoder) {
|
ArchiveService archiveService, PasswordEncoder passwordEcoder) {
|
||||||
|
|
||||||
this.flingRepository = flingRepository;
|
this.flingRepository = flingRepository;
|
||||||
this.flingMapper = flingMapper;
|
this.flingMapper = flingMapper;
|
||||||
|
this.artifactMapper = artifactMapper;
|
||||||
this.archiveService = archiveService;
|
this.archiveService = archiveService;
|
||||||
this.passwordEncoder = passwordEcoder;
|
this.passwordEncoder = passwordEcoder;
|
||||||
}
|
}
|
||||||
|
@ -92,6 +98,12 @@ public class FlingService {
|
||||||
log.debug("Deleted fling {}", id);
|
log.debug("Deleted fling {}", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<ArtifactDto> getArtifacts(UUID id) {
|
||||||
|
FlingEntity flingEntity = flingRepository.getOne(id);
|
||||||
|
Set<ArtifactDto> artifactDto = artifactMapper.mapEntities(flingEntity.getArtifacts());
|
||||||
|
return artifactDto == null ? Set.of() : artifactDto;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean validateAuthCode(UUID id, String authCode) {
|
public boolean validateAuthCode(UUID id, String authCode) {
|
||||||
FlingEntity flingEntity = flingRepository.getOne(id);
|
FlingEntity flingEntity = flingRepository.getOne(id);
|
||||||
if (StringUtils.hasText(flingEntity.getAuthCode()) != StringUtils.hasText(authCode)) {
|
if (StringUtils.hasText(flingEntity.getAuthCode()) != StringUtils.hasText(authCode)) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.friedl.fling.controller;
|
package net.friedl.fling.controller;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.anyOf;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
@ -20,6 +21,7 @@ import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.persistence.EntityNotFoundException;
|
import javax.persistence.EntityNotFoundException;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
|
@ -108,7 +110,7 @@ public class FlingControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void postArtifact_ok() throws Exception {
|
public void postArtifact_ok() throws Exception {
|
||||||
mockMvc.perform(post("/api/fling/{id}/artifact", flingId)
|
mockMvc.perform(post("/api/fling/{id}/artifacts", flingId)
|
||||||
.content(mapper.writeValueAsString(artifactDto))
|
.content(mapper.writeValueAsString(artifactDto))
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
|
@ -118,12 +120,49 @@ public class FlingControllerTest {
|
||||||
public void postArtifact_validatesBody_notOk() throws Exception {
|
public void postArtifact_validatesBody_notOk() throws Exception {
|
||||||
ArtifactDto invalidArtifactDto = new ArtifactDto();
|
ArtifactDto invalidArtifactDto = new ArtifactDto();
|
||||||
|
|
||||||
mockMvc.perform(post("/api/fling/{id}/artifact", flingId)
|
mockMvc.perform(post("/api/fling/{id}/artifacts", flingId)
|
||||||
.content(mapper.writeValueAsString(invalidArtifactDto))
|
.content(mapper.writeValueAsString(invalidArtifactDto))
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
.andExpect(status().isBadRequest());
|
.andExpect(status().isBadRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getArtifact_noFlingWithId_notFound() throws Exception {
|
||||||
|
doThrow(EntityNotFoundException.class).when(flingService).getArtifacts(flingId);
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/fling/{id}/artifacts", flingId))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getArtifact_flingFound_noArtifacts_emptySet() throws Exception {
|
||||||
|
when(flingService.getArtifacts(flingId)).thenReturn(Set.of());
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/fling/{id}/artifacts", flingId))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().string(equalTo("[]")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getArtifact_flingFound_hasArtifacts_returnArtifacts() throws Exception {
|
||||||
|
ArtifactDto artifactDto1 = ArtifactDto.builder()
|
||||||
|
.id(new UUID(0, 0))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ArtifactDto artifactDto2 = ArtifactDto.builder()
|
||||||
|
.id(new UUID(0, 1))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
when(flingService.getArtifacts(flingId)).thenReturn(Set.of(artifactDto1, artifactDto2));
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/fling/{id}/artifacts", flingId))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$[0].id",
|
||||||
|
anyOf(equalTo(new UUID(0, 0).toString()), equalTo(new UUID(0, 1).toString()))))
|
||||||
|
.andExpect(jsonPath("$[1].id",
|
||||||
|
anyOf(equalTo(new UUID(0, 0).toString()), equalTo(new UUID(0, 1).toString()))));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFling_noFlingWithId_notFound() throws Exception {
|
public void getFling_noFlingWithId_notFound() throws Exception {
|
||||||
doThrow(EntityNotFoundException.class).when(flingService).getById(flingId);
|
doThrow(EntityNotFoundException.class).when(flingService).getById(flingId);
|
||||||
|
|
|
@ -118,7 +118,7 @@ public class AuthenticationServiceTest {
|
||||||
@Test
|
@Test
|
||||||
public void parseAuthentication_owner_AdminAuthority() {
|
public void parseAuthentication_owner_AdminAuthority() {
|
||||||
Jws<Claims> jwsClaims = new DefaultJws<>(new DefaultJwsHeader(),
|
Jws<Claims> jwsClaims = new DefaultJws<>(new DefaultJwsHeader(),
|
||||||
new DefaultClaims(Map.of("sub", "owner")), "signature");
|
new DefaultClaims(Map.of("sub", "admin")), "signature");
|
||||||
when(jwtParser.parseClaimsJws(any(String.class))).thenReturn(jwsClaims);
|
when(jwtParser.parseClaimsJws(any(String.class))).thenReturn(jwsClaims);
|
||||||
|
|
||||||
FlingToken flingToken = authenticationService.parseAuthentication("any");
|
FlingToken flingToken = authenticationService.parseAuthentication("any");
|
||||||
|
|
|
@ -4,8 +4,10 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.hasItems;
|
import static org.hamcrest.CoreMatchers.hasItems;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.emptyOrNullString;
|
import static org.hamcrest.Matchers.emptyOrNullString;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
@ -13,7 +15,9 @@ import static org.mockito.Mockito.when;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
@ -25,9 +29,13 @@ import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import net.friedl.fling.model.dto.ArtifactDto;
|
||||||
import net.friedl.fling.model.dto.FlingDto;
|
import net.friedl.fling.model.dto.FlingDto;
|
||||||
|
import net.friedl.fling.model.mapper.ArtifactMapper;
|
||||||
|
import net.friedl.fling.model.mapper.ArtifactMapperImpl;
|
||||||
import net.friedl.fling.model.mapper.FlingMapper;
|
import net.friedl.fling.model.mapper.FlingMapper;
|
||||||
import net.friedl.fling.model.mapper.FlingMapperImpl;
|
import net.friedl.fling.model.mapper.FlingMapperImpl;
|
||||||
|
import net.friedl.fling.persistence.entities.ArtifactEntity;
|
||||||
import net.friedl.fling.persistence.entities.FlingEntity;
|
import net.friedl.fling.persistence.entities.FlingEntity;
|
||||||
import net.friedl.fling.persistence.repositories.FlingRepository;
|
import net.friedl.fling.persistence.repositories.FlingRepository;
|
||||||
import net.friedl.fling.service.archive.ArchiveService;
|
import net.friedl.fling.service.archive.ArchiveService;
|
||||||
|
@ -60,10 +68,17 @@ public class FlingServiceTest {
|
||||||
return new FlingMapperImpl();
|
return new FlingMapperImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ArtifactMapper ArtifactMapper() {
|
||||||
|
return new ArtifactMapperImpl();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public FlingService flingService(FlingRepository flingRepository, FlingMapper flingMapper,
|
public FlingService flingService(FlingRepository flingRepository, FlingMapper flingMapper,
|
||||||
|
ArtifactMapper artifactMapper,
|
||||||
ArchiveService archiveService, PasswordEncoder passwordEncoder) {
|
ArchiveService archiveService, PasswordEncoder passwordEncoder) {
|
||||||
return new FlingService(flingRepository, flingMapper, archiveService, passwordEncoder);
|
return new FlingService(flingRepository, flingMapper, artifactMapper, archiveService,
|
||||||
|
passwordEncoder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +173,37 @@ public class FlingServiceTest {
|
||||||
verify(flingRepository).deleteById(testId);
|
verify(flingRepository).deleteById(testId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getArtifacts_noArtifacts_emptySet() throws IOException {
|
||||||
|
UUID testId = UUID.randomUUID();
|
||||||
|
FlingEntity flingEntity = new FlingEntity();
|
||||||
|
flingEntity.setId(testId);
|
||||||
|
flingEntity.setArtifacts(null);
|
||||||
|
|
||||||
|
when(flingRepository.getOne(testId)).thenReturn(flingEntity);
|
||||||
|
|
||||||
|
assertThat(flingService.getArtifacts(testId), is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getArtifacts_flingWithArtifacts_artifactSet() throws Exception {
|
||||||
|
UUID artifactId = UUID.randomUUID();
|
||||||
|
ArtifactEntity artifactEntity = new ArtifactEntity();
|
||||||
|
artifactEntity.setId(artifactId);
|
||||||
|
|
||||||
|
UUID flingId = UUID.randomUUID();
|
||||||
|
FlingEntity flingEntity = new FlingEntity();
|
||||||
|
flingEntity.setId(flingId);
|
||||||
|
flingEntity.setArtifacts(Set.of(artifactEntity));
|
||||||
|
|
||||||
|
when(flingRepository.getOne(flingId)).thenReturn(flingEntity);
|
||||||
|
|
||||||
|
Set<ArtifactDto> artifacts = flingService.getArtifacts(flingId);
|
||||||
|
assertThat(artifacts, hasSize(1));
|
||||||
|
assertThat(artifacts.stream().map(ArtifactDto::getId).collect(Collectors.toSet()),
|
||||||
|
contains(artifactId));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void validateAuthCode_codesMatch_true() {
|
public void validateAuthCode_codesMatch_true() {
|
||||||
when(flingRepository.getOne(flingEntity1.getId())).thenReturn(flingEntity1);
|
when(flingRepository.getOne(flingEntity1.getId())).thenReturn(flingEntity1);
|
||||||
|
|
Loading…
Reference in a new issue