Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions shogun-boot/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
</dependency>

<!-- Database driver -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,18 @@

import de.terrestris.shogun.config.KeycloakConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;

@ConditionalOnExpression("${keycloak.enabled:true}")
@Configuration
public class BootKeycloakConfig extends KeycloakConfig { }
public class BootKeycloakConfig extends KeycloakConfig {

@Bean
// todo: move to generic config (non-keycloak systems need this as well)
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,9 @@ public void findAll_shouldReturnNoEntitiesForRoleUserWithoutExplicitPermissions(
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(0)));
.andExpect(jsonPath("$").isMap())
.andExpect(jsonPath("$.content").isArray())
.andExpect(jsonPath("$.content", hasSize(0)));
}

@Test
Expand All @@ -242,8 +243,9 @@ public void findAll_shouldReturnAllAvailableEntitiesForRoleUser() throws Excepti
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(1)));
.andExpect(jsonPath("$").isMap())
.andExpect(jsonPath("$.content").isArray())
.andExpect(jsonPath("$.content", hasSize(1)));
}

@Test
Expand All @@ -256,8 +258,9 @@ public void findAll_shouldReturnAllAvailableEntitiesForRoleAdmin() throws Except
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(testData.size())));
.andExpect(jsonPath("$").isMap())
.andExpect(jsonPath("$.content").isArray())
.andExpect(jsonPath("$.content", hasSize(testData.size())));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ public void findAll_shouldReturnAllAvailableEntitiesForRoleAdmin() throws Except
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(testData.size() + 2)));
.andExpect(jsonPath("$").isMap())
.andExpect(jsonPath("$.content").isArray())
.andExpect(jsonPath("$.content", hasSize(testData.size() + 2)));
}

@Test
Expand Down
1 change: 1 addition & 0 deletions shogun-config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,9 @@
import de.terrestris.shogun.lib.model.User;
import de.terrestris.shogun.lib.security.SecurityContextUtil;
import de.terrestris.shogun.lib.security.access.entity.BaseEntityPermissionEvaluator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.List;

