Skip to content

Commit

Permalink
Merge pull request #9 from cabinetoffice/release/2.4
Browse files Browse the repository at this point in the history
Release/2.4
  • Loading branch information
dominicwest authored Jun 22, 2023
2 parents bf13620 + ed2bdb5 commit d08a724
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public class CreateGrantBeneficiaryDto {
private Boolean ethnicGroup4;
private Boolean ethnicGroup5;
private Boolean ethnicGroupOther;
private Boolean organisationGroup1;
private Boolean organisationGroup2;
private Boolean organisationGroup3;

@Size(max = 100, message = "Other ethnic group details can not be longer than 100 characters")
private String ethnicOtherDetails;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public class GetGrantBeneficiaryDto {
private Boolean ethnicGroupOther;
private String ethnicOtherDetails;
private Boolean ethnicGroupAll;
private Boolean organisationGroup1;
private Boolean organisationGroup2;
private Boolean organisationGroup3;
private Boolean supportingDisabilities;
private Boolean sexualOrientationGroup1;
private Boolean sexualOrientationGroup2;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package gov.cabinetoffice.gap.applybackend.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends RuntimeException {

public UnauthorizedException() {
}

public UnauthorizedException(String message) {
super(message);
}

public UnauthorizedException(String message, Throwable cause) {
super(message, cause);
}

public UnauthorizedException(Throwable cause) {
super(cause);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ public class GrantBeneficiary {
@Column
private Boolean ethnicGroupAll;

@Column
private Boolean organisationGroup1;

@Column
private Boolean organisationGroup2;

@Column
private Boolean organisationGroup3;

@Column
private Boolean supportingDisabilities;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package gov.cabinetoffice.gap.applybackend.service;

import gov.cabinetoffice.gap.applybackend.exception.UnauthorizedException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Service
@RequiredArgsConstructor
public class SecretAuthService {

@Value("${lambda.secret}")
private String lambdaSecret;

/**
* Intended to authenticate requests coming from lambdas, which shouldn't pass through
* the JWT auth process. TODO I think this could be converted into an annotation for
* lambda controller methods
* @param authHeader value taken from Authorization header
*/
public void authenticateSecret(String authHeader) {
if (!Objects.equals(lambdaSecret, authHeader)) {
throw new UnauthorizedException("Secret key does not match");
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@
import gov.cabinetoffice.gap.applybackend.dto.api.*;
import gov.cabinetoffice.gap.applybackend.enums.GrantAttachmentStatus;
import gov.cabinetoffice.gap.applybackend.enums.SubmissionSectionStatus;
import gov.cabinetoffice.gap.applybackend.exception.AttachmentException;
import gov.cabinetoffice.gap.applybackend.exception.GrantApplicationNotPublishedException;
import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
import gov.cabinetoffice.gap.applybackend.exception.SubmissionAlreadyCreatedException;
import gov.cabinetoffice.gap.applybackend.exception.*;
import gov.cabinetoffice.gap.applybackend.model.*;
import gov.cabinetoffice.gap.applybackend.service.*;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
Expand All @@ -35,6 +34,8 @@ public class SubmissionController {
private final GrantApplicantService grantApplicantService;
private final GrantAttachmentService grantAttachmentService;
private final GrantApplicationService grantApplicationService;

private final SecretAuthService secretAuthService;
private final AttachmentService attachmentService;
private final Logger logger = LoggerFactory.getLogger(SubmissionController.class);
private final Clock clock;
Expand Down Expand Up @@ -198,7 +199,11 @@ public ResponseEntity<CreateSubmissionResponseDto> createApplication(@PathVariab
@PutMapping("/{submissionId}/question/{questionId}/attachment/scanresult")
public ResponseEntity<String> updateAttachment(@PathVariable final UUID submissionId,
@PathVariable final String questionId,
@RequestBody final UpdateAttachmentDto updateDetails) {
@RequestBody final UpdateAttachmentDto updateDetails,
@RequestHeader(HttpHeaders.AUTHORIZATION) final String authHeader) {

secretAuthService.authenticateSecret(authHeader);

Submission submission = submissionService.getSubmissionFromDatabaseBySubmissionId(submissionId);
GrantAttachment attachment = grantAttachmentService.getAttachmentBySubmissionAndQuestion(submission, questionId);

Expand Down Expand Up @@ -277,6 +282,7 @@ public ResponseEntity<GetNavigationParamsDto> removeAttachment(@PathVariable fin
final GrantAttachment attachment = grantAttachmentService.getAttachment(attachmentId);
attachmentService.deleteAttachment(attachment, applicationId, submissionId, questionId);
submissionService.deleteQuestionResponse(submissionId, questionId);
submissionService.handleSectionReview(submissionId, sectionId, Boolean.FALSE);

final GetNavigationParamsDto nextNav = GetNavigationParamsDto.builder()
.responseAccepted(Boolean.TRUE)
Expand Down
24 changes: 11 additions & 13 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,22 @@
springdoc.api-docs.enabled=false
springdoc.swagger-ui.url=/swagger.yml

spring.servlet.multipart.max-request-size=a-size
spring.servlet.multipart.max-file-size=a-size
spring.servlet.multipart.max-request-size=300MB
spring.servlet.multipart.max-file-size=300MB

# Spring Data
spring.datasource.url=a-url
spring.datasource.username=a-username
spring.datasource.password=a-password
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=a-boolean
spring.jpa.properties.hibernate.dialect=a-dialect
spring.jpa.properties.hibernate.jdbc.time_zone=a-timezone
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.jdbc.time_zone=UTC

# AWS Cognito
cognito.secretKey=a-secret-key
cognito.accessKey=an-access-key
cognito.region=a-region
cognito.domain=a-cognito-domain
cognito.appClientId=a-cognito-client-id
spring.security.user.name=root
spring.security.user.password=root

spring.security.user.name=a-user-name
spring.security.user.password=a-password
user-service.domain=http://localhost:8082
user-service.cookieName=user-service-token

# AWS Configuration
aws.bucket=a-bucket
Expand All @@ -38,3 +34,5 @@ gov-notify.submissionConfirmationTemplate=a-notify-template-id
# environment specific props
frontEndUri=a-front-end-url
environmentName=an-environment-name

lambda.secret=lambdaSecretKey
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public static GetGrantBeneficiaryDto.GetGrantBeneficiaryDtoBuilder generateRando
.ethnicGroupOther(true)
.ethnicOtherDetails("Other ethnic datils")
.ethnicGroupAll(true)
.organisationGroup1(true)
.organisationGroup2(true)
.organisationGroup3(true)
.supportingDisabilities(true)
.sexualOrientationGroup1(true)
.sexualOrientationGroup2(true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package gov.cabinetoffice.gap.applybackend.service;

import gov.cabinetoffice.gap.applybackend.exception.UnauthorizedException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.util.ReflectionTestUtils;

import static org.assertj.core.api.AssertionsForClassTypes.assertThatNoException;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

@SpringJUnitConfig
class SecretAuthServiceTest {

@InjectMocks
private SecretAuthService secretAuthService;

private final String correctSecretKey = "topSecretKey";

@BeforeEach
void beforeEach() {
ReflectionTestUtils.setField(secretAuthService, "lambdaSecret", correctSecretKey);
}

@Test
void authenticateSecret_HappyPath() {
assertThatNoException().isThrownBy(() -> secretAuthService.authenticateSecret(correctSecretKey));
}

@Test
void authenticateSecret_UnhappyPath() {
assertThatThrownBy(() -> secretAuthService.authenticateSecret("wrongKey"))
.isInstanceOf(UnauthorizedException.class).hasMessage("Secret key does not match");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
import gov.cabinetoffice.gap.applybackend.enums.SubmissionQuestionResponseType;
import gov.cabinetoffice.gap.applybackend.enums.SubmissionSectionStatus;
import gov.cabinetoffice.gap.applybackend.enums.SubmissionStatus;
import gov.cabinetoffice.gap.applybackend.exception.AttachmentException;
import gov.cabinetoffice.gap.applybackend.exception.GrantApplicationNotPublishedException;
import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
import gov.cabinetoffice.gap.applybackend.exception.SubmissionAlreadyCreatedException;
import gov.cabinetoffice.gap.applybackend.exception.*;
import gov.cabinetoffice.gap.applybackend.model.*;
import gov.cabinetoffice.gap.applybackend.service.*;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -22,6 +19,7 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -43,6 +41,8 @@
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ExtendWith(MockitoExtension.class)
class SubmissionControllerTest {
Expand Down Expand Up @@ -247,6 +247,9 @@ class SubmissionControllerTest {
private GrantApplicationService grantApplicationService;
@Mock
private GrantAttachmentService grantAttachmentService;

@Mock
private SecretAuthService secretAuthService;
@Mock
private AttachmentService attachmentService;

Expand All @@ -257,7 +260,7 @@ class SubmissionControllerTest {

@BeforeEach
void setup() {
controllerUnderTest = new SubmissionController(submissionService, grantApplicantService, grantAttachmentService, grantApplicationService, attachmentService, clock);
controllerUnderTest = new SubmissionController(submissionService, grantApplicantService, grantAttachmentService, grantApplicationService, secretAuthService, attachmentService, clock);
}

@Test
Expand Down Expand Up @@ -568,7 +571,7 @@ void updateAttachment_UpdatesExpectedAttachment(UpdateAttachmentDto update, Gran

final ArgumentCaptor<GrantAttachment> attachmentCaptor = ArgumentCaptor.forClass(GrantAttachment.class);

final ResponseEntity<String> methodResponse = controllerUnderTest.updateAttachment(SUBMISSION_ID, QUESTION_ID_1, update);
final ResponseEntity<String> methodResponse = controllerUnderTest.updateAttachment(SUBMISSION_ID, QUESTION_ID_1, update, "topSecretKey");

assertThat(methodResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(methodResponse.getBody()).isEqualTo("Attachment Updated");
Expand All @@ -579,6 +582,14 @@ void updateAttachment_UpdatesExpectedAttachment(UpdateAttachmentDto update, Gran
assertThat(attachmentCaptor.getValue().getLocation()).isEqualTo(update.getUri());
}

@ParameterizedTest
@MethodSource("provideGrantAttachmentUpdates")
void updateAttachment_unauthenticatedError(UpdateAttachmentDto update) {
doThrow(new UnauthorizedException("Unauthorized oh nooo")).when(secretAuthService).authenticateSecret(anyString());

assertThrows(UnauthorizedException.class, () -> controllerUnderTest.updateAttachment(SUBMISSION_ID, QUESTION_ID_1, update, "topSecretKey"));
}

// it's frightening how simultaneously good and bad this test is
@Test
void postAttachment_SavesTheDocumentAndCreatesADatabaseEntry() {
Expand Down Expand Up @@ -756,6 +767,7 @@ void removeAttachment_RemovesFileFromS3_AndDeletesDatabaseEntry() {

verify(attachmentService).deleteAttachment(attachment, applicationId, SUBMISSION_ID, QUESTION_ID_1);
verify(submissionService).deleteQuestionResponse(SUBMISSION_ID, QUESTION_ID_1);
verify(submissionService).handleSectionReview(SUBMISSION_ID, SECTION_ID_1, Boolean.FALSE);
}

@Test
Expand Down

0 comments on commit d08a724

Please sign in to comment.