Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ Page<Recording> searchAllBy(

List<Recording> findAllByParentRecordingIsNull();

boolean existsByParentRecordingIdIsAndReencodeIs(UUID id, boolean reencode);

boolean existsByCaptureSessionAndDeletedAtIsNull(CaptureSession captureSession);

Optional<Recording> findFirstByCaptureSessionAndDeletedAtIsNull(CaptureSession captureSession);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package uk.gov.hmcts.reform.preapi.security;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import uk.gov.hmcts.reform.preapi.dto.CreateBookingDTO;
import uk.gov.hmcts.reform.preapi.dto.CreateCaptureSessionDTO;
Expand Down Expand Up @@ -30,7 +31,7 @@
import java.util.UUID;

@Service
@SuppressWarnings("PMD.CouplingBetweenObjects")
@SuppressWarnings({"PMD.CouplingBetweenObjects", "PMD.GodClass", "PMD.TooManyMethods"})
public class AuthorisationService {
private final BookingRepository bookingRepository;
private final CaseRepository caseRepository;
Expand Down Expand Up @@ -120,10 +121,10 @@ public boolean hasRecordingAccess(UserAuthentication authentication, UUID record
}

if (enableMigratedData && authentication.isAdmin()) {
return canViewReencodedRecording(authentication, entity);
return canViewRecording(authentication, entity);
}

return canViewReencodedRecording(authentication, entity)
return canViewRecording(authentication, entity)
&& hasCaptureSessionAccess(authentication, entity.getCaptureSession().getId());
}

Expand Down Expand Up @@ -214,10 +215,23 @@ public boolean canViewVodafoneData(UserAuthentication authentication) {
return enableMigratedData || authentication.hasRole(ROLE_SUPER_USER);
}

public boolean canViewReencodedRecording(UserAuthentication authentication, Recording recording) {
return !hideReencodedRecordings
|| !recording.isReencode()
|| authentication.hasRole(ROLE_SUPER_USER);
public boolean canViewRecording(UserAuthentication authentication, Recording recording) {
if (authentication != null && authentication.hasRole(ROLE_SUPER_USER)
|| recording.getCaptureSession().getOrigin() != RecordingOrigin.VODAFONE) {
return true;
}

if (!hideReencodedRecordings && !recording.isReencode()) {
// Show original recording if no re-encoded version exists
return !recordingRepository.existsByParentRecordingIdIsAndReencodeIs(recording.getId(), true);
}

return hideReencodedRecordings ^ recording.isReencode();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ means exclusive-or (one or the other is true, but not both)

}

public boolean canViewReencodedRecordings() {
UserAuthentication auth = (UserAuthentication) SecurityContextHolder.getContext().getAuthentication();
return !hideReencodedRecordings || auth != null && auth.hasRole(ROLE_SUPER_USER);
}

public boolean isVodafoneData(Case caseEntity) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.util.Pair;
Expand All @@ -28,6 +27,7 @@
import uk.gov.hmcts.reform.preapi.exception.ResourceInWrongStateException;
import uk.gov.hmcts.reform.preapi.exception.UnknownServerException;
import uk.gov.hmcts.reform.preapi.repositories.RecordingRepository;
import uk.gov.hmcts.reform.preapi.security.AuthorisationService;
import uk.gov.hmcts.reform.preapi.security.authentication.UserAuthentication;
import uk.gov.hmcts.reform.preapi.services.edit.EditRequestCrudService;
import uk.gov.hmcts.reform.preapi.utils.InputSanitizerUtils;
Expand All @@ -43,40 +43,37 @@

@Slf4j
@Service
@SuppressWarnings("PMD.CouplingBetweenObjects")
public class EditRequestService {
private final EditRequestCrudService editRequestCrudService;
private final RecordingRepository recordingRepository;
private final RecordingService recordingService;
private final EditNotificationService editNotificationService;
private final boolean hideReencodedRecordings;

private static final String ROLE_SUPER_USER = "ROLE_SUPER_USER";
private final AuthorisationService authorisationService;

@Autowired
public EditRequestService(final EditRequestCrudService editRequestCrudService,
final RecordingRepository recordingRepository,
final RecordingService recordingService,
final EditNotificationService editNotificationService,
@Value("${feature-flags.hide-reencoded-recordings:true}")
final boolean hideReencodedRecordings) {
final AuthorisationService authorisationService) {
this.editRequestCrudService = editRequestCrudService;
this.recordingRepository = recordingRepository;
this.recordingService = recordingService;
this.editNotificationService = editNotificationService;
this.hideReencodedRecordings = hideReencodedRecordings;
this.authorisationService = authorisationService;
}

@Transactional
@PreAuthorize("@authorisationService.hasEditRequestAccess(authentication, #id)")
public EditRequestDTO findById(UUID id) {
boolean includeReencodedRecordings = canViewReencodedRecordings();
return editRequestCrudService.findById(id, includeReencodedRecordings);
return editRequestCrudService.findById(id);
}

@Transactional
public Page<EditRequestDTO> findAll(@NotNull SearchEditRequests params, Pageable pageable) {
UserAuthentication auth = (UserAuthentication) SecurityContextHolder.getContext().getAuthentication();
boolean includeReencodedRecordings = canViewReencodedRecordings(auth);
boolean includeReencodedRecordings = authorisationService.canViewReencodedRecordings();
params.setAuthorisedBookings(auth.isAdmin() || auth.isAppUser() ? null : auth.getSharedBookings());
params.setAuthorisedCourt(auth.isPortalUser() || auth.isAdmin() ? null : auth.getCourtId());

Expand Down Expand Up @@ -148,7 +145,7 @@ public EditRequestDTO upsert(UUID sourceRecordingId, MultipartFile file) {

upsert(dto);

return editRequestCrudService.findById(id, canViewReencodedRecordings());
return editRequestCrudService.findById(id);
}

private Recording getSourceRecording(UUID sourceRecordingId) {
Expand Down Expand Up @@ -179,15 +176,6 @@ private void notifyOnUpdatedRequest(CreateEditRequestDTO dto, Pair<UpsertResult,
editNotificationService.onEditRequestRejected(upserted.getSecond());
}

private boolean canViewReencodedRecordings() {
UserAuthentication auth = (UserAuthentication) SecurityContextHolder.getContext().getAuthentication();
return canViewReencodedRecordings(auth);
}

private boolean canViewReencodedRecordings(UserAuthentication auth) {
return !hideReencodedRecordings || auth != null && auth.hasRole(ROLE_SUPER_USER);
}

private List<EditCutInstructionDTO> parseCsv(MultipartFile file) {
try {
@Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package uk.gov.hmcts.reform.preapi.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -29,6 +28,7 @@
import uk.gov.hmcts.reform.preapi.repositories.RecordingRepository;
import uk.gov.hmcts.reform.preapi.repositories.ShareBookingRepository;
import uk.gov.hmcts.reform.preapi.repositories.UserRepository;
import uk.gov.hmcts.reform.preapi.security.AuthorisationService;
import uk.gov.hmcts.reform.preapi.security.authentication.UserAuthentication;

import java.util.Comparator;
Expand All @@ -47,9 +47,7 @@ public class LegacyReportService {
private final UserRepository userRepository;
private final AppAccessRepository appAccessRepository;
private final PortalAccessRepository portalAccessRepository;
private final boolean hideReencodedRecordings;

private static final String ROLE_SUPER_USER = "ROLE_SUPER_USER";
private final AuthorisationService authorisationService;

@Autowired
public LegacyReportService(CaptureSessionRepository captureSessionRepository,
Expand All @@ -59,16 +57,15 @@ public LegacyReportService(CaptureSessionRepository captureSessionRepository,
UserRepository userRepository,
AppAccessRepository appAccessRepository,
PortalAccessRepository portalAccessRepository,
@Value("${feature-flags.hide-reencoded-recordings:true}")
boolean hideReencodedRecordings) {
AuthorisationService authorisationService) {
this.captureSessionRepository = captureSessionRepository;
this.recordingRepository = recordingRepository;
this.shareBookingRepository = shareBookingRepository;
this.auditRepository = auditRepository;
this.userRepository = userRepository;
this.appAccessRepository = appAccessRepository;
this.portalAccessRepository = portalAccessRepository;
this.hideReencodedRecordings = hideReencodedRecordings;
this.authorisationService = authorisationService;
}

@Transactional
Expand All @@ -82,19 +79,21 @@ public List<ConcurrentCaptureSessionReportDTO> reportCaptureSessions() {

@Transactional
public List<RecordingsPerCaseReportDTO> reportRecordingsPerCase() {
boolean includeReencodedRecordings = authorisationService.canViewReencodedRecordings();
return recordingRepository
.countRecordingsPerCase(canViewReencodedRecordings())
.countRecordingsPerCase(includeReencodedRecordings)
.stream()
.map(data -> new RecordingsPerCaseReportDTO((Case) data[0], ((Long) data[1]).intValue()))
.toList();
}

@Transactional
public List<EditReportDTO> reportEdits() {
UserAuthentication auth = (UserAuthentication) SecurityContextHolder.getContext().getAuthentication();
return recordingRepository
.findAllByParentRecordingIsNotNull()
.stream()
.filter(this::canViewRecording)
.filter(rec -> authorisationService.canViewRecording(auth, rec))
.sorted(Comparator.comparing(Recording::getCreatedAt))
.map(EditReportDTO::new)
.collect(Collectors.toList());
Expand Down Expand Up @@ -156,10 +155,11 @@ public List<PlaybackReportDTO> reportPlayback(AuditLogSource source) {

@Transactional
public List<CompletedCaptureSessionReportDTO> reportCompletedCaptureSessions() {
UserAuthentication auth = (UserAuthentication) SecurityContextHolder.getContext().getAuthentication();
return recordingRepository
.findAllByParentRecordingIsNull()
.stream()
.filter(this::canViewRecording)
.filter(rec -> authorisationService.canViewRecording(auth, rec))
.sorted(Comparator.comparing(r -> r.getCaptureSession().getBooking().getScheduledFor()))
.map(CompletedCaptureSessionReportDTO::new)
.collect(Collectors.toList());
Expand Down Expand Up @@ -187,6 +187,8 @@ private PlaybackReportDTO toPlaybackReport(Audit audit) {
}
}

UserAuthentication auth = (UserAuthentication) SecurityContextHolder.getContext().getAuthentication();

return new PlaybackReportDTO(
audit,
audit.getCreatedBy() != null
Expand All @@ -199,24 +201,11 @@ private PlaybackReportDTO toPlaybackReport(Audit audit) {
.orElse(null)))
: null,
recordingId != null
? recordingRepository.findById(recordingId).filter(this::canViewRecording).orElse(null)
? recordingRepository.findById(recordingId)
.filter(rec -> authorisationService.canViewRecording(auth, rec))
.orElse(null)
: null
);
}

private boolean canViewRecording(Recording recording) {
return recording == null
|| !hideReencodedRecordings
|| !recording.isReencode()
|| getAuthentication() != null && getAuthentication().hasRole(ROLE_SUPER_USER);
}

private boolean canViewReencodedRecordings() {
UserAuthentication auth = getAuthentication();
return !hideReencodedRecordings || auth != null && auth.hasRole(ROLE_SUPER_USER);
}

private UserAuthentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication() instanceof UserAuthentication auth ? auth : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import uk.gov.hmcts.reform.preapi.media.storage.AzureFinalStorageService;
import uk.gov.hmcts.reform.preapi.repositories.CaptureSessionRepository;
import uk.gov.hmcts.reform.preapi.repositories.RecordingRepository;
import uk.gov.hmcts.reform.preapi.security.AuthorisationService;
import uk.gov.hmcts.reform.preapi.security.authentication.UserAuthentication;

import java.sql.Timestamp;
Expand All @@ -51,15 +52,13 @@ public class RecordingService {
private final CaptureSessionRepository captureSessionRepository;
private final CaptureSessionService captureSessionService;
private final AzureFinalStorageService azureFinalStorageService;
private final AuthorisationService authorisationService;

@Setter
private boolean enableMigratedData;

private final boolean rtmpsSuffixEnabled;

@Setter
private boolean hideReencodedRecordings;

@Autowired
public RecordingService(RecordingRepository recordingRepository,
CaptureSessionRepository captureSessionRepository,
Expand All @@ -68,21 +67,20 @@ public RecordingService(RecordingRepository recordingRepository,
@Value("${migration.enableMigratedData:false}") boolean enableMigratedData,
@Value("${mediakind.rtmpsSuffixEnabled:false}")
boolean rtmpsSuffixEnabled,
@Value("${feature-flags.hide-reencoded-recordings:true}")
boolean hideReencodedRecordings) {
AuthorisationService authorisationService) {
this.recordingRepository = recordingRepository;
this.captureSessionRepository = captureSessionRepository;
this.captureSessionService = captureSessionService;
this.azureFinalStorageService = azureFinalStorageService;
this.enableMigratedData = enableMigratedData;
this.rtmpsSuffixEnabled = rtmpsSuffixEnabled;
this.hideReencodedRecordings = hideReencodedRecordings;
this.authorisationService = authorisationService;
}

@Transactional
@PreAuthorize("@authorisationService.hasRecordingAccess(authentication, #recordingId)")
public RecordingDTO findById(UUID recordingId) {
boolean includeReencodedRecordings = canViewReencodedRecordings();
boolean includeReencodedRecordings = authorisationService.canViewReencodedRecordings();
return recordingRepository.findByIdAndDeletedAtIsNull(recordingId, includeReencodedRecordings)
.map(recording -> new RecordingDTO(recording, includeReencodedRecordings, rtmpsSuffixEnabled))
.orElseThrow(() -> new NotFoundException("RecordingDTO: " + recordingId));
Expand Down Expand Up @@ -114,7 +112,7 @@ public Page<RecordingDTO> findAll(
);

UserAuthentication auth = (UserAuthentication) SecurityContextHolder.getContext().getAuthentication();
boolean includeReencodedRecordings = canViewReencodedRecordings(auth);
boolean includeReencodedRecordings = authorisationService.canViewReencodedRecordings();
params.setAuthorisedBookings(
auth.isAdmin() || auth.isAppUser() ? null : auth.getSharedBookings()
);
Expand Down Expand Up @@ -199,15 +197,6 @@ private boolean isReencodedRecording(String editInstructions) {
}
}

private boolean canViewReencodedRecordings() {
UserAuthentication auth = (UserAuthentication) SecurityContextHolder.getContext().getAuthentication();
return canViewReencodedRecordings(auth);
}

private boolean canViewReencodedRecordings(UserAuthentication auth) {
return !hideReencodedRecordings || auth != null && auth.hasRole(ROLE_SUPER_USER);
}

@Transactional
public UpsertResult forceUpsert(CreateRecordingDTO createRecordingDTO) {
// ignores deleted_at and case state
Expand Down
Loading
Loading