/**
* Permission evaluator for {@link InterceptorRule}s
*/
Expand All @@ -40,13 +36,13 @@ public class InterceptorRulePermissionEvaluator extends BaseEntityPermissionEval
@Override
public boolean hasPermission(User user, InterceptorRule entity, PermissionType permission) {


if (securityContextUtil.isInterceptorAdmin()) {
return true;
}

return super.hasPermission(user, entity, permission);
}

}


Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.GenericTypeResolver;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.history.Revision;
import org.springframework.data.history.Revisions;
import org.springframework.data.web.PageableDefault;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
Expand Down Expand Up @@ -83,14 +86,14 @@ public abstract class BaseController<T extends BaseService<?, S>, S extends Base
description = "Internal Server Error: Something internal went wrong while deleting the entity"
)
})
public List<S> findAll() {
public Page<S> findAll(@PageableDefault(20) Pageable pageable) {
log.trace("Requested to return all entities of type {}", getGenericClassName());

try {
List<S> persistedEntities = service.findAll();
Page<S> persistedEntities = service.findAll(pageable);

log.trace("Successfully got all entities of type {} (count: {})",
getGenericClassName(), persistedEntities.size());
getGenericClassName(), persistedEntities.getTotalElements());

return persistedEntities;
} catch (AccessDeniedException ade) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.GenericTypeResolver;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.*;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.*;
Expand All @@ -49,14 +52,14 @@ public abstract class BaseFileController<T extends BaseFileService<?, S>, S exte

@GetMapping
@ResponseStatus(HttpStatus.OK)
public List<S> findAll() {
public Page<S> findAll(@PageableDefault(Integer.MAX_VALUE) Pageable pageable) {
log.trace("Requested to return all entities of type {}", getGenericClassName());

try {
List<S> persistedEntities = service.findAll();
Page<S> persistedEntities = service.findAll(pageable);

log.trace("Successfully got all entities of type {} (count: {})",
getGenericClassName(), persistedEntities.size());
getGenericClassName(), persistedEntities.getTotalElements());

return persistedEntities;
} catch (AccessDeniedException ade) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package de.terrestris.shogun.lib.dto;

import graphql.PublicApi;
import graphql.relay.DefaultConnection;
import graphql.relay.Edge;
import graphql.relay.PageInfo;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.List;

@PublicApi
@Getter
@Setter
@ToString
@EqualsAndHashCode(callSuper = false)
public class DefaultGraphQLConnection<T> extends DefaultConnection<T> {

private Long totalCount;

/**
* A connection consists of a list of edges and page info
*
* @param edges a non null list of edges
* @param pageInfo a non null page info
* @throws IllegalArgumentException if edges or page info is null. use {@link Collections#emptyList()} for empty edges.
*/
public DefaultGraphQLConnection(Long totalCount, List<Edge<T>> edges, PageInfo pageInfo) {
super(edges, pageInfo);
this.totalCount = totalCount;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package de.terrestris.shogun.lib.dto;

import de.terrestris.shogun.lib.model.BaseEntity;
import graphql.relay.Connection;

public interface GraphQLConnection<T extends BaseEntity> extends Connection<T> {

Integer getTotalCount();

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@
*/
package de.terrestris.shogun.lib.graphql.controller;

import de.terrestris.shogun.lib.dto.DefaultGraphQLConnection;
import de.terrestris.shogun.lib.graphql.dto.MutateApplication;
import de.terrestris.shogun.lib.model.Application;
import de.terrestris.shogun.lib.service.ApplicationService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.history.Revision;
import org.springframework.data.history.Revisions;
import org.springframework.graphql.data.method.annotation.Argument;
Expand All @@ -34,8 +38,8 @@
public class ApplicationGraphQLController extends BaseGraphQLController<Application, ApplicationService> {

@QueryMapping
public List<Application> allApplications() {
return super.findAll();
public DefaultGraphQLConnection<Application> allApplications(@Argument("first") int first, @Argument("offset") int offset) {
return super.findAll(first, offset);
}

@QueryMapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,32 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.terrestris.shogun.lib.dto.DefaultGraphQLConnection;
import de.terrestris.shogun.lib.dto.GraphQLConnection;
import de.terrestris.shogun.lib.graphql.exception.EntityNotAvailableException;
import de.terrestris.shogun.lib.model.BaseEntity;
import de.terrestris.shogun.lib.repository.BaseCrudRepository;
import de.terrestris.shogun.lib.service.BaseService;
import graphql.relay.DefaultConnectionCursor;
import graphql.relay.DefaultEdge;
import graphql.relay.DefaultPageInfo;
import graphql.relay.Edge;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.history.Revision;
import org.springframework.data.history.Revisions;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Log4j2
public abstract class BaseGraphQLController<E extends BaseEntity, S extends BaseService<? extends BaseCrudRepository<E, Long>, E>> {
Expand All @@ -43,8 +54,26 @@ public abstract class BaseGraphQLController<E extends BaseEntity, S extends Base
@Autowired
protected S service;

public List<E> findAll() {
return this.service.findAll();
public DefaultGraphQLConnection<E> findAll(Integer first, Integer offset) {
Pageable pageable = PageRequest.of(first, offset); // todo: calculate first / offset
Page<E> entities = service.findAll(pageable);
List<Edge<E>> defaultEdge = entities.get().map(e -> new DefaultEdge<E>(
e,
new DefaultConnectionCursor("DK")
)).collect(Collectors.toList());

DefaultPageInfo pageInfo = new DefaultPageInfo(
new DefaultConnectionCursor("LL"), // todo: find out
new DefaultConnectionCursor("JW"),
entities.hasPrevious(),
entities.hasNext()
);
DefaultGraphQLConnection graphQLConnection = new DefaultGraphQLConnection<>(
entities.getTotalElements(),
defaultEdge,
pageInfo
);
return graphQLConnection;
}

public Optional<E> findOne(Long id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@
*/
package de.terrestris.shogun.lib.graphql.controller;

import de.terrestris.shogun.lib.dto.DefaultGraphQLConnection;
import de.terrestris.shogun.lib.model.Application;
import de.terrestris.shogun.lib.model.File;
import de.terrestris.shogun.lib.service.FileService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
Expand All @@ -29,8 +34,8 @@
public class FileGraphQLController extends BaseGraphQLController<File, FileService> {

@QueryMapping
public List<File> allFiles() {
return super.findAll();
public DefaultGraphQLConnection<File> allFiles(@Argument("page") Integer page, @Argument("size") Integer size) {
return super.findAll(page, size);
}

@QueryMapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@
*/
package de.terrestris.shogun.lib.graphql.controller;

import de.terrestris.shogun.lib.dto.DefaultGraphQLConnection;
import de.terrestris.shogun.lib.graphql.dto.MutateGroup;
import de.terrestris.shogun.lib.model.Application;
import de.terrestris.shogun.lib.model.Group;
import de.terrestris.shogun.lib.service.GroupService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.history.Revision;
import org.springframework.data.history.Revisions;
import org.springframework.graphql.data.method.annotation.Argument;
Expand All @@ -34,8 +39,8 @@
public class GroupGraphQLController extends BaseGraphQLController<Group, GroupService> {

@QueryMapping
public List<Group> allGroups() {
return super.findAll();
public DefaultGraphQLConnection<Group> allGroups(@Argument("page") Integer page, @Argument("size") Integer size) {
return super.findAll(page, size);
}

@QueryMapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@
*/
package de.terrestris.shogun.lib.graphql.controller;

import de.terrestris.shogun.lib.dto.DefaultGraphQLConnection;
import de.terrestris.shogun.lib.model.ImageFile;
import de.terrestris.shogun.lib.service.ImageFileService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
Expand All @@ -29,8 +33,8 @@
public class ImageFileGraphQLController extends BaseGraphQLController<ImageFile, ImageFileService> {

@QueryMapping
public List<ImageFile> allImageFiles() {
return super.findAll();
public DefaultGraphQLConnection<ImageFile> allImageFiles(@Argument("page") Integer page, @Argument("size") Integer size) {
return super.findAll(page, size);
}

@QueryMapping
Expand Down
Loading