From 7ea73f21cd64d6989db30a231a4a6a5959d812a9 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 14 Apr 2023 01:56:14 -0400 Subject: [PATCH 01/43] commiting changes related to visa implementation --- .../ego/controller/VisaController.java | 103 ++++++++++++++++++ .../overture/ego/model/dto/VisaRequest.java | 24 ++++ .../bio/overture/ego/model/entity/Visa.java | 67 ++++++++++++ .../overture/ego/model/enums/JavaFields.java | 5 + .../overture/ego/model/enums/SqlFields.java | 4 + .../bio/overture/ego/model/enums/Tables.java | 2 + .../overture/ego/model/enums/VisaType.java | 47 ++++++++ .../ego/repository/VisaRepository.java | 16 +++ .../bio/overture/ego/service/VisaService.java | 91 ++++++++++++++++ 9 files changed, 359 insertions(+) create mode 100644 src/main/java/bio/overture/ego/controller/VisaController.java create mode 100644 src/main/java/bio/overture/ego/model/dto/VisaRequest.java create mode 100644 src/main/java/bio/overture/ego/model/entity/Visa.java create mode 100644 src/main/java/bio/overture/ego/model/enums/VisaType.java create mode 100644 src/main/java/bio/overture/ego/repository/VisaRepository.java create mode 100644 src/main/java/bio/overture/ego/service/VisaService.java diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java new file mode 100644 index 000000000..e6a44a51b --- /dev/null +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -0,0 +1,103 @@ +package bio.overture.ego.controller; + +import static bio.overture.ego.controller.resolver.PageableResolver.*; +import static org.springframework.web.bind.annotation.RequestMethod.*; + +import bio.overture.ego.model.dto.*; +import bio.overture.ego.model.entity.*; +import bio.overture.ego.security.AdminScoped; +import bio.overture.ego.service.*; +import bio.overture.ego.view.Views; +import com.fasterxml.jackson.annotation.JsonView; +import io.swagger.annotations.*; +import java.util.UUID; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; + +@Slf4j +@RestController +@RequestMapping("/visa") +@Api(tags = "Visa") +public class VisaController { + + /** Dependencies */ + private final VisaService visaService; + + private final UserPermissionService userPermissionService; + private final GroupPermissionService groupPermissionService; + private final ApplicationPermissionService applicationPermissionService; + + @Autowired + public VisaController( + @NonNull VisaService visaService, + @NonNull UserPermissionService userPermissionService, + @NonNull GroupPermissionService groupPermissionService, + @NonNull ApplicationPermissionService applicationPermissionService) { + this.visaService = visaService; + this.groupPermissionService = groupPermissionService; + this.userPermissionService = userPermissionService; + this.applicationPermissionService = applicationPermissionService; + } + + @AdminScoped + @RequestMapping(method = GET, value = "/{id}") + @ApiResponses( + value = {@ApiResponse(code = 200, message = "Get Visa by id", response = Visa.class)}) + @JsonView(Views.REST.class) + public @ResponseBody Visa getVisa( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "id", required = true) UUID id) { + return visaService.getById(id); + } + + @AdminScoped + @RequestMapping(method = GET, value = "") + @ApiResponses(value = {@ApiResponse(code = 200, message = "All Visas")}) + @JsonView(Views.REST.class) + public @ResponseBody PageDTO listVisa( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @ApiIgnore Pageable pageable) { + return new PageDTO<>(visaService.listVisa(pageable)); + } + + @AdminScoped + @RequestMapping(method = POST, value = "") + @ApiResponses( + value = { + @ApiResponse(code = 200, message = "New Visa", response = Visa.class), + }) + public @ResponseBody Visa createVisa( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @RequestBody(required = true) VisaRequest visaRequest) { + return visaService.create(visaRequest); + } + + @AdminScoped + @RequestMapping(method = PUT, value = "/{id}") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Update Visa", response = Visa.class)}) + public @ResponseBody Visa updateVisa( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "id") UUID id, + @RequestBody(required = true) VisaRequest visaRequest) { + return visaService.partialUpdate(id, visaRequest); + } + + @AdminScoped + @RequestMapping(method = DELETE, value = "/{id}") + @ResponseStatus(value = HttpStatus.OK) + public void deleteVisa( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "id", required = true) UUID id) { + visaService.delete(id); + } +} diff --git a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java new file mode 100644 index 000000000..dcf7a0d01 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java @@ -0,0 +1,24 @@ +package bio.overture.ego.model.dto; + +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class VisaRequest { + + @NotNull private String id; + + @NotNull private String type; + + @NotNull private String source; + + @NotNull private String value; + + @NotNull private String by; +} diff --git a/src/main/java/bio/overture/ego/model/entity/Visa.java b/src/main/java/bio/overture/ego/model/entity/Visa.java new file mode 100644 index 000000000..295c7bdc6 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/entity/Visa.java @@ -0,0 +1,67 @@ +package bio.overture.ego.model.entity; + +import bio.overture.ego.model.enums.JavaFields; +import bio.overture.ego.model.enums.SqlFields; +import bio.overture.ego.model.enums.Tables; +import bio.overture.ego.view.Views; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonView; +import java.util.UUID; +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import lombok.*; +import lombok.experimental.FieldNameConstants; +import org.hibernate.annotations.GenericGenerator; + +@Entity +@Table(name = Tables.GA4GHVISA) +@JsonInclude() +@JsonPropertyOrder({ + JavaFields.ID, + JavaFields.TYPE, + JavaFields.SOURCE, + JavaFields.VALUE, + JavaFields.BY +}) +@JsonView(Views.REST.class) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@FieldNameConstants +@EqualsAndHashCode(of = {"id"}) +@NamedEntityGraph( + name = "policy-entity-with-relationships", + attributeNodes = { + @NamedAttributeNode(value = JavaFields.USERPERMISSIONS), + @NamedAttributeNode(value = JavaFields.GROUPPERMISSIONS), + }) +public class Visa implements Identifiable { + + @Id + @Column(name = SqlFields.ID, updatable = false, nullable = false) + @GenericGenerator(name = "visa_uuid", strategy = "org.hibernate.id.UUIDGenerator") + @GeneratedValue(generator = "visa_uuid") + private UUID id; + + @NotNull + @Column(name = SqlFields.TYPE, nullable = false) + @JsonView({Views.JWTAccessToken.class, Views.REST.class}) + private String type; + + @NotNull + @JsonView({Views.JWTAccessToken.class, Views.REST.class}) + @Column(name = SqlFields.SOURCE) + private String source; + + @NotNull + @JsonView({Views.JWTAccessToken.class, Views.REST.class}) + @Column(name = SqlFields.VALUE) + private String value; + + @NotNull + @JsonView({Views.JWTAccessToken.class, Views.REST.class}) + @Column(name = SqlFields.BY) + private String by; +} diff --git a/src/main/java/bio/overture/ego/model/enums/JavaFields.java b/src/main/java/bio/overture/ego/model/enums/JavaFields.java index 7ec650a4e..38f9df6c1 100644 --- a/src/main/java/bio/overture/ego/model/enums/JavaFields.java +++ b/src/main/java/bio/overture/ego/model/enums/JavaFields.java @@ -66,4 +66,9 @@ public class JavaFields { public static final String PROVIDERTYPE = "providerType"; public static final String PROVIDER_SUBJECT_ID = "providerSubjectId"; public static final String ERROR_REDIRECT_URI = "errorRedirectUri"; + // Visas Added + public static final String SOURCE = "source"; + public static final String VALUE = "value"; + + public static final String BY = "by"; } diff --git a/src/main/java/bio/overture/ego/model/enums/SqlFields.java b/src/main/java/bio/overture/ego/model/enums/SqlFields.java index 5fde6918d..afc7d0845 100644 --- a/src/main/java/bio/overture/ego/model/enums/SqlFields.java +++ b/src/main/java/bio/overture/ego/model/enums/SqlFields.java @@ -38,4 +38,8 @@ public class SqlFields { public static final String PROVIDERSUBJECTID = "providersubjectid"; public static final String INITIALIZED = "initialized"; public static final String ERRORREDIRECTURI = "errorredirecturi"; + public static final String SOURCE = "source"; + public static final String VALUE = "value"; + + public static final String BY = "by"; } diff --git a/src/main/java/bio/overture/ego/model/enums/Tables.java b/src/main/java/bio/overture/ego/model/enums/Tables.java index 9eab02c90..50ec199aa 100644 --- a/src/main/java/bio/overture/ego/model/enums/Tables.java +++ b/src/main/java/bio/overture/ego/model/enums/Tables.java @@ -22,4 +22,6 @@ public class Tables { public static final String APPLICATION_PERMISSION = "applicationpermission"; public static final String DEFAULTPROVIDERTRIPWIRE = "defaultprovidertripwire"; public static final String INITTRIPWIRE = "inittripwire"; + + public static final String GA4GHVISA = "ga4ghvisa"; } diff --git a/src/main/java/bio/overture/ego/model/enums/VisaType.java b/src/main/java/bio/overture/ego/model/enums/VisaType.java new file mode 100644 index 000000000..0eb87dab1 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/enums/VisaType.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bio.overture.ego.model.enums; + +import static bio.overture.ego.utils.Joiners.COMMA; +import static bio.overture.ego.utils.Streams.stream; +import static java.lang.String.format; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum VisaType { + STANDARD_VISA_TYPE, + CUSTOM_VISA_TYPE; + + public static VisaType resolveStatusType(@NonNull String statusType) { + return stream(values()) + .filter(x -> x.toString().equals(statusType)) + .findFirst() + .orElseThrow( + () -> + new IllegalArgumentException( + format( + "The status type '%s' cannot be resolved. Must be one of: [%s]", + statusType, COMMA.join(values())))); + } + + @Override + public String toString() { + return this.name(); + } +} diff --git a/src/main/java/bio/overture/ego/repository/VisaRepository.java b/src/main/java/bio/overture/ego/repository/VisaRepository.java new file mode 100644 index 000000000..50d1ec130 --- /dev/null +++ b/src/main/java/bio/overture/ego/repository/VisaRepository.java @@ -0,0 +1,16 @@ +package bio.overture.ego.repository; + +import bio.overture.ego.model.entity.Visa; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface VisaRepository extends NamedRepository { + @Override + @Deprecated + default Optional findByName(String name) { + return null; + } + + List findAll(); +} diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java new file mode 100644 index 000000000..c8ac9968d --- /dev/null +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -0,0 +1,91 @@ +package bio.overture.ego.service; + +import static bio.overture.ego.model.exceptions.NotFoundException.checkNotFound; +import static bio.overture.ego.model.exceptions.RequestValidationException.checkRequestValid; +import static org.mapstruct.factory.Mappers.getMapper; + +import bio.overture.ego.event.token.ApiKeyEventsPublisher; +import bio.overture.ego.model.dto.PolicyRequest; +import bio.overture.ego.model.dto.VisaRequest; +import bio.overture.ego.model.entity.Policy; +import bio.overture.ego.model.entity.Visa; +import bio.overture.ego.repository.VisaRepository; +import java.util.Optional; +import java.util.UUID; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.ReportingPolicy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@Transactional +public class VisaService extends AbstractNamedService { + + /** Constants */ + private static final VisaService.VisaConverter VISA_CONVERTER = getMapper(VisaService.VisaConverter.class); + + /** Dependencies */ + @Autowired + + private VisaRepository visaRepository; + + private final ApiKeyEventsPublisher apiKeyEventsPublisher; + + @Autowired + public VisaService( + @NonNull VisaRepository visaRepository, + @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher) { + super(Visa.class, visaRepository); + this.visaRepository = visaRepository; + this.apiKeyEventsPublisher = apiKeyEventsPublisher; + } + + public Visa create(@NonNull VisaRequest createRequest) { + checkRequestValid(createRequest); + val visa = VISA_CONVERTER.convertToVisa(createRequest); + return getRepository().save(visa); + } + + @Override + public Visa getById(@NonNull UUID uuid) { + val result = (Optional) getRepository().findById(uuid); + checkNotFound(result.isPresent(), "The visaId '%s' does not exist", uuid); + return result.get(); + } + + public void delete(@NonNull UUID id) { + checkExistence(id); + super.delete(id); + } + + @Override + public Visa getWithRelationships(UUID uuid) { + return null; + } + + public Page listVisa(@NonNull Pageable pageable) { + return visaRepository.findAll(pageable); + } + + public Visa partialUpdate(@NonNull UUID id, @NonNull VisaRequest updateRequest) { + val visa = getById(id); + VISA_CONVERTER.updateVisa(updateRequest, visa); + return getRepository().save(visa); + } + @Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + unmappedTargetPolicy = ReportingPolicy.WARN) + public abstract static class VisaConverter { + public abstract Visa convertToVisa(VisaRequest request); + public abstract void updateVisa(VisaRequest request, @MappingTarget Visa visaToUpdate); + + }} From 8da9be8be8729850fc315da0d2e589fa3b2b4cf4 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 14 Apr 2023 12:18:22 -0400 Subject: [PATCH 02/43] commiting changes related to visa implementation --- .../ego/controller/VisaController.java | 5 ++-- .../overture/ego/model/dto/VisaRequest.java | 3 ++- .../ego/model/dto/VisaUpdateRequest.java | 25 ++++++++++++++++++ .../bio/overture/ego/model/entity/Visa.java | 6 ----- .../bio/overture/ego/service/VisaService.java | 26 +++++++++---------- .../resources/flyway/sql/V1_22__add_visa.sql | 8 ++++++ 6 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java create mode 100644 src/main/resources/flyway/sql/V1_22__add_visa.sql diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index e6a44a51b..f0b56c4a0 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -86,9 +86,8 @@ public VisaController( public @ResponseBody Visa updateVisa( @ApiIgnore @RequestHeader(value = "Authorization", required = true) final String authorization, - @PathVariable(value = "id") UUID id, - @RequestBody(required = true) VisaRequest visaRequest) { - return visaService.partialUpdate(id, visaRequest); + @RequestBody(required = true) VisaUpdateRequest visaRequest) { + return visaService.partialUpdate(visaRequest); } @AdminScoped diff --git a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java index dcf7a0d01..2a60d7a60 100644 --- a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java @@ -1,5 +1,6 @@ package bio.overture.ego.model.dto; +import java.util.UUID; import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; @@ -12,7 +13,7 @@ @NoArgsConstructor public class VisaRequest { - @NotNull private String id; + private UUID id; @NotNull private String type; diff --git a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java new file mode 100644 index 000000000..d7008a759 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java @@ -0,0 +1,25 @@ +package bio.overture.ego.model.dto; + +import java.util.UUID; +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class VisaUpdateRequest { + + @NotNull private UUID id; + + @NotNull private String type; + + @NotNull private String source; + + @NotNull private String value; + + @NotNull private String by; +} diff --git a/src/main/java/bio/overture/ego/model/entity/Visa.java b/src/main/java/bio/overture/ego/model/entity/Visa.java index 295c7bdc6..b4204f4c8 100644 --- a/src/main/java/bio/overture/ego/model/entity/Visa.java +++ b/src/main/java/bio/overture/ego/model/entity/Visa.java @@ -31,12 +31,6 @@ @AllArgsConstructor @FieldNameConstants @EqualsAndHashCode(of = {"id"}) -@NamedEntityGraph( - name = "policy-entity-with-relationships", - attributeNodes = { - @NamedAttributeNode(value = JavaFields.USERPERMISSIONS), - @NamedAttributeNode(value = JavaFields.GROUPPERMISSIONS), - }) public class Visa implements Identifiable { @Id diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index c8ac9968d..7adc66f08 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -5,9 +5,8 @@ import static org.mapstruct.factory.Mappers.getMapper; import bio.overture.ego.event.token.ApiKeyEventsPublisher; -import bio.overture.ego.model.dto.PolicyRequest; import bio.overture.ego.model.dto.VisaRequest; -import bio.overture.ego.model.entity.Policy; +import bio.overture.ego.model.dto.VisaUpdateRequest; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.repository.VisaRepository; import java.util.Optional; @@ -31,12 +30,11 @@ public class VisaService extends AbstractNamedService { /** Constants */ - private static final VisaService.VisaConverter VISA_CONVERTER = getMapper(VisaService.VisaConverter.class); + private static final VisaService.VisaConverter VISA_CONVERTER = + getMapper(VisaService.VisaConverter.class); /** Dependencies */ - @Autowired - - private VisaRepository visaRepository; + @Autowired private VisaRepository visaRepository; private final ApiKeyEventsPublisher apiKeyEventsPublisher; @@ -76,16 +74,18 @@ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } - public Visa partialUpdate(@NonNull UUID id, @NonNull VisaRequest updateRequest) { - val visa = getById(id); + public Visa partialUpdate(@NonNull VisaUpdateRequest updateRequest) { + val visa = getById(updateRequest.getId()); VISA_CONVERTER.updateVisa(updateRequest, visa); return getRepository().save(visa); } + @Mapper( - nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, - unmappedTargetPolicy = ReportingPolicy.WARN) + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + unmappedTargetPolicy = ReportingPolicy.WARN) public abstract static class VisaConverter { - public abstract Visa convertToVisa(VisaRequest request); - public abstract void updateVisa(VisaRequest request, @MappingTarget Visa visaToUpdate); + public abstract Visa convertToVisa(VisaRequest request); - }} + public abstract void updateVisa(VisaUpdateRequest request, @MappingTarget Visa visaToUpdate); + } +} diff --git a/src/main/resources/flyway/sql/V1_22__add_visa.sql b/src/main/resources/flyway/sql/V1_22__add_visa.sql new file mode 100644 index 000000000..bf99727bf --- /dev/null +++ b/src/main/resources/flyway/sql/V1_22__add_visa.sql @@ -0,0 +1,8 @@ +CREATE TABLE GA4GHVISA ( + id UUID PRIMARY KEY, + type varchar(255) NOT NULL, + source varchar(255) NOT NULL, + value varchar(255) NOT NULL, + by varchar(255) NOT NULL +); + From c02cb4dfaef0677ebad64e805aee9e42345081ef Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Wed, 19 Apr 2023 10:55:12 -0400 Subject: [PATCH 03/43] committing changes related to Visa permissions schema --- .../ego/controller/VisaController.java | 5 ++ .../bio/overture/ego/model/entity/Visa.java | 9 +++ .../ego/model/entity/VisaPermission.java | 62 +++++++++++++++++++ .../overture/ego/model/enums/JavaFields.java | 2 + .../overture/ego/model/enums/SqlFields.java | 6 ++ .../bio/overture/ego/model/enums/Tables.java | 2 + .../ego/service/VisaPermissionService.java | 16 +++++ .../bio/overture/ego/service/VisaService.java | 10 +-- .../flyway/sql/V1_23__add_visa_pcl.sql | 8 +++ 9 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 src/main/java/bio/overture/ego/model/entity/VisaPermission.java create mode 100644 src/main/java/bio/overture/ego/service/VisaPermissionService.java create mode 100644 src/main/resources/flyway/sql/V1_23__add_visa_pcl.sql diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index f0b56c4a0..396a967be 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -44,6 +44,11 @@ public VisaController( this.applicationPermissionService = applicationPermissionService; } + /* + * This method is used to fetch visa using id + * @param id UUID + * @return visa Visa + */ @AdminScoped @RequestMapping(method = GET, value = "/{id}") @ApiResponses( diff --git a/src/main/java/bio/overture/ego/model/entity/Visa.java b/src/main/java/bio/overture/ego/model/entity/Visa.java index b4204f4c8..403b16849 100644 --- a/src/main/java/bio/overture/ego/model/entity/Visa.java +++ b/src/main/java/bio/overture/ego/model/entity/Visa.java @@ -1,12 +1,16 @@ package bio.overture.ego.model.entity; +import static com.google.common.collect.Sets.newHashSet; + import bio.overture.ego.model.enums.JavaFields; import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; import bio.overture.ego.view.Views; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonView; +import java.util.Set; import java.util.UUID; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -58,4 +62,9 @@ public class Visa implements Identifiable { @JsonView({Views.JWTAccessToken.class, Views.REST.class}) @Column(name = SqlFields.BY) private String by; + + @JsonIgnore + @ManyToMany(mappedBy = "visaId", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @Builder.Default + private Set visaPermissions = newHashSet(); } diff --git a/src/main/java/bio/overture/ego/model/entity/VisaPermission.java b/src/main/java/bio/overture/ego/model/entity/VisaPermission.java new file mode 100644 index 000000000..e441e5962 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/entity/VisaPermission.java @@ -0,0 +1,62 @@ +package bio.overture.ego.model.entity; + +import static bio.overture.ego.model.enums.AccessLevel.EGO_ACCESS_LEVEL_ENUM; + +import bio.overture.ego.model.enums.AccessLevel; +import bio.overture.ego.model.enums.SqlFields; +import bio.overture.ego.model.enums.Tables; +import bio.overture.ego.view.Views; +import com.fasterxml.jackson.annotation.JsonView; +import java.util.Collection; +import java.util.UUID; +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import lombok.*; +import lombok.experimental.FieldNameConstants; +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Type; + +@Entity +@Table(name = Tables.ACLVISAPERMISSION) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonView(Views.REST.class) +@ToString(callSuper = true) +@FieldNameConstants +public class VisaPermission extends AbstractPermission { + + @Id + @Column(name = SqlFields.ID, updatable = false, nullable = false) + @GenericGenerator(name = "aclp_uuid", strategy = "org.hibernate.id.UUIDGenerator") + @GeneratedValue(generator = "aclp_uuid") + private UUID id; + + @JoinColumn(name = SqlFields.ID, nullable = false) + private UUID entity; + + @JoinColumn(name = SqlFields.ID, nullable = false) + private UUID visaId; + + @NotNull + @Column(name = SqlFields.MASK, nullable = false) + @Enumerated(EnumType.STRING) + @Type(type = EGO_ACCESS_LEVEL_ENUM) + private AccessLevel mask; + + @ManyToMany + @JoinTable( + name = "ga4ghvisa", + joinColumns = @JoinColumn(name = "aclp_id", referencedColumnName = "visaId"), + inverseJoinColumns = @JoinColumn(name = "visa_id", referencedColumnName = "id")) + private Collection visas; + + @Override + public Visa getOwner() { + return null; + } + + @Override + public void setOwner(Visa owner) {} +} diff --git a/src/main/java/bio/overture/ego/model/enums/JavaFields.java b/src/main/java/bio/overture/ego/model/enums/JavaFields.java index 38f9df6c1..aecbeaf19 100644 --- a/src/main/java/bio/overture/ego/model/enums/JavaFields.java +++ b/src/main/java/bio/overture/ego/model/enums/JavaFields.java @@ -71,4 +71,6 @@ public class JavaFields { public static final String VALUE = "value"; public static final String BY = "by"; + + public static final String VISAPERMISSION = "ACLVISAPERMISSION"; } diff --git a/src/main/java/bio/overture/ego/model/enums/SqlFields.java b/src/main/java/bio/overture/ego/model/enums/SqlFields.java index afc7d0845..488b3c8ca 100644 --- a/src/main/java/bio/overture/ego/model/enums/SqlFields.java +++ b/src/main/java/bio/overture/ego/model/enums/SqlFields.java @@ -42,4 +42,10 @@ public class SqlFields { public static final String VALUE = "value"; public static final String BY = "by"; + + public static final String ENTITY = "entity"; + + public static final String VISAID = "visaId"; + + public static final String MASK = "mask"; } diff --git a/src/main/java/bio/overture/ego/model/enums/Tables.java b/src/main/java/bio/overture/ego/model/enums/Tables.java index 50ec199aa..861fe7978 100644 --- a/src/main/java/bio/overture/ego/model/enums/Tables.java +++ b/src/main/java/bio/overture/ego/model/enums/Tables.java @@ -24,4 +24,6 @@ public class Tables { public static final String INITTRIPWIRE = "inittripwire"; public static final String GA4GHVISA = "ga4ghvisa"; + + public static final String ACLVISAPERMISSION = "ACLVISAPERMISSION"; } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java new file mode 100644 index 000000000..65440038d --- /dev/null +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -0,0 +1,16 @@ +package bio.overture.ego.service; + +import bio.overture.ego.model.entity.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@Transactional +public class VisaPermissionService { + + /** Dependencies */ + @Autowired private VisaService visaService; +} diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 7adc66f08..c919b7db0 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -65,11 +65,6 @@ public void delete(@NonNull UUID id) { super.delete(id); } - @Override - public Visa getWithRelationships(UUID uuid) { - return null; - } - public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } @@ -88,4 +83,9 @@ public abstract static class VisaConverter { public abstract void updateVisa(VisaUpdateRequest request, @MappingTarget Visa visaToUpdate); } + + @Override + public Visa getWithRelationships(UUID uuid) { + return null; + } } diff --git a/src/main/resources/flyway/sql/V1_23__add_visa_pcl.sql b/src/main/resources/flyway/sql/V1_23__add_visa_pcl.sql new file mode 100644 index 000000000..35557eef4 --- /dev/null +++ b/src/main/resources/flyway/sql/V1_23__add_visa_pcl.sql @@ -0,0 +1,8 @@ +CREATE TABLE ACLVISAPERMISSION ( + id UUID PRIMARY KEY, + entity UUID, + visaId UUID, + mask ACLMASK NOT NULL, + FOREIGN KEY (entity) REFERENCES POLICY(id), + FOREIGN KEY (visaId) REFERENCES GA4GHVISA(id) +); From 806ea718a5778e11471e137370f5dd9507516fab Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 21 Apr 2023 00:25:06 -0400 Subject: [PATCH 04/43] Committing changes related to visa permission api changes --- .../ego/controller/VisaController.java | 26 ++++++++++- .../ego/model/dto/VisaUpdateRequest.java | 3 -- .../repository/VisaPermissionRepository.java | 18 ++++++++ .../ego/service/VisaPermissionService.java | 46 ++++++++++++++++++- .../bio/overture/ego/service/VisaService.java | 5 +- 5 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index 396a967be..771004ff6 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -10,7 +10,9 @@ import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; import io.swagger.annotations.*; +import java.util.List; import java.util.UUID; +import javax.validation.constraints.NotNull; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +30,8 @@ public class VisaController { /** Dependencies */ private final VisaService visaService; + private final VisaPermissionService visaPermissionService; + private final UserPermissionService userPermissionService; private final GroupPermissionService groupPermissionService; private final ApplicationPermissionService applicationPermissionService; @@ -35,10 +39,12 @@ public class VisaController { @Autowired public VisaController( @NonNull VisaService visaService, + @NotNull VisaPermissionService visaPermissionService, @NonNull UserPermissionService userPermissionService, @NonNull GroupPermissionService groupPermissionService, @NonNull ApplicationPermissionService applicationPermissionService) { this.visaService = visaService; + this.visaPermissionService = visaPermissionService; this.groupPermissionService = groupPermissionService; this.userPermissionService = userPermissionService; this.applicationPermissionService = applicationPermissionService; @@ -91,8 +97,9 @@ public VisaController( public @ResponseBody Visa updateVisa( @ApiIgnore @RequestHeader(value = "Authorization", required = true) final String authorization, + @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) VisaUpdateRequest visaRequest) { - return visaService.partialUpdate(visaRequest); + return visaService.partialUpdate(id, visaRequest); } @AdminScoped @@ -104,4 +111,21 @@ public void deleteVisa( @PathVariable(value = "id", required = true) UUID id) { visaService.delete(id); } + + /* + * This method is used to fetch visa permissions using visa id + * @param visaId UUID + * @return visaPermissions List + */ + @AdminScoped + @RequestMapping(method = GET, value = "/permissions/{id}") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Get VisaPermissions by visaId")}) + @JsonView(Views.REST.class) + public @ResponseBody List getPermissionsByVisaId( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "id", required = true) UUID id) { + System.out.println(id); + return visaPermissionService.getPermissionsByVisaId(id); + } } diff --git a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java index d7008a759..ecf7d08f2 100644 --- a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java @@ -1,6 +1,5 @@ package bio.overture.ego.model.dto; -import java.util.UUID; import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,8 +12,6 @@ @NoArgsConstructor public class VisaUpdateRequest { - @NotNull private UUID id; - @NotNull private String type; @NotNull private String source; diff --git a/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java b/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java new file mode 100644 index 000000000..9236fa7b2 --- /dev/null +++ b/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java @@ -0,0 +1,18 @@ +package bio.overture.ego.repository; + +import bio.overture.ego.model.entity.VisaPermission; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface VisaPermissionRepository extends NamedRepository { + @Override + @Deprecated + default Optional findByName(String name) { + return null; + } + + List findAll(); + + List findByVisaId(UUID visaId); +} diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 65440038d..98d32b0b6 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -1,7 +1,16 @@ package bio.overture.ego.service; -import bio.overture.ego.model.entity.*; +import static java.lang.String.format; + +import bio.overture.ego.event.token.ApiKeyEventsPublisher; +import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.model.exceptions.NotFoundException; +import bio.overture.ego.repository.VisaPermissionRepository; +import java.util.List; +import java.util.UUID; +import lombok.NonNull; import lombok.extern.slf4j.Slf4j; +import lombok.val; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -9,8 +18,41 @@ @Slf4j @Service @Transactional -public class VisaPermissionService { +public class VisaPermissionService extends AbstractNamedService { /** Dependencies */ @Autowired private VisaService visaService; + + @Autowired private VisaPermissionRepository visaPermissionRepository; + private final ApiKeyEventsPublisher apiKeyEventsPublisher; + + @Autowired + public VisaPermissionService( + @NonNull VisaPermissionRepository visaPermissionRepository, + @NonNull VisaService visaService, + @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher) { + super(VisaPermission.class, visaPermissionRepository); + this.visaPermissionRepository = visaPermissionRepository; + this.visaService = visaService; + this.apiKeyEventsPublisher = apiKeyEventsPublisher; + } + + public List getPermissionsByVisaId(@NonNull UUID visaId) { + val result = (List) visaPermissionRepository.findByVisaId(visaId); + System.out.println("Result :::::::::::::::::::::::" + result); + if (result.isEmpty()) { + throw new NotFoundException(format("No VisaPermissions exists with visaId '%s'", visaId)); + } + return result; + } + + @Override + public VisaPermission getById(@NonNull UUID uuid) { + return super.getById(uuid); + } + + @Override + public VisaPermission getWithRelationships(UUID uuid) { + return null; + } } diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index c919b7db0..72b4184b3 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -11,6 +11,7 @@ import bio.overture.ego.repository.VisaRepository; import java.util.Optional; import java.util.UUID; +import javax.validation.constraints.NotNull; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; @@ -69,8 +70,8 @@ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } - public Visa partialUpdate(@NonNull VisaUpdateRequest updateRequest) { - val visa = getById(updateRequest.getId()); + public Visa partialUpdate(@NotNull UUID id, @NonNull VisaUpdateRequest updateRequest) { + val visa = getById(id); VISA_CONVERTER.updateVisa(updateRequest, visa); return getRepository().save(visa); } From 409b7997d07ccec03da79f6a09e835df765229fb Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 21 Apr 2023 00:30:22 -0400 Subject: [PATCH 05/43] Committing changes related to visa update api review comment changes --- .../java/bio/overture/ego/controller/VisaController.java | 3 ++- .../java/bio/overture/ego/model/dto/VisaUpdateRequest.java | 3 --- src/main/java/bio/overture/ego/service/VisaService.java | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index f0b56c4a0..c1e71b29d 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -86,8 +86,9 @@ public VisaController( public @ResponseBody Visa updateVisa( @ApiIgnore @RequestHeader(value = "Authorization", required = true) final String authorization, + @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) VisaUpdateRequest visaRequest) { - return visaService.partialUpdate(visaRequest); + return visaService.partialUpdate(id, visaRequest); } @AdminScoped diff --git a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java index d7008a759..ecf7d08f2 100644 --- a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java @@ -1,6 +1,5 @@ package bio.overture.ego.model.dto; -import java.util.UUID; import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,8 +12,6 @@ @NoArgsConstructor public class VisaUpdateRequest { - @NotNull private UUID id; - @NotNull private String type; @NotNull private String source; diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 7adc66f08..191f89b81 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -11,6 +11,7 @@ import bio.overture.ego.repository.VisaRepository; import java.util.Optional; import java.util.UUID; +import javax.validation.constraints.NotNull; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; @@ -74,8 +75,8 @@ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } - public Visa partialUpdate(@NonNull VisaUpdateRequest updateRequest) { - val visa = getById(updateRequest.getId()); + public Visa partialUpdate(@NotNull UUID id, @NonNull VisaUpdateRequest updateRequest) { + val visa = getById(id); VISA_CONVERTER.updateVisa(updateRequest, visa); return getRepository().save(visa); } From 07d4ead86ca9101721d8886da6e3092c67a85569 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 21 Apr 2023 00:39:07 -0400 Subject: [PATCH 06/43] Committing changes related to visa update api review comment changes --- .../ego/controller/VisaController.java | 2 +- .../overture/ego/model/dto/VisaRequest.java | 3 --- .../ego/model/dto/VisaUpdateRequest.java | 22 ------------------- .../bio/overture/ego/service/VisaService.java | 5 ++--- 4 files changed, 3 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index c1e71b29d..853400cdc 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -87,7 +87,7 @@ public VisaController( @ApiIgnore @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, - @RequestBody(required = true) VisaUpdateRequest visaRequest) { + @RequestBody(required = true) VisaRequest visaRequest) { return visaService.partialUpdate(id, visaRequest); } diff --git a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java index 2a60d7a60..6225d995a 100644 --- a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java @@ -1,6 +1,5 @@ package bio.overture.ego.model.dto; -import java.util.UUID; import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,8 +12,6 @@ @NoArgsConstructor public class VisaRequest { - private UUID id; - @NotNull private String type; @NotNull private String source; diff --git a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java deleted file mode 100644 index ecf7d08f2..000000000 --- a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java +++ /dev/null @@ -1,22 +0,0 @@ -package bio.overture.ego.model.dto; - -import javax.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class VisaUpdateRequest { - - @NotNull private String type; - - @NotNull private String source; - - @NotNull private String value; - - @NotNull private String by; -} diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 191f89b81..9f5b07a66 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -6,7 +6,6 @@ import bio.overture.ego.event.token.ApiKeyEventsPublisher; import bio.overture.ego.model.dto.VisaRequest; -import bio.overture.ego.model.dto.VisaUpdateRequest; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.repository.VisaRepository; import java.util.Optional; @@ -75,7 +74,7 @@ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } - public Visa partialUpdate(@NotNull UUID id, @NonNull VisaUpdateRequest updateRequest) { + public Visa partialUpdate(@NotNull UUID id, @NonNull VisaRequest updateRequest) { val visa = getById(id); VISA_CONVERTER.updateVisa(updateRequest, visa); return getRepository().save(visa); @@ -87,6 +86,6 @@ public Visa partialUpdate(@NotNull UUID id, @NonNull VisaUpdateRequest updateReq public abstract static class VisaConverter { public abstract Visa convertToVisa(VisaRequest request); - public abstract void updateVisa(VisaUpdateRequest request, @MappingTarget Visa visaToUpdate); + public abstract void updateVisa(VisaRequest request, @MappingTarget Visa visaToUpdate); } } From 5f7a843806481fef852d7b014ba47ff81bb506cf Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 21 Apr 2023 02:12:02 -0400 Subject: [PATCH 07/43] Committing changes related to visa permissions create and update api --- .../ego/controller/VisaController.java | 37 ++++++++++++++-- .../ego/model/dto/VisaPermissionRequest.java | 18 ++++++++ .../overture/ego/model/dto/VisaRequest.java | 3 -- .../ego/model/dto/VisaUpdateRequest.java | 22 ---------- .../repository/VisaPermissionRepository.java | 4 ++ .../ego/service/VisaPermissionService.java | 44 ++++++++++++++++++- .../bio/overture/ego/service/VisaService.java | 5 +-- 7 files changed, 101 insertions(+), 32 deletions(-) create mode 100644 src/main/java/bio/overture/ego/model/dto/VisaPermissionRequest.java delete mode 100644 src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index 771004ff6..957d92146 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -98,7 +98,7 @@ public VisaController( @ApiIgnore @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, - @RequestBody(required = true) VisaUpdateRequest visaRequest) { + @RequestBody(required = true) VisaRequest visaRequest) { return visaService.partialUpdate(id, visaRequest); } @@ -118,14 +118,45 @@ public void deleteVisa( * @return visaPermissions List */ @AdminScoped - @RequestMapping(method = GET, value = "/permissions/{id}") + @RequestMapping(method = GET, value = "/permissions/visaId/{id}") @ApiResponses(value = {@ApiResponse(code = 200, message = "Get VisaPermissions by visaId")}) @JsonView(Views.REST.class) public @ResponseBody List getPermissionsByVisaId( @ApiIgnore @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { - System.out.println(id); return visaPermissionService.getPermissionsByVisaId(id); } + + /* + * This method is used to fetch visa permissions using policy id + * @param policyId UUID + * @return visaPermissions List + */ + @AdminScoped + @RequestMapping(method = GET, value = "/permissions/policyId/{id}") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Get VisaPermissions by policyId")}) + @JsonView(Views.REST.class) + public @ResponseBody List getPermissionsByPolicyId( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "id", required = true) UUID id) { + return visaPermissionService.getPermissionsByPolicyId(id); + } + + /* + * This method is used to create/update visa permissions + * @param visaPermissionRequest VisaPermissionRequest + * @return visaPermission VisaPermission + */ + @AdminScoped + @RequestMapping(method = POST, value = "/permissions") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Create or Update VisaPermission")}) + @JsonView(Views.REST.class) + public @ResponseBody VisaPermission createOrUpdatePermissions( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @RequestBody(required = true) VisaPermissionRequest visaPermissionRequest) { + return visaPermissionService.createOrUpdatePermissions(visaPermissionRequest); + } } diff --git a/src/main/java/bio/overture/ego/model/dto/VisaPermissionRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaPermissionRequest.java new file mode 100644 index 000000000..83c382236 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/VisaPermissionRequest.java @@ -0,0 +1,18 @@ +package bio.overture.ego.model.dto; + +import bio.overture.ego.model.enums.AccessLevel; +import java.util.UUID; +import lombok.*; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class VisaPermissionRequest { + + private UUID entity; + + private UUID visaId; + + private AccessLevel mask; +} diff --git a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java index 2a60d7a60..6225d995a 100644 --- a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java @@ -1,6 +1,5 @@ package bio.overture.ego.model.dto; -import java.util.UUID; import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,8 +12,6 @@ @NoArgsConstructor public class VisaRequest { - private UUID id; - @NotNull private String type; @NotNull private String source; diff --git a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java deleted file mode 100644 index ecf7d08f2..000000000 --- a/src/main/java/bio/overture/ego/model/dto/VisaUpdateRequest.java +++ /dev/null @@ -1,22 +0,0 @@ -package bio.overture.ego.model.dto; - -import javax.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class VisaUpdateRequest { - - @NotNull private String type; - - @NotNull private String source; - - @NotNull private String value; - - @NotNull private String by; -} diff --git a/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java b/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java index 9236fa7b2..504d20cbc 100644 --- a/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java +++ b/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java @@ -15,4 +15,8 @@ default Optional findByName(String name) { List findAll(); List findByVisaId(UUID visaId); + + List findByPolicyId(UUID entity); + + List findByPolicyIdAndVisaId(UUID entity, UUID visaId); } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 98d32b0b6..090c1d8c3 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -1,8 +1,10 @@ package bio.overture.ego.service; import static java.lang.String.format; +import static org.mapstruct.factory.Mappers.getMapper; import bio.overture.ego.event.token.ApiKeyEventsPublisher; +import bio.overture.ego.model.dto.VisaPermissionRequest; import bio.overture.ego.model.entity.VisaPermission; import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.repository.VisaPermissionRepository; @@ -11,6 +13,10 @@ import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.ReportingPolicy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -26,6 +32,9 @@ public class VisaPermissionService extends AbstractNamedService getPermissionsByVisaId(@NonNull UUID visaId) { val result = (List) visaPermissionRepository.findByVisaId(visaId); - System.out.println("Result :::::::::::::::::::::::" + result); if (result.isEmpty()) { throw new NotFoundException(format("No VisaPermissions exists with visaId '%s'", visaId)); } return result; } + public List getPermissionsByPolicyId(@NonNull UUID policyId) { + val result = (List) visaPermissionRepository.findByPolicyId(policyId); + if (result.isEmpty()) { + throw new NotFoundException(format("No VisaPermissions exists with policyId '%s'", policyId)); + } + return result; + } + + public VisaPermission createOrUpdatePermissions( + @NonNull VisaPermissionRequest visaPermissionRequest) { + List visaPermissionEntities = + visaPermissionRepository.findByPolicyIdAndVisaId( + visaPermissionRequest.getEntity(), visaPermissionRequest.getVisaId()); + if (visaPermissionEntities == null && visaPermissionEntities.isEmpty()) { + return visaPermissionRepository.save( + VISA_PERMISSION_CONVERTER.createVisaPermission(visaPermissionRequest)); + } else { + VISA_PERMISSION_CONVERTER.updateVisaPermission( + visaPermissionRequest, visaPermissionEntities.get(0)); + return visaPermissionRepository.save(visaPermissionEntities.get(0)); + } + } + @Override public VisaPermission getById(@NonNull UUID uuid) { return super.getById(uuid); @@ -55,4 +86,15 @@ public VisaPermission getById(@NonNull UUID uuid) { public VisaPermission getWithRelationships(UUID uuid) { return null; } + + @Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + unmappedTargetPolicy = ReportingPolicy.WARN) + public abstract static class VisaPermissionConverter { + public abstract VisaPermission createVisaPermission( + VisaPermissionRequest visaPermissionRequest); + + public abstract void updateVisaPermission( + VisaPermissionRequest visaPermissionRequest, @MappingTarget VisaPermission visaPermission); + } } diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 72b4184b3..70cf00c2d 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -6,7 +6,6 @@ import bio.overture.ego.event.token.ApiKeyEventsPublisher; import bio.overture.ego.model.dto.VisaRequest; -import bio.overture.ego.model.dto.VisaUpdateRequest; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.repository.VisaRepository; import java.util.Optional; @@ -70,7 +69,7 @@ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } - public Visa partialUpdate(@NotNull UUID id, @NonNull VisaUpdateRequest updateRequest) { + public Visa partialUpdate(@NotNull UUID id, @NonNull VisaRequest updateRequest) { val visa = getById(id); VISA_CONVERTER.updateVisa(updateRequest, visa); return getRepository().save(visa); @@ -82,7 +81,7 @@ public Visa partialUpdate(@NotNull UUID id, @NonNull VisaUpdateRequest updateReq public abstract static class VisaConverter { public abstract Visa convertToVisa(VisaRequest request); - public abstract void updateVisa(VisaUpdateRequest request, @MappingTarget Visa visaToUpdate); + public abstract void updateVisa(VisaRequest request, @MappingTarget Visa visaToUpdate); } @Override From 8c17775c3df91b1546ae9aaa4815db62c4b0cabb Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Wed, 26 Apr 2023 06:59:02 -0400 Subject: [PATCH 08/43] throw exception on auth failure --- .../ego/model/exceptions/SSOAuthenticationFailureHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/bio/overture/ego/model/exceptions/SSOAuthenticationFailureHandler.java b/src/main/java/bio/overture/ego/model/exceptions/SSOAuthenticationFailureHandler.java index 132d46c45..d35121741 100644 --- a/src/main/java/bio/overture/ego/model/exceptions/SSOAuthenticationFailureHandler.java +++ b/src/main/java/bio/overture/ego/model/exceptions/SSOAuthenticationFailureHandler.java @@ -56,7 +56,7 @@ public void onAuthenticationFailure( } else if (rootExceptionThrowable instanceof OAuth2Exception) { errorUri = buildOAuth2ExceptionResponse(errorUri, providerType); } else { - throw new InternalServerException("Invalid response from OAuth Service"); + throw new InternalServerException("Invalid response from OAuth Service:" + exception); } response.setStatus(403); response.sendRedirect(errorUri.toString()); From c320557095db212af4982b77371f1da88976c59f Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Wed, 26 Apr 2023 10:41:23 -0400 Subject: [PATCH 09/43] push docker image for develop-passport --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 8d59c0e17..9464be5dd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -128,6 +128,7 @@ spec: when { anyOf { branch 'develop' + branch 'feature/develop-passport' branch 'main' expression { return params.PUBLISH_IMAGE } } From e10d449aa82eabedaef371e694eed9c4d4d35dbc Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Wed, 26 Apr 2023 11:36:33 -0400 Subject: [PATCH 10/43] change clientAuthenticationMethod --- src/main/resources/application.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 47cbd5234..d2d185265 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -54,7 +54,7 @@ spring: clientId: ego-client clientSecret: authorizationGrantType: authorization_code - clientAuthenticationMethod: post + clientAuthenticationMethod: client_secret_post redirectUri: "http://localhost:8081/oauth/code/google" scope: - openid @@ -66,7 +66,7 @@ spring: clientId: ego-client clientSecret: redirectUri: "http://localhost:8081/oauth/code/github" - clientAuthenticationMethod: post + clientAuthenticationMethod: client_secret_post authorizationGrantType: authorization_code scope: - "read:user" From 4bfa395474690cc082d75e06d9b32d980ddbacb1 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Wed, 26 Apr 2023 13:11:19 -0400 Subject: [PATCH 11/43] Committing changes related to visaPermission CRUD endpoints implementation --- Jenkinsfile | 4 +- .../ego/controller/VisaController.java | 36 ++++++++++++++- .../ego/model/dto/VisaPermissionRequest.java | 4 +- .../bio/overture/ego/model/entity/Visa.java | 2 +- .../ego/model/entity/VisaPermission.java | 45 ++++++------------- .../overture/ego/model/enums/JavaFields.java | 3 +- .../overture/ego/model/enums/SqlFields.java | 8 +--- .../bio/overture/ego/model/enums/Tables.java | 2 - .../repository/VisaPermissionRepository.java | 12 +++-- .../ego/service/VisaPermissionService.java | 31 +++++++++---- .../flyway/sql/V1_23__add_visa_pcl.sql | 10 ++--- 11 files changed, 91 insertions(+), 66 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e99a99238..6b8ed599b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,4 @@ -def commit = "UNKNOWN" -def version = "UNKNOWN" -def chartversion = "3.1.0" +def chartversion = "3.1.1" pipeline { agent { diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index 957d92146..d320d0484 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -1,6 +1,5 @@ package bio.overture.ego.controller; -import static bio.overture.ego.controller.resolver.PageableResolver.*; import static org.springframework.web.bind.annotation.RequestMethod.*; import bio.overture.ego.model.dto.*; @@ -67,6 +66,10 @@ public VisaController( return visaService.getById(id); } + /* + * This method is used to list all visas + * @return visas List + */ @AdminScoped @RequestMapping(method = GET, value = "") @ApiResponses(value = {@ApiResponse(code = 200, message = "All Visas")}) @@ -78,6 +81,11 @@ public VisaController( return new PageDTO<>(visaService.listVisa(pageable)); } + /* + * This method is used to create visa using visa create request + * @param visaRequest VisaRequest + * @return Visa visa + */ @AdminScoped @RequestMapping(method = POST, value = "") @ApiResponses( @@ -91,6 +99,12 @@ public VisaController( return visaService.create(visaRequest); } + /* + * This method is used to update visa using visa id and update request + * @param visaId UUID + * @param visaRequest VisaRequest + * @return Visa visa + */ @AdminScoped @RequestMapping(method = PUT, value = "/{id}") @ApiResponses(value = {@ApiResponse(code = 200, message = "Update Visa", response = Visa.class)}) @@ -102,6 +116,10 @@ public VisaController( return visaService.partialUpdate(id, visaRequest); } + /* + * This method is used to delete visa using visa id + * @param visaId UUID + */ @AdminScoped @RequestMapping(method = DELETE, value = "/{id}") @ResponseStatus(value = HttpStatus.OK) @@ -159,4 +177,20 @@ public void deleteVisa( @RequestBody(required = true) VisaPermissionRequest visaPermissionRequest) { return visaPermissionService.createOrUpdatePermissions(visaPermissionRequest); } + + /* + * This method is used to delete/remove visa permissions + * @param visaPermissionRequest VisaPermissionRequest + */ + @AdminScoped + @RequestMapping(method = DELETE, value = "/permissions") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Remove VisaPermission")}) + @JsonView(Views.REST.class) + public @ResponseBody void removePermissions( + @ApiIgnore @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "policyId", required = true) UUID policyId, + @PathVariable(value = "visaId", required = true) UUID visaId) { + visaPermissionService.removePermission(policyId, visaId); + } } diff --git a/src/main/java/bio/overture/ego/model/dto/VisaPermissionRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaPermissionRequest.java index 83c382236..770c1e42d 100644 --- a/src/main/java/bio/overture/ego/model/dto/VisaPermissionRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/VisaPermissionRequest.java @@ -10,9 +10,9 @@ @NoArgsConstructor public class VisaPermissionRequest { - private UUID entity; + private UUID policyId; private UUID visaId; - private AccessLevel mask; + private AccessLevel accessLevel; } diff --git a/src/main/java/bio/overture/ego/model/entity/Visa.java b/src/main/java/bio/overture/ego/model/entity/Visa.java index 403b16849..f4574d692 100644 --- a/src/main/java/bio/overture/ego/model/entity/Visa.java +++ b/src/main/java/bio/overture/ego/model/entity/Visa.java @@ -64,7 +64,7 @@ public class Visa implements Identifiable { private String by; @JsonIgnore - @ManyToMany(mappedBy = "visaId", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @OneToMany(mappedBy = JavaFields.VISA, cascade = CascadeType.ALL, fetch = FetchType.LAZY) @Builder.Default private Set visaPermissions = newHashSet(); } diff --git a/src/main/java/bio/overture/ego/model/entity/VisaPermission.java b/src/main/java/bio/overture/ego/model/entity/VisaPermission.java index e441e5962..3b7207b43 100644 --- a/src/main/java/bio/overture/ego/model/entity/VisaPermission.java +++ b/src/main/java/bio/overture/ego/model/entity/VisaPermission.java @@ -1,20 +1,13 @@ package bio.overture.ego.model.entity; -import static bio.overture.ego.model.enums.AccessLevel.EGO_ACCESS_LEVEL_ENUM; - -import bio.overture.ego.model.enums.AccessLevel; +import bio.overture.ego.model.enums.JavaFields; import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import java.util.Collection; -import java.util.UUID; import javax.persistence.*; -import javax.validation.constraints.NotNull; import lombok.*; import lombok.experimental.FieldNameConstants; -import org.hibernate.annotations.GenericGenerator; -import org.hibernate.annotations.Type; @Entity @Table(name = Tables.ACLVISAPERMISSION) @@ -25,32 +18,20 @@ @JsonView(Views.REST.class) @ToString(callSuper = true) @FieldNameConstants +@EqualsAndHashCode( + callSuper = true, + of = {"id"}) +@NamedEntityGraph( + name = "visa-permission-entity-with-relationships", + attributeNodes = { + @NamedAttributeNode(value = JavaFields.POLICY), + @NamedAttributeNode(value = JavaFields.VISA) + }) public class VisaPermission extends AbstractPermission { - @Id - @Column(name = SqlFields.ID, updatable = false, nullable = false) - @GenericGenerator(name = "aclp_uuid", strategy = "org.hibernate.id.UUIDGenerator") - @GeneratedValue(generator = "aclp_uuid") - private UUID id; - - @JoinColumn(name = SqlFields.ID, nullable = false) - private UUID entity; - - @JoinColumn(name = SqlFields.ID, nullable = false) - private UUID visaId; - - @NotNull - @Column(name = SqlFields.MASK, nullable = false) - @Enumerated(EnumType.STRING) - @Type(type = EGO_ACCESS_LEVEL_ENUM) - private AccessLevel mask; - - @ManyToMany - @JoinTable( - name = "ga4ghvisa", - joinColumns = @JoinColumn(name = "aclp_id", referencedColumnName = "visaId"), - inverseJoinColumns = @JoinColumn(name = "visa_id", referencedColumnName = "id")) - private Collection visas; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = SqlFields.VISA_ID, nullable = false) + private Visa visa; @Override public Visa getOwner() { diff --git a/src/main/java/bio/overture/ego/model/enums/JavaFields.java b/src/main/java/bio/overture/ego/model/enums/JavaFields.java index aecbeaf19..5592b257b 100644 --- a/src/main/java/bio/overture/ego/model/enums/JavaFields.java +++ b/src/main/java/bio/overture/ego/model/enums/JavaFields.java @@ -71,6 +71,7 @@ public class JavaFields { public static final String VALUE = "value"; public static final String BY = "by"; - public static final String VISAPERMISSION = "ACLVISAPERMISSION"; + public static final String GA4GHVISA = "ga4ghvisa"; + public static final String VISA = "visa"; } diff --git a/src/main/java/bio/overture/ego/model/enums/SqlFields.java b/src/main/java/bio/overture/ego/model/enums/SqlFields.java index 488b3c8ca..dfdf0a5fb 100644 --- a/src/main/java/bio/overture/ego/model/enums/SqlFields.java +++ b/src/main/java/bio/overture/ego/model/enums/SqlFields.java @@ -40,12 +40,6 @@ public class SqlFields { public static final String ERRORREDIRECTURI = "errorredirecturi"; public static final String SOURCE = "source"; public static final String VALUE = "value"; - public static final String BY = "by"; - - public static final String ENTITY = "entity"; - - public static final String VISAID = "visaId"; - - public static final String MASK = "mask"; + public static final String VISA_ID = "visa_id"; } diff --git a/src/main/java/bio/overture/ego/model/enums/Tables.java b/src/main/java/bio/overture/ego/model/enums/Tables.java index 861fe7978..e4198aaf9 100644 --- a/src/main/java/bio/overture/ego/model/enums/Tables.java +++ b/src/main/java/bio/overture/ego/model/enums/Tables.java @@ -22,8 +22,6 @@ public class Tables { public static final String APPLICATION_PERMISSION = "applicationpermission"; public static final String DEFAULTPROVIDERTRIPWIRE = "defaultprovidertripwire"; public static final String INITTRIPWIRE = "inittripwire"; - public static final String GA4GHVISA = "ga4ghvisa"; - public static final String ACLVISAPERMISSION = "ACLVISAPERMISSION"; } diff --git a/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java b/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java index 504d20cbc..abee391d1 100644 --- a/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java +++ b/src/main/java/bio/overture/ego/repository/VisaPermissionRepository.java @@ -1,9 +1,12 @@ package bio.overture.ego.repository; +import static org.springframework.data.jpa.repository.EntityGraph.EntityGraphType.FETCH; + import bio.overture.ego.model.entity.VisaPermission; import java.util.List; import java.util.Optional; import java.util.UUID; +import org.springframework.data.jpa.repository.EntityGraph; public interface VisaPermissionRepository extends NamedRepository { @Override @@ -14,9 +17,12 @@ default Optional findByName(String name) { List findAll(); - List findByVisaId(UUID visaId); + @EntityGraph(value = "visa-permission-entity-with-relationships", type = FETCH) + List findByVisa_Id(UUID visa_id); - List findByPolicyId(UUID entity); + @EntityGraph(value = "visa-permission-entity-with-relationships", type = FETCH) + List findByPolicy_Id(UUID policy_id); - List findByPolicyIdAndVisaId(UUID entity, UUID visaId); + @EntityGraph(value = "visa-permission-entity-with-relationships", type = FETCH) + List findByPolicyIdAndVisaId(UUID policy_id, UUID visa_id); } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 090c1d8c3..20ae80963 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -10,6 +10,7 @@ import bio.overture.ego.repository.VisaPermissionRepository; import java.util.List; import java.util.UUID; +import javax.validation.constraints.NotNull; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; @@ -29,6 +30,8 @@ public class VisaPermissionService extends AbstractNamedService getPermissionsByVisaId(@NonNull UUID visaId) { - val result = (List) visaPermissionRepository.findByVisaId(visaId); + val result = (List) visaPermissionRepository.findByVisa_Id(visaId); if (result.isEmpty()) { throw new NotFoundException(format("No VisaPermissions exists with visaId '%s'", visaId)); } @@ -55,7 +58,7 @@ public List getPermissionsByVisaId(@NonNull UUID visaId) { } public List getPermissionsByPolicyId(@NonNull UUID policyId) { - val result = (List) visaPermissionRepository.findByPolicyId(policyId); + val result = (List) visaPermissionRepository.findByPolicy_Id(policyId); if (result.isEmpty()) { throw new NotFoundException(format("No VisaPermissions exists with policyId '%s'", policyId)); } @@ -64,12 +67,16 @@ public List getPermissionsByPolicyId(@NonNull UUID policyId) { public VisaPermission createOrUpdatePermissions( @NonNull VisaPermissionRequest visaPermissionRequest) { + VisaPermission visaPermission = null; List visaPermissionEntities = visaPermissionRepository.findByPolicyIdAndVisaId( - visaPermissionRequest.getEntity(), visaPermissionRequest.getVisaId()); - if (visaPermissionEntities == null && visaPermissionEntities.isEmpty()) { - return visaPermissionRepository.save( - VISA_PERMISSION_CONVERTER.createVisaPermission(visaPermissionRequest)); + visaPermissionRequest.getPolicyId(), visaPermissionRequest.getVisaId()); + if (visaPermissionEntities.isEmpty()) { + visaPermission = new VisaPermission(); + visaPermission.setVisa(visaService.getById(visaPermissionRequest.getVisaId())); + visaPermission.setPolicy(policyService.getById(visaPermissionRequest.getPolicyId())); + visaPermission.setAccessLevel(visaPermissionRequest.getAccessLevel()); + return visaPermissionRepository.save(visaPermission); } else { VISA_PERMISSION_CONVERTER.updateVisaPermission( visaPermissionRequest, visaPermissionEntities.get(0)); @@ -77,6 +84,15 @@ public VisaPermission createOrUpdatePermissions( } } + public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { + VisaPermission visaPermission = null; + List visaPermissionEntities = + visaPermissionRepository.findByPolicyIdAndVisaId(policyId, visaId); + if (!visaPermissionEntities.isEmpty()) { + visaPermissionRepository.deleteById(visaPermissionEntities.get(0).getId()); + } + } + @Override public VisaPermission getById(@NonNull UUID uuid) { return super.getById(uuid); @@ -91,9 +107,6 @@ public VisaPermission getWithRelationships(UUID uuid) { nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.WARN) public abstract static class VisaPermissionConverter { - public abstract VisaPermission createVisaPermission( - VisaPermissionRequest visaPermissionRequest); - public abstract void updateVisaPermission( VisaPermissionRequest visaPermissionRequest, @MappingTarget VisaPermission visaPermission); } diff --git a/src/main/resources/flyway/sql/V1_23__add_visa_pcl.sql b/src/main/resources/flyway/sql/V1_23__add_visa_pcl.sql index 35557eef4..0d2e780c8 100644 --- a/src/main/resources/flyway/sql/V1_23__add_visa_pcl.sql +++ b/src/main/resources/flyway/sql/V1_23__add_visa_pcl.sql @@ -1,8 +1,8 @@ CREATE TABLE ACLVISAPERMISSION ( id UUID PRIMARY KEY, - entity UUID, - visaId UUID, - mask ACLMASK NOT NULL, - FOREIGN KEY (entity) REFERENCES POLICY(id), - FOREIGN KEY (visaId) REFERENCES GA4GHVISA(id) + policy_id UUID, + visa_id UUID, + access_level ACLMASK NOT NULL, + FOREIGN KEY (policy_id) REFERENCES POLICY(id), + FOREIGN KEY (visa_id) REFERENCES GA4GHVISA(id) ); From 99bc18ce74aec2fd2f02aba587f9f6ea6054a9ed Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Thu, 27 Apr 2023 13:53:11 -0400 Subject: [PATCH 12/43] SpringBoot 3 migration (#689) * Update to Spring Boot 2.7 * Update to Spring Boot 3.0.5 * order Spring security filters * use JDK 17 docker image * spring migration * Spring migration --------- Co-authored-by: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> --- Dockerfile | 8 +- Jenkinsfile | 5 +- pom.xml | 78 ++--- .../ego/config/AppSecureServerConfig.java | 90 ++++++ .../ego/config/AuthorizationServerConfig.java | 10 +- .../ego/config/InitializationConfig.java | 6 +- ...essTokenResponseConverterWithDefaults.java | 22 +- .../ego/config/OAuth2ClientConfig.java | 2 +- .../ego/config/OauthSecureServerConfig.java | 154 ++++++++++ .../ego/config/SecureServerConfig.java | 166 +--------- .../bio/overture/ego/config/ServerConfig.java | 20 +- .../overture/ego/config/SwaggerConfig.java | 207 ++++++------- .../overture/ego/config/WebRequestConfig.java | 4 +- .../ego/controller/ApiKeyController.java | 70 +++-- .../ego/controller/ApplicationController.java | 223 +++++++------- .../ego/controller/AuthController.java | 14 +- .../ego/controller/GroupController.java | 253 +++++++-------- .../ego/controller/PolicyController.java | 289 +++++++++--------- .../ego/controller/TransactionController.java | 6 +- .../ego/controller/UserController.java | 265 ++++++++-------- .../ego/controller/VisaController.java | 30 +- .../model/dto/CreateApplicationRequest.java | 2 +- .../ego/model/dto/CreateTokenRequest.java | 2 +- .../ego/model/dto/CreateUserRequest.java | 2 +- .../overture/ego/model/dto/GroupRequest.java | 2 +- .../bio/overture/ego/model/dto/MaskDTO.java | 2 +- .../ego/model/dto/PermissionRequest.java | 2 +- .../overture/ego/model/dto/PolicyRequest.java | 4 +- .../overture/ego/model/dto/VisaRequest.java | 2 +- .../ego/model/entity/AbstractPermission.java | 26 +- .../bio/overture/ego/model/entity/ApiKey.java | 22 +- .../ego/model/entity/ApiKeyScope.java | 26 +- .../ego/model/entity/Application.java | 30 +- .../model/entity/ApplicationPermission.java | 2 +- .../ego/model/entity/DefaultProvider.java | 7 +- .../bio/overture/ego/model/entity/Group.java | 27 +- .../ego/model/entity/GroupPermission.java | 14 +- .../ego/model/entity/InitTripWire.java | 8 +- .../bio/overture/ego/model/entity/Policy.java | 24 +- .../ego/model/entity/RefreshToken.java | 4 +- .../bio/overture/ego/model/entity/User.java | 15 +- .../ego/model/entity/UserPermission.java | 14 +- .../bio/overture/ego/model/entity/Visa.java | 4 +- .../ego/model/entity/VisaPermission.java | 8 +- .../model/exceptions/ExceptionHandlers.java | 4 +- .../RequestValidationException.java | 4 +- .../model/exceptions/RequestViolation.java | 2 +- .../SSOAuthenticationFailureHandler.java | 4 +- .../ego/model/join/GroupApplication.java | 16 +- .../ego/model/join/GroupApplicationId.java | 4 +- .../ego/model/join/UserApplication.java | 16 +- .../ego/model/join/UserApplicationId.java | 4 +- .../overture/ego/model/join/UserGroup.java | 16 +- .../overture/ego/model/join/UserGroupId.java | 4 +- .../ego/repository/BaseRepository.java | 3 +- .../AbstractPermissionSpecification.java | 2 +- .../ApplicationSpecification.java | 2 +- .../GroupSpecification.java | 2 +- .../SimpleCriteriaBuilder.java | 2 +- .../queryspecification/SpecificationBase.java | 6 +- .../TokenStoreSpecification.java | 2 +- .../UserPermissionSpecification.java | 2 +- .../queryspecification/UserSpecification.java | 2 +- .../builder/AbstractSpecificationBuilder.java | 6 +- .../ApplicationSpecificationBuilder.java | 8 +- .../builder/GroupSpecificationBuilder.java | 4 +- .../RefreshTokenSpecificationBuilder.java | 4 +- .../builder/TokenSpecificationBuilder.java | 4 +- .../builder/UserSpecificationBuilder.java | 8 +- .../bio/overture/ego/security/CorsFilter.java | 6 +- .../ego/security/JWTAuthorizationFilter.java | 6 +- .../ego/security/OAuth2RequestResolver.java | 2 +- .../service/AbstractPermissionService.java | 2 +- .../overture/ego/service/GroupService.java | 2 +- .../ego/service/InitializationService.java | 2 +- .../overture/ego/service/PolicyService.java | 2 +- .../ego/service/RefreshContextService.java | 2 +- .../bio/overture/ego/service/UserService.java | 2 +- .../bio/overture/ego/service/VisaService.java | 2 +- .../ego/token/CustomTokenEnhancer.java | 4 +- .../ego/token/signer/DefaultTokenSigner.java | 2 +- .../ego/token/signer/JKSTokenSigner.java | 2 +- .../overture/ego/utils/HibernateSessions.java | 2 +- .../overture/ego/utils/SwaggerConstants.java | 13 + .../V1_1__complete_uuid_migration.java | 12 +- .../db/migration/V1_3__string_to_date.java | 11 +- src/main/resources/application.yml | 10 + .../controller/AbstractControllerTest.java | 2 +- .../overture/ego/controller/AppJWTTest.java | 1 - .../InitializationServiceTest.java | 2 +- .../ego/utils/web/AbstractWebResource.java | 4 +- 91 files changed, 1244 insertions(+), 1151 deletions(-) create mode 100644 src/main/java/bio/overture/ego/config/AppSecureServerConfig.java create mode 100644 src/main/java/bio/overture/ego/config/OauthSecureServerConfig.java diff --git a/Dockerfile b/Dockerfile index e93c528f8..74204e3a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,18 @@ -FROM adoptopenjdk/openjdk11:jdk-11.0.6_10-alpine-slim as builder +FROM eclipse-temurin:17.0.6_10-jdk-focal as builder WORKDIR /usr/src/app ADD . . RUN ./mvnw package -Dmaven.test.skip=true ##################################################### -FROM adoptopenjdk/openjdk11:jre-11.0.6_10-alpine +FROM eclipse-temurin:17.0.6_10-jre-focal COPY --from=builder /usr/src/app/target/ego-*-exec.jar /usr/bin/ego.jar ENV EGO_USER ego ENV EGO_USER_ID 9999 ENV EGO_GROUP_ID 9999 ENV EGO_DIR /target -RUN addgroup -S -g $EGO_GROUP_ID $EGO_USER \ - && adduser -S -u $EGO_USER_ID -G $EGO_USER $EGO_USER \ +RUN addgroup --system --gid $EGO_GROUP_ID $EGO_USER \ + && adduser --system --uid $EGO_USER_ID --ingroup $EGO_USER $EGO_USER \ && mkdir -p $EGO_DIR \ && chown -R $EGO_USER $EGO_DIR USER $EGO_USER_ID diff --git a/Jenkinsfile b/Jenkinsfile index 9464be5dd..cdfc58f00 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -12,10 +12,10 @@ spec: - name: maven command: ['cat'] tty: true - image: maven:3.6.3-openjdk-11 + image: maven:3.8.5-openjdk-17 - name: jdk tty: true - image: adoptopenjdk/openjdk11:jdk-11.0.7_10-alpine-slim + image: eclipse-temurin:17.0.6_10-jdk-focal env: - name: DOCKER_HOST value: tcp://localhost:2375 @@ -128,7 +128,6 @@ spec: when { anyOf { branch 'develop' - branch 'feature/develop-passport' branch 'main' expression { return params.PUBLISH_IMAGE } } diff --git a/pom.xml b/pom.xml index 37bcaa7d7..20fcf2d30 100644 --- a/pom.xml +++ b/pom.xml @@ -13,16 +13,18 @@ org.springframework.boot spring-boot-starter-parent - 2.5.12 + 3.0.5 UTF-8 UTF-8 - 11 + 17 1.2.0.Final - 1.34.1 + 1.54.0 + + 6.0.3 @@ -34,6 +36,14 @@ org.springframework.boot spring-boot-starter-actuator + + + + org.springframework.security + spring-security-oauth2-authorization-server + 1.0.1 + + org.springframework.boot spring-boot-starter-security @@ -52,8 +62,8 @@ org.springframework.security - spring-security-oauth2-authorization-server - 0.2.1 + spring-security-oauth2-client + 6.0.3 @@ -68,27 +78,15 @@ org.projectlombok lombok - 1.18.16 + + 1.18.22 true - + - io.springfox - springfox-swagger2 - 2.9.2 - compile - - - org.mapstruct - mapstruct - - - - - io.springfox - springfox-swagger-ui - 2.9.2 - compile + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.1.0 org.springframework.boot @@ -135,25 +133,25 @@ com.vladmihalcea - hibernate-types-52 - 2.2.2 + hibernate-types-60 + 2.21.1 org.testcontainers testcontainers - 1.15.1 + 1.18.0 org.testcontainers jdbc - 1.15.1 + 1.18.0 org.testcontainers postgresql - 1.15.1 + 1.18.0 commons-io @@ -166,11 +164,11 @@ 2.6 - + org.flywaydb flyway-core - 5.2.4 + 9.16.3 @@ -304,6 +302,13 @@ test + + + javax.annotation + javax.annotation-api + 1.3.2 + + org.junit.vintage junit-vintage-engine @@ -356,7 +361,7 @@ spring-boot-maven-plugin exec - true + @@ -389,12 +394,16 @@ org.xolstice.maven.plugins protobuf-maven-plugin - 0.5.1 + 0.6.1 com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} + + ${basedir}/src/main/proto grpc-java - io.grpc:protoc-gen-grpc-java:1.34.1:exe:${os.detected.classifier} + io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier} + + @@ -434,7 +443,8 @@ org.springframework.cloud spring-cloud-dependencies - 2020.0.4 + + 2021.0.5 pom import diff --git a/src/main/java/bio/overture/ego/config/AppSecureServerConfig.java b/src/main/java/bio/overture/ego/config/AppSecureServerConfig.java new file mode 100644 index 000000000..426615aca --- /dev/null +++ b/src/main/java/bio/overture/ego/config/AppSecureServerConfig.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bio.overture.ego.config; + +import bio.overture.ego.security.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.context.annotation.*; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +@Configuration +@EnableWebSecurity +@Import(OAuth2ClientConfig.class) +@Profile("auth") +public class AppSecureServerConfig { + + OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = + new OAuth2AuthorizationServerConfigurer(); + @Autowired JWTAuthorizationFilter authorizationFilter; + + @Bean + @Order(SecurityProperties.BASIC_AUTH_ORDER - 6) + public SecurityFilterChain appFilterChain(HttpSecurity http) throws Exception { + return http.csrf() + .disable() + .apply(authorizationServerConfigurer) + .and() + .securityMatcher( + "/", + "/favicon.ico", + "/swagger-ui/**", + "/v3/api-docs/**", + "/swagger-resources/**", + "/configuration/ui", + "/configuration/**", + "/v2/api**", + "/webjars/**", + "/actuator/**", + "/o/**", + "/oauth/token", + "/oauth/token/verify", + "/oauth/token/public_key") + .authorizeRequests() + .requestMatchers( + "/", + "/favicon.ico", + "/swagger-ui/**", + "/v3/api-docs/**", + "/swagger-resources/**", + "/configuration/ui", + "/configuration/**", + "/v2/api**", + "/webjars/**", + "/actuator/**", + "/oauth/token/verify", + "/oauth/token/public_key") + .permitAll() + .requestMatchers(HttpMethod.OPTIONS, "/**") + .permitAll() + .anyRequest() + .authenticated() + .and() + .addFilterBefore(authorizationFilter, BasicAuthenticationFilter.class) + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .build(); + } +} diff --git a/src/main/java/bio/overture/ego/config/AuthorizationServerConfig.java b/src/main/java/bio/overture/ego/config/AuthorizationServerConfig.java index a3f33602b..d46580d20 100644 --- a/src/main/java/bio/overture/ego/config/AuthorizationServerConfig.java +++ b/src/main/java/bio/overture/ego/config/AuthorizationServerConfig.java @@ -16,7 +16,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; -import org.springframework.security.oauth2.server.authorization.config.ProviderSettings; +import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; @Configuration public class AuthorizationServerConfig { @@ -48,7 +48,11 @@ public JwtDecoder jwtDecoder(@Autowired TokenSigner tokenSigner) { } @Bean - public ProviderSettings providerSettings(@Value("${token.issuer}") String issuer) { - return ProviderSettings.builder().tokenEndpoint("/oauth/token").issuer(issuer).build(); + public AuthorizationServerSettings providerSettings(@Value("${token.issuer}") String issuer) { + + return AuthorizationServerSettings.builder() + .tokenEndpoint("/oauth/token") + .issuer(issuer) + .build(); } } diff --git a/src/main/java/bio/overture/ego/config/InitializationConfig.java b/src/main/java/bio/overture/ego/config/InitializationConfig.java index 76b28054b..83c9d1511 100644 --- a/src/main/java/bio/overture/ego/config/InitializationConfig.java +++ b/src/main/java/bio/overture/ego/config/InitializationConfig.java @@ -1,11 +1,11 @@ package bio.overture.ego.config; import bio.overture.ego.model.enums.ApplicationType; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/bio/overture/ego/config/OAuth2AccessTokenResponseConverterWithDefaults.java b/src/main/java/bio/overture/ego/config/OAuth2AccessTokenResponseConverterWithDefaults.java index ff4693a2c..1901176b1 100644 --- a/src/main/java/bio/overture/ego/config/OAuth2AccessTokenResponseConverterWithDefaults.java +++ b/src/main/java/bio/overture/ego/config/OAuth2AccessTokenResponseConverterWithDefaults.java @@ -14,7 +14,7 @@ // oauth2 spec. // https://github.com/spring-projects/spring-security/issues/5983 public class OAuth2AccessTokenResponseConverterWithDefaults - implements Converter, OAuth2AccessTokenResponse> { + implements Converter, OAuth2AccessTokenResponse> { private static final Set TOKEN_RESPONSE_PARAMETER_NAMES = Stream.of( OAuth2ParameterNames.ACCESS_TOKEN, @@ -27,27 +27,31 @@ public class OAuth2AccessTokenResponseConverterWithDefaults private OAuth2AccessToken.TokenType defaultAccessTokenType = OAuth2AccessToken.TokenType.BEARER; @Override - public OAuth2AccessTokenResponse convert(Map tokenResponseParameters) { - String accessToken = tokenResponseParameters.get(OAuth2ParameterNames.ACCESS_TOKEN); + public OAuth2AccessTokenResponse convert(Map tokenResponseParameters) { + String accessToken = + getParameterValue(tokenResponseParameters, OAuth2ParameterNames.ACCESS_TOKEN); OAuth2AccessToken.TokenType accessTokenType = this.defaultAccessTokenType; if (OAuth2AccessToken.TokenType.BEARER .getValue() - .equalsIgnoreCase(tokenResponseParameters.get(OAuth2ParameterNames.TOKEN_TYPE))) { + .equalsIgnoreCase( + getParameterValue(tokenResponseParameters, OAuth2ParameterNames.TOKEN_TYPE))) { accessTokenType = OAuth2AccessToken.TokenType.BEARER; } long expiresIn = 0; if (tokenResponseParameters.containsKey(OAuth2ParameterNames.EXPIRES_IN)) { try { - expiresIn = Long.parseLong(tokenResponseParameters.get(OAuth2ParameterNames.EXPIRES_IN)); + expiresIn = + Long.parseLong( + getParameterValue(tokenResponseParameters, OAuth2ParameterNames.EXPIRES_IN)); } catch (NumberFormatException ignored) { } } Set scopes = Collections.emptySet(); if (tokenResponseParameters.containsKey(OAuth2ParameterNames.SCOPE)) { - String scope = tokenResponseParameters.get(OAuth2ParameterNames.SCOPE); + String scope = getParameterValue(tokenResponseParameters, OAuth2ParameterNames.SCOPE); scopes = Arrays.stream(StringUtils.delimitedListToStringArray(scope, " ")) .collect(Collectors.toSet()); @@ -70,4 +74,10 @@ public final void setDefaultAccessTokenType(OAuth2AccessToken.TokenType defaultA Assert.notNull(defaultAccessTokenType, "defaultAccessTokenType cannot be null"); this.defaultAccessTokenType = defaultAccessTokenType; } + + private static String getParameterValue( + Map tokenResponseParameters, String parameterName) { + Object obj = tokenResponseParameters.get(parameterName); + return obj != null ? obj.toString() : null; + } } diff --git a/src/main/java/bio/overture/ego/config/OAuth2ClientConfig.java b/src/main/java/bio/overture/ego/config/OAuth2ClientConfig.java index a5165f0e6..683eb3ba0 100644 --- a/src/main/java/bio/overture/ego/config/OAuth2ClientConfig.java +++ b/src/main/java/bio/overture/ego/config/OAuth2ClientConfig.java @@ -30,7 +30,7 @@ public class OAuth2ClientConfig { @Bean public OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver( ClientRegistrationRepository clientRegistrationRepository) { - return new OAuth2RequestResolver(clientRegistrationRepository, "/oauth/login/"); + return new OAuth2RequestResolver(clientRegistrationRepository, "/oauth/login"); } @Bean diff --git a/src/main/java/bio/overture/ego/config/OauthSecureServerConfig.java b/src/main/java/bio/overture/ego/config/OauthSecureServerConfig.java new file mode 100644 index 000000000..fb4367dfc --- /dev/null +++ b/src/main/java/bio/overture/ego/config/OauthSecureServerConfig.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bio.overture.ego.config; + +import bio.overture.ego.model.exceptions.SSOAuthenticationFailureHandler; +import bio.overture.ego.security.*; +import bio.overture.ego.service.ApplicationService; +import bio.overture.ego.utils.Redirects; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; +import lombok.val; +import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.context.annotation.*; +import org.springframework.core.annotation.Order; +import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient; +import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; +import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; +import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; +import org.springframework.web.client.RestTemplate; + +@Configuration +@EnableWebSecurity +@Import(OAuth2ClientConfig.class) +@Profile("auth") +public class OauthSecureServerConfig { + + @Bean + public AuthorizationManager authorizationManager() { + return new SecureAuthorizationManager(); + } + + final OAuth2AuthorizationRequestResolver oAuth2RequestResolver; + final CustomOAuth2UserInfoService customOAuth2UserInfoService; + final CustomOidc2UserInfoService customOidc2UserInfoService; + final ApplicationService applicationService; + final SSOAuthenticationFailureHandler failureHandler; + + public OauthSecureServerConfig( + OAuth2AuthorizationRequestResolver requestResolver, + CustomOAuth2UserInfoService customOAuth2UserInfoService, + CustomOidc2UserInfoService customOidc2UserInfoService, + ApplicationService applicationService, + SSOAuthenticationFailureHandler failureHandler) { + this.oAuth2RequestResolver = requestResolver; + this.customOAuth2UserInfoService = customOAuth2UserInfoService; + this.customOidc2UserInfoService = customOidc2UserInfoService; + this.applicationService = applicationService; + this.failureHandler = failureHandler; + } + + @Bean + public SimpleUrlAuthenticationSuccessHandler successHandler() { + return new SimpleUrlAuthenticationSuccessHandler() { + public void onAuthenticationSuccess( + HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws IOException, ServletException { + val application = + applicationService.getByClientId( + (String) request.getSession().getAttribute("ego_client_id")); + + String redirectUri = (String) request.getSession().getAttribute("ego_redirect_uri"); + + val redirect = Redirects.getRedirectUri(application, redirectUri); + if (!redirect.isEmpty()) { + this.setDefaultTargetUrl(redirect); + super.onAuthenticationSuccess(request, response, authentication); + } else { + throw new OAuth2AuthenticationException( + new OAuth2Error(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT), + "Incorrect redirect uri for ego client."); + } + } + }; + } + + @Bean + @Order(SecurityProperties.BASIC_AUTH_ORDER + 3000) + public SecurityFilterChain oathFilterChain(HttpSecurity http) throws Exception { + return http.csrf() + .disable() + .securityMatcher( + "/oauth/code/*", + "/oauth/login/*", + "/oauth/ego-token", + "/oauth/update-ego-token", + "/oauth/refresh") + .authorizeHttpRequests() + .requestMatchers( + "/oauth/code/*", + "/oauth/login/*", + "/oauth/ego-token", + "/oauth/update-ego-token", + "/oauth/refresh") + .permitAll() + .and() + .oauth2Login( + x -> { + x.redirectionEndpoint().baseUri("/oauth/code/{registrationId}"); + x.authorizationEndpoint(y -> y.authorizationRequestResolver(oAuth2RequestResolver)); + x.tokenEndpoint() + .accessTokenResponseClient(this.authorizationCodeTokenResponseClient()); + x.userInfoEndpoint().oidcUserService(this.customOidc2UserInfoService); + x.userInfoEndpoint().userService(customOAuth2UserInfoService); + x.successHandler(this.successHandler()); + x.failureHandler(this.failureHandler); + }) + .build(); + } + + private OAuth2AccessTokenResponseClient + authorizationCodeTokenResponseClient() { + val tokenResponseHttpMessageConverter = new OAuth2AccessTokenResponseHttpMessageConverter(); + tokenResponseHttpMessageConverter.setAccessTokenResponseConverter( + new OAuth2AccessTokenResponseConverterWithDefaults()); + + val restTemplate = + new RestTemplate( + Arrays.asList(new FormHttpMessageConverter(), tokenResponseHttpMessageConverter)); + restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler()); + + val tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient(); + tokenResponseClient.setRestOperations(restTemplate); + + return tokenResponseClient; + } +} diff --git a/src/main/java/bio/overture/ego/config/SecureServerConfig.java b/src/main/java/bio/overture/ego/config/SecureServerConfig.java index 7ddeb2447..533b0f02b 100644 --- a/src/main/java/bio/overture/ego/config/SecureServerConfig.java +++ b/src/main/java/bio/overture/ego/config/SecureServerConfig.java @@ -16,43 +16,13 @@ package bio.overture.ego.config; -import bio.overture.ego.model.exceptions.SSOAuthenticationFailureHandler; import bio.overture.ego.security.*; import bio.overture.ego.service.ApplicationService; import bio.overture.ego.service.TokenService; -import bio.overture.ego.utils.Redirects; -import java.io.IOException; -import java.util.Arrays; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.SneakyThrows; -import lombok.val; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.*; -import org.springframework.core.annotation.Order; -import org.springframework.http.HttpMethod; -import org.springframework.http.converter.FormHttpMessageConverter; -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.WebSecurityConfigurerAdapter; -import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient; -import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; -import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; -import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler; -import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.core.OAuth2Error; -import org.springframework.security.oauth2.core.OAuth2ErrorCodes; -import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; -import org.springframework.web.client.RestTemplate; @Configuration @EnableWebSecurity @@ -86,144 +56,10 @@ public AuthorizationManager authorizationManager() { return new SecureAuthorizationManager(); } - @Configuration - @Order(SecurityProperties.BASIC_AUTH_ORDER - 3) - public class OAuthConfigurerAdapter extends WebSecurityConfigurerAdapter { - - final OAuth2AuthorizationRequestResolver oAuth2RequestResolver; - final CustomOAuth2UserInfoService customOAuth2UserInfoService; - final CustomOidc2UserInfoService customOidc2UserInfoService; - final ApplicationService applicationService; - final SSOAuthenticationFailureHandler failureHandler; - - public OAuthConfigurerAdapter( - OAuth2AuthorizationRequestResolver requestResolver, - CustomOAuth2UserInfoService customOAuth2UserInfoService, - CustomOidc2UserInfoService customOidc2UserInfoService, - ApplicationService applicationService, - SSOAuthenticationFailureHandler failureHandler) { - this.oAuth2RequestResolver = requestResolver; - this.customOAuth2UserInfoService = customOAuth2UserInfoService; - this.customOidc2UserInfoService = customOidc2UserInfoService; - this.applicationService = applicationService; - this.failureHandler = failureHandler; - } - - @Bean - public SimpleUrlAuthenticationSuccessHandler successHandler() { - return new SimpleUrlAuthenticationSuccessHandler() { - public void onAuthenticationSuccess( - HttpServletRequest request, HttpServletResponse response, Authentication authentication) - throws IOException, ServletException { - val application = - applicationService.getByClientId( - (String) request.getSession().getAttribute("ego_client_id")); - - String redirectUri = (String) request.getSession().getAttribute("ego_redirect_uri"); - - val redirect = Redirects.getRedirectUri(application, redirectUri); - if (!redirect.isEmpty()) { - this.setDefaultTargetUrl(redirect); - super.onAuthenticationSuccess(request, response, authentication); - } else { - throw new OAuth2AuthenticationException( - new OAuth2Error(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT), - "Incorrect redirect uri for ego client."); - } - } - }; - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.requestMatchers() - .antMatchers( - "/oauth/code/*", - "/oauth/login/*", - "/oauth/ego-token", - "/oauth/update-ego-token", - "/oauth/refresh") - .and() - .csrf() - .disable() - .authorizeRequests() - .anyRequest() - .permitAll() - .and() - .oauth2Login( - x -> { - x.redirectionEndpoint().baseUri("/oauth/code/{registrationId}"); - x.authorizationEndpoint(y -> y.authorizationRequestResolver(oAuth2RequestResolver)); - x.tokenEndpoint() - .accessTokenResponseClient(this.authorizationCodeTokenResponseClient()); - x.userInfoEndpoint().oidcUserService(this.customOidc2UserInfoService); - x.userInfoEndpoint().userService(customOAuth2UserInfoService); - x.successHandler(this.successHandler()); - x.failureHandler(this.failureHandler); - }); - } - - private OAuth2AccessTokenResponseClient - authorizationCodeTokenResponseClient() { - val tokenResponseHttpMessageConverter = new OAuth2AccessTokenResponseHttpMessageConverter(); - tokenResponseHttpMessageConverter.setTokenResponseConverter( - new OAuth2AccessTokenResponseConverterWithDefaults()); - - val restTemplate = - new RestTemplate( - Arrays.asList(new FormHttpMessageConverter(), tokenResponseHttpMessageConverter)); - restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler()); - - val tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient(); - tokenResponseClient.setRestOperations(restTemplate); - - return tokenResponseClient; - } - } - @Bean @SneakyThrows - public JWTAuthorizationFilter authorizationFilter( + public JWTAuthorizationFilter authorizationFilterBean( TokenService tokenService, ApplicationService applicationService) { return new JWTAuthorizationFilter(PUBLIC_ENDPOINTS, tokenService, applicationService); } - - @Configuration - @Order(SecurityProperties.BASIC_AUTH_ORDER + 3) - public class AppConfigurerAdapter extends WebSecurityConfigurerAdapter { - - OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = - new OAuth2AuthorizationServerConfigurer<>(); - @Autowired JWTAuthorizationFilter authorizationFilter; - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf() - .disable() - .apply(authorizationServerConfigurer) - .and() - .authorizeRequests() - .antMatchers( - "/", - "/favicon.ico", - "/swagger**", - "/swagger-resources/**", - "/configuration/ui", - "/configuration/**", - "/v2/api**", - "/webjars/**", - "/actuator/**", - "/oauth/token/verify", - "/oauth/token/public_key") - .permitAll() - .antMatchers(HttpMethod.OPTIONS, "/**") - .permitAll() - .anyRequest() - .authenticated() - .and() - .addFilterBefore(authorizationFilter, BasicAuthenticationFilter.class) - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); - } - } } diff --git a/src/main/java/bio/overture/ego/config/ServerConfig.java b/src/main/java/bio/overture/ego/config/ServerConfig.java index b34939818..bc1fd8a6c 100644 --- a/src/main/java/bio/overture/ego/config/ServerConfig.java +++ b/src/main/java/bio/overture/ego/config/ServerConfig.java @@ -23,32 +23,34 @@ import org.springframework.context.annotation.Profile; 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.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity @Profile("!auth") -public class ServerConfig extends WebSecurityConfigurerAdapter { +public class ServerConfig { @Bean public AuthorizationManager authorizationManager() { return new DefaultAuthorizationManager(); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf() + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http.csrf() .disable() - .authorizeRequests() - .antMatchers("/**") + .authorizeHttpRequests() + .requestMatchers("/**") .permitAll() .anyRequest() .authenticated() .and() - .authorizeRequests() + .authorizeHttpRequests() .and() .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .build(); } } diff --git a/src/main/java/bio/overture/ego/config/SwaggerConfig.java b/src/main/java/bio/overture/ego/config/SwaggerConfig.java index e42d60779..808b60cdf 100644 --- a/src/main/java/bio/overture/ego/config/SwaggerConfig.java +++ b/src/main/java/bio/overture/ego/config/SwaggerConfig.java @@ -16,58 +16,40 @@ package bio.overture.ego.config; -import static bio.overture.ego.utils.SwaggerConstants.AUTH_CONTROLLER; -import static bio.overture.ego.utils.SwaggerConstants.POST_ACCESS_TOKEN; -import static java.util.stream.Collectors.toUnmodifiableList; -import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; -import static springfox.documentation.spi.DocumentationType.SWAGGER_2; - -import com.fasterxml.classmate.TypeResolver; -import com.google.common.base.Predicates; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import static bio.overture.ego.utils.SwaggerConstants.*; + +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import java.net.URISyntaxException; +import java.util.*; +import java.util.stream.Collectors; import lombok.Getter; import lombok.NonNull; import lombok.Setter; -import lombok.val; +import org.apache.http.client.utils.URIBuilder; +import org.springdoc.core.customizers.OpenApiCustomizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.info.BuildProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; -import springfox.documentation.builders.ParameterBuilder; -import springfox.documentation.schema.ModelRef; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.service.ApiKey; -import springfox.documentation.service.AuthorizationScope; -import springfox.documentation.service.Contact; -import springfox.documentation.service.Parameter; -import springfox.documentation.service.SecurityReference; -import springfox.documentation.service.VendorExtension; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spi.service.ParameterBuilderPlugin; -import springfox.documentation.spi.service.contexts.ParameterContext; -import springfox.documentation.spi.service.contexts.SecurityContext; -import springfox.documentation.spring.web.paths.RelativePathProvider; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger.common.SwaggerPluginSupport; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@EnableSwagger2 + +/** Open API Configuration Bean */ @Configuration public class SwaggerConfig { - private static final Set POST_ACCESS_TOKEN_PARAMS = - Set.of("client_secret", "client_id", "grant_type"); - private static final Set APPLICATION_SCOPED_PATHS = - Set.of( - "/o/check_api_key", - "/o/check_token", - "/transaction/group_permissions", - "/transaction/mass_delete"); - private final BuildProperties buildProperties; @Autowired @@ -76,103 +58,54 @@ public SwaggerConfig(@NonNull BuildProperties buildProperties) { } @Bean - public ParameterBuilderPlugin parameterBuilderPlugin() { - return new ParameterBuilderPlugin() { - @Override - public void apply(ParameterContext context) { - if (context.getGroupName().equals(AUTH_CONTROLLER) - && context.getOperationContext().getName().equals(POST_ACCESS_TOKEN)) { - context - .getOperationContext() - .operationBuilder() - .parameters(generatePostAccessTokenParameters()); - - // hide default "parameters" arg - val defaultName = context.resolvedMethodParameter().defaultName(); - if (defaultName.isPresent() && defaultName.get().equals("parameters")) { - context.parameterBuilder().required(false).hidden(true).build(); - } - } - } - - @Override - public boolean supports(DocumentationType delimiter) { - return SwaggerPluginSupport.pluginDoesApply(delimiter); - } - }; + public OpenAPI productApi(SwaggerProperties swaggerProperties) { + + URIBuilder uriBuilder = null; + try { + uriBuilder = new URIBuilder(swaggerProperties.host); + uriBuilder.setPath(swaggerProperties.baseUrl).build().normalize(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + return new OpenAPI() + .info(metaInfo()) + .servers(List.of(new Server().url(uriBuilder.toString()))) + .components(new Components().addSecuritySchemes(SECURITY_SCHEME_NAME, securityScheme())); } - @Bean - public Docket productApi(SwaggerProperties swaggerProperties) { - return new Docket(SWAGGER_2) - .select() - .apis(Predicates.or(basePackage("bio.overture.ego.controller"))) - .build() - .host(swaggerProperties.host) - .pathProvider( - new RelativePathProvider(null) { - @Override - public String getApplicationBasePath() { - return swaggerProperties.getBaseUrl(); - } - }) - .securitySchemes(List.of(apiKey())) - .securityContexts(List.of(securityContext())) - .apiInfo(metaInfo()) - .produces(Set.of("application/json")) - .consumes(Set.of("application/json")); - } - - private ApiInfo metaInfo() { - - return new ApiInfo( - "Ego Service API", - "Ego API Documentation", - buildProperties.getVersion(), - "", - new Contact("", "", ""), - "GNU Affero General Public License v3.0", - "", - new ArrayList()); - } + private Info metaInfo() { - private static ApiKey apiKey() { - return new ApiKey("Bearer", "Authorization", "header"); + return new Info() + .title("Ego Service API") + .description("Ego API Documentation") + .version(buildProperties.getVersion()) + .contact(new Contact()) + .license(new License().name("GNU Affero General Public License v3.0")); } - private static SecurityContext securityContext() { - return SecurityContext.builder() - .securityReferences(List.of(securityReference())) - // We want the default Bearer auth applied only for non-ApplicationScoped endpoints. - // For ApplicationScoped endpoints, an explicit RequestHeader - // fields will be present in the ui - .forPaths(x -> !isApplicationScopedPath(x)) - .build(); + private static SecurityScheme securityScheme() { + return new SecurityScheme() + .name(SECURITY_SCHEME_NAME) + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT"); } private static boolean isApplicationScopedPath(@NonNull String path) { return APPLICATION_SCOPED_PATHS.contains(path); } - private static SecurityReference securityReference() { - return SecurityReference.builder() - .reference("Bearer") - .scopes(new AuthorizationScope[0]) - .build(); - } - private static List generatePostAccessTokenParameters() { return POST_ACCESS_TOKEN_PARAMS.stream() .map( name -> - new ParameterBuilder() - .type(new TypeResolver().resolve(String.class)) + new Parameter() + .schema(new Schema().type("string")) .name(name) - .parameterType("query") - .required(true) - .modelRef(new ModelRef("String")) - .build()) - .collect(toUnmodifiableList()); + .in(ParameterIn.QUERY.toString()) + .required(true)) + .collect(Collectors.toList()); } @Component @@ -189,4 +122,36 @@ class SwaggerProperties { */ private String baseUrl = ""; } + + @Bean + public OpenApiCustomizer openApiCustomiser() { + return openApi -> { + openApi + .getPaths() + .forEach( + (path, pathItem) -> { + + // We want the default Bearer auth applied only for non-ApplicationScoped endpoints. + // For ApplicationScoped endpoints, an explicit RequestHeader + if (!isApplicationScopedPath(path)) { + pathItem + .readOperations() + .forEach( + operation -> { + operation.addSecurityItem( + new SecurityRequirement().addList(SECURITY_SCHEME_NAME)); + }); + } + }); + + // generate access token parameters + PathItem accessTokenPath = + new PathItem() + .post( + new Operation() + .addTagsItem("Auth") + .parameters(generatePostAccessTokenParameters())); + openApi.getPaths().addPathItem("/oauth/token", accessTokenPath); + }; + } } diff --git a/src/main/java/bio/overture/ego/config/WebRequestConfig.java b/src/main/java/bio/overture/ego/config/WebRequestConfig.java index e99bcd589..3e9a709d4 100644 --- a/src/main/java/bio/overture/ego/config/WebRequestConfig.java +++ b/src/main/java/bio/overture/ego/config/WebRequestConfig.java @@ -24,10 +24,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration -public class WebRequestConfig extends WebMvcConfigurerAdapter { +public class WebRequestConfig implements WebMvcConfigurer { @Bean public List fieldValues() { diff --git a/src/main/java/bio/overture/ego/controller/ApiKeyController.java b/src/main/java/bio/overture/ego/controller/ApiKeyController.java index 9a23b7c94..0f6c84567 100644 --- a/src/main/java/bio/overture/ego/controller/ApiKeyController.java +++ b/src/main/java/bio/overture/ego/controller/ApiKeyController.java @@ -46,12 +46,18 @@ import bio.overture.ego.security.ApplicationScoped; import bio.overture.ego.security.AuthorizationManager; import bio.overture.ego.service.TokenService; -import io.swagger.annotations.*; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.UUID; -import javax.servlet.http.HttpServletRequest; import lombok.NonNull; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -64,12 +70,11 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.web.bind.annotation.*; -import springfox.documentation.annotations.ApiIgnore; @Slf4j @RestController @RequestMapping("/o") -@Api(tags = "Api Keys") +@Tag(name = "Api Keys") public class ApiKeyController { /** Dependencies */ @@ -118,7 +123,7 @@ public ApiKeyController( @ResponseStatus(value = OK) @SneakyThrows public @ResponseBody UserScopesResponse getUserScope( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "userId") final UUID userId) { return tokenService.userScopes(userId); @@ -127,7 +132,7 @@ public ApiKeyController( @RequestMapping(method = POST, value = "/api_key") @ResponseStatus(value = OK) public @ResponseBody ApiKeyResponse issueApiKey( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "user_id") UUID userId, @RequestParam(value = "scopes") ArrayList scopes, @@ -153,7 +158,7 @@ public ApiKeyController( @RequestMapping(method = POST, value = "/token") @ResponseStatus(value = OK) public @ResponseBody TokenResponse issueToken( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "user_id") UUID userId, @RequestParam(value = "scopes") ArrayList scopes, @@ -175,7 +180,7 @@ public ApiKeyController( @RequestMapping(method = DELETE, value = "/api_key") @ResponseStatus(value = OK) public @ResponseBody GenericResponse revokeApiKey( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "apiKey") final String apiKey) { tokenService.revokeApiKey(apiKey); @@ -187,7 +192,7 @@ public ApiKeyController( @RequestMapping(method = DELETE, value = "/token") @ResponseStatus(value = OK) public @ResponseBody String revokeToken( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "token") final String token) { tokenService.revokeApiKey(token); @@ -195,42 +200,43 @@ public ApiKeyController( } @RequestMapping(method = GET, value = "/api_key") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page ApiKeys for a User")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Page ApiKeys for a User")}) public @ResponseBody PageDTO listApiKeys( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "user_id") UUID userId, - @ApiParam(value = "Query string compares to ApiKey's Name fields.", required = false) + @Parameter(description = "Query string compares to ApiKey's Name fields.", required = false) @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { checkAdminOrOwner(userId); if (isEmpty(query)) { return new PageDTO<>(tokenService.listApiKeysForUser(userId, filters, pageable)); @@ -244,7 +250,7 @@ public ApiKeyController( @RequestMapping(method = GET, value = "/token") @ResponseStatus(value = OK) public @ResponseBody List listTokens( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "user_id") UUID userId) { checkAdminOrOwner(userId); diff --git a/src/main/java/bio/overture/ego/controller/ApplicationController.java b/src/main/java/bio/overture/ego/controller/ApplicationController.java index cefecf2be..cafe4407f 100644 --- a/src/main/java/bio/overture/ego/controller/ApplicationController.java +++ b/src/main/java/bio/overture/ego/controller/ApplicationController.java @@ -38,11 +38,13 @@ import bio.overture.ego.service.UserService; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.Collection; import java.util.List; import java.util.UUID; @@ -52,12 +54,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import springfox.documentation.annotations.ApiIgnore; @Slf4j @RestController @RequestMapping("/applications") -@Api(tags = "Applications") +@Tag(name = "Applications") public class ApplicationController { /** Dependencies */ @@ -81,40 +82,40 @@ public ApplicationController( @AdminScoped @RequestMapping(method = GET, value = "") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Applications")}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Page Applications")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO listApplications( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (isEmpty(query)) { return new PageDTO<>(applicationService.listApps(filters, pageable)); } else { @@ -124,10 +125,9 @@ public ApplicationController( @AdminScoped @RequestMapping(method = POST, value = "") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "New Application", response = Application.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "New Application")}) public @ResponseBody Application createApplication( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestBody(required = true) CreateApplicationRequest request) { return applicationService.create(request); @@ -135,13 +135,10 @@ public ApplicationController( @AdminScoped @RequestMapping(method = GET, value = "/{id}") - @ApiResponses( - value = { - @ApiResponse(code = 200, message = "Application Details", response = Application.class) - }) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Application Details")}) @JsonView(Views.REST.class) public @ResponseBody Application getApplication( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { return applicationService.getById(id); @@ -150,11 +147,9 @@ public ApplicationController( @AdminScoped @RequestMapping(method = PUT, value = "/{id}") @ApiResponses( - value = { - @ApiResponse(code = 200, message = "Updated application info", response = Application.class) - }) + value = {@ApiResponse(responseCode = "200", description = "Updated application info")}) public @ResponseBody Application updateApplication( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(name = "id", required = true) UUID id, @RequestBody(required = true) UpdateApplicationRequest updateRequest) { @@ -165,7 +160,7 @@ public ApplicationController( @RequestMapping(method = DELETE, value = "/{id}") @ResponseStatus(value = HttpStatus.OK) public void deleteApplication( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { applicationService.delete(id); @@ -173,41 +168,42 @@ public void deleteApplication( @AdminScoped @RequestMapping(method = GET, value = "/{id}/users") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Users for an Application")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Page Users for an Application")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO getUsersForApplication( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (isEmpty(query)) { return new PageDTO<>(userService.findUsersForApplication(id, filters, pageable)); } else { @@ -217,41 +213,42 @@ public void deleteApplication( @AdminScoped @RequestMapping(method = GET, value = "/{id}/groups") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Groups for an Application")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Page Groups for an Application")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO getGroupsForApplication( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (isEmpty(query)) { return new PageDTO<>(groupService.findGroupsForApplication(id, filters, pageable)); } else { @@ -264,56 +261,51 @@ public void deleteApplication( */ @AdminScoped @RequestMapping(method = GET, value = "/{id}/permissions") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) @ApiResponses( value = { - @ApiResponse(code = 200, message = "Page Permissions for an Application"), + @ApiResponse(responseCode = "200", description = "Page Permissions for an Application"), }) @JsonView(Views.REST.class) public @ResponseBody PageDTO getPermissionsForApplication( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) Pageable pageable) { return new PageDTO<>(applicationPermissionService.getPermissions(id, pageable)); } @AdminScoped @RequestMapping(method = POST, value = "/{id}/permissions") @ApiResponses( - value = { - @ApiResponse( - code = 200, - message = "Add application permissions", - response = Application.class) - }) + value = {@ApiResponse(responseCode = "200", description = "Add application permissions")}) public @ResponseBody Application addPermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) List permissions) { @@ -322,10 +314,11 @@ public void deleteApplication( @AdminScoped @RequestMapping(method = DELETE, value = "/{id}/permissions/{permissionIds}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Delete application permissions")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Delete application permissions")}) @ResponseStatus(value = OK) public void deletePermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "permissionIds", required = true) List permissionIds) { @@ -337,13 +330,13 @@ public void deletePermissions( @ApiResponses( value = { @ApiResponse( - code = 200, - message = + responseCode = "200", + description = "Get effective permissions for an application with application and group permissions") }) @ResponseStatus(value = HttpStatus.OK) public @ResponseBody Collection getResolvedPermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { return applicationPermissionService.getResolvedPermissions(id); diff --git a/src/main/java/bio/overture/ego/controller/AuthController.java b/src/main/java/bio/overture/ego/controller/AuthController.java index 927b189ce..b6b696a4a 100644 --- a/src/main/java/bio/overture/ego/controller/AuthController.java +++ b/src/main/java/bio/overture/ego/controller/AuthController.java @@ -32,9 +32,10 @@ import bio.overture.ego.token.IDToken; import bio.overture.ego.token.signer.TokenSigner; import bio.overture.ego.utils.Tokens; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; import java.util.Objects; -import javax.servlet.http.HttpServletResponse; import lombok.NonNull; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -47,12 +48,11 @@ import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; -import springfox.documentation.annotations.ApiIgnore; @Slf4j @RestController @RequestMapping("/oauth") -@Api(tags = "Auth", value = AUTH_CONTROLLER) +@Tag(name = "Auth", description = AUTH_CONTROLLER) public class AuthController { @Value("${auth.token.prefix}") @@ -146,7 +146,7 @@ public ResponseEntity user( method = {GET, POST}, value = "/update-ego-token") public ResponseEntity updateEgoToken( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization) { val currentToken = Tokens.removeTokenPrefix(authorization, TOKEN_PREFIX); return new ResponseEntity<>(tokenService.updateUserToken(currentToken), OK); @@ -154,7 +154,7 @@ public ResponseEntity updateEgoToken( @RequestMapping(method = DELETE, value = "/refresh") public ResponseEntity deleteRefreshToken( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @CookieValue(value = REFRESH_ID, defaultValue = "missing") String refreshId, HttpServletResponse response) { @@ -170,7 +170,7 @@ public ResponseEntity deleteRefreshToken( @RequestMapping(method = POST, value = "/refresh") public ResponseEntity refreshEgoToken( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @CookieValue(value = REFRESH_ID, defaultValue = "missing") String refreshId, HttpServletResponse response) { diff --git a/src/main/java/bio/overture/ego/controller/GroupController.java b/src/main/java/bio/overture/ego/controller/GroupController.java index 5edcfc24e..c0088bca9 100644 --- a/src/main/java/bio/overture/ego/controller/GroupController.java +++ b/src/main/java/bio/overture/ego/controller/GroupController.java @@ -43,11 +43,13 @@ import bio.overture.ego.service.UserService; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import java.util.UUID; import lombok.NonNull; @@ -64,12 +66,11 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import springfox.documentation.annotations.ApiIgnore; @Slf4j @RestController @RequestMapping("/groups") -@Api(tags = "Groups") +@Tag(name = "Groups") public class GroupController { /** Dependencies */ @@ -95,40 +96,40 @@ public GroupController( @AdminScoped @RequestMapping(method = GET, value = "") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Groups")}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Page Groups")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO listGroups( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (isEmpty(query)) { return new PageDTO<>(groupService.listGroups(filters, pageable)); } else { @@ -140,10 +141,10 @@ public GroupController( @RequestMapping(method = POST, value = "") @ApiResponses( value = { - @ApiResponse(code = 200, message = "New Group", response = Group.class), + @ApiResponse(responseCode = "200", description = "New Group"), }) public @ResponseBody Group createGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestBody GroupRequest createRequest) { return groupService.create(createRequest); @@ -151,11 +152,10 @@ public GroupController( @AdminScoped @RequestMapping(method = GET, value = "/{id}") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Group Details", response = Group.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Group Details")}) @JsonView(Views.REST.class) public @ResponseBody Group getGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id") UUID id) { return groupService.getById(id); @@ -163,10 +163,9 @@ public GroupController( @AdminScoped @RequestMapping(method = RequestMethod.PUT, value = "/{id}") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Updated group info", response = Group.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Updated group info")}) public @ResponseBody Group updateGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id") UUID id, @RequestBody(required = true) GroupRequest updateRequest) { @@ -177,7 +176,7 @@ public GroupController( @RequestMapping(method = DELETE, value = "/{id}") @ResponseStatus(value = OK) public void deleteGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { groupService.delete(id); @@ -188,57 +187,56 @@ public void deleteGroup( */ @AdminScoped @RequestMapping(method = GET, value = "/{id}/permissions") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = Fields.ID, required = true, - dataType = "string", - paramType = "path", - value = "Search for ids containing this text"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Search for ids containing this text"), + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) @ApiResponses( value = { - @ApiResponse(code = 200, message = "Page GroupPermissions for a Group"), + @ApiResponse(responseCode = "200", description = "Page GroupPermissions for a Group"), }) @JsonView(Views.REST.class) public @ResponseBody PageDTO getGroupPermissionsForGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) Pageable pageable) { return new PageDTO<>(groupPermissionService.getPermissions(id, pageable)); } @AdminScoped @RequestMapping(method = POST, value = "/{id}/permissions") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Add group permissions", response = Group.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Add group permissions")}) public @ResponseBody Group addPermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) List permissions) { @@ -247,10 +245,11 @@ public void deleteGroup( @AdminScoped @RequestMapping(method = DELETE, value = "/{id}/permissions/{permissionIds}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Delete group permissions")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Delete group permissions")}) @ResponseStatus(value = OK) public void deletePermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "permissionIds", required = true) List permissionIds) { @@ -262,47 +261,48 @@ public void deletePermissions( */ @AdminScoped @RequestMapping(method = GET, value = "/{id}/applications") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = Fields.ID, required = true, - dataType = "string", - paramType = "path", - value = "Search for ids containing this text"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Search for ids containing this text"), + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Applications for a Group")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Page Applications for a Group")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO getApplicationsForGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (StringUtils.isEmpty(query)) { return new PageDTO<>(applicationService.findApplicationsForGroup(id, filters, pageable)); } else { @@ -313,10 +313,9 @@ public void deletePermissions( @AdminScoped @RequestMapping(method = POST, value = "/{id}/applications") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Add Apps to Group", response = Group.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Add Apps to Group")}) public @ResponseBody Group addApplicationsToGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) List appIds) { @@ -325,10 +324,11 @@ public void deletePermissions( @AdminScoped @RequestMapping(method = DELETE, value = "/{id}/applications/{appIds}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Delete Apps from Group")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Delete Apps from Group")}) @ResponseStatus(value = OK) public void deleteApplicationsFromGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "appIds", required = true) List appIds) { @@ -340,47 +340,48 @@ public void deleteApplicationsFromGroup( */ @AdminScoped @RequestMapping(method = GET, value = "/{id}/users") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = Fields.ID, required = true, - dataType = "string", - paramType = "path", - value = "Search for ids containing this text"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Search for ids containing this text"), + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Users for a Group")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Page Users for a Group")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO getUsersForGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (StringUtils.isEmpty(query)) { return new PageDTO<>(userService.findUsersForGroup(id, filters, pageable)); } else { @@ -390,10 +391,9 @@ public void deleteApplicationsFromGroup( @AdminScoped @RequestMapping(method = POST, value = "/{id}/users") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Add Users to Group", response = Group.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Add Users to Group")}) public @ResponseBody Group addUsersToGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) List userIds) { @@ -402,10 +402,11 @@ public void deleteApplicationsFromGroup( @AdminScoped @RequestMapping(method = DELETE, value = "/{id}/users/{userIds}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Delete Users from Group")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Delete Users from Group")}) @ResponseStatus(value = OK) public void deleteUsersFromGroup( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "userIds", required = true) List userIds) { diff --git a/src/main/java/bio/overture/ego/controller/PolicyController.java b/src/main/java/bio/overture/ego/controller/PolicyController.java index 7493542e5..ca7590e47 100644 --- a/src/main/java/bio/overture/ego/controller/PolicyController.java +++ b/src/main/java/bio/overture/ego/controller/PolicyController.java @@ -28,7 +28,14 @@ import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; import com.google.common.collect.ImmutableList; -import io.swagger.annotations.*; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import java.util.UUID; import lombok.NonNull; @@ -38,12 +45,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import springfox.documentation.annotations.ApiIgnore; @Slf4j @RestController @RequestMapping("/policies") -@Api(tags = "Policies") +@Tag(name = "Policies") public class PolicyController { /** Dependencies */ @@ -67,11 +73,10 @@ public PolicyController( @AdminScoped @RequestMapping(method = GET, value = "/{id}") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Get policy by id", response = Policy.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Get policy by id")}) @JsonView(Views.REST.class) public @ResponseBody Policy getPolicy( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { return policyService.getById(id); @@ -79,51 +84,51 @@ public PolicyController( @AdminScoped @RequestMapping(method = GET, value = "") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = Fields.ID, required = false, - dataType = "string", - paramType = "query", - value = "Search for ids containing this text"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Search for ids containing this text"), + @Parameter( name = Fields.NAME, required = false, - dataType = "string", - paramType = "query", - value = "Search for policies whose names contain this text"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Search for policies whose names contain this text"), + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Policies")}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Page Policies")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO listPolicies( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { return new PageDTO<>(policyService.listPolicies(filters, pageable)); } @@ -131,10 +136,10 @@ public PolicyController( @RequestMapping(method = POST, value = "") @ApiResponses( value = { - @ApiResponse(code = 200, message = "New Policy", response = Policy.class), + @ApiResponse(responseCode = "200", description = "New Policy"), }) public @ResponseBody Policy createPolicy( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestBody(required = true) PolicyRequest createRequest) { return policyService.create(createRequest); @@ -142,10 +147,9 @@ public PolicyController( @AdminScoped @RequestMapping(method = PUT, value = "/{id}") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Updated Policy", response = Policy.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Updated Policy")}) public @ResponseBody Policy updatePolicy( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id") UUID id, @RequestBody(required = true) PolicyRequest updatedRequst) { @@ -156,7 +160,7 @@ public PolicyController( @RequestMapping(method = DELETE, value = "/{id}") @ResponseStatus(value = HttpStatus.OK) public void deletePolicy( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { policyService.delete(id); @@ -165,10 +169,15 @@ public void deletePolicy( @AdminScoped @RequestMapping(method = POST, value = "/{id}/permission/group/{group_id}") @ApiResponses( - value = {@ApiResponse(code = 200, message = "Add group permission", response = String.class)}) + value = { + @ApiResponse( + responseCode = "200", + description = "Add group permission", + content = @Content(schema = @Schema(implementation = String.class))) + }) @JsonView(Views.REST.class) public @ResponseBody Group createGroupPermission( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "group_id", required = true) UUID groupId, @@ -180,14 +189,9 @@ public void deletePolicy( @AdminScoped @RequestMapping(method = DELETE, value = "/{id}/permission/group/{group_id}") @ApiResponses( - value = { - @ApiResponse( - code = 200, - message = "Delete group permission", - response = GenericResponse.class) - }) + value = {@ApiResponse(responseCode = "200", description = "Delete group permission")}) public @ResponseBody GenericResponse deleteGroupPermission( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "group_id", required = true) UUID groupId) { @@ -198,9 +202,14 @@ public void deletePolicy( @AdminScoped @RequestMapping(method = POST, value = "/{id}/permission/user/{user_id}") @ApiResponses( - value = {@ApiResponse(code = 200, message = "Add user permission", response = String.class)}) + value = { + @ApiResponse( + responseCode = "200", + description = "Add user permission", + content = @Content(schema = @Schema(implementation = String.class))) + }) public @ResponseBody User createUserPermission( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "user_id", required = true) UUID userId, @@ -212,14 +221,9 @@ public void deletePolicy( @AdminScoped @RequestMapping(method = DELETE, value = "/{id}/permission/user/{user_id}") @ApiResponses( - value = { - @ApiResponse( - code = 200, - message = "Delete group permission", - response = GenericResponse.class) - }) + value = {@ApiResponse(responseCode = "200", description = "Delete group permission")}) public @ResponseBody GenericResponse deleteUserPermission( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "user_id", required = true) UUID userId) { @@ -232,10 +236,13 @@ public void deletePolicy( @RequestMapping(method = POST, value = "/{id}/permission/application/{application_id}") @ApiResponses( value = { - @ApiResponse(code = 200, message = "Add application permission", response = String.class) + @ApiResponse( + responseCode = "200", + description = "Add application permission", + content = @Content(schema = @Schema(implementation = String.class))) }) public @ResponseBody Application createApplicationPermission( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "application_id", required = true) UUID applicationId, @@ -247,14 +254,9 @@ public void deletePolicy( @AdminScoped @RequestMapping(method = DELETE, value = "/{id}/permission/application/{application_id}") @ApiResponses( - value = { - @ApiResponse( - code = 200, - message = "Delete application permission", - response = GenericResponse.class) - }) + value = {@ApiResponse(responseCode = "200", description = "Delete application permission")}) public @ResponseBody GenericResponse deleteApplicationPermission( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "application_id", required = true) UUID applicationId) { @@ -265,49 +267,51 @@ public void deletePolicy( @AdminScoped @RequestMapping(method = GET, value = "/{id}/users") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC. Note: ascending sort order for the mask field is: READ,WRITE,DENY"), }) @ApiResponses( value = { @ApiResponse( - code = 200, - message = "Get list of user ids with given policy id", - response = String.class) + responseCode = "200", + description = "Get list of user ids with given policy id", + content = @Content(schema = @Schema(implementation = String.class))) }) public @ResponseBody PageDTO findUserIds( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, - @ApiParam(value = "Query string compares to AccessLevel and user Id field.", required = false) + @Parameter( + description = "Query string compares to AccessLevel and user Id field.", + required = false) @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { val decoratedPageable = new IgnoreCaseSortDecorator(pageable); if (isEmpty(query)) { return new PageDTO<>( @@ -320,51 +324,51 @@ public void deletePolicy( @AdminScoped @RequestMapping(method = GET, value = "/{id}/groups") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC. Note: ascending sort order for the mask field is: READ,WRITE,DENY"), }) @ApiResponses( value = { @ApiResponse( - code = 200, - message = "Get list of group ids with given policy id", - response = String.class) + responseCode = "200", + description = "Get list of group ids with given policy id", + content = @Content(schema = @Schema(implementation = String.class))) }) public @ResponseBody PageDTO findGroupIds( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, - @ApiParam( - value = "Query string compares to AccessLevel and group Id and Name fields.", + @Parameter( + description = "Query string compares to AccessLevel and group Id and Name fields.", required = false) @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { val decoratedPageable = new IgnoreCaseSortDecorator(pageable); if (isEmpty(query)) { return new PageDTO( @@ -378,51 +382,52 @@ public void deletePolicy( @AdminScoped @RequestMapping(method = GET, value = "/{id}/applications") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC. Note: ascending sort order for the mask field is: READ,WRITE,DENY"), }) @ApiResponses( value = { @ApiResponse( - code = 200, - message = "Get list of application ids with given policy id", - response = String.class) + responseCode = "200", + description = "Get list of application ids with given policy id", + content = @Content(schema = @Schema(implementation = String.class))) }) public @ResponseBody PageDTO findApplicationIds( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, - @ApiParam( - value = "Query string compares to AccessLevel and Application Id and Name fields.", + @Parameter( + description = + "Query string compares to AccessLevel and Application Id and Name fields.", required = false) @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { val decoratedPageable = new IgnoreCaseSortDecorator(pageable); if (isEmpty(query)) { return new PageDTO( diff --git a/src/main/java/bio/overture/ego/controller/TransactionController.java b/src/main/java/bio/overture/ego/controller/TransactionController.java index 435b15925..14e635151 100644 --- a/src/main/java/bio/overture/ego/controller/TransactionController.java +++ b/src/main/java/bio/overture/ego/controller/TransactionController.java @@ -33,11 +33,11 @@ import bio.overture.ego.service.GroupService; import bio.overture.ego.service.PolicyService; import com.google.common.collect.ImmutableList; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; import java.util.List; import java.util.Optional; import java.util.UUID; -import javax.servlet.http.HttpServletRequest; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; @@ -52,7 +52,7 @@ @RestController @Transactional @RequestMapping("/transaction") -@Api(tags = "Transactions") +@Tag(name = "Transactions") public class TransactionController { PolicyService policyService; GroupService groupService; diff --git a/src/main/java/bio/overture/ego/controller/UserController.java b/src/main/java/bio/overture/ego/controller/UserController.java index 7152047d0..22b8e55a5 100644 --- a/src/main/java/bio/overture/ego/controller/UserController.java +++ b/src/main/java/bio/overture/ego/controller/UserController.java @@ -31,12 +31,13 @@ import bio.overture.ego.service.*; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.Collection; import java.util.List; import java.util.UUID; @@ -54,12 +55,11 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import springfox.documentation.annotations.ApiIgnore; @Slf4j @RestController @RequestMapping("/users") -@Api(tags = "Users") +@Tag(name = "Users") public class UserController { /** Dependencies */ @@ -83,51 +83,51 @@ public UserController( @AdminScoped @RequestMapping(method = RequestMethod.GET, value = "") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = Fields.ID, required = false, - dataType = "string", - paramType = "query", - value = "Search for ids containing this text"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Search for ids containing this text"), + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Users")}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Page Users")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO listUsers( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, - @ApiParam( - value = + @Parameter( + description = "Query string compares to Users Email, First Name, Last Name, Status and ProviderType fields.", required = false) @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (isEmpty(query)) { return new PageDTO<>(userService.listUsers(filters, pageable)); } else { @@ -137,10 +137,10 @@ public UserController( @AdminScoped @RequestMapping(method = RequestMethod.GET, value = "/{id}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "User Details", response = User.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "User Details")}) @JsonView(Views.REST.class) public @ResponseBody User getUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { return userService.getById(id); @@ -151,12 +151,11 @@ public UserController( @ApiResponses( value = { @ApiResponse( - code = 200, - message = "Partially update using non-null user info", - response = User.class) + responseCode = "200", + description = "Partially update using non-null user info") }) public @ResponseBody User updateUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) UpdateUserRequest updateUserRequest) { @@ -167,7 +166,7 @@ public UserController( @RequestMapping(method = RequestMethod.DELETE, value = "/{id}") @ResponseStatus(value = HttpStatus.OK) public void deleteUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { userService.delete(id); @@ -178,48 +177,50 @@ public void deleteUser( */ @AdminScoped @RequestMapping(method = RequestMethod.GET, value = "/{id}/permissions") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page User Permissions for a User")}) + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "Page User Permissions for a User") + }) @JsonView(Views.REST.class) public @ResponseBody PageDTO getPermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) Pageable pageable) { return new PageDTO<>(userPermissionService.getPermissions(id, pageable)); } @AdminScoped @RequestMapping(method = RequestMethod.POST, value = "/{id}/permissions") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Add user permissions", response = User.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Add user permissions")}) public @ResponseBody User addPermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) List permissions) { @@ -228,10 +229,11 @@ public void deleteUser( @AdminScoped @RequestMapping(method = RequestMethod.DELETE, value = "/{id}/permissions/{permissionIds}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Delete User permissions")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Delete User permissions")}) @ResponseStatus(value = HttpStatus.OK) public void deletePermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "permissionIds", required = true) List permissionIds) { @@ -243,12 +245,12 @@ public void deletePermissions( @ApiResponses( value = { @ApiResponse( - code = 200, - message = "Get effective permissions for a user with user and group permissions") + responseCode = "200", + description = "Get effective permissions for a user with user and group permissions") }) @ResponseStatus(value = HttpStatus.OK) public @ResponseBody Collection getResolvedPermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { return userPermissionService.getResolvedPermissions(id); @@ -259,47 +261,48 @@ public void deletePermissions( */ @AdminScoped @RequestMapping(method = RequestMethod.GET, value = "/{id}/groups") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = Fields.ID, required = true, - dataType = "string", - paramType = "path", - value = "Search for ids containing this text"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Search for ids containing this text"), + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Groups for a User")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Page Groups for a User")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO getGroupsFromUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (isEmpty(query)) { return new PageDTO<>(groupService.findGroupsForUser(id, filters, pageable)); } else { @@ -309,10 +312,9 @@ public void deletePermissions( @AdminScoped @RequestMapping(method = RequestMethod.POST, value = "/{id}/groups") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Add Groups to user", response = User.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Add Groups to user")}) public @ResponseBody User addGroupsToUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) List groupIds) { @@ -321,10 +323,11 @@ public void deletePermissions( @AdminScoped @RequestMapping(method = RequestMethod.DELETE, value = "/{id}/groups/{groupIDs}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Delete Groups from User")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Delete Groups from User")}) @ResponseStatus(value = HttpStatus.OK) public void deleteGroupsFromUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "groupIDs", required = true) List groupIds) { @@ -336,47 +339,48 @@ public void deleteGroupsFromUser( */ @AdminScoped @RequestMapping(method = RequestMethod.GET, value = "/{id}/applications") - @ApiImplicitParams({ - @ApiImplicitParam( + @Parameters({ + @Parameter( name = Fields.ID, required = true, - dataType = "string", - paramType = "path", - value = "Search for ids containing this text"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Search for ids containing this text"), + @Parameter( name = LIMIT, required = false, - dataType = "string", - paramType = "query", - value = "Number of results to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Number of results to retrieve"), + @Parameter( name = OFFSET, required = false, - dataType = "string", - paramType = "query", - value = "Index of first result to retrieve"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Index of first result to retrieve"), + @Parameter( name = SORT, required = false, - dataType = "string", - paramType = "query", - value = "Field to sort on"), - @ApiImplicitParam( + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Field to sort on"), + @Parameter( name = SORTORDER, required = false, - dataType = "string", - paramType = "query", - value = "Sorting order: ASC|DESC. Default order: DESC"), + schema = @Schema(type = "string"), + in = ParameterIn.QUERY, + description = "Sorting order: ASC|DESC. Default order: DESC"), }) - @ApiResponses(value = {@ApiResponse(code = 200, message = "Page Applications for a User")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Page Applications for a User")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO getApplicationsFromUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestParam(value = "query", required = false) String query, - @ApiIgnore @Filters List filters, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) @Filters List filters, + @Parameter(hidden = true) Pageable pageable) { if (isEmpty(query)) { return new PageDTO<>(applicationService.findApplicationsForUser(id, filters, pageable)); } else { @@ -388,11 +392,9 @@ public void deleteGroupsFromUser( @AdminScoped @RequestMapping(method = RequestMethod.POST, value = "/{id}/applications") @ApiResponses( - value = { - @ApiResponse(code = 200, message = "Add Applications to User", response = User.class) - }) + value = {@ApiResponse(responseCode = "200", description = "Add Applications to User")}) public @ResponseBody User addApplicationsToUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) List applicationIds) { @@ -401,10 +403,11 @@ public void deleteGroupsFromUser( @AdminScoped @RequestMapping(method = RequestMethod.DELETE, value = "/{id}/applications/{applicationIds}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Delete Applications from User")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Delete Applications from User")}) @ResponseStatus(value = HttpStatus.OK) public void deleteApplicationsFromUser( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @PathVariable(value = "applicationIds", required = true) List applicationIds) { diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index 53983a94a..647defcc0 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -1,6 +1,5 @@ package bio.overture.ego.controller; -import static bio.overture.ego.controller.resolver.PageableResolver.*; import static org.springframework.web.bind.annotation.RequestMethod.*; import bio.overture.ego.model.dto.*; @@ -9,7 +8,10 @@ import bio.overture.ego.service.*; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import io.swagger.annotations.*; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.UUID; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -17,12 +19,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import springfox.documentation.annotations.ApiIgnore; @Slf4j @RestController @RequestMapping("/visa") -@Api(tags = "Visa") +@Tag(name = "Visa") public class VisaController { /** Dependencies */ @@ -51,11 +52,10 @@ public VisaController( */ @AdminScoped @RequestMapping(method = GET, value = "/{id}") - @ApiResponses( - value = {@ApiResponse(code = 200, message = "Get Visa by id", response = Visa.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Get Visa by id")}) @JsonView(Views.REST.class) public @ResponseBody Visa getVisa( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { return visaService.getById(id); @@ -63,12 +63,12 @@ public VisaController( @AdminScoped @RequestMapping(method = GET, value = "") - @ApiResponses(value = {@ApiResponse(code = 200, message = "All Visas")}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "All Visas")}) @JsonView(Views.REST.class) public @ResponseBody PageDTO listVisa( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, - @ApiIgnore Pageable pageable) { + @Parameter(hidden = true) Pageable pageable) { return new PageDTO<>(visaService.listVisa(pageable)); } @@ -76,10 +76,10 @@ public VisaController( @RequestMapping(method = POST, value = "") @ApiResponses( value = { - @ApiResponse(code = 200, message = "New Visa", response = Visa.class), + @ApiResponse(responseCode = "200", description = "New Visa"), }) public @ResponseBody Visa createVisa( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestBody(required = true) VisaRequest visaRequest) { return visaService.create(visaRequest); @@ -87,9 +87,9 @@ public VisaController( @AdminScoped @RequestMapping(method = PUT, value = "/{id}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Update Visa", response = Visa.class)}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Update Visa")}) public @ResponseBody Visa updateVisa( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) VisaRequest visaRequest) { @@ -100,7 +100,7 @@ public VisaController( @RequestMapping(method = DELETE, value = "/{id}") @ResponseStatus(value = HttpStatus.OK) public void deleteVisa( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { visaService.delete(id); diff --git a/src/main/java/bio/overture/ego/model/dto/CreateApplicationRequest.java b/src/main/java/bio/overture/ego/model/dto/CreateApplicationRequest.java index 62387df73..a03c92c6f 100644 --- a/src/main/java/bio/overture/ego/model/dto/CreateApplicationRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/CreateApplicationRequest.java @@ -18,7 +18,7 @@ import bio.overture.ego.model.enums.ApplicationType; import bio.overture.ego.model.enums.StatusType; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/dto/CreateTokenRequest.java b/src/main/java/bio/overture/ego/model/dto/CreateTokenRequest.java index e9e19c360..1d8828065 100644 --- a/src/main/java/bio/overture/ego/model/dto/CreateTokenRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/CreateTokenRequest.java @@ -1,7 +1,7 @@ package bio.overture.ego.model.dto; +import jakarta.validation.constraints.NotNull; import java.util.Date; -import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/dto/CreateUserRequest.java b/src/main/java/bio/overture/ego/model/dto/CreateUserRequest.java index fba667fab..f0ffc790a 100644 --- a/src/main/java/bio/overture/ego/model/dto/CreateUserRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/CreateUserRequest.java @@ -20,7 +20,7 @@ import bio.overture.ego.model.enums.ProviderType; import bio.overture.ego.model.enums.StatusType; import bio.overture.ego.model.enums.UserType; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/dto/GroupRequest.java b/src/main/java/bio/overture/ego/model/dto/GroupRequest.java index 25124e102..37af37ad7 100644 --- a/src/main/java/bio/overture/ego/model/dto/GroupRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/GroupRequest.java @@ -17,7 +17,7 @@ package bio.overture.ego.model.dto; import bio.overture.ego.model.enums.StatusType; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/dto/MaskDTO.java b/src/main/java/bio/overture/ego/model/dto/MaskDTO.java index 92c6dcdac..21f30ce50 100644 --- a/src/main/java/bio/overture/ego/model/dto/MaskDTO.java +++ b/src/main/java/bio/overture/ego/model/dto/MaskDTO.java @@ -1,7 +1,7 @@ package bio.overture.ego.model.dto; import bio.overture.ego.model.enums.AccessLevel; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/dto/PermissionRequest.java b/src/main/java/bio/overture/ego/model/dto/PermissionRequest.java index 2baf41782..321671107 100644 --- a/src/main/java/bio/overture/ego/model/dto/PermissionRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/PermissionRequest.java @@ -1,8 +1,8 @@ package bio.overture.ego.model.dto; import bio.overture.ego.model.enums.AccessLevel; +import jakarta.validation.constraints.NotNull; import java.util.UUID; -import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/dto/PolicyRequest.java b/src/main/java/bio/overture/ego/model/dto/PolicyRequest.java index e5ce8a4e9..96be27804 100644 --- a/src/main/java/bio/overture/ego/model/dto/PolicyRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/PolicyRequest.java @@ -1,7 +1,7 @@ package bio.overture.ego.model.dto; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java index 6225d995a..d903df140 100644 --- a/src/main/java/bio/overture/ego/model/dto/VisaRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/VisaRequest.java @@ -1,6 +1,6 @@ package bio.overture.ego.model.dto; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/entity/AbstractPermission.java b/src/main/java/bio/overture/ego/model/entity/AbstractPermission.java index 971d99f6f..d0d30f87d 100644 --- a/src/main/java/bio/overture/ego/model/entity/AbstractPermission.java +++ b/src/main/java/bio/overture/ego/model/entity/AbstractPermission.java @@ -1,38 +1,34 @@ package bio.overture.ego.model.entity; -import static bio.overture.ego.model.enums.AccessLevel.EGO_ACCESS_LEVEL_ENUM; - import bio.overture.ego.model.enums.AccessLevel; import bio.overture.ego.model.enums.JavaFields; import bio.overture.ego.model.enums.SqlFields; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; +import jakarta.persistence.Column; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; +import jakarta.validation.constraints.NotNull; import java.util.UUID; -import javax.persistence.Column; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MappedSuperclass; -import javax.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.experimental.FieldNameConstants; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; @Data @MappedSuperclass @FieldNameConstants @EqualsAndHashCode(of = {"id"}) @ToString(exclude = {"policy"}) -@TypeDef(name = EGO_ACCESS_LEVEL_ENUM, typeClass = PostgreSQLEnumType.class) @JsonPropertyOrder({JavaFields.ID, JavaFields.POLICY, JavaFields.OWNER, JavaFields.ACCESS_LEVEL}) @JsonSubTypes({ @JsonSubTypes.Type(value = UserPermission.class, name = JavaFields.USERPERMISSIONS), @@ -54,7 +50,7 @@ public abstract class AbstractPermission> @NotNull @Column(name = SqlFields.ACCESS_LEVEL, nullable = false) @Enumerated(EnumType.STRING) - @Type(type = EGO_ACCESS_LEVEL_ENUM) + @Type(PostgreSQLEnumType.class) private AccessLevel accessLevel; public abstract O getOwner(); diff --git a/src/main/java/bio/overture/ego/model/entity/ApiKey.java b/src/main/java/bio/overture/ego/model/entity/ApiKey.java index bc048d670..2f7ad0a4b 100644 --- a/src/main/java/bio/overture/ego/model/entity/ApiKey.java +++ b/src/main/java/bio/overture/ego/model/entity/ApiKey.java @@ -8,18 +8,18 @@ import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; import java.util.*; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/entity/ApiKeyScope.java b/src/main/java/bio/overture/ego/model/entity/ApiKeyScope.java index 0e8edba40..4aa35225c 100644 --- a/src/main/java/bio/overture/ego/model/entity/ApiKeyScope.java +++ b/src/main/java/bio/overture/ego/model/entity/ApiKeyScope.java @@ -1,35 +1,31 @@ package bio.overture.ego.model.entity; -import static bio.overture.ego.model.enums.AccessLevel.EGO_ACCESS_LEVEL_ENUM; - import bio.overture.ego.model.enums.AccessLevel; import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; import com.fasterxml.jackson.annotation.JsonIgnore; import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; // TODO: rename TOKENSCOPE to API_KEY_SCOPE [anncatton] @NoArgsConstructor @AllArgsConstructor @Data @Entity -@TypeDef(name = EGO_ACCESS_LEVEL_ENUM, typeClass = PostgreSQLEnumType.class) @Table(name = Tables.TOKENSCOPE) public class ApiKeyScope implements Serializable { @@ -51,7 +47,7 @@ public class ApiKeyScope implements Serializable { @NotNull @Enumerated(EnumType.STRING) - @Type(type = EGO_ACCESS_LEVEL_ENUM) + @Type(PostgreSQLEnumType.class) @Column(name = SqlFields.ACCESS_LEVEL, nullable = false) private AccessLevel accessLevel; diff --git a/src/main/java/bio/overture/ego/model/entity/Application.java b/src/main/java/bio/overture/ego/model/entity/Application.java index d1a1044f8..b5f685f15 100644 --- a/src/main/java/bio/overture/ego/model/entity/Application.java +++ b/src/main/java/bio/overture/ego/model/entity/Application.java @@ -16,7 +16,6 @@ package bio.overture.ego.model.entity; -import static bio.overture.ego.model.enums.AccessLevel.EGO_ENUM; import static com.google.common.collect.Sets.newHashSet; import bio.overture.ego.model.enums.ApplicationType; @@ -32,19 +31,19 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonView; import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; import java.util.Set; import java.util.UUID; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -55,7 +54,6 @@ import lombok.experimental.FieldNameConstants; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; @Entity @Table(name = Tables.APPLICATION) @@ -79,8 +77,6 @@ @NoArgsConstructor @JsonView(Views.REST.class) @FieldNameConstants -@TypeDef(name = "application_type_enum", typeClass = PostgreSQLEnumType.class) -@TypeDef(name = EGO_ENUM, typeClass = PostgreSQLEnumType.class) @JsonInclude(JsonInclude.Include.CUSTOM) public class Application implements PolicyOwner, NameableEntity { @@ -96,7 +92,7 @@ public class Application implements PolicyOwner, NameableEntity { private String name; @NotNull - @Type(type = EGO_ENUM) + @Type(PostgreSQLEnumType.class) @Enumerated(EnumType.STRING) @Column(name = SqlFields.TYPE, nullable = false) @JsonView({Views.JWTAccessToken.class, Views.REST.class}) @@ -124,7 +120,7 @@ public class Application implements PolicyOwner, NameableEntity { private String errorRedirectUri; @NotNull - @Type(type = EGO_ENUM) + @Type(PostgreSQLEnumType.class) @Enumerated(EnumType.STRING) @JsonView({Views.JWTAccessToken.class, Views.REST.class}) @Column(name = SqlFields.STATUS, nullable = false) diff --git a/src/main/java/bio/overture/ego/model/entity/ApplicationPermission.java b/src/main/java/bio/overture/ego/model/entity/ApplicationPermission.java index 47d89ac6d..37f6d8e48 100644 --- a/src/main/java/bio/overture/ego/model/entity/ApplicationPermission.java +++ b/src/main/java/bio/overture/ego/model/entity/ApplicationPermission.java @@ -5,7 +5,7 @@ import bio.overture.ego.model.enums.Tables; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import javax.persistence.*; +import jakarta.persistence.*; import lombok.*; import lombok.experimental.FieldNameConstants; diff --git a/src/main/java/bio/overture/ego/model/entity/DefaultProvider.java b/src/main/java/bio/overture/ego/model/entity/DefaultProvider.java index da1216217..f8db8487e 100644 --- a/src/main/java/bio/overture/ego/model/entity/DefaultProvider.java +++ b/src/main/java/bio/overture/ego/model/entity/DefaultProvider.java @@ -1,11 +1,10 @@ package bio.overture.ego.model.entity; -import static bio.overture.ego.model.enums.AccessLevel.EGO_ENUM; - import bio.overture.ego.model.enums.ProviderType; import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; -import javax.persistence.*; +import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; +import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.Type; @@ -19,7 +18,7 @@ public class DefaultProvider implements Identifiable { @Id @Column(name = SqlFields.ID, nullable = false) - @Type(type = EGO_ENUM) + @Type(PostgreSQLEnumType.class) @Enumerated(EnumType.STRING) private ProviderType id; } diff --git a/src/main/java/bio/overture/ego/model/entity/Group.java b/src/main/java/bio/overture/ego/model/entity/Group.java index e81fbd6e0..0ad549d21 100644 --- a/src/main/java/bio/overture/ego/model/entity/Group.java +++ b/src/main/java/bio/overture/ego/model/entity/Group.java @@ -16,7 +16,6 @@ package bio.overture.ego.model.entity; -import static bio.overture.ego.model.enums.AccessLevel.EGO_ENUM; import static com.google.common.collect.Sets.newHashSet; import bio.overture.ego.model.enums.JavaFields; @@ -30,19 +29,19 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonView; import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; import java.util.Set; import java.util.UUID; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -51,7 +50,6 @@ import lombok.ToString; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; @Data @Entity @@ -61,7 +59,6 @@ @Table(name = Tables.GROUP) @JsonView(Views.REST.class) @EqualsAndHashCode(of = "id") -@TypeDef(name = EGO_ENUM, typeClass = PostgreSQLEnumType.class) @ToString(exclude = {"userGroups", "groupApplications", "permissions"}) @JsonPropertyOrder({ JavaFields.ID, @@ -87,7 +84,7 @@ public class Group implements PolicyOwner, NameableEntity { private String description; @NotNull - @Type(type = EGO_ENUM) + @Type(PostgreSQLEnumType.class) @Enumerated(EnumType.STRING) @Column(name = SqlFields.STATUS, nullable = false) private StatusType status; diff --git a/src/main/java/bio/overture/ego/model/entity/GroupPermission.java b/src/main/java/bio/overture/ego/model/entity/GroupPermission.java index 83bf7d919..ec1551ce5 100644 --- a/src/main/java/bio/overture/ego/model/entity/GroupPermission.java +++ b/src/main/java/bio/overture/ego/model/entity/GroupPermission.java @@ -6,13 +6,13 @@ import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonView; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedAttributeNode; +import jakarta.persistence.NamedEntityGraph; +import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/main/java/bio/overture/ego/model/entity/InitTripWire.java b/src/main/java/bio/overture/ego/model/entity/InitTripWire.java index 22ef4ad28..f736a6973 100644 --- a/src/main/java/bio/overture/ego/model/entity/InitTripWire.java +++ b/src/main/java/bio/overture/ego/model/entity/InitTripWire.java @@ -2,10 +2,10 @@ import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/entity/Policy.java b/src/main/java/bio/overture/ego/model/entity/Policy.java index dd11c17fd..32347191a 100644 --- a/src/main/java/bio/overture/ego/model/entity/Policy.java +++ b/src/main/java/bio/overture/ego/model/entity/Policy.java @@ -10,20 +10,20 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonView; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.NamedAttributeNode; +import jakarta.persistence.NamedEntityGraph; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; import java.util.Set; import java.util.UUID; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/entity/RefreshToken.java b/src/main/java/bio/overture/ego/model/entity/RefreshToken.java index 1470d32e2..dc63d7d2b 100644 --- a/src/main/java/bio/overture/ego/model/entity/RefreshToken.java +++ b/src/main/java/bio/overture/ego/model/entity/RefreshToken.java @@ -3,9 +3,9 @@ import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; import java.util.*; -import javax.persistence.*; -import javax.validation.constraints.NotNull; import lombok.*; import lombok.experimental.FieldNameConstants; import org.hibernate.annotations.GenericGenerator; diff --git a/src/main/java/bio/overture/ego/model/entity/User.java b/src/main/java/bio/overture/ego/model/entity/User.java index cc1ea6148..88f5d7fe8 100644 --- a/src/main/java/bio/overture/ego/model/entity/User.java +++ b/src/main/java/bio/overture/ego/model/entity/User.java @@ -17,7 +17,6 @@ package bio.overture.ego.model.entity; import static bio.overture.ego.grpc.ProtoUtils.toProtoString; -import static bio.overture.ego.model.enums.AccessLevel.EGO_ENUM; import static bio.overture.ego.service.UserService.resolveUsersPermissions; import static bio.overture.ego.utils.CollectionUtils.mapToImmutableSet; import static bio.overture.ego.utils.PolicyPermissionUtils.extractPermissionStrings; @@ -34,11 +33,11 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonView; import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; -import javax.persistence.*; -import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -51,7 +50,6 @@ import org.hibernate.LazyInitializationException; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; @Slf4j @Entity @@ -83,7 +81,6 @@ @AllArgsConstructor @NoArgsConstructor @JsonView(Views.REST.class) -@TypeDef(name = EGO_ENUM, typeClass = PostgreSQLEnumType.class) @FieldNameConstants public class User implements PolicyOwner, Identifiable { @@ -99,14 +96,14 @@ public class User implements PolicyOwner, Identifiable { private String email; @NotNull - @Type(type = EGO_ENUM) + @Type(PostgreSQLEnumType.class) @Enumerated(EnumType.STRING) @Column(name = SqlFields.TYPE, nullable = false) @JsonView({Views.JWTAccessToken.class, Views.REST.class}) private UserType type; @NotNull - @Type(type = EGO_ENUM) + @Type(PostgreSQLEnumType.class) @Enumerated(EnumType.STRING) @JsonView({Views.JWTAccessToken.class, Views.REST.class}) @Column(name = SqlFields.STATUS, nullable = false) @@ -133,14 +130,14 @@ public class User implements PolicyOwner, Identifiable { @Temporal(value = TemporalType.TIMESTAMP) private Date lastLogin; - @Type(type = EGO_ENUM) + @Type(PostgreSQLEnumType.class) @Enumerated(EnumType.STRING) @Column(name = SqlFields.PREFERREDLANGUAGE) @JsonView({Views.JWTAccessToken.class, Views.REST.class}) private LanguageType preferredLanguage; @NotNull - @Type(type = EGO_ENUM) + @Type(PostgreSQLEnumType.class) @Enumerated(EnumType.STRING) @Column(name = SqlFields.PROVIDERTYPE, nullable = false) @JsonView({Views.JWTAccessToken.class, Views.REST.class}) diff --git a/src/main/java/bio/overture/ego/model/entity/UserPermission.java b/src/main/java/bio/overture/ego/model/entity/UserPermission.java index 7a3f37c61..0628faa31 100644 --- a/src/main/java/bio/overture/ego/model/entity/UserPermission.java +++ b/src/main/java/bio/overture/ego/model/entity/UserPermission.java @@ -5,13 +5,13 @@ import bio.overture.ego.model.enums.Tables; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedAttributeNode; +import jakarta.persistence.NamedEntityGraph; +import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/entity/Visa.java b/src/main/java/bio/overture/ego/model/entity/Visa.java index 403b16849..f44a20af2 100644 --- a/src/main/java/bio/overture/ego/model/entity/Visa.java +++ b/src/main/java/bio/overture/ego/model/entity/Visa.java @@ -10,10 +10,10 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonView; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; import java.util.Set; import java.util.UUID; -import javax.persistence.*; -import javax.validation.constraints.NotNull; import lombok.*; import lombok.experimental.FieldNameConstants; import org.hibernate.annotations.GenericGenerator; diff --git a/src/main/java/bio/overture/ego/model/entity/VisaPermission.java b/src/main/java/bio/overture/ego/model/entity/VisaPermission.java index e441e5962..67223b63c 100644 --- a/src/main/java/bio/overture/ego/model/entity/VisaPermission.java +++ b/src/main/java/bio/overture/ego/model/entity/VisaPermission.java @@ -1,16 +1,16 @@ package bio.overture.ego.model.entity; -import static bio.overture.ego.model.enums.AccessLevel.EGO_ACCESS_LEVEL_ENUM; import bio.overture.ego.model.enums.AccessLevel; import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; +import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; import java.util.Collection; import java.util.UUID; -import javax.persistence.*; -import javax.validation.constraints.NotNull; import lombok.*; import lombok.experimental.FieldNameConstants; import org.hibernate.annotations.GenericGenerator; @@ -42,7 +42,7 @@ public class VisaPermission extends AbstractPermission { @NotNull @Column(name = SqlFields.MASK, nullable = false) @Enumerated(EnumType.STRING) - @Type(type = EGO_ACCESS_LEVEL_ENUM) + @Type(value = PostgreSQLEnumType.class) private AccessLevel mask; @ManyToMany diff --git a/src/main/java/bio/overture/ego/model/exceptions/ExceptionHandlers.java b/src/main/java/bio/overture/ego/model/exceptions/ExceptionHandlers.java index 20835a1c5..0e80a20d0 100644 --- a/src/main/java/bio/overture/ego/model/exceptions/ExceptionHandlers.java +++ b/src/main/java/bio/overture/ego/model/exceptions/ExceptionHandlers.java @@ -5,10 +5,10 @@ import static org.springframework.http.HttpStatus.NOT_FOUND; import bio.overture.ego.utils.Joiners; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.ConstraintViolationException; import java.util.Date; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.springframework.http.HttpHeaders; diff --git a/src/main/java/bio/overture/ego/model/exceptions/RequestValidationException.java b/src/main/java/bio/overture/ego/model/exceptions/RequestValidationException.java index 0a86301f2..0519cbe2d 100644 --- a/src/main/java/bio/overture/ego/model/exceptions/RequestValidationException.java +++ b/src/main/java/bio/overture/ego/model/exceptions/RequestValidationException.java @@ -5,8 +5,8 @@ import static java.lang.String.format; import static org.springframework.http.HttpStatus.BAD_REQUEST; -import javax.validation.Validation; -import javax.validation.Validator; +import jakarta.validation.Validation; +import jakarta.validation.Validator; import lombok.NonNull; import lombok.val; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/src/main/java/bio/overture/ego/model/exceptions/RequestViolation.java b/src/main/java/bio/overture/ego/model/exceptions/RequestViolation.java index c9eb2f850..9f9182837 100644 --- a/src/main/java/bio/overture/ego/model/exceptions/RequestViolation.java +++ b/src/main/java/bio/overture/ego/model/exceptions/RequestViolation.java @@ -1,6 +1,6 @@ package bio.overture.ego.model.exceptions; -import javax.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolation; import lombok.Builder; import lombok.NonNull; import lombok.Value; diff --git a/src/main/java/bio/overture/ego/model/exceptions/SSOAuthenticationFailureHandler.java b/src/main/java/bio/overture/ego/model/exceptions/SSOAuthenticationFailureHandler.java index d35121741..7dab5dd89 100644 --- a/src/main/java/bio/overture/ego/model/exceptions/SSOAuthenticationFailureHandler.java +++ b/src/main/java/bio/overture/ego/model/exceptions/SSOAuthenticationFailureHandler.java @@ -6,11 +6,11 @@ import bio.overture.ego.model.enums.ProviderType; import bio.overture.ego.service.ApplicationService; import bio.overture.ego.utils.Redirects; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/model/join/GroupApplication.java b/src/main/java/bio/overture/ego/model/join/GroupApplication.java index 0b49e4e3d..99fb1ca13 100644 --- a/src/main/java/bio/overture/ego/model/join/GroupApplication.java +++ b/src/main/java/bio/overture/ego/model/join/GroupApplication.java @@ -6,14 +6,14 @@ import bio.overture.ego.model.enums.JavaFields; import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; -import javax.persistence.CascadeType; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapsId; -import javax.persistence.Table; +import jakarta.persistence.CascadeType; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/join/GroupApplicationId.java b/src/main/java/bio/overture/ego/model/join/GroupApplicationId.java index c7e5ab2bc..aa5144d93 100644 --- a/src/main/java/bio/overture/ego/model/join/GroupApplicationId.java +++ b/src/main/java/bio/overture/ego/model/join/GroupApplicationId.java @@ -1,10 +1,10 @@ package bio.overture.ego.model.join; import bio.overture.ego.model.enums.SqlFields; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; import java.io.Serializable; import java.util.UUID; -import javax.persistence.Column; -import javax.persistence.Embeddable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/join/UserApplication.java b/src/main/java/bio/overture/ego/model/join/UserApplication.java index f6b5f6b6a..63ec91e3e 100644 --- a/src/main/java/bio/overture/ego/model/join/UserApplication.java +++ b/src/main/java/bio/overture/ego/model/join/UserApplication.java @@ -6,14 +6,14 @@ import bio.overture.ego.model.enums.JavaFields; import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; -import javax.persistence.CascadeType; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapsId; -import javax.persistence.Table; +import jakarta.persistence.CascadeType; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/join/UserApplicationId.java b/src/main/java/bio/overture/ego/model/join/UserApplicationId.java index 22b942273..cae1172f0 100644 --- a/src/main/java/bio/overture/ego/model/join/UserApplicationId.java +++ b/src/main/java/bio/overture/ego/model/join/UserApplicationId.java @@ -1,10 +1,10 @@ package bio.overture.ego.model.join; import bio.overture.ego.model.enums.SqlFields; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; import java.io.Serializable; import java.util.UUID; -import javax.persistence.Column; -import javax.persistence.Embeddable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/join/UserGroup.java b/src/main/java/bio/overture/ego/model/join/UserGroup.java index 21700719b..40a9f326b 100644 --- a/src/main/java/bio/overture/ego/model/join/UserGroup.java +++ b/src/main/java/bio/overture/ego/model/join/UserGroup.java @@ -6,14 +6,14 @@ import bio.overture.ego.model.enums.JavaFields; import bio.overture.ego.model.enums.SqlFields; import bio.overture.ego.model.enums.Tables; -import javax.persistence.CascadeType; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapsId; -import javax.persistence.Table; +import jakarta.persistence.CascadeType; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/model/join/UserGroupId.java b/src/main/java/bio/overture/ego/model/join/UserGroupId.java index 5d74805e4..9dcb16c4e 100644 --- a/src/main/java/bio/overture/ego/model/join/UserGroupId.java +++ b/src/main/java/bio/overture/ego/model/join/UserGroupId.java @@ -1,10 +1,10 @@ package bio.overture.ego.model.join; import bio.overture.ego.model.enums.SqlFields; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; import java.io.Serializable; import java.util.UUID; -import javax.persistence.Column; -import javax.persistence.Embeddable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/bio/overture/ego/repository/BaseRepository.java b/src/main/java/bio/overture/ego/repository/BaseRepository.java index 060365171..69f58e78a 100644 --- a/src/main/java/bio/overture/ego/repository/BaseRepository.java +++ b/src/main/java/bio/overture/ego/repository/BaseRepository.java @@ -3,12 +3,13 @@ import java.util.Collection; import java.util.Set; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.PagingAndSortingRepository; @NoRepositoryBean public interface BaseRepository - extends PagingAndSortingRepository, JpaSpecificationExecutor { + extends PagingAndSortingRepository, CrudRepository, JpaSpecificationExecutor { T findFirstBy(); Set findAllByIdIn(Collection ids); diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/AbstractPermissionSpecification.java b/src/main/java/bio/overture/ego/repository/queryspecification/AbstractPermissionSpecification.java index a66bfb5d3..882911298 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/AbstractPermissionSpecification.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/AbstractPermissionSpecification.java @@ -10,10 +10,10 @@ import bio.overture.ego.model.search.SearchFilter; import bio.overture.ego.utils.QueryUtils; import com.google.common.collect.Lists; +import jakarta.persistence.criteria.Predicate; import java.util.List; import java.util.UUID; import java.util.stream.Stream; -import javax.persistence.criteria.Predicate; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/ApplicationSpecification.java b/src/main/java/bio/overture/ego/repository/queryspecification/ApplicationSpecification.java index 04e1a7852..cfc9477df 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/ApplicationSpecification.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/ApplicationSpecification.java @@ -33,8 +33,8 @@ import bio.overture.ego.model.join.GroupApplication; import bio.overture.ego.model.join.UserApplication; import bio.overture.ego.utils.QueryUtils; +import jakarta.persistence.criteria.Join; import java.util.UUID; -import javax.persistence.criteria.Join; import lombok.NonNull; import lombok.val; import org.springframework.data.jpa.domain.Specification; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/GroupSpecification.java b/src/main/java/bio/overture/ego/repository/queryspecification/GroupSpecification.java index 80cdfa11d..664b3004b 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/GroupSpecification.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/GroupSpecification.java @@ -31,8 +31,8 @@ import bio.overture.ego.model.join.GroupApplication; import bio.overture.ego.model.join.UserGroup; import bio.overture.ego.utils.QueryUtils; +import jakarta.persistence.criteria.Join; import java.util.UUID; -import javax.persistence.criteria.Join; import lombok.NonNull; import lombok.val; import org.springframework.data.jpa.domain.Specification; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/SimpleCriteriaBuilder.java b/src/main/java/bio/overture/ego/repository/queryspecification/SimpleCriteriaBuilder.java index f4ff1fab5..475ae60cc 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/SimpleCriteriaBuilder.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/SimpleCriteriaBuilder.java @@ -6,10 +6,10 @@ import bio.overture.ego.model.search.SearchFilter; import bio.overture.ego.utils.QueryUtils; +import jakarta.persistence.criteria.*; import java.util.Collection; import java.util.List; import java.util.UUID; -import javax.persistence.criteria.*; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.val; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/SpecificationBase.java b/src/main/java/bio/overture/ego/repository/queryspecification/SpecificationBase.java index f7e1a8004..ae5277bdb 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/SpecificationBase.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/SpecificationBase.java @@ -18,11 +18,11 @@ import bio.overture.ego.model.search.SearchFilter; import bio.overture.ego.utils.QueryUtils; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; import java.util.Arrays; import java.util.List; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; import lombok.NonNull; import lombok.val; import org.springframework.data.jpa.domain.Specification; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/TokenStoreSpecification.java b/src/main/java/bio/overture/ego/repository/queryspecification/TokenStoreSpecification.java index 386e15bad..446ad3126 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/TokenStoreSpecification.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/TokenStoreSpecification.java @@ -21,8 +21,8 @@ import bio.overture.ego.model.entity.ApiKey; import bio.overture.ego.model.entity.User; import bio.overture.ego.utils.QueryUtils; +import jakarta.persistence.criteria.Join; import java.util.UUID; -import javax.persistence.criteria.Join; import lombok.NonNull; import lombok.val; import org.springframework.data.jpa.domain.Specification; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/UserPermissionSpecification.java b/src/main/java/bio/overture/ego/repository/queryspecification/UserPermissionSpecification.java index 5ef7bb928..42fd722b0 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/UserPermissionSpecification.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/UserPermissionSpecification.java @@ -29,9 +29,9 @@ import bio.overture.ego.model.search.SearchFilter; import bio.overture.ego.utils.QueryUtils; import com.google.common.collect.Lists; +import jakarta.persistence.criteria.Predicate; import java.util.List; import java.util.UUID; -import javax.persistence.criteria.Predicate; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/UserSpecification.java b/src/main/java/bio/overture/ego/repository/queryspecification/UserSpecification.java index 2f3826ea5..2bd063152 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/UserSpecification.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/UserSpecification.java @@ -25,9 +25,9 @@ import bio.overture.ego.model.join.UserApplication; import bio.overture.ego.model.join.UserGroup; import bio.overture.ego.utils.QueryUtils; +import jakarta.persistence.criteria.Join; import java.util.Collection; import java.util.UUID; -import javax.persistence.criteria.Join; import lombok.NonNull; import lombok.val; import org.springframework.data.jpa.domain.Specification; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/builder/AbstractSpecificationBuilder.java b/src/main/java/bio/overture/ego/repository/queryspecification/builder/AbstractSpecificationBuilder.java index 4f9f10d3a..6f61161bc 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/builder/AbstractSpecificationBuilder.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/builder/AbstractSpecificationBuilder.java @@ -3,10 +3,10 @@ import static bio.overture.ego.model.enums.JavaFields.NAME; import bio.overture.ego.model.enums.JavaFields; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; import java.util.Collection; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; import lombok.NonNull; import lombok.val; import org.springframework.data.jpa.domain.Specification; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/builder/ApplicationSpecificationBuilder.java b/src/main/java/bio/overture/ego/repository/queryspecification/builder/ApplicationSpecificationBuilder.java index 3052fda41..94646eb27 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/builder/ApplicationSpecificationBuilder.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/builder/ApplicationSpecificationBuilder.java @@ -1,13 +1,13 @@ package bio.overture.ego.repository.queryspecification.builder; import static bio.overture.ego.model.enums.JavaFields.*; -import static javax.persistence.criteria.JoinType.LEFT; +import static jakarta.persistence.criteria.JoinType.LEFT; import bio.overture.ego.model.entity.Application; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; import java.util.UUID; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; import lombok.NonNull; import lombok.Setter; import lombok.experimental.Accessors; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/builder/GroupSpecificationBuilder.java b/src/main/java/bio/overture/ego/repository/queryspecification/builder/GroupSpecificationBuilder.java index 092a33593..c8a7884b9 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/builder/GroupSpecificationBuilder.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/builder/GroupSpecificationBuilder.java @@ -5,11 +5,11 @@ import static bio.overture.ego.model.enums.JavaFields.PERMISSIONS; import static bio.overture.ego.model.enums.JavaFields.USER; import static bio.overture.ego.model.enums.JavaFields.USERGROUPS; -import static javax.persistence.criteria.JoinType.LEFT; +import static jakarta.persistence.criteria.JoinType.LEFT; import bio.overture.ego.model.entity.Group; +import jakarta.persistence.criteria.Root; import java.util.UUID; -import javax.persistence.criteria.Root; import lombok.Setter; import lombok.experimental.Accessors; import lombok.val; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/builder/RefreshTokenSpecificationBuilder.java b/src/main/java/bio/overture/ego/repository/queryspecification/builder/RefreshTokenSpecificationBuilder.java index 4aae74ebf..453e48126 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/builder/RefreshTokenSpecificationBuilder.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/builder/RefreshTokenSpecificationBuilder.java @@ -1,10 +1,10 @@ package bio.overture.ego.repository.queryspecification.builder; -import static javax.persistence.criteria.JoinType.LEFT; +import static jakarta.persistence.criteria.JoinType.LEFT; import bio.overture.ego.model.entity.RefreshToken; +import jakarta.persistence.criteria.Root; import java.util.UUID; -import javax.persistence.criteria.Root; import lombok.Setter; import lombok.experimental.Accessors; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/builder/TokenSpecificationBuilder.java b/src/main/java/bio/overture/ego/repository/queryspecification/builder/TokenSpecificationBuilder.java index 44ed9aaeb..38b5d3ef2 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/builder/TokenSpecificationBuilder.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/builder/TokenSpecificationBuilder.java @@ -2,11 +2,11 @@ import static bio.overture.ego.model.enums.JavaFields.OWNER; import static bio.overture.ego.model.enums.JavaFields.SCOPES; -import static javax.persistence.criteria.JoinType.LEFT; +import static jakarta.persistence.criteria.JoinType.LEFT; import bio.overture.ego.model.entity.ApiKey; +import jakarta.persistence.criteria.Root; import java.util.UUID; -import javax.persistence.criteria.Root; import lombok.Setter; import lombok.experimental.Accessors; diff --git a/src/main/java/bio/overture/ego/repository/queryspecification/builder/UserSpecificationBuilder.java b/src/main/java/bio/overture/ego/repository/queryspecification/builder/UserSpecificationBuilder.java index 9079b7ea6..badee2024 100644 --- a/src/main/java/bio/overture/ego/repository/queryspecification/builder/UserSpecificationBuilder.java +++ b/src/main/java/bio/overture/ego/repository/queryspecification/builder/UserSpecificationBuilder.java @@ -1,14 +1,14 @@ package bio.overture.ego.repository.queryspecification.builder; import static bio.overture.ego.model.enums.JavaFields.*; -import static javax.persistence.criteria.JoinType.LEFT; +import static jakarta.persistence.criteria.JoinType.LEFT; import bio.overture.ego.model.entity.User; import bio.overture.ego.model.enums.ProviderType; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; import java.util.UUID; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; import lombok.NonNull; import lombok.Setter; import lombok.experimental.Accessors; diff --git a/src/main/java/bio/overture/ego/security/CorsFilter.java b/src/main/java/bio/overture/ego/security/CorsFilter.java index b6e054b34..7e5d70cb4 100644 --- a/src/main/java/bio/overture/ego/security/CorsFilter.java +++ b/src/main/java/bio/overture/ego/security/CorsFilter.java @@ -18,10 +18,10 @@ import bio.overture.ego.service.ApplicationService; import bio.overture.ego.utils.Redirects; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.net.URI; -import javax.servlet.*; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/security/JWTAuthorizationFilter.java b/src/main/java/bio/overture/ego/security/JWTAuthorizationFilter.java index 995c1d341..49b57b72d 100644 --- a/src/main/java/bio/overture/ego/security/JWTAuthorizationFilter.java +++ b/src/main/java/bio/overture/ego/security/JWTAuthorizationFilter.java @@ -25,11 +25,11 @@ import bio.overture.ego.token.app.AppTokenClaims; import bio.overture.ego.token.user.UserTokenClaims; import bio.overture.ego.view.Views; +import jakarta.servlet.FilterChain; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Arrays; -import javax.servlet.FilterChain; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/security/OAuth2RequestResolver.java b/src/main/java/bio/overture/ego/security/OAuth2RequestResolver.java index 1f0acc356..340af2a37 100644 --- a/src/main/java/bio/overture/ego/security/OAuth2RequestResolver.java +++ b/src/main/java/bio/overture/ego/security/OAuth2RequestResolver.java @@ -2,8 +2,8 @@ import static java.util.Objects.isNull; +import jakarta.servlet.http.HttpServletRequest; import java.net.URI; -import javax.servlet.http.HttpServletRequest; import lombok.SneakyThrows; import lombok.val; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; diff --git a/src/main/java/bio/overture/ego/service/AbstractPermissionService.java b/src/main/java/bio/overture/ego/service/AbstractPermissionService.java index 75d7683ed..e3a2761d3 100644 --- a/src/main/java/bio/overture/ego/service/AbstractPermissionService.java +++ b/src/main/java/bio/overture/ego/service/AbstractPermissionService.java @@ -13,13 +13,13 @@ import static bio.overture.ego.utils.PermissionRequestAnalyzer.analyze; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Maps.uniqueIndex; +import static jakarta.persistence.criteria.JoinType.LEFT; import static java.util.Arrays.stream; import static java.util.Collections.reverse; import static java.util.Comparator.comparing; import static java.util.Objects.isNull; import static java.util.function.Function.identity; import static java.util.stream.Collectors.*; -import static javax.persistence.criteria.JoinType.LEFT; import bio.overture.ego.model.dto.PermissionRequest; import bio.overture.ego.model.dto.ResolvedPermissionResponse; diff --git a/src/main/java/bio/overture/ego/service/GroupService.java b/src/main/java/bio/overture/ego/service/GroupService.java index d3041c476..7bfada9fd 100644 --- a/src/main/java/bio/overture/ego/service/GroupService.java +++ b/src/main/java/bio/overture/ego/service/GroupService.java @@ -51,11 +51,11 @@ import bio.overture.ego.repository.queryspecification.builder.GroupSpecificationBuilder; import bio.overture.ego.utils.EntityServices; import com.google.common.collect.ImmutableSet; +import jakarta.transaction.Transactional; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.UUID; -import javax.transaction.Transactional; import lombok.NonNull; import lombok.val; import org.mapstruct.Mapper; diff --git a/src/main/java/bio/overture/ego/service/InitializationService.java b/src/main/java/bio/overture/ego/service/InitializationService.java index 65d507a77..7650afdd3 100644 --- a/src/main/java/bio/overture/ego/service/InitializationService.java +++ b/src/main/java/bio/overture/ego/service/InitializationService.java @@ -8,7 +8,7 @@ import bio.overture.ego.model.dto.CreateApplicationRequest; import bio.overture.ego.model.entity.InitTripWire; import bio.overture.ego.repository.InitTripWireRepository; -import javax.transaction.Transactional; +import jakarta.transaction.Transactional; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/service/PolicyService.java b/src/main/java/bio/overture/ego/service/PolicyService.java index 92fb6122e..f0d249947 100644 --- a/src/main/java/bio/overture/ego/service/PolicyService.java +++ b/src/main/java/bio/overture/ego/service/PolicyService.java @@ -7,7 +7,7 @@ import static bio.overture.ego.model.exceptions.RequestValidationException.checkRequestValid; import static bio.overture.ego.model.exceptions.UniqueViolationException.checkUnique; import static bio.overture.ego.utils.FieldUtils.onUpdateDetected; -import static javax.persistence.criteria.JoinType.LEFT; +import static jakarta.persistence.criteria.JoinType.LEFT; import static org.mapstruct.factory.Mappers.getMapper; import bio.overture.ego.event.token.ApiKeyEventsPublisher; diff --git a/src/main/java/bio/overture/ego/service/RefreshContextService.java b/src/main/java/bio/overture/ego/service/RefreshContextService.java index 0a71991a8..419700067 100644 --- a/src/main/java/bio/overture/ego/service/RefreshContextService.java +++ b/src/main/java/bio/overture/ego/service/RefreshContextService.java @@ -11,12 +11,12 @@ import bio.overture.ego.model.exceptions.ForbiddenException; import bio.overture.ego.repository.RefreshTokenRepository; import bio.overture.ego.repository.queryspecification.builder.RefreshTokenSpecificationBuilder; +import jakarta.servlet.http.Cookie; import java.sql.Date; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Optional; import java.util.UUID; -import javax.servlet.http.Cookie; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/service/UserService.java b/src/main/java/bio/overture/ego/service/UserService.java index 04dcb9d0e..894a394a3 100644 --- a/src/main/java/bio/overture/ego/service/UserService.java +++ b/src/main/java/bio/overture/ego/service/UserService.java @@ -51,8 +51,8 @@ import bio.overture.ego.token.IDToken; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import jakarta.transaction.Transactional; import java.util.*; -import javax.transaction.Transactional; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 70cf00c2d..9e65f8db1 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -8,9 +8,9 @@ import bio.overture.ego.model.dto.VisaRequest; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.repository.VisaRepository; +import jakarta.validation.constraints.NotNull; import java.util.Optional; import java.util.UUID; -import javax.validation.constraints.NotNull; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/token/CustomTokenEnhancer.java b/src/main/java/bio/overture/ego/token/CustomTokenEnhancer.java index aa44c8ee8..9aba737d8 100644 --- a/src/main/java/bio/overture/ego/token/CustomTokenEnhancer.java +++ b/src/main/java/bio/overture/ego/token/CustomTokenEnhancer.java @@ -26,8 +26,8 @@ import lombok.val; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.oauth2.core.AuthorizationGrantType; -import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; -import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; +import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; import org.springframework.stereotype.Component; // This class is responsible to modify and customize the jwt claims diff --git a/src/main/java/bio/overture/ego/token/signer/DefaultTokenSigner.java b/src/main/java/bio/overture/ego/token/signer/DefaultTokenSigner.java index 478d5cd7c..b9edb2ad9 100644 --- a/src/main/java/bio/overture/ego/token/signer/DefaultTokenSigner.java +++ b/src/main/java/bio/overture/ego/token/signer/DefaultTokenSigner.java @@ -16,13 +16,13 @@ package bio.overture.ego.token.signer; +import jakarta.annotation.PostConstruct; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.Optional; -import javax.annotation.PostConstruct; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/token/signer/JKSTokenSigner.java b/src/main/java/bio/overture/ego/token/signer/JKSTokenSigner.java index 395ba4b1a..5b53b403f 100644 --- a/src/main/java/bio/overture/ego/token/signer/JKSTokenSigner.java +++ b/src/main/java/bio/overture/ego/token/signer/JKSTokenSigner.java @@ -16,12 +16,12 @@ package bio.overture.ego.token.signer; +import jakarta.annotation.PostConstruct; import java.io.FileInputStream; import java.io.IOException; import java.security.*; import java.util.Base64; import java.util.Optional; -import javax.annotation.PostConstruct; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/utils/HibernateSessions.java b/src/main/java/bio/overture/ego/utils/HibernateSessions.java index fe6d67920..8e0ff6a49 100644 --- a/src/main/java/bio/overture/ego/utils/HibernateSessions.java +++ b/src/main/java/bio/overture/ego/utils/HibernateSessions.java @@ -6,7 +6,7 @@ import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.hibernate.collection.internal.AbstractPersistentCollection; +import org.hibernate.collection.spi.AbstractPersistentCollection; @Slf4j public class HibernateSessions { diff --git a/src/main/java/bio/overture/ego/utils/SwaggerConstants.java b/src/main/java/bio/overture/ego/utils/SwaggerConstants.java index 6ea6e25b3..1aee5d3d3 100644 --- a/src/main/java/bio/overture/ego/utils/SwaggerConstants.java +++ b/src/main/java/bio/overture/ego/utils/SwaggerConstants.java @@ -1,6 +1,19 @@ package bio.overture.ego.utils; +import java.util.Set; + public class SwaggerConstants { public static final String AUTH_CONTROLLER = "auth-controller"; public static final String POST_ACCESS_TOKEN = "postAccessToken"; + + public static final String SECURITY_SCHEME_NAME = "Bearer"; + + public static final Set POST_ACCESS_TOKEN_PARAMS = + Set.of("client_secret", "client_id", "grant_type"); + public static final Set APPLICATION_SCOPED_PATHS = + Set.of( + "/o/check_api_key", + "/o/check_token", + "/transaction/group_permissions", + "/transaction/mass_delete"); } diff --git a/src/main/java/db/migration/V1_1__complete_uuid_migration.java b/src/main/java/db/migration/V1_1__complete_uuid_migration.java index 9a7a8d254..45556a3e7 100644 --- a/src/main/java/db/migration/V1_1__complete_uuid_migration.java +++ b/src/main/java/db/migration/V1_1__complete_uuid_migration.java @@ -8,13 +8,15 @@ import java.util.UUID; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.flywaydb.core.api.migration.spring.SpringJdbcMigration; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.SingleConnectionDataSource; @Slf4j -public class V1_1__complete_uuid_migration implements SpringJdbcMigration { - public void migrate(JdbcTemplate jdbcTemplate) throws Exception { +public class V1_1__complete_uuid_migration extends BaseJavaMigration { + public void migrate(Context context) throws Exception { log.info( "Flyway java migration: V1_1__complete_uuid_migration running ******************************"); @@ -24,6 +26,10 @@ public void migrate(JdbcTemplate jdbcTemplate) throws Exception { UUID userOneId = UUID.randomUUID(); UUID userTwoId = UUID.randomUUID(); + JdbcTemplate jdbcTemplate = + new JdbcTemplate(new SingleConnectionDataSource(context.getConnection(), true)); + ; + // Test data (if set to true) if (runWithTest) { createTestData(jdbcTemplate, userOneId, userTwoId); diff --git a/src/main/java/db/migration/V1_3__string_to_date.java b/src/main/java/db/migration/V1_3__string_to_date.java index 0146de4ca..963a2059b 100644 --- a/src/main/java/db/migration/V1_3__string_to_date.java +++ b/src/main/java/db/migration/V1_3__string_to_date.java @@ -7,21 +7,26 @@ import java.util.UUID; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.flywaydb.core.api.migration.spring.SpringJdbcMigration; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.SingleConnectionDataSource; @Slf4j -public class V1_3__string_to_date implements SpringJdbcMigration { +public class V1_3__string_to_date extends BaseJavaMigration { @Override - public void migrate(JdbcTemplate jdbcTemplate) throws Exception { + public void migrate(Context context) throws Exception { log.info("Flyway java migration: V1_3__string_to_date running ******************************"); boolean runWithTest = false; UUID userOneId = UUID.randomUUID(); UUID userTwoId = UUID.randomUUID(); + JdbcTemplate jdbcTemplate = + new JdbcTemplate(new SingleConnectionDataSource(context.getConnection(), true)); + if (runWithTest) { createTestData(jdbcTemplate, userOneId, userTwoId); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d2d185265..3eec0363b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -27,6 +27,15 @@ refreshToken: cookieIsSecure: false domain: localhost +# Swagger +springdoc: + packagesToScan: bio.overture.ego.controller + swagger-ui: + display-operation-id: true + doc-expansion: none # initial collapse groups + operations-sorter: alpha + tags-sorter: alpha + # security auth: token: @@ -50,6 +59,7 @@ spring: client: registration: google: + provider: google clientName: ego clientId: ego-client clientSecret: diff --git a/src/test/java/bio/overture/ego/controller/AbstractControllerTest.java b/src/test/java/bio/overture/ego/controller/AbstractControllerTest.java index 79bff5286..1de374b34 100644 --- a/src/test/java/bio/overture/ego/controller/AbstractControllerTest.java +++ b/src/test/java/bio/overture/ego/controller/AbstractControllerTest.java @@ -29,7 +29,7 @@ import lombok.val; import org.junit.Before; import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpHeaders; @Slf4j diff --git a/src/test/java/bio/overture/ego/controller/AppJWTTest.java b/src/test/java/bio/overture/ego/controller/AppJWTTest.java index d7c285677..f428bd4ed 100644 --- a/src/test/java/bio/overture/ego/controller/AppJWTTest.java +++ b/src/test/java/bio/overture/ego/controller/AppJWTTest.java @@ -407,5 +407,4 @@ public void applicationJwtIsValidAndUsable() { val users = MAPPER.readTree(resolvedUsers); assertNotNull(users); } - } diff --git a/src/test/java/bio/overture/ego/service/initialization/InitializationServiceTest.java b/src/test/java/bio/overture/ego/service/initialization/InitializationServiceTest.java index 433c829f3..9fdeb6ac5 100644 --- a/src/test/java/bio/overture/ego/service/initialization/InitializationServiceTest.java +++ b/src/test/java/bio/overture/ego/service/initialization/InitializationServiceTest.java @@ -16,7 +16,7 @@ import bio.overture.ego.service.ApplicationService; import bio.overture.ego.service.InitializationService; import bio.overture.ego.utils.EntityGenerator; -import javax.transaction.Transactional; +import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.junit.Rule; diff --git a/src/test/java/bio/overture/ego/utils/web/AbstractWebResource.java b/src/test/java/bio/overture/ego/utils/web/AbstractWebResource.java index aaee7a2d1..e9d776630 100644 --- a/src/test/java/bio/overture/ego/utils/web/AbstractWebResource.java +++ b/src/test/java/bio/overture/ego/utils/web/AbstractWebResource.java @@ -169,8 +169,8 @@ private static void logResponse(boolean enable, boolean pretty, ResponseEnti val output = CleanResponse.builder() .body(response.hasBody() ? response.getBody() : null) - .statusCodeName(response.getStatusCode().name()) - .statusCodeValue(response.getStatusCodeValue()) + .statusCodeName(response.getStatusCode().toString()) + .statusCodeValue(response.getStatusCode().value()) .build(); if (pretty) { log.info("[RESPONSE] > \n{}", PRETTY_MAPPER.writeValueAsString(output)); From 9a6367c6f03dec4b9b0e3f45e8944f527cd76a88 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 28 Apr 2023 12:22:39 -0400 Subject: [PATCH 13/43] committing changes related to remove api fixes --- src/main/java/bio/overture/ego/controller/VisaController.java | 2 +- .../java/bio/overture/ego/service/VisaPermissionService.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index d320d0484..aa9e64479 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -183,7 +183,7 @@ public void deleteVisa( * @param visaPermissionRequest VisaPermissionRequest */ @AdminScoped - @RequestMapping(method = DELETE, value = "/permissions") + @RequestMapping(method = DELETE, value = "/permissions/{policyId}/{visaId}") @ApiResponses(value = {@ApiResponse(code = 200, message = "Remove VisaPermission")}) @JsonView(Views.REST.class) public @ResponseBody void removePermissions( diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 20ae80963..21b98ce36 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -90,6 +90,9 @@ public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { visaPermissionRepository.findByPolicyIdAndVisaId(policyId, visaId); if (!visaPermissionEntities.isEmpty()) { visaPermissionRepository.deleteById(visaPermissionEntities.get(0).getId()); + } else { + throw new NotFoundException( + format("No VisaPermissions exists with policyId '%s' and visaId '%s'", policyId, visaId)); } } From c39e6fbcdcf0e0fd3a5d1cb4c946816af594982f Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Tue, 2 May 2023 15:16:55 -0400 Subject: [PATCH 14/43] Committing changes related to spring migration --- .../ego/controller/VisaController.java | 26 ++++++++++++------- .../ego/model/entity/VisaPermission.java | 4 --- .../ego/service/VisaPermissionService.java | 2 +- .../bio/overture/ego/service/VisaService.java | 1 - 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index 7c3066fd6..03997a974 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -8,10 +8,13 @@ import bio.overture.ego.service.*; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import io.swagger.annotations.*; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.NotNull; import java.util.List; import java.util.UUID; -import javax.validation.constraints.NotNull; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -135,10 +138,11 @@ public void deleteVisa( */ @AdminScoped @RequestMapping(method = GET, value = "/permissions/visaId/{id}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Get VisaPermissions by visaId")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Get VisaPermissions by visaId")}) @JsonView(Views.REST.class) public @ResponseBody List getPermissionsByVisaId( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { return visaPermissionService.getPermissionsByVisaId(id); @@ -151,10 +155,11 @@ public void deleteVisa( */ @AdminScoped @RequestMapping(method = GET, value = "/permissions/policyId/{id}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Get VisaPermissions by policyId")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Get VisaPermissions by policyId")}) @JsonView(Views.REST.class) public @ResponseBody List getPermissionsByPolicyId( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "id", required = true) UUID id) { return visaPermissionService.getPermissionsByPolicyId(id); @@ -167,10 +172,11 @@ public void deleteVisa( */ @AdminScoped @RequestMapping(method = POST, value = "/permissions") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Create or Update VisaPermission")}) + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Create or Update VisaPermission")}) @JsonView(Views.REST.class) public @ResponseBody VisaPermission createOrUpdatePermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @RequestBody(required = true) VisaPermissionRequest visaPermissionRequest) { return visaPermissionService.createOrUpdatePermissions(visaPermissionRequest); @@ -182,10 +188,10 @@ public void deleteVisa( */ @AdminScoped @RequestMapping(method = DELETE, value = "/permissions/{policyId}/{visaId}") - @ApiResponses(value = {@ApiResponse(code = 200, message = "Remove VisaPermission")}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Remove VisaPermission")}) @JsonView(Views.REST.class) public @ResponseBody void removePermissions( - @ApiIgnore @RequestHeader(value = "Authorization", required = true) + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "policyId", required = true) UUID policyId, @PathVariable(value = "visaId", required = true) UUID visaId) { diff --git a/src/main/java/bio/overture/ego/model/entity/VisaPermission.java b/src/main/java/bio/overture/ego/model/entity/VisaPermission.java index 9c0a5b419..ebac950a0 100644 --- a/src/main/java/bio/overture/ego/model/entity/VisaPermission.java +++ b/src/main/java/bio/overture/ego/model/entity/VisaPermission.java @@ -5,11 +5,7 @@ import bio.overture.ego.model.enums.Tables; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; -import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; import jakarta.persistence.*; -import jakarta.validation.constraints.NotNull; -import java.util.Collection; -import java.util.UUID; import lombok.*; import lombok.experimental.FieldNameConstants; diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 21b98ce36..6057ce5bc 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -8,9 +8,9 @@ import bio.overture.ego.model.entity.VisaPermission; import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.repository.VisaPermissionRepository; +import jakarta.validation.constraints.NotNull; import java.util.List; import java.util.UUID; -import javax.validation.constraints.NotNull; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index cac9c9b40..9e65f8db1 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -11,7 +11,6 @@ import jakarta.validation.constraints.NotNull; import java.util.Optional; import java.util.UUID; -import javax.validation.constraints.NotNull; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; From d0cb76eb72da6584cd8a6c936bfe0de61321f18f Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Wed, 3 May 2023 00:34:47 -0400 Subject: [PATCH 15/43] Committing changes related to clientId fix --- src/main/resources/application.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3eec0363b..b90530d8d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -59,10 +59,10 @@ spring: client: registration: google: + client-id: ego-client + client-secret: provider: google clientName: ego - clientId: ego-client - clientSecret: authorizationGrantType: authorization_code clientAuthenticationMethod: client_secret_post redirectUri: "http://localhost:8081/oauth/code/google" From ea59624af51afbe5f57e4be48cc1927f4c8a0647 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Wed, 3 May 2023 12:54:00 -0400 Subject: [PATCH 16/43] Committing changes related to clientId fix --- src/main/resources/application.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b90530d8d..bcf27223b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -59,10 +59,10 @@ spring: client: registration: google: - client-id: ego-client - client-secret: provider: google clientName: ego + client_id: ego-client + clientSecret: authorizationGrantType: authorization_code clientAuthenticationMethod: client_secret_post redirectUri: "http://localhost:8081/oauth/code/google" @@ -73,7 +73,7 @@ spring: github: clientName: ego - clientId: ego-client + client_id: ego-client clientSecret: redirectUri: "http://localhost:8081/oauth/code/github" clientAuthenticationMethod: client_secret_post From a78a900b571615c9facba726208880505782db34 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 5 May 2023 14:52:49 -0400 Subject: [PATCH 17/43] Commiting changes --- pom.xml | 14 +++++++++----- src/main/resources/application.yml | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 20fcf2d30..934054ab3 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,6 @@ 3.0.5 - UTF-8 UTF-8 @@ -241,6 +240,11 @@ spring-cloud-starter-vault-config 2.1.2.RELEASE + + org.springframework.cloud + spring-cloud-vault-config-databases + 4.0.1 + com.amazonaws aws-java-sdk-core @@ -396,14 +400,14 @@ protobuf-maven-plugin 0.6.1 - com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} + - + com.google.protobuf:protoc:3.21.7:exe:osx-x86_64 ${basedir}/src/main/proto grpc-java - io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier} + - + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:osx-x86_64 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bcf27223b..3eec0363b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -61,7 +61,7 @@ spring: google: provider: google clientName: ego - client_id: ego-client + clientId: ego-client clientSecret: authorizationGrantType: authorization_code clientAuthenticationMethod: client_secret_post @@ -73,7 +73,7 @@ spring: github: clientName: ego - client_id: ego-client + clientId: ego-client clientSecret: redirectUri: "http://localhost:8081/oauth/code/github" clientAuthenticationMethod: client_secret_post From 924397534b9e83ce48069064b8423048bc2beb2a Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 5 May 2023 15:00:34 -0400 Subject: [PATCH 18/43] Reverting the changes to feature/develop-passport --- pom.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 934054ab3..b97fcaab5 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ 3.0.5 + UTF-8 UTF-8 @@ -400,14 +401,14 @@ protobuf-maven-plugin 0.6.1 - + com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} - com.google.protobuf:protoc:3.21.7:exe:osx-x86_64 + ${basedir}/src/main/proto grpc-java - + io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier} - io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:osx-x86_64 + From 3e6c876be9143b3aebe74bcd8b55731f20e87986 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 5 May 2023 15:13:35 -0400 Subject: [PATCH 19/43] changes to Key-Value Backend --- src/main/resources/application.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3eec0363b..ee273dfd0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -131,7 +131,9 @@ spring: jwkSetUri: https://orcid.org/oauth/jwks cloud: vault: - enabled: false + kv: + backend: kv + enabled: true flyway: enabled: true locations: "classpath:flyway/sql,classpath:db/migration" From 35044abeb575854880fd7e90b2bd3479fdb6be71 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Tue, 16 May 2023 02:42:42 -0400 Subject: [PATCH 20/43] Creating Passport Service --- .../ego/controller/AuthController.java | 15 ++- .../bio/overture/ego/model/dto/Passport.java | 35 +++++ .../bio/overture/ego/model/entity/User.java | 2 +- .../overture/ego/service/PassportService.java | 121 ++++++++++++++++++ src/main/resources/application.yml | 6 + src/main/resources/mockData/passport.json | 7 + 6 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 src/main/java/bio/overture/ego/model/dto/Passport.java create mode 100644 src/main/java/bio/overture/ego/service/PassportService.java create mode 100644 src/main/resources/mockData/passport.json diff --git a/src/main/java/bio/overture/ego/controller/AuthController.java b/src/main/java/bio/overture/ego/controller/AuthController.java index b6b696a4a..2dfb2c6ae 100644 --- a/src/main/java/bio/overture/ego/controller/AuthController.java +++ b/src/main/java/bio/overture/ego/controller/AuthController.java @@ -27,6 +27,7 @@ import bio.overture.ego.model.exceptions.InvalidTokenException; import bio.overture.ego.provider.google.GoogleTokenService; import bio.overture.ego.security.CustomOAuth2User; +import bio.overture.ego.service.PassportService; import bio.overture.ego.service.RefreshContextService; import bio.overture.ego.service.TokenService; import bio.overture.ego.token.IDToken; @@ -36,6 +37,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import java.util.Objects; + +import jakarta.validation.constraints.NotNull; import lombok.NonNull; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -62,17 +65,20 @@ public class AuthController { private final GoogleTokenService googleTokenService; private final TokenSigner tokenSigner; private final RefreshContextService refreshContextService; + private final PassportService passportService; @Autowired public AuthController( - @NonNull TokenService tokenService, - @NonNull GoogleTokenService googleTokenService, - @NonNull TokenSigner tokenSigner, - @NonNull RefreshContextService refreshContextService) { + @NonNull TokenService tokenService, + @NonNull GoogleTokenService googleTokenService, + @NonNull TokenSigner tokenSigner, + @NonNull RefreshContextService refreshContextService, + @NotNull PassportService passportService) { this.tokenService = tokenService; this.googleTokenService = googleTokenService; this.tokenSigner = tokenSigner; this.refreshContextService = refreshContextService; + this.passportService = passportService; } @RequestMapping(method = GET, value = "/google/token") @@ -83,6 +89,7 @@ public AuthController( if (!googleTokenService.validToken(idToken)) throw new InvalidTokenException("Invalid user token:" + idToken); val authInfo = googleTokenService.decode(idToken); + passportService.validatePassportPermissions(idToken); return tokenService.generateUserToken(authInfo); } diff --git a/src/main/java/bio/overture/ego/model/dto/Passport.java b/src/main/java/bio/overture/ego/model/dto/Passport.java new file mode 100644 index 000000000..c228ac826 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/Passport.java @@ -0,0 +1,35 @@ +package bio.overture.ego.model.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Passport { + + @JsonProperty("sub") + @NotNull private String sub; + + @JsonProperty("iss") + @NotNull private String iss; + + @JsonProperty("exp") + @NotNull private int exp; + + @JsonProperty("iat") + @NotNull private int iat; + + @JsonProperty("ga4gh_passport_v1") + @NotNull private List ga4ghPassportV1; + + @JsonProperty("jti") + @NotNull private String jti; +} diff --git a/src/main/java/bio/overture/ego/model/entity/User.java b/src/main/java/bio/overture/ego/model/entity/User.java index 88f5d7fe8..157d4f113 100644 --- a/src/main/java/bio/overture/ego/model/entity/User.java +++ b/src/main/java/bio/overture/ego/model/entity/User.java @@ -85,7 +85,7 @@ public class User implements PolicyOwner, Identifiable { // TODO: find JPA equivalent for GenericGenerator - @Id + @Idx @Column(name = SqlFields.ID, updatable = false, nullable = false) @GenericGenerator(name = "user_uuid", strategy = "org.hibernate.id.UUIDGenerator") @GeneratedValue(generator = "user_uuid") diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java new file mode 100644 index 000000000..a8f442770 --- /dev/null +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -0,0 +1,121 @@ +package bio.overture.ego.service; + +import bio.overture.ego.model.dto.Passport; +import bio.overture.ego.model.entity.Visa; +import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.model.exceptions.ForbiddenException; +import bio.overture.ego.model.exceptions.InternalServerException; +import bio.overture.ego.token.signer.TokenSigner; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jwt.JWT; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import jakarta.validation.constraints.NotNull; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static java.lang.String.format; + +@Slf4j +@Service +@Transactional +public class PassportService { + + @Value("${broker.passport.url}") + private String passportBrokerUrl; + + @Value("${broker.token.config.public-key}") + private String publicKey; + + /** Dependencies */ + @Autowired private VisaService visaService; + + @Autowired private VisaPermissionService visaPermissionService; + + private RestTemplate restTemplate; + private final TokenSigner tokenSigner; + + @Autowired + public PassportService( + @NonNull VisaPermissionService visaPermissionService, + @NonNull VisaService visaService, + @NotNull TokenSigner tokenSigner) { + this.visaService = visaService; + this.visaPermissionService = visaPermissionService; + this.tokenSigner = tokenSigner; + } + + public String validatePassportPermissions (String authToken) throws JsonProcessingException { + + val passportToken = fetchPassport(authToken); + if (!isValidPassport(passportToken)) { + + } + Object parsedPassport = parse (authToken); + ObjectMapper mapper = new ObjectMapper(); + Passport passport = mapper.readValue((String) parsedPassport, Passport.class); + //getPermissionsForPassport(visaId); + //prepareUserPermissions(visaPermissions); + return null; + } + + private Object fetchPassport (String authToken) { + val response = + restTemplate.exchange( + passportBrokerUrl, HttpMethod.POST, new HttpEntity<>(authToken, null), String.class); + return response.getBody(); + } + + private boolean isValidPassport(@NonNull Object passport) { + + return true; + } + + private boolean isValidVisa(@NonNull Object visa) { + + return true; + } + + private List getVisaPermissions (List visaIds) { + List visaPermissions = new ArrayList<>(); + visaIds.stream().distinct().forEach(visaId -> { + if (visaService.getById(visaId) != null) { + visaPermissions.addAll(visaPermissionService.getPermissionsByVisaId(visaId)); + } + }); + return visaPermissions; + } + + + private Optional parse (@NonNull String token) { + Object parsedObj; + val tokenKey = + tokenSigner + .getKey() + .orElseThrow(() -> new InternalServerException("Internal issue with token signer.")); + + try { + parsedObj = Jwts.parser().setSigningKey(tokenKey).parse(token); + } catch (JwtException e) { + log.error("JWT token is invalid", e); + throw new ForbiddenException("Authorization is required for this action."); + } + return parsedObj == null ? Optional.empty() : Optional.of(parsedObj); + } + + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ee273dfd0..3dbe2621a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -202,6 +202,12 @@ initialization: redirectUri: https://example.org # optional description: Some description about this application # optional +broker: + passport: + url: + token: + config: + public-key: --- ############################################################################### # Profile - "jks" diff --git a/src/main/resources/mockData/passport.json b/src/main/resources/mockData/passport.json new file mode 100644 index 000000000..be145ba0b --- /dev/null +++ b/src/main/resources/mockData/passport.json @@ -0,0 +1,7 @@ +{ + "access_token": "eyJqa3UiOiJodHRwczpcL1wvbG9naW4uZWxpeGlyLWN6ZWNoLm9yZ1wvcGVydW4tZ2E0Z2gtYnJva2VyXC9qd2siLCJraWQiOiJyc2ExIiwidHlwIjoidm5kLmdhNGdoLnBhc3Nwb3J0K2p3dCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIwNjdhNDQ4NzJkOWI1NWExMTRmYTZlY2I1OTc2NzM1YzM5NjY5Mjc2QGVsaXhpci1ldXJvcGUub3JnIiwiaXNzIjoiaHR0cHM6XC9cL2xvZ2luLmVsaXhpci1jemVjaC5vcmdcL29pZGMiLCJleHAiOjE3MTUyNzYwMjQsImlhdCI6MTY4Mzg3MjAwOSwiZ2E0Z2hfcGFzc3BvcnRfdjEiOlsiZXlKcWEzVWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZjR1Z5ZFc0dFoyRTBaMmd0WW5KdmEyVnlYQzlxZDJzaUxDSnJhV1FpT2lKeWMyRXhJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUp6ZFdJaU9pSXdOamRoTkRRNE56SmtPV0kxTldFeE1UUm1ZVFpsWTJJMU9UYzJOek0xWXpNNU5qWTVNamMyUUdWc2FYaHBjaTFsZFhKdmNHVXViM0puSWl3aVoyRTBaMmhmZG1sellWOTJNU0k2ZXlKaGMzTmxjblJsWkNJNk1UWTRNemczTWpBd09Td2lZbmtpT2lKemVYTjBaVzBpTENKemIzVnlZMlVpT201MWJHd3NJblI1Y0dVaU9pSkJabVpwYkdsaGRHbHZia0Z1WkZKdmJHVWlMQ0oyWVd4MVpTSTZJbUZtWm1sc2FXRjBaVUJsYkdsNGFYSXRaWFZ5YjNCbExtOXlaeUo5TENKcGMzTWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZiMmxrWXlJc0ltVjRjQ0k2TVRjeE5UUTVORFF3T1N3aWFXRjBJam94Tmpnek9EY3lNREE1TENKcWRHa2lPaUl6Wm1Jd01XSTFaaTFpTW1aa0xUUmlNR1l0T1RBNU15MWlNakV3T1dFeFpqRmxaR1lpZlEub19jSEdRcjFmdXlDNUFOT0dlTXNxckxXNFpHakpzRmVvQk50YVZXSjNHeDlkRG9Sbmk5d1RiSjR5Sm01QWdkNGtjRXhaWFV3WVZaLVc1aWhMUG9CLVZJUExlQURLOTJkeTRCNTJudV9zYUM2TGZqczUzcEJIQllQLTFoYU1YQS1EWWNDT1Q3MEdvU1Y4eXpPdFNqTDFyRGZFUkdEdFNoOXdPNVZuc2dLWFMydWppLVYxMmVDdGNCMS1tb2dkUGtXQ3EybHVzazdWRHNYc0JJbWMtZHVHOVZWN3MwVXdtQ2FFRFpXZ0xWdUU2OTF0bEpmUjZmXzJjT0s3bVBsQXhvMDhiOUdINldtZVFqNWFFWTdpYzdib1Y4SnJubFZPdmRsck44UnJ6cjNCVFRFbkFabWlSUGhNRTBEOVYtM2JvMXpTakxNbnBxTU80WDlkZHBHNGxyczd3IiwiZXlKcWEzVWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZjR1Z5ZFc0dFoyRTBaMmd0WW5KdmEyVnlYQzlxZDJzaUxDSnJhV1FpT2lKeWMyRXhJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUp6ZFdJaU9pSXdOamRoTkRRNE56SmtPV0kxTldFeE1UUm1ZVFpsWTJJMU9UYzJOek0xWXpNNU5qWTVNamMyUUd4cFptVnpZMmxsYm1ObExYSnBMbVYxSWl3aVoyRTBaMmhmZG1sellWOTJNU0k2ZXlKaGMzTmxjblJsWkNJNk1UWTRNelkxTXpZeU5Dd2lZbmtpT2lKemVYTjBaVzBpTENKemIzVnlZMlVpT2lKb2RIUndjenBjTDF3dmNHVnlkVzR1WVdGcExteHBabVZ6WTJsbGJtTmxMWEpwTG1WMVhDOGlMQ0owZVhCbElqb2lUR2x1YTJWa1NXUmxiblJwZEdsbGN5SXNJblpoYkhWbElqb2lNRFkzWVRRME9EY3laRGxpTlRWaE1URTBabUUyWldOaU5UazNOamN6TldNek9UWTJPVEkzTmlVME1HVnNhWGhwY2kxbGRYSnZjR1V1YjNKbkxHaDBkSEJ6SlROQkpUSkdKVEpHYkc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVp5VXlSbWxrY0NVeVJpSjlMQ0pwYzNNaU9pSm9kSFJ3Y3pwY0wxd3ZiRzluYVc0dVpXeHBlR2x5TFdONlpXTm9MbTl5WjF3dmIybGtZeUlzSW1WNGNDSTZORGd6T1RNeU56SXlOQ3dpYVdGMElqb3hOamd6T0RjeU1EQTVMQ0pxZEdraU9pSTFNRFZqT0RCaE5pMDJOMlUyTFRReFlqVXRZVFUyTnkxaU5UQTJOMlkzWkdVMk1EVWlmUS5PVTVkSERGWEhWY1RFNm5xSHJzMUJXV1NLQndaNjNxNlZfel9zNmVPenp2N3hTVUFNQ0FFVlFtb0FIeFhnbUZXaWZoQnhxMlZxaE5RUGhDUTFNUG5ydnk3UVNHM1cxSE15amRIUWxaYkNrdVdweUlLUXFCa1hQQVFRTnJ0N0tiODZkbVZJb0lHOV9lN2JQSnUtR29EMUdITm1pc29hTzBWUzg0YW85UGRMaDNYeXcwQ2ZiX2F3dGhmSHlwZjZWcmFRUFFlNFpUWnEzbTF5MDdlZkt2TUpWWFh2UXFpYm5kSTF6cEtjQVZRQllLQXFRbmtzbEdkSGtrOG9wOFROZEVOcGw3OWtkNnNWeWJUSnNuT1B3VUtaY0haXzA2MnRRblNJeWllbjg5WWxDdVBQMTZMMnJKb1NGR0ROOWZ2b21yZU0xNnBDVkxkTVJsSVJDS1p3bHBPRkEiLCJleUpxYTNVaU9pSm9kSFJ3Y3pwY0wxd3ZiRzluYVc0dVpXeHBlR2x5TFdONlpXTm9MbTl5WjF3dmNHVnlkVzR0WjJFMFoyZ3RZbkp2YTJWeVhDOXFkMnNpTENKcmFXUWlPaUp5YzJFeElpd2lkSGx3SWpvaVNsZFVJaXdpWVd4bklqb2lVbE15TlRZaWZRLmV5SnpkV0lpT2lJd05qZGhORFE0TnpKa09XSTFOV0V4TVRSbVlUWmxZMkkxT1RjMk56TTFZek01TmpZNU1qYzJRR3hwWm1WelkybGxibU5sTFhKcExtVjFJaXdpWjJFMFoyaGZkbWx6WVY5Mk1TSTZleUpoYzNObGNuUmxaQ0k2TVRZNE16WTFNell5TkN3aVlua2lPaUp6ZVhOMFpXMGlMQ0p6YjNWeVkyVWlPaUpvZEhSd2N6cGNMMXd2Y0dWeWRXNHVZV0ZwTG14cFptVnpZMmxsYm1ObExYSnBMbVYxWEM4aUxDSjBlWEJsSWpvaVRHbHVhMlZrU1dSbGJuUnBkR2xsY3lJc0luWmhiSFZsSWpvaU1EWTNZVFEwT0RjeVpEbGlOVFZoTVRFMFptRTJaV05pTlRrM05qY3pOV016T1RZMk9USTNOaVUwTUd4cFptVnpZMmxsYm1ObExYSnBMbVYxTEdoMGRIQnpKVE5CSlRKR0pUSkdjSEp2ZUhrdVlXRnBMbXhwWm1WelkybGxibU5sTFhKcExtVjFKVEpHY0hKdmVIa2lmU3dpYVhOeklqb2lhSFIwY0hNNlhDOWNMMnh2WjJsdUxtVnNhWGhwY2kxamVtVmphQzV2Y21kY0wyOXBaR01pTENKbGVIQWlPalE0TXprek1qY3lNalFzSW1saGRDSTZNVFk0TXpnM01qQXdPU3dpYW5ScElqb2lNamMwTURaa01EQXRNRE5oTVMwME5EUmtMVGszWW1RdE1HSmlNMlF3TlRReE9UYzJJbjAuQ0xSV1J4bDIwNThVc1Y2Zi14U2psNFdMaFJkLWZrRnZEdTlIOEUteWJINmZZdXcwNWl1QkJNbm1mMUNZYU90RlBRZVpxbVh2YWZqV1VIaFE2ZmxXemhhVHdGYmpIUUh4a0lzY0Z3dHdEb2pLelpWcGJXRGlGdGtiNHBWQTJRdXhKSVAya2NlSEF1WElkNXJITWpzOGQxOXBXMTIyVFFIMlJYeHJibDNjWjZpZkJhMndtV0RtSzNvNkhLeGx6cXVlUXpEcWg5VEZaUWZSQlVHdmRmNUFkYnZuNS11bThTdzhjazRfZ3hFckk4STc5OGc1al9HMHBSRVIyWFp4NE5PVWVUbWkxbHNXTkxqTFlYQjJaZzRaa1dyQVA3dFdwVXRrSUx6Nk1Nb0hyRDFxUEs1OWw2dldTLVpxX0NtLVRSck1ZMGdkZUhCX05FQWlMdEotdGlXYm5RIiwiZXlKcWEzVWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZjR1Z5ZFc0dFoyRTBaMmd0WW5KdmEyVnlYQzlxZDJzaUxDSnJhV1FpT2lKeWMyRXhJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUp6ZFdJaU9pSXdOamRoTkRRNE56SmtPV0kxTldFeE1UUm1ZVFpsWTJJMU9UYzJOek0xWXpNNU5qWTVNamMyUUd4cFptVnpZMmxsYm1ObExYSnBMbVYxSWl3aVoyRTBaMmhmZG1sellWOTJNU0k2ZXlKaGMzTmxjblJsWkNJNk1UWTRNelkxTXpZeU5Dd2lZbmtpT2lKemVYTjBaVzBpTENKemIzVnlZMlVpT2lKb2RIUndjenBjTDF3dmNHVnlkVzR1WVdGcExteHBabVZ6WTJsbGJtTmxMWEpwTG1WMVhDOGlMQ0owZVhCbElqb2lUR2x1YTJWa1NXUmxiblJwZEdsbGN5SXNJblpoYkhWbElqb2lNVEEwTmpVMU1qZzROelkyT1RJNE5UWTVNREEwSlRRd1lXTmpiM1Z1ZEhNdVoyOXZaMnhsTG1OdmJTeG9kSFJ3Y3lVelFTVXlSaVV5Um1sa2FIVmlMbUZoYVM1c2FXWmxjMk5wWlc1alpTMXlhUzVsZFNVeVJuQnliM2g1SlRKR1lVaFNNR05JVFRaTWVUbG9XVEpPZG1SWE5UQmplVFZ1WWpJNWJtSkhWWFZaTWpsMEluMHNJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOXNiMmRwYmk1bGJHbDRhWEl0WTNwbFkyZ3ViM0puWEM5dmFXUmpJaXdpWlhod0lqb3hOekUxTWpjMk1ESTBMQ0pwWVhRaU9qRTJPRE00TnpJd01Ea3NJbXAwYVNJNklqQXlPVEJsTURVekxUYzFaak10TkdObU1DMDRPVEF3TFRSaE5ERTRZbVEyWlRCbVpDSjkuTmV0NV9XdE4zMUdWZlhwR2xGblVWS29fS0s2MU9iM2xkTWlHVTVHUGdlbU9SNlBDNjlUbXozTTJMMzl0MVRkOXkxb1BuVHRaVWpxU1lTbUhIWXpJc2dPUTJDRFZxc0ZPNFlxbjNnX2pVTlI2Y2UyalhvSjFkelBWdTY1V3lsTmloV2EtaEFBUEVtbFVIbEFIbnpSbnpmejc5MlU0aHBQM1JRWWtEaml1VG5oV2JabUZDcGs2UmZNa3lrSVNlQ1l2MWpxXzVaeS15NWlvR0N3U2U0MWNwbTBIS2cxdEc5Z3BWMW9oNHBBNWxNNzVHY1RKT29MVUkwZEE2dTBtU1JxTVRUVGNYbG5XSzBKRS01Yk80ZE9WM0JlSHlnTkprVi1WN3VBN1RfQWFDVDNEZFFOZkdhT3NPT2daQlVMZW1rcWNrZjBGMVN3YzN0THlOSmhfMWxBU1VRIiwiZXlKcWEzVWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZjR1Z5ZFc0dFoyRTBaMmd0WW5KdmEyVnlYQzlxZDJzaUxDSnJhV1FpT2lKeWMyRXhJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUp6ZFdJaU9pSXdOamRoTkRRNE56SmtPV0kxTldFeE1UUm1ZVFpsWTJJMU9UYzJOek0xWXpNNU5qWTVNamMyUUd4cFptVnpZMmxsYm1ObExYSnBMbVYxSWl3aVoyRTBaMmhmZG1sellWOTJNU0k2ZXlKaGMzTmxjblJsWkNJNk1UWTRNelkxTXpZeU5Dd2lZbmtpT2lKemVYTjBaVzBpTENKemIzVnlZMlVpT2lKb2RIUndjenBjTDF3dmNHVnlkVzR1WVdGcExteHBabVZ6WTJsbGJtTmxMWEpwTG1WMVhDOGlMQ0owZVhCbElqb2lUR2x1YTJWa1NXUmxiblJwZEdsbGN5SXNJblpoYkhWbElqb2lNRFkzWVRRME9EY3laRGxpTlRWaE1URTBabUUyWldOaU5UazNOamN6TldNek9UWTJPVEkzTmlVME1HSmliWEpwTG1WMUxHaDBkSEJ6SlROQkpUSkdKVEpHYkc5bmFXNHVZbUp0Y21rdFpYSnBZeTVsZFNVeVJtbGtjQ1V5UmlKOUxDSnBjM01pT2lKb2RIUndjenBjTDF3dmJHOW5hVzR1Wld4cGVHbHlMV042WldOb0xtOXlaMXd2YjJsa1l5SXNJbVY0Y0NJNk1UY3hOVEkzTmpBeU5Dd2lhV0YwSWpveE5qZ3pPRGN5TURBNUxDSnFkR2tpT2lKbU1qSmpaalZqWkMxa1l6UXlMVFEwTVRrdE9HVXlaUzB4T1RGa04yRXhNV014WlRBaWZRLlhhT3hSR3MxM1R6cnFGTGo5eGh1SGV6WUhHVXNQLUxvV1prUEZKSTAyWXVQdDhkOE5VVW14dk04ZlBpdjhoa2FyYkNyeFBobnRRT3BpbXJwaVdZVFFqRFQ0OFFEM0VWcHVaY1lnV1RUd24weThqcWhHZzkzT1dwM0Q4cVFaVElzYW5aQ1Z1WXVmSU9iSEo3akxIRk5EaE5DaWhyMmRVUi1Na3plUm05UmpkbGhmcXh0VFBYQlB0UTZpYkVOcGxiYjRyeEVaYll0djdlOTc3S3NMYzZvaE1KaXN4TVotQWI1Y0JoM21QdC1hSy00NUxGY00wdEY0dVBkSTc5LXFtbFh1VjIxQ1RSZHVyamZ0NVBNMTFra0RXaEM2NzJteE5tNk5DNmw1QXA2QXBINnN1TWtFLXZybzU4MU9iaGRMZTViaVpYX2s2dzBwYklZakV6NGJ6Y1prZyJdLCJqdGkiOiI0Y2Q4NjgxMi03OGE3LTRkNGItOTBkMy03Y2U4NmFkNjk5ZWUifQ.i5ang5Thhae_H84ybCrbyNxQ62YF4IvX301AFECUkyn7Ry3E05KFRm7UC1hmX-p2udZe7RO1oRjW-fa9UomTXARh0DB5OwMKrHeJastoKLDwND05lZJpQx9FkTK4qkUy8WGsqlQY3uKzDEmDDjgawQYaJsJKxUICJnOOxybq-O9AWQeJMEQcRMaGBtM2cda6t8OZWhpGLoK4Mwc2YBTxwn-p06IiLTkEurc9euLqV6xNfb4qQlgw1-NRTHrvhdgN3kDkBrv0VG3ZjbS_BNlPDRZOrsMCk-JVojbVXZNeMUyhgddp-Axc1szCQtPYy7ydeMNyP1mVYOAJS2mrCJE6vw", + "token_type": "Bearer", + "refresh_token": "", + "expires_in": 31404014, + "issued_token_type": "urn:ga4gh:params:oauth:token-type:passport" +} \ No newline at end of file From c2e8742c8a868e9fadaa62ad4a0c2fb98e3c12de Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Tue, 16 May 2023 12:44:34 -0400 Subject: [PATCH 21/43] Committing changes related to visa service and passport service --- .../ego/controller/AuthController.java | 15 +- .../bio/overture/ego/model/dto/Passport.java | 21 +-- .../bio/overture/ego/model/entity/User.java | 2 +- .../overture/ego/service/PassportService.java | 129 ++++++++---------- .../ego/service/VisaPermissionService.java | 14 +- .../bio/overture/ego/service/VisaService.java | 17 ++- src/main/resources/mockData/passport.json | 7 - 7 files changed, 100 insertions(+), 105 deletions(-) delete mode 100644 src/main/resources/mockData/passport.json diff --git a/src/main/java/bio/overture/ego/controller/AuthController.java b/src/main/java/bio/overture/ego/controller/AuthController.java index 2dfb2c6ae..b6b696a4a 100644 --- a/src/main/java/bio/overture/ego/controller/AuthController.java +++ b/src/main/java/bio/overture/ego/controller/AuthController.java @@ -27,7 +27,6 @@ import bio.overture.ego.model.exceptions.InvalidTokenException; import bio.overture.ego.provider.google.GoogleTokenService; import bio.overture.ego.security.CustomOAuth2User; -import bio.overture.ego.service.PassportService; import bio.overture.ego.service.RefreshContextService; import bio.overture.ego.service.TokenService; import bio.overture.ego.token.IDToken; @@ -37,8 +36,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import java.util.Objects; - -import jakarta.validation.constraints.NotNull; import lombok.NonNull; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -65,20 +62,17 @@ public class AuthController { private final GoogleTokenService googleTokenService; private final TokenSigner tokenSigner; private final RefreshContextService refreshContextService; - private final PassportService passportService; @Autowired public AuthController( - @NonNull TokenService tokenService, - @NonNull GoogleTokenService googleTokenService, - @NonNull TokenSigner tokenSigner, - @NonNull RefreshContextService refreshContextService, - @NotNull PassportService passportService) { + @NonNull TokenService tokenService, + @NonNull GoogleTokenService googleTokenService, + @NonNull TokenSigner tokenSigner, + @NonNull RefreshContextService refreshContextService) { this.tokenService = tokenService; this.googleTokenService = googleTokenService; this.tokenSigner = tokenSigner; this.refreshContextService = refreshContextService; - this.passportService = passportService; } @RequestMapping(method = GET, value = "/google/token") @@ -89,7 +83,6 @@ public AuthController( if (!googleTokenService.validToken(idToken)) throw new InvalidTokenException("Invalid user token:" + idToken); val authInfo = googleTokenService.decode(idToken); - passportService.validatePassportPermissions(idToken); return tokenService.generateUserToken(authInfo); } diff --git a/src/main/java/bio/overture/ego/model/dto/Passport.java b/src/main/java/bio/overture/ego/model/dto/Passport.java index c228ac826..a3bb8211e 100644 --- a/src/main/java/bio/overture/ego/model/dto/Passport.java +++ b/src/main/java/bio/overture/ego/model/dto/Passport.java @@ -2,13 +2,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; - @Data @Builder @AllArgsConstructor @@ -16,20 +15,26 @@ public class Passport { @JsonProperty("sub") - @NotNull private String sub; + @NotNull + private String sub; @JsonProperty("iss") - @NotNull private String iss; + @NotNull + private String iss; @JsonProperty("exp") - @NotNull private int exp; + @NotNull + private int exp; @JsonProperty("iat") - @NotNull private int iat; + @NotNull + private int iat; @JsonProperty("ga4gh_passport_v1") - @NotNull private List ga4ghPassportV1; + @NotNull + private List ga4ghPassportV1; @JsonProperty("jti") - @NotNull private String jti; + @NotNull + private String jti; } diff --git a/src/main/java/bio/overture/ego/model/entity/User.java b/src/main/java/bio/overture/ego/model/entity/User.java index 157d4f113..88f5d7fe8 100644 --- a/src/main/java/bio/overture/ego/model/entity/User.java +++ b/src/main/java/bio/overture/ego/model/entity/User.java @@ -85,7 +85,7 @@ public class User implements PolicyOwner, Identifiable { // TODO: find JPA equivalent for GenericGenerator - @Idx + @Id @Column(name = SqlFields.ID, updatable = false, nullable = false) @GenericGenerator(name = "user_uuid", strategy = "org.hibernate.id.UUIDGenerator") @GeneratedValue(generator = "user_uuid") diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index a8f442770..7a5fac08d 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -3,41 +3,24 @@ import bio.overture.ego.model.dto.Passport; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; -import bio.overture.ego.model.exceptions.ForbiddenException; -import bio.overture.ego.model.exceptions.InternalServerException; -import bio.overture.ego.token.signer.TokenSigner; +import bio.overture.ego.model.exceptions.InvalidTokenException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.nimbusds.jwt.JWT; -import io.jsonwebtoken.JwtException; -import io.jsonwebtoken.Jwts; -import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; -import lombok.val; +import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.client.RestTemplate; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import static java.lang.String.format; @Slf4j @Service @Transactional public class PassportService { - @Value("${broker.passport.url}") - private String passportBrokerUrl; - @Value("${broker.token.config.public-key}") private String publicKey; @@ -46,76 +29,76 @@ public class PassportService { @Autowired private VisaPermissionService visaPermissionService; - private RestTemplate restTemplate; - private final TokenSigner tokenSigner; - @Autowired public PassportService( - @NonNull VisaPermissionService visaPermissionService, - @NonNull VisaService visaService, - @NotNull TokenSigner tokenSigner) { + @NonNull VisaPermissionService visaPermissionService, + @NonNull VisaService visaService) { this.visaService = visaService; this.visaPermissionService = visaPermissionService; - this.tokenSigner = tokenSigner; } - public String validatePassportPermissions (String authToken) throws JsonProcessingException { - - val passportToken = fetchPassport(authToken); - if (!isValidPassport(passportToken)) { - + public List getPermissions(String authToken) throws JsonProcessingException { + // Validates passport auth token + if (!isValidPassport(authToken)) { + throw new InvalidTokenException("The passport token received from broker is invalid"); } - Object parsedPassport = parse (authToken); - ObjectMapper mapper = new ObjectMapper(); - Passport passport = mapper.readValue((String) parsedPassport, Passport.class); - //getPermissionsForPassport(visaId); - //prepareUserPermissions(visaPermissions); - return null; - } - - private Object fetchPassport (String authToken) { - val response = - restTemplate.exchange( - passportBrokerUrl, HttpMethod.POST, new HttpEntity<>(authToken, null), String.class); - return response.getBody(); + // Parses passport JWT token + Passport parsedPassport = parsePassport(authToken); + // Fetches visas for parsed passport + List visas = getVisas(parsedPassport); + // Fetches visa permissions for extracted visas + List visaPermissions = getVisaPermissions(visas); + // removes deuplicates from visaPermissions + // TO_DO : visaPermissions = deDupeVisaPermissions (visaPermissions); + return visaPermissions; } + // TO_DO : Validates passport token based on public key private boolean isValidPassport(@NonNull Object passport) { - return true; } - private boolean isValidVisa(@NonNull Object visa) { - - return true; + // Extracts Visas from parsed passport object + private List getVisas(Passport passport) { + List visas = new ArrayList<>(); + passport.getGa4ghPassportV1().stream() + .forEach( + visaJwt -> { + try { + Visa visa = visaService.parseVisa(visaJwt); + if (visa != null) { + visas.add(visa); + } + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + }); + return visas; } - private List getVisaPermissions (List visaIds) { + // Fetches Visa Permissions for extracted Visa list + private List getVisaPermissions(List visas) { List visaPermissions = new ArrayList<>(); - visaIds.stream().distinct().forEach(visaId -> { - if (visaService.getById(visaId) != null) { - visaPermissions.addAll(visaPermissionService.getPermissionsByVisaId(visaId)); - } - }); + visas.stream() + .distinct() + .forEach( + visa -> { + if (visaService.getById(visa.getId()) != null) { + visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visa)); + } + }); return visaPermissions; } - - private Optional parse (@NonNull String token) { - Object parsedObj; - val tokenKey = - tokenSigner - .getKey() - .orElseThrow(() -> new InternalServerException("Internal issue with token signer.")); - - try { - parsedObj = Jwts.parser().setSigningKey(tokenKey).parse(token); - } catch (JwtException e) { - log.error("JWT token is invalid", e); - throw new ForbiddenException("Authorization is required for this action."); - } - return parsedObj == null ? Optional.empty() : Optional.of(parsedObj); + // Parse Passport token to extract the passport body + public Passport parsePassport(@NonNull String passportJwtToken) throws JsonProcessingException { + String[] split_string = passportJwtToken.split("//."); + String base64EncodedHeader = split_string[0]; + String base64EncodedBody = split_string[1]; + String base64EncodedSignature = split_string[2]; + Base64 base64Url = new Base64(true); + String header = new String(base64Url.decode(base64EncodedHeader)); + String body = new String(base64Url.decode(base64EncodedBody)); + return new ObjectMapper().readValue(body, Passport.class); } - - } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 6057ce5bc..0afe23ba1 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -5,6 +5,7 @@ import bio.overture.ego.event.token.ApiKeyEventsPublisher; import bio.overture.ego.model.dto.VisaPermissionRequest; +import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.repository.VisaPermissionRepository; @@ -26,15 +27,12 @@ @Service @Transactional public class VisaPermissionService extends AbstractNamedService { - /** Dependencies */ @Autowired private VisaService visaService; @Autowired private PolicyService policyService; - @Autowired private VisaPermissionRepository visaPermissionRepository; private final ApiKeyEventsPublisher apiKeyEventsPublisher; - private static final VisaPermissionService.VisaPermissionConverter VISA_PERMISSION_CONVERTER = getMapper(VisaPermissionService.VisaPermissionConverter.class); @@ -96,6 +94,16 @@ public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { } } + // Fetches visa permissions for given visa request + public List getPermissionsForVisa(@NonNull Visa visa) { + val result = (List) visaPermissionRepository.findByVisa_Id(visa.getId()); + if (result.isEmpty()) { + throw new NotFoundException( + format("No VisaPermissions exists with visaId '%s'", visa.getId())); + } + return result; + } + @Override public VisaPermission getById(@NonNull UUID uuid) { return super.getById(uuid); diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 9e65f8db1..e91c1b091 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -8,12 +8,15 @@ import bio.overture.ego.model.dto.VisaRequest; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.repository.VisaRepository; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.validation.constraints.NotNull; import java.util.Optional; import java.util.UUID; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.val; +import org.apache.commons.codec.binary.Base64; import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.NullValueCheckStrategy; @@ -28,11 +31,9 @@ @Service @Transactional public class VisaService extends AbstractNamedService { - /** Constants */ private static final VisaService.VisaConverter VISA_CONVERTER = getMapper(VisaService.VisaConverter.class); - /** Dependencies */ @Autowired private VisaRepository visaRepository; @@ -65,6 +66,18 @@ public void delete(@NonNull UUID id) { super.delete(id); } + // Parses Visa JWT token to convert into Visa Object + public Visa parseVisa(@NonNull String visaJwtToken) throws JsonProcessingException { + String[] split_string = visaJwtToken.split("//."); + String base64EncodedHeader = split_string[0]; + String base64EncodedBody = split_string[1]; + String base64EncodedSignature = split_string[2]; + Base64 base64Url = new Base64(true); + String header = new String(base64Url.decode(base64EncodedHeader)); + String body = new String(base64Url.decode(base64EncodedBody)); + return new ObjectMapper().readValue(body, Visa.class); + } + public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } diff --git a/src/main/resources/mockData/passport.json b/src/main/resources/mockData/passport.json deleted file mode 100644 index be145ba0b..000000000 --- a/src/main/resources/mockData/passport.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "access_token": "eyJqa3UiOiJodHRwczpcL1wvbG9naW4uZWxpeGlyLWN6ZWNoLm9yZ1wvcGVydW4tZ2E0Z2gtYnJva2VyXC9qd2siLCJraWQiOiJyc2ExIiwidHlwIjoidm5kLmdhNGdoLnBhc3Nwb3J0K2p3dCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIwNjdhNDQ4NzJkOWI1NWExMTRmYTZlY2I1OTc2NzM1YzM5NjY5Mjc2QGVsaXhpci1ldXJvcGUub3JnIiwiaXNzIjoiaHR0cHM6XC9cL2xvZ2luLmVsaXhpci1jemVjaC5vcmdcL29pZGMiLCJleHAiOjE3MTUyNzYwMjQsImlhdCI6MTY4Mzg3MjAwOSwiZ2E0Z2hfcGFzc3BvcnRfdjEiOlsiZXlKcWEzVWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZjR1Z5ZFc0dFoyRTBaMmd0WW5KdmEyVnlYQzlxZDJzaUxDSnJhV1FpT2lKeWMyRXhJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUp6ZFdJaU9pSXdOamRoTkRRNE56SmtPV0kxTldFeE1UUm1ZVFpsWTJJMU9UYzJOek0xWXpNNU5qWTVNamMyUUdWc2FYaHBjaTFsZFhKdmNHVXViM0puSWl3aVoyRTBaMmhmZG1sellWOTJNU0k2ZXlKaGMzTmxjblJsWkNJNk1UWTRNemczTWpBd09Td2lZbmtpT2lKemVYTjBaVzBpTENKemIzVnlZMlVpT201MWJHd3NJblI1Y0dVaU9pSkJabVpwYkdsaGRHbHZia0Z1WkZKdmJHVWlMQ0oyWVd4MVpTSTZJbUZtWm1sc2FXRjBaVUJsYkdsNGFYSXRaWFZ5YjNCbExtOXlaeUo5TENKcGMzTWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZiMmxrWXlJc0ltVjRjQ0k2TVRjeE5UUTVORFF3T1N3aWFXRjBJam94Tmpnek9EY3lNREE1TENKcWRHa2lPaUl6Wm1Jd01XSTFaaTFpTW1aa0xUUmlNR1l0T1RBNU15MWlNakV3T1dFeFpqRmxaR1lpZlEub19jSEdRcjFmdXlDNUFOT0dlTXNxckxXNFpHakpzRmVvQk50YVZXSjNHeDlkRG9Sbmk5d1RiSjR5Sm01QWdkNGtjRXhaWFV3WVZaLVc1aWhMUG9CLVZJUExlQURLOTJkeTRCNTJudV9zYUM2TGZqczUzcEJIQllQLTFoYU1YQS1EWWNDT1Q3MEdvU1Y4eXpPdFNqTDFyRGZFUkdEdFNoOXdPNVZuc2dLWFMydWppLVYxMmVDdGNCMS1tb2dkUGtXQ3EybHVzazdWRHNYc0JJbWMtZHVHOVZWN3MwVXdtQ2FFRFpXZ0xWdUU2OTF0bEpmUjZmXzJjT0s3bVBsQXhvMDhiOUdINldtZVFqNWFFWTdpYzdib1Y4SnJubFZPdmRsck44UnJ6cjNCVFRFbkFabWlSUGhNRTBEOVYtM2JvMXpTakxNbnBxTU80WDlkZHBHNGxyczd3IiwiZXlKcWEzVWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZjR1Z5ZFc0dFoyRTBaMmd0WW5KdmEyVnlYQzlxZDJzaUxDSnJhV1FpT2lKeWMyRXhJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUp6ZFdJaU9pSXdOamRoTkRRNE56SmtPV0kxTldFeE1UUm1ZVFpsWTJJMU9UYzJOek0xWXpNNU5qWTVNamMyUUd4cFptVnpZMmxsYm1ObExYSnBMbVYxSWl3aVoyRTBaMmhmZG1sellWOTJNU0k2ZXlKaGMzTmxjblJsWkNJNk1UWTRNelkxTXpZeU5Dd2lZbmtpT2lKemVYTjBaVzBpTENKemIzVnlZMlVpT2lKb2RIUndjenBjTDF3dmNHVnlkVzR1WVdGcExteHBabVZ6WTJsbGJtTmxMWEpwTG1WMVhDOGlMQ0owZVhCbElqb2lUR2x1YTJWa1NXUmxiblJwZEdsbGN5SXNJblpoYkhWbElqb2lNRFkzWVRRME9EY3laRGxpTlRWaE1URTBabUUyWldOaU5UazNOamN6TldNek9UWTJPVEkzTmlVME1HVnNhWGhwY2kxbGRYSnZjR1V1YjNKbkxHaDBkSEJ6SlROQkpUSkdKVEpHYkc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVp5VXlSbWxrY0NVeVJpSjlMQ0pwYzNNaU9pSm9kSFJ3Y3pwY0wxd3ZiRzluYVc0dVpXeHBlR2x5TFdONlpXTm9MbTl5WjF3dmIybGtZeUlzSW1WNGNDSTZORGd6T1RNeU56SXlOQ3dpYVdGMElqb3hOamd6T0RjeU1EQTVMQ0pxZEdraU9pSTFNRFZqT0RCaE5pMDJOMlUyTFRReFlqVXRZVFUyTnkxaU5UQTJOMlkzWkdVMk1EVWlmUS5PVTVkSERGWEhWY1RFNm5xSHJzMUJXV1NLQndaNjNxNlZfel9zNmVPenp2N3hTVUFNQ0FFVlFtb0FIeFhnbUZXaWZoQnhxMlZxaE5RUGhDUTFNUG5ydnk3UVNHM1cxSE15amRIUWxaYkNrdVdweUlLUXFCa1hQQVFRTnJ0N0tiODZkbVZJb0lHOV9lN2JQSnUtR29EMUdITm1pc29hTzBWUzg0YW85UGRMaDNYeXcwQ2ZiX2F3dGhmSHlwZjZWcmFRUFFlNFpUWnEzbTF5MDdlZkt2TUpWWFh2UXFpYm5kSTF6cEtjQVZRQllLQXFRbmtzbEdkSGtrOG9wOFROZEVOcGw3OWtkNnNWeWJUSnNuT1B3VUtaY0haXzA2MnRRblNJeWllbjg5WWxDdVBQMTZMMnJKb1NGR0ROOWZ2b21yZU0xNnBDVkxkTVJsSVJDS1p3bHBPRkEiLCJleUpxYTNVaU9pSm9kSFJ3Y3pwY0wxd3ZiRzluYVc0dVpXeHBlR2x5TFdONlpXTm9MbTl5WjF3dmNHVnlkVzR0WjJFMFoyZ3RZbkp2YTJWeVhDOXFkMnNpTENKcmFXUWlPaUp5YzJFeElpd2lkSGx3SWpvaVNsZFVJaXdpWVd4bklqb2lVbE15TlRZaWZRLmV5SnpkV0lpT2lJd05qZGhORFE0TnpKa09XSTFOV0V4TVRSbVlUWmxZMkkxT1RjMk56TTFZek01TmpZNU1qYzJRR3hwWm1WelkybGxibU5sTFhKcExtVjFJaXdpWjJFMFoyaGZkbWx6WVY5Mk1TSTZleUpoYzNObGNuUmxaQ0k2TVRZNE16WTFNell5TkN3aVlua2lPaUp6ZVhOMFpXMGlMQ0p6YjNWeVkyVWlPaUpvZEhSd2N6cGNMMXd2Y0dWeWRXNHVZV0ZwTG14cFptVnpZMmxsYm1ObExYSnBMbVYxWEM4aUxDSjBlWEJsSWpvaVRHbHVhMlZrU1dSbGJuUnBkR2xsY3lJc0luWmhiSFZsSWpvaU1EWTNZVFEwT0RjeVpEbGlOVFZoTVRFMFptRTJaV05pTlRrM05qY3pOV016T1RZMk9USTNOaVUwTUd4cFptVnpZMmxsYm1ObExYSnBMbVYxTEdoMGRIQnpKVE5CSlRKR0pUSkdjSEp2ZUhrdVlXRnBMbXhwWm1WelkybGxibU5sTFhKcExtVjFKVEpHY0hKdmVIa2lmU3dpYVhOeklqb2lhSFIwY0hNNlhDOWNMMnh2WjJsdUxtVnNhWGhwY2kxamVtVmphQzV2Y21kY0wyOXBaR01pTENKbGVIQWlPalE0TXprek1qY3lNalFzSW1saGRDSTZNVFk0TXpnM01qQXdPU3dpYW5ScElqb2lNamMwTURaa01EQXRNRE5oTVMwME5EUmtMVGszWW1RdE1HSmlNMlF3TlRReE9UYzJJbjAuQ0xSV1J4bDIwNThVc1Y2Zi14U2psNFdMaFJkLWZrRnZEdTlIOEUteWJINmZZdXcwNWl1QkJNbm1mMUNZYU90RlBRZVpxbVh2YWZqV1VIaFE2ZmxXemhhVHdGYmpIUUh4a0lzY0Z3dHdEb2pLelpWcGJXRGlGdGtiNHBWQTJRdXhKSVAya2NlSEF1WElkNXJITWpzOGQxOXBXMTIyVFFIMlJYeHJibDNjWjZpZkJhMndtV0RtSzNvNkhLeGx6cXVlUXpEcWg5VEZaUWZSQlVHdmRmNUFkYnZuNS11bThTdzhjazRfZ3hFckk4STc5OGc1al9HMHBSRVIyWFp4NE5PVWVUbWkxbHNXTkxqTFlYQjJaZzRaa1dyQVA3dFdwVXRrSUx6Nk1Nb0hyRDFxUEs1OWw2dldTLVpxX0NtLVRSck1ZMGdkZUhCX05FQWlMdEotdGlXYm5RIiwiZXlKcWEzVWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZjR1Z5ZFc0dFoyRTBaMmd0WW5KdmEyVnlYQzlxZDJzaUxDSnJhV1FpT2lKeWMyRXhJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUp6ZFdJaU9pSXdOamRoTkRRNE56SmtPV0kxTldFeE1UUm1ZVFpsWTJJMU9UYzJOek0xWXpNNU5qWTVNamMyUUd4cFptVnpZMmxsYm1ObExYSnBMbVYxSWl3aVoyRTBaMmhmZG1sellWOTJNU0k2ZXlKaGMzTmxjblJsWkNJNk1UWTRNelkxTXpZeU5Dd2lZbmtpT2lKemVYTjBaVzBpTENKemIzVnlZMlVpT2lKb2RIUndjenBjTDF3dmNHVnlkVzR1WVdGcExteHBabVZ6WTJsbGJtTmxMWEpwTG1WMVhDOGlMQ0owZVhCbElqb2lUR2x1YTJWa1NXUmxiblJwZEdsbGN5SXNJblpoYkhWbElqb2lNVEEwTmpVMU1qZzROelkyT1RJNE5UWTVNREEwSlRRd1lXTmpiM1Z1ZEhNdVoyOXZaMnhsTG1OdmJTeG9kSFJ3Y3lVelFTVXlSaVV5Um1sa2FIVmlMbUZoYVM1c2FXWmxjMk5wWlc1alpTMXlhUzVsZFNVeVJuQnliM2g1SlRKR1lVaFNNR05JVFRaTWVUbG9XVEpPZG1SWE5UQmplVFZ1WWpJNWJtSkhWWFZaTWpsMEluMHNJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOXNiMmRwYmk1bGJHbDRhWEl0WTNwbFkyZ3ViM0puWEM5dmFXUmpJaXdpWlhod0lqb3hOekUxTWpjMk1ESTBMQ0pwWVhRaU9qRTJPRE00TnpJd01Ea3NJbXAwYVNJNklqQXlPVEJsTURVekxUYzFaak10TkdObU1DMDRPVEF3TFRSaE5ERTRZbVEyWlRCbVpDSjkuTmV0NV9XdE4zMUdWZlhwR2xGblVWS29fS0s2MU9iM2xkTWlHVTVHUGdlbU9SNlBDNjlUbXozTTJMMzl0MVRkOXkxb1BuVHRaVWpxU1lTbUhIWXpJc2dPUTJDRFZxc0ZPNFlxbjNnX2pVTlI2Y2UyalhvSjFkelBWdTY1V3lsTmloV2EtaEFBUEVtbFVIbEFIbnpSbnpmejc5MlU0aHBQM1JRWWtEaml1VG5oV2JabUZDcGs2UmZNa3lrSVNlQ1l2MWpxXzVaeS15NWlvR0N3U2U0MWNwbTBIS2cxdEc5Z3BWMW9oNHBBNWxNNzVHY1RKT29MVUkwZEE2dTBtU1JxTVRUVGNYbG5XSzBKRS01Yk80ZE9WM0JlSHlnTkprVi1WN3VBN1RfQWFDVDNEZFFOZkdhT3NPT2daQlVMZW1rcWNrZjBGMVN3YzN0THlOSmhfMWxBU1VRIiwiZXlKcWEzVWlPaUpvZEhSd2N6cGNMMXd2Ykc5bmFXNHVaV3hwZUdseUxXTjZaV05vTG05eVoxd3ZjR1Z5ZFc0dFoyRTBaMmd0WW5KdmEyVnlYQzlxZDJzaUxDSnJhV1FpT2lKeWMyRXhJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUp6ZFdJaU9pSXdOamRoTkRRNE56SmtPV0kxTldFeE1UUm1ZVFpsWTJJMU9UYzJOek0xWXpNNU5qWTVNamMyUUd4cFptVnpZMmxsYm1ObExYSnBMbVYxSWl3aVoyRTBaMmhmZG1sellWOTJNU0k2ZXlKaGMzTmxjblJsWkNJNk1UWTRNelkxTXpZeU5Dd2lZbmtpT2lKemVYTjBaVzBpTENKemIzVnlZMlVpT2lKb2RIUndjenBjTDF3dmNHVnlkVzR1WVdGcExteHBabVZ6WTJsbGJtTmxMWEpwTG1WMVhDOGlMQ0owZVhCbElqb2lUR2x1YTJWa1NXUmxiblJwZEdsbGN5SXNJblpoYkhWbElqb2lNRFkzWVRRME9EY3laRGxpTlRWaE1URTBabUUyWldOaU5UazNOamN6TldNek9UWTJPVEkzTmlVME1HSmliWEpwTG1WMUxHaDBkSEJ6SlROQkpUSkdKVEpHYkc5bmFXNHVZbUp0Y21rdFpYSnBZeTVsZFNVeVJtbGtjQ1V5UmlKOUxDSnBjM01pT2lKb2RIUndjenBjTDF3dmJHOW5hVzR1Wld4cGVHbHlMV042WldOb0xtOXlaMXd2YjJsa1l5SXNJbVY0Y0NJNk1UY3hOVEkzTmpBeU5Dd2lhV0YwSWpveE5qZ3pPRGN5TURBNUxDSnFkR2tpT2lKbU1qSmpaalZqWkMxa1l6UXlMVFEwTVRrdE9HVXlaUzB4T1RGa04yRXhNV014WlRBaWZRLlhhT3hSR3MxM1R6cnFGTGo5eGh1SGV6WUhHVXNQLUxvV1prUEZKSTAyWXVQdDhkOE5VVW14dk04ZlBpdjhoa2FyYkNyeFBobnRRT3BpbXJwaVdZVFFqRFQ0OFFEM0VWcHVaY1lnV1RUd24weThqcWhHZzkzT1dwM0Q4cVFaVElzYW5aQ1Z1WXVmSU9iSEo3akxIRk5EaE5DaWhyMmRVUi1Na3plUm05UmpkbGhmcXh0VFBYQlB0UTZpYkVOcGxiYjRyeEVaYll0djdlOTc3S3NMYzZvaE1KaXN4TVotQWI1Y0JoM21QdC1hSy00NUxGY00wdEY0dVBkSTc5LXFtbFh1VjIxQ1RSZHVyamZ0NVBNMTFra0RXaEM2NzJteE5tNk5DNmw1QXA2QXBINnN1TWtFLXZybzU4MU9iaGRMZTViaVpYX2s2dzBwYklZakV6NGJ6Y1prZyJdLCJqdGkiOiI0Y2Q4NjgxMi03OGE3LTRkNGItOTBkMy03Y2U4NmFkNjk5ZWUifQ.i5ang5Thhae_H84ybCrbyNxQ62YF4IvX301AFECUkyn7Ry3E05KFRm7UC1hmX-p2udZe7RO1oRjW-fa9UomTXARh0DB5OwMKrHeJastoKLDwND05lZJpQx9FkTK4qkUy8WGsqlQY3uKzDEmDDjgawQYaJsJKxUICJnOOxybq-O9AWQeJMEQcRMaGBtM2cda6t8OZWhpGLoK4Mwc2YBTxwn-p06IiLTkEurc9euLqV6xNfb4qQlgw1-NRTHrvhdgN3kDkBrv0VG3ZjbS_BNlPDRZOrsMCk-JVojbVXZNeMUyhgddp-Axc1szCQtPYy7ydeMNyP1mVYOAJS2mrCJE6vw", - "token_type": "Bearer", - "refresh_token": "", - "expires_in": 31404014, - "issued_token_type": "urn:ga4gh:params:oauth:token-type:passport" -} \ No newline at end of file From 7a3c0c8e70ae65c0e74369c0a805daa79b055f21 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Tue, 16 May 2023 12:54:22 -0400 Subject: [PATCH 22/43] Committing changes related to visa service and passport service --- src/main/resources/application.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3dbe2621a..9714fe865 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -203,8 +203,6 @@ initialization: description: Some description about this application # optional broker: - passport: - url: token: config: public-key: From 360cadce107a83daa97e8bcc424b80d2421b7e12 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 19 May 2023 03:39:48 -0400 Subject: [PATCH 23/43] Committing changes related to passport permissions --- src/main/bin/ego | 0 src/main/bin/wrapper-macosx-universal-64 | Bin src/main/bin/wrapper.log | 221 ------------------ .../ego/controller/PassportController.java | 51 ++++ .../overture/ego/service/PassportService.java | 55 +++-- .../ego/service/VisaPermissionService.java | 4 +- .../bio/overture/ego/service/VisaService.java | 32 ++- .../ego/token/signer/BrokerTokenSigner.java | 92 ++++++++ src/main/resources/application.yml | 5 +- .../resources/dummy-data/reset-dummy-data.sh | 0 src/main/resources/scripts/env_template.sh | 0 .../resources/scripts/jwt/export-pub-key.sh | 0 .../resources/scripts/jwt/gen-key-pair.sh | 0 .../resources/scripts/jwt/gen-keystore.sh | 0 src/main/resources/scripts/run.sh | 0 .../resources/scripts/start-server-iam.sh | 0 .../resources/scripts/start-server-token.sh | 0 src/main/resources/scripts/start-server.sh | 0 src/main/resources/scripts/stop-server.sh | 0 .../scripts/vault/setup-local-vault.sh | 0 20 files changed, 219 insertions(+), 241 deletions(-) mode change 100755 => 100644 src/main/bin/ego mode change 100755 => 100644 src/main/bin/wrapper-macosx-universal-64 delete mode 100644 src/main/bin/wrapper.log create mode 100644 src/main/java/bio/overture/ego/controller/PassportController.java create mode 100644 src/main/java/bio/overture/ego/token/signer/BrokerTokenSigner.java mode change 100755 => 100644 src/main/resources/dummy-data/reset-dummy-data.sh mode change 100755 => 100644 src/main/resources/scripts/env_template.sh mode change 100755 => 100644 src/main/resources/scripts/jwt/export-pub-key.sh mode change 100755 => 100644 src/main/resources/scripts/jwt/gen-key-pair.sh mode change 100755 => 100644 src/main/resources/scripts/jwt/gen-keystore.sh mode change 100755 => 100644 src/main/resources/scripts/run.sh mode change 100755 => 100644 src/main/resources/scripts/start-server-iam.sh mode change 100755 => 100644 src/main/resources/scripts/start-server-token.sh mode change 100755 => 100644 src/main/resources/scripts/start-server.sh mode change 100755 => 100644 src/main/resources/scripts/stop-server.sh mode change 100755 => 100644 src/main/resources/scripts/vault/setup-local-vault.sh diff --git a/src/main/bin/ego b/src/main/bin/ego old mode 100755 new mode 100644 diff --git a/src/main/bin/wrapper-macosx-universal-64 b/src/main/bin/wrapper-macosx-universal-64 old mode 100755 new mode 100644 diff --git a/src/main/bin/wrapper.log b/src/main/bin/wrapper.log deleted file mode 100644 index f45ee9531..000000000 --- a/src/main/bin/wrapper.log +++ /dev/null @@ -1,221 +0,0 @@ -FATAL | wrapper | 2017/11/15 11:19:39 | Unable to open configuration file: /Users/jeubank/workspace/overture-stack/ego/src/main/bin/../conf/wrapper.conf (No such file or directory) -FATAL | wrapper | 2017/11/15 11:19:39 | Current working directory: /Users/jeubank/workspace/overture-stack/ego/src/main/bin -WARN | wrapper | 2017/11/15 11:20:22 | Unable to write to the configured log directory: ../logs (No such file or directory) -WARN | wrapper | 2017/11/15 11:20:22 | The directory does not exist. -WARN | wrapper | 2017/11/15 11:20:22 | Unable to write to the configured log file: ../logs/wrapper.20171115.log (No such file or directory) -WARN | wrapper | 2017/11/15 11:20:22 | Falling back to the default file in the current working directory: wrapper.log -WARN | wrapper | 2017/11/15 11:20:22 | The version of the script (3.5.19) doesn't match the version of this Wrapper (3.5.21). This might cause some problems -STATUS | wrapper | 2017/11/15 11:20:22 | --> Wrapper Started as Daemon -STATUS | wrapper | 2017/11/15 11:20:22 | Java Service Wrapper Community Edition 64-bit 3.5.21 -STATUS | wrapper | 2017/11/15 11:20:22 | Copyright (C) 1999-2013 Tanuki Software, Ltd. All Rights Reserved. -STATUS | wrapper | 2017/11/15 11:20:22 | http://wrapper.tanukisoftware.com -STATUS | wrapper | 2017/11/15 11:20:22 | -STATUS | wrapper | 2017/11/15 11:20:22 | Launching a JVM... -INFO | jvm 1 | 2017/11/15 11:20:23 | WrapperManager: Initializing... -INFO | jvm 1 | 2017/11/15 11:20:23 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 1 | 2017/11/15 11:20:23 | -INFO | jvm 1 | 2017/11/15 11:20:23 | WrapperSimpleApp Usage: -INFO | jvm 1 | 2017/11/15 11:20:23 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 1 | 2017/11/15 11:20:23 | -INFO | jvm 1 | 2017/11/15 11:20:23 | Where: -INFO | jvm 1 | 2017/11/15 11:20:23 | app_class: The fully qualified class name of the application to run. -INFO | jvm 1 | 2017/11/15 11:20:23 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 1 | 2017/11/15 11:20:23 | application. -ERROR | wrapper | 2017/11/15 11:20:25 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:20:29 | Launching a JVM... -INFO | jvm 2 | 2017/11/15 11:20:30 | WrapperManager: Initializing... -INFO | jvm 2 | 2017/11/15 11:20:30 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 2 | 2017/11/15 11:20:30 | -INFO | jvm 2 | 2017/11/15 11:20:30 | WrapperSimpleApp Usage: -INFO | jvm 2 | 2017/11/15 11:20:30 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 2 | 2017/11/15 11:20:30 | -INFO | jvm 2 | 2017/11/15 11:20:30 | Where: -INFO | jvm 2 | 2017/11/15 11:20:30 | app_class: The fully qualified class name of the application to run. -INFO | jvm 2 | 2017/11/15 11:20:30 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 2 | 2017/11/15 11:20:30 | application. -ERROR | wrapper | 2017/11/15 11:20:32 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:20:36 | Launching a JVM... -INFO | jvm 3 | 2017/11/15 11:20:37 | WrapperManager: Initializing... -INFO | jvm 3 | 2017/11/15 11:20:37 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 3 | 2017/11/15 11:20:37 | -INFO | jvm 3 | 2017/11/15 11:20:37 | WrapperSimpleApp Usage: -INFO | jvm 3 | 2017/11/15 11:20:37 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 3 | 2017/11/15 11:20:37 | -INFO | jvm 3 | 2017/11/15 11:20:37 | Where: -INFO | jvm 3 | 2017/11/15 11:20:37 | app_class: The fully qualified class name of the application to run. -INFO | jvm 3 | 2017/11/15 11:20:37 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 3 | 2017/11/15 11:20:37 | application. -ERROR | wrapper | 2017/11/15 11:20:39 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:20:44 | Launching a JVM... -INFO | jvm 4 | 2017/11/15 11:20:44 | WrapperManager: Initializing... -INFO | jvm 4 | 2017/11/15 11:20:44 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 4 | 2017/11/15 11:20:44 | -INFO | jvm 4 | 2017/11/15 11:20:44 | WrapperSimpleApp Usage: -INFO | jvm 4 | 2017/11/15 11:20:44 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 4 | 2017/11/15 11:20:44 | -INFO | jvm 4 | 2017/11/15 11:20:44 | Where: -INFO | jvm 4 | 2017/11/15 11:20:44 | app_class: The fully qualified class name of the application to run. -INFO | jvm 4 | 2017/11/15 11:20:44 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 4 | 2017/11/15 11:20:44 | application. -ERROR | wrapper | 2017/11/15 11:20:46 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:20:51 | Launching a JVM... -INFO | jvm 5 | 2017/11/15 11:20:51 | WrapperManager: Initializing... -INFO | jvm 5 | 2017/11/15 11:20:51 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 5 | 2017/11/15 11:20:51 | -INFO | jvm 5 | 2017/11/15 11:20:51 | WrapperSimpleApp Usage: -INFO | jvm 5 | 2017/11/15 11:20:51 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 5 | 2017/11/15 11:20:51 | -INFO | jvm 5 | 2017/11/15 11:20:51 | Where: -INFO | jvm 5 | 2017/11/15 11:20:51 | app_class: The fully qualified class name of the application to run. -INFO | jvm 5 | 2017/11/15 11:20:51 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 5 | 2017/11/15 11:20:51 | application. -ERROR | wrapper | 2017/11/15 11:20:53 | JVM exited while loading the application. -FATAL | wrapper | 2017/11/15 11:20:53 | There were 5 failed launches in a row, each lasting less than 300 seconds. Giving up. -FATAL | wrapper | 2017/11/15 11:20:53 | There may be a configuration problem: please check the logs. -STATUS | wrapper | 2017/11/15 11:20:53 | <-- Wrapper Stopped -WARN | wrapper | 2017/11/15 11:21:01 | Unable to write to the configured log directory: ../logs (No such file or directory) -WARN | wrapper | 2017/11/15 11:21:01 | The directory does not exist. -WARN | wrapper | 2017/11/15 11:21:01 | Unable to write to the configured log file: ../logs/wrapper.20171115.log (No such file or directory) -WARN | wrapper | 2017/11/15 11:21:01 | Falling back to the default file in the current working directory: wrapper.log -WARN | wrapper | 2017/11/15 11:21:01 | The version of the script (3.5.19) doesn't match the version of this Wrapper (3.5.21). This might cause some problems -STATUS | wrapper | 2017/11/15 11:21:01 | --> Wrapper Started as Daemon -STATUS | wrapper | 2017/11/15 11:21:01 | Java Service Wrapper Community Edition 64-bit 3.5.21 -STATUS | wrapper | 2017/11/15 11:21:01 | Copyright (C) 1999-2013 Tanuki Software, Ltd. All Rights Reserved. -STATUS | wrapper | 2017/11/15 11:21:01 | http://wrapper.tanukisoftware.com -STATUS | wrapper | 2017/11/15 11:21:01 | -STATUS | wrapper | 2017/11/15 11:21:01 | Launching a JVM... -INFO | jvm 1 | 2017/11/15 11:21:02 | WrapperManager: Initializing... -INFO | jvm 1 | 2017/11/15 11:21:02 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 1 | 2017/11/15 11:21:02 | -INFO | jvm 1 | 2017/11/15 11:21:02 | WrapperSimpleApp Usage: -INFO | jvm 1 | 2017/11/15 11:21:02 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 1 | 2017/11/15 11:21:02 | -INFO | jvm 1 | 2017/11/15 11:21:02 | Where: -INFO | jvm 1 | 2017/11/15 11:21:02 | app_class: The fully qualified class name of the application to run. -INFO | jvm 1 | 2017/11/15 11:21:02 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 1 | 2017/11/15 11:21:02 | application. -ERROR | wrapper | 2017/11/15 11:21:04 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:21:08 | Launching a JVM... -INFO | jvm 2 | 2017/11/15 11:21:09 | WrapperManager: Initializing... -INFO | jvm 2 | 2017/11/15 11:21:09 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 2 | 2017/11/15 11:21:09 | -INFO | jvm 2 | 2017/11/15 11:21:09 | WrapperSimpleApp Usage: -INFO | jvm 2 | 2017/11/15 11:21:09 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 2 | 2017/11/15 11:21:09 | -INFO | jvm 2 | 2017/11/15 11:21:09 | Where: -INFO | jvm 2 | 2017/11/15 11:21:09 | app_class: The fully qualified class name of the application to run. -INFO | jvm 2 | 2017/11/15 11:21:09 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 2 | 2017/11/15 11:21:09 | application. -ERROR | wrapper | 2017/11/15 11:21:11 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:21:15 | Launching a JVM... -INFO | jvm 3 | 2017/11/15 11:21:16 | WrapperManager: Initializing... -INFO | jvm 3 | 2017/11/15 11:21:16 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 3 | 2017/11/15 11:21:16 | -INFO | jvm 3 | 2017/11/15 11:21:16 | WrapperSimpleApp Usage: -INFO | jvm 3 | 2017/11/15 11:21:16 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 3 | 2017/11/15 11:21:16 | -INFO | jvm 3 | 2017/11/15 11:21:16 | Where: -INFO | jvm 3 | 2017/11/15 11:21:16 | app_class: The fully qualified class name of the application to run. -INFO | jvm 3 | 2017/11/15 11:21:16 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 3 | 2017/11/15 11:21:16 | application. -ERROR | wrapper | 2017/11/15 11:21:18 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:21:22 | Launching a JVM... -INFO | jvm 4 | 2017/11/15 11:21:23 | WrapperManager: Initializing... -INFO | jvm 4 | 2017/11/15 11:21:23 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 4 | 2017/11/15 11:21:23 | -INFO | jvm 4 | 2017/11/15 11:21:23 | WrapperSimpleApp Usage: -INFO | jvm 4 | 2017/11/15 11:21:23 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 4 | 2017/11/15 11:21:23 | -INFO | jvm 4 | 2017/11/15 11:21:23 | Where: -INFO | jvm 4 | 2017/11/15 11:21:23 | app_class: The fully qualified class name of the application to run. -INFO | jvm 4 | 2017/11/15 11:21:23 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 4 | 2017/11/15 11:21:23 | application. -ERROR | wrapper | 2017/11/15 11:21:25 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:21:30 | Launching a JVM... -INFO | jvm 5 | 2017/11/15 11:21:30 | WrapperManager: Initializing... -INFO | jvm 5 | 2017/11/15 11:21:30 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 5 | 2017/11/15 11:21:30 | -INFO | jvm 5 | 2017/11/15 11:21:30 | WrapperSimpleApp Usage: -INFO | jvm 5 | 2017/11/15 11:21:30 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 5 | 2017/11/15 11:21:30 | -INFO | jvm 5 | 2017/11/15 11:21:30 | Where: -INFO | jvm 5 | 2017/11/15 11:21:30 | app_class: The fully qualified class name of the application to run. -INFO | jvm 5 | 2017/11/15 11:21:30 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 5 | 2017/11/15 11:21:30 | application. -ERROR | wrapper | 2017/11/15 11:21:32 | JVM exited while loading the application. -FATAL | wrapper | 2017/11/15 11:21:32 | There were 5 failed launches in a row, each lasting less than 300 seconds. Giving up. -FATAL | wrapper | 2017/11/15 11:21:32 | There may be a configuration problem: please check the logs. -STATUS | wrapper | 2017/11/15 11:21:32 | <-- Wrapper Stopped -WARN | wrapper | 2017/11/15 11:21:42 | Unable to write to the configured log directory: ../logs (No such file or directory) -WARN | wrapper | 2017/11/15 11:21:42 | The directory does not exist. -WARN | wrapper | 2017/11/15 11:21:42 | Unable to write to the configured log file: ../logs/wrapper.20171115.log (No such file or directory) -WARN | wrapper | 2017/11/15 11:21:42 | Falling back to the default file in the current working directory: wrapper.log -WARN | wrapper | 2017/11/15 11:21:42 | The version of the script (3.5.19) doesn't match the version of this Wrapper (3.5.21). This might cause some problems -STATUS | wrapper | 2017/11/15 11:21:42 | --> Wrapper Started as Daemon -STATUS | wrapper | 2017/11/15 11:21:42 | Java Service Wrapper Community Edition 64-bit 3.5.21 -STATUS | wrapper | 2017/11/15 11:21:42 | Copyright (C) 1999-2013 Tanuki Software, Ltd. All Rights Reserved. -STATUS | wrapper | 2017/11/15 11:21:42 | http://wrapper.tanukisoftware.com -STATUS | wrapper | 2017/11/15 11:21:42 | -STATUS | wrapper | 2017/11/15 11:21:42 | Launching a JVM... -INFO | jvm 1 | 2017/11/15 11:21:42 | WrapperManager: Initializing... -INFO | jvm 1 | 2017/11/15 11:21:42 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 1 | 2017/11/15 11:21:42 | -INFO | jvm 1 | 2017/11/15 11:21:42 | WrapperSimpleApp Usage: -INFO | jvm 1 | 2017/11/15 11:21:42 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 1 | 2017/11/15 11:21:42 | -INFO | jvm 1 | 2017/11/15 11:21:42 | Where: -INFO | jvm 1 | 2017/11/15 11:21:42 | app_class: The fully qualified class name of the application to run. -INFO | jvm 1 | 2017/11/15 11:21:42 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 1 | 2017/11/15 11:21:42 | application. -ERROR | wrapper | 2017/11/15 11:21:44 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:21:49 | Launching a JVM... -INFO | jvm 2 | 2017/11/15 11:21:49 | WrapperManager: Initializing... -INFO | jvm 2 | 2017/11/15 11:21:49 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 2 | 2017/11/15 11:21:49 | -INFO | jvm 2 | 2017/11/15 11:21:49 | WrapperSimpleApp Usage: -INFO | jvm 2 | 2017/11/15 11:21:49 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 2 | 2017/11/15 11:21:49 | -INFO | jvm 2 | 2017/11/15 11:21:49 | Where: -INFO | jvm 2 | 2017/11/15 11:21:49 | app_class: The fully qualified class name of the application to run. -INFO | jvm 2 | 2017/11/15 11:21:49 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 2 | 2017/11/15 11:21:49 | application. -ERROR | wrapper | 2017/11/15 11:21:52 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:21:56 | Launching a JVM... -INFO | jvm 3 | 2017/11/15 11:21:56 | WrapperManager: Initializing... -INFO | jvm 3 | 2017/11/15 11:21:56 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 3 | 2017/11/15 11:21:56 | -INFO | jvm 3 | 2017/11/15 11:21:56 | WrapperSimpleApp Usage: -INFO | jvm 3 | 2017/11/15 11:21:56 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 3 | 2017/11/15 11:21:56 | -INFO | jvm 3 | 2017/11/15 11:21:56 | Where: -INFO | jvm 3 | 2017/11/15 11:21:56 | app_class: The fully qualified class name of the application to run. -INFO | jvm 3 | 2017/11/15 11:21:56 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 3 | 2017/11/15 11:21:56 | application. -ERROR | wrapper | 2017/11/15 11:21:59 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:22:03 | Launching a JVM... -INFO | jvm 4 | 2017/11/15 11:22:03 | WrapperManager: Initializing... -INFO | jvm 4 | 2017/11/15 11:22:04 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 4 | 2017/11/15 11:22:04 | -INFO | jvm 4 | 2017/11/15 11:22:04 | WrapperSimpleApp Usage: -INFO | jvm 4 | 2017/11/15 11:22:04 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 4 | 2017/11/15 11:22:04 | -INFO | jvm 4 | 2017/11/15 11:22:04 | Where: -INFO | jvm 4 | 2017/11/15 11:22:04 | app_class: The fully qualified class name of the application to run. -INFO | jvm 4 | 2017/11/15 11:22:04 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 4 | 2017/11/15 11:22:04 | application. -ERROR | wrapper | 2017/11/15 11:22:06 | JVM exited while loading the application. -STATUS | wrapper | 2017/11/15 11:22:10 | Launching a JVM... -INFO | jvm 5 | 2017/11/15 11:22:11 | WrapperManager: Initializing... -INFO | jvm 5 | 2017/11/15 11:22:11 | WrapperSimpleApp Error: Unable to locate the class org.springframework.boot.loader.JarLauncher : java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher -INFO | jvm 5 | 2017/11/15 11:22:11 | -INFO | jvm 5 | 2017/11/15 11:22:11 | WrapperSimpleApp Usage: -INFO | jvm 5 | 2017/11/15 11:22:11 | java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments] -INFO | jvm 5 | 2017/11/15 11:22:11 | -INFO | jvm 5 | 2017/11/15 11:22:11 | Where: -INFO | jvm 5 | 2017/11/15 11:22:11 | app_class: The fully qualified class name of the application to run. -INFO | jvm 5 | 2017/11/15 11:22:11 | app_arguments: The arguments that would normally be passed to the -INFO | jvm 5 | 2017/11/15 11:22:11 | application. -ERROR | wrapper | 2017/11/15 11:22:13 | JVM exited while loading the application. -FATAL | wrapper | 2017/11/15 11:22:13 | There were 5 failed launches in a row, each lasting less than 300 seconds. Giving up. -FATAL | wrapper | 2017/11/15 11:22:13 | There may be a configuration problem: please check the logs. -STATUS | wrapper | 2017/11/15 11:22:13 | <-- Wrapper Stopped diff --git a/src/main/java/bio/overture/ego/controller/PassportController.java b/src/main/java/bio/overture/ego/controller/PassportController.java new file mode 100644 index 000000000..2af638d89 --- /dev/null +++ b/src/main/java/bio/overture/ego/controller/PassportController.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bio.overture.ego.controller; + +import static org.springframework.http.HttpStatus.*; +import static org.springframework.web.bind.annotation.RequestMethod.*; + +import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.service.PassportService; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import lombok.NonNull; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@RestController +@RequestMapping("/passport") +@Tag(name = "Passport", description = "poassport-controller") +public class PassportController { + + private final PassportService passportService; + + @Autowired + public PassportController(@NonNull PassportService passportService) { + this.passportService = passportService; + } + + @RequestMapping(method = POST, value = "/passport/token") + @ResponseStatus(value = OK) + @SneakyThrows + public @ResponseBody List getVisaPermissions(@RequestBody String authToken) { + return passportService.getPermissions(authToken); + } +} diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 7a5fac08d..226262d03 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -3,16 +3,23 @@ import bio.overture.ego.model.dto.Passport; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.model.exceptions.InternalServerException; import bio.overture.ego.model.exceptions.InvalidTokenException; +import bio.overture.ego.token.signer.BrokerTokenSigner; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; +import lombok.val; import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -21,9 +28,7 @@ @Transactional public class PassportService { - @Value("${broker.token.config.public-key}") - private String publicKey; - + private final BrokerTokenSigner tokenSigner; /** Dependencies */ @Autowired private VisaService visaService; @@ -32,9 +37,11 @@ public class PassportService { @Autowired public PassportService( @NonNull VisaPermissionService visaPermissionService, - @NonNull VisaService visaService) { + @NonNull VisaService visaService, + @NonNull BrokerTokenSigner tokenSigner) { this.visaService = visaService; this.visaPermissionService = visaPermissionService; + this.tokenSigner = tokenSigner; } public List getPermissions(String authToken) throws JsonProcessingException { @@ -48,14 +55,27 @@ public List getPermissions(String authToken) throws JsonProcessi List visas = getVisas(parsedPassport); // Fetches visa permissions for extracted visas List visaPermissions = getVisaPermissions(visas); - // removes deuplicates from visaPermissions - // TO_DO : visaPermissions = deDupeVisaPermissions (visaPermissions); + // removes deduplicates from visaPermissions + visaPermissions = deDupeVisaPermissions(visaPermissions); return visaPermissions; } - // TO_DO : Validates passport token based on public key - private boolean isValidPassport(@NonNull Object passport) { - return true; + // Validates passport token based on public key + private boolean isValidPassport(@NonNull String authToken) { + Claims claims; + val tokenKey = + tokenSigner + .getEncodedPublicKey() + .orElseThrow(() -> new InternalServerException("Internal issue with token signer.")); + try { + claims = Jwts.parser().setSigningKey(tokenKey).parseClaimsJws(authToken).getBody(); + if (claims != null) { + return true; + } + } catch (Exception exception) { + throw new InvalidTokenException("The passport token received from broker is invalid"); + } + return false; } // Extracts Visas from parsed passport object @@ -65,9 +85,11 @@ private List getVisas(Passport passport) { .forEach( visaJwt -> { try { - Visa visa = visaService.parseVisa(visaJwt); - if (visa != null) { - visas.add(visa); + if (visaService.isValidVisa(visaJwt)) { + Visa visa = visaService.parseVisa(visaJwt); + if (visa != null) { + visas.add(visa); + } } } catch (JsonProcessingException e) { e.printStackTrace(); @@ -101,4 +123,11 @@ public Passport parsePassport(@NonNull String passportJwtToken) throws JsonProce String body = new String(base64Url.decode(base64EncodedBody)); return new ObjectMapper().readValue(body, Passport.class); } + + // Removes duplicates from the VisaPermissons List + private List deDupeVisaPermissions(List visaPermissions) { + Set permissionsSet = new HashSet(); + permissionsSet.addAll(visaPermissions); + return permissionsSet.stream().collect(Collectors.toList()); + } } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 0afe23ba1..907a833ce 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -33,8 +33,8 @@ public class VisaPermissionService extends AbstractNamedService { /** Constants */ - private static final VisaService.VisaConverter VISA_CONVERTER = - getMapper(VisaService.VisaConverter.class); + private static final VisaConverter VISA_CONVERTER = getMapper(VisaConverter.class); + + private final BrokerTokenSigner tokenSigner; /** Dependencies */ @Autowired private VisaRepository visaRepository; @@ -42,10 +48,12 @@ public class VisaService extends AbstractNamedService { @Autowired public VisaService( @NonNull VisaRepository visaRepository, - @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher) { + @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher, + @NonNull BrokerTokenSigner tokenSigner) { super(Visa.class, visaRepository); this.visaRepository = visaRepository; this.apiKeyEventsPublisher = apiKeyEventsPublisher; + this.tokenSigner = tokenSigner; } public Visa create(@NonNull VisaRequest createRequest) { @@ -78,6 +86,24 @@ public Visa parseVisa(@NonNull String visaJwtToken) throws JsonProcessingExcepti return new ObjectMapper().readValue(body, Visa.class); } + // Checks if the visa is a valid visa + public boolean isValidVisa(@NonNull String authToken) { + Claims claims; + val tokenKey = + tokenSigner + .getEncodedPublicKey() + .orElseThrow(() -> new InternalServerException("Internal issue with token signer.")); + try { + claims = Jwts.parser().setSigningKey(tokenKey).parseClaimsJws(authToken).getBody(); + if (claims != null) { + return true; + } + } catch (Exception exception) { + throw new InvalidTokenException("The passport token received from broker is invalid"); + } + return false; + } + public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } diff --git a/src/main/java/bio/overture/ego/token/signer/BrokerTokenSigner.java b/src/main/java/bio/overture/ego/token/signer/BrokerTokenSigner.java new file mode 100644 index 000000000..e0dfc53f7 --- /dev/null +++ b/src/main/java/bio/overture/ego/token/signer/BrokerTokenSigner.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bio.overture.ego.token.signer; + +import jakarta.annotation.PostConstruct; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.Optional; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@Profile("!jks") +public class BrokerTokenSigner { + + /* + Constants + */ + private static final String KEYFACTORY_TYPE = "RSA"; + /* + Dependencies + */ + @Value("${broker.token.private-key}") + private String encodedPrivKey; + + @Value("${broker.token.public-key}") + private String encodedPubKey; + + /* + Variables + */ + private KeyFactory keyFactory; + private PrivateKey privateKey; + private PublicKey publicKey; + + @PostConstruct + @SneakyThrows + private void init() { + keyFactory = KeyFactory.getInstance(KEYFACTORY_TYPE); + try { + val decodedpriv = Base64.getDecoder().decode(encodedPrivKey); + val decodedPub = Base64.getDecoder().decode(encodedPubKey); + X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(decodedPub); + PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(decodedpriv); + publicKey = keyFactory.generatePublic(pubKeySpec); + privateKey = keyFactory.generatePrivate(privKeySpec); + } catch (InvalidKeySpecException specEx) { + log.error("Error loading keys:{}", specEx); + } + } + + public Optional getKey() { + return Optional.of(privateKey); + } + + public Optional getKeyPair() { + return Optional.of(new KeyPair(publicKey, privateKey)); + } + + public Optional getEncodedPublicKey() { + if (publicKey != null) { + val b64 = Base64.getEncoder(); + String encodedKey = b64.encodeToString(publicKey.getEncoded()); + encodedKey = "-----BEGIN PUBLIC KEY-----\r\n" + encodedKey + "\r\n-----END PUBLIC KEY-----"; + return Optional.of(encodedKey); + } else { + return Optional.empty(); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9714fe865..a32c5810a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -204,8 +204,9 @@ initialization: broker: token: - config: - public-key: + issuer: http://localhost:8081 + private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSU6oy48sJW6xzqzOSU1dAvUUeFKQSBHsCf7wGWUGpOxEczhtFiiyx4YUJtg+fyvwWxa4wO3GnQLBPIxBHY8JsnvjQN2lsTUoLqMB9nGpwF617uA/S2igm1u+cDpfi82kbi6SG1Sg30PM047R6oxTRGDLLkeMRF1gRaTBM0HfSL0j6ccU5KPgwYsFLE2We6jeR56iYJGC2KYLH4v8rcc2jRAdMbUntHMtUByF9BPSW7elQnyQH5Qzr/o0b59XLKwnJFn2Bp2yviC8cdyTDyhQGna0e+oESQR1j6u3Ux/mOmm3slRXscA8sH+pHmOEAtjYVf/ww36U8uZv+ctBCJyFVAgMBAAECggEBALrEeJqAFUfWFCkSmdUSFKT0bW/svFUTjXgGnZy1ncz9GpENpMH3lQDQVibteKpYwcom+Cr0XlQ66VUcudPrDjcOY7vhuMfnSh1YWLYyM4IeRHtcUxDVkFoM+vEFNHLf2zIOqqbgmboW3iDVIurT7iRO7KxAe/YtWJL9aVqMtBn7Lu7S7OvAU4ji5iLIBxjl82JYA+9lu/aQ6YGaoZuSO7bcU8Sivi+DKAahqN9XMKiB1XpC+PpaS/aec2S7xIlTdzoDGxEALRGlMe+xBEeQTBVJHBWrRIDPoHLTREeRC/9Pp+1Y4Dz8hd5Bi0n8/5r/q0liD+0vtmjsdU4E2QrktYECgYEA73qWvhCYHPMREAFtwz1mpp9ZhDCW6SF+njG7fBKcjz8OLcy15LXiTGc268ewtQqTMjPQlm1n2C6hGccGAIlMibQJo3KZHlTs125FUzDpTVgdlei6vU7M+gmfRSZed00J6jC04/qMR1tnV3HME3np7eRTKTA6Ts+zBwEvkbCetSkCgYEA4NY5iSBO1ybouIecDdD15uI2ItLPCBNMzu7IiK7IygIzuf+SyKyjhtFSR4vEi0gScOM7UMlwCMOVU10e4nMDknIWCDG9iFvmIEkGHGxgRrN5hX1Wrq74wF212lvvagH1IVWSHa8cVpMe+UwKu5Q1h4yzuYt6Q9wPQ7Qtn5emBE0CgYB2syispMUA9GnsqQii0Xhj9nAEWaEzhOqhtrzbTs5TIkoA4Yr3BkBY5oAOdjhcRBWZuJ0XMrtaKCKqCEAtW+CYEKkGXvMOWcHbNkkeZwv8zkQ73dNRqhFnjgVn3RDNyV20uteueK23YNLkQP+KV89fnuCpdcIw9joiqq/NYuIHoQKBgB5WaZ8KH/lCA8babYEjv/pubZWXUl4plISbja17wBYZ4/bl+F1hhhMr7Wk//743dF2NG7TT6W0VTvHXr9IoaMP65uQmKgfbNpsGn294ZClGEFClz+t0KpZyTpZvL0fjibr8u+GLfkxkP5qt2wjif7KRlrKjklTTva+KAVn2cW1FAoGBAMkX9ekIwhx/7uY6ndxKl8ZMDerjr6MhV0b08hHp3RxHbYVbcpN0UKspoYvZVgHwP18xlDij8yWRE2fapwgi4m82ZmYlg0qqJmyqIU9vBB3Jow903h1KPQrkmQEZxJ/4H8yrbgVf2HT+WUfjTFgaDZRl01bI3YkydCw91/Ub9HU6 + public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lOqMuPLCVusc6szklNXQL1FHhSkEgR7An+8BllBqTsRHM4bRYosseGFCbYPn8r8FsWuMDtxp0CwTyMQR2PCbJ740DdpbE1KC6jAfZxqcBete7gP0tooJtbvnA6X4vNpG4ukhtUoN9DzNOO0eqMU0Rgyy5HjERdYEWkwTNB30i9I+nHFOSj4MGLBSxNlnuo3keeomCRgtimCx+L/K3HNo0QHTG1J7RzLVAchfQT0lu3pUJ8kB+UM6/6NG+fVyysJyRZ9gadsr4gvHHckw8oUBp2tHvqBEkEdY+rt1Mf5jppt7JUV7HAPLB/qR5jhALY2FX/8MN+lPLmb/nLQQichVQIDAQAB --- ############################################################################### # Profile - "jks" diff --git a/src/main/resources/dummy-data/reset-dummy-data.sh b/src/main/resources/dummy-data/reset-dummy-data.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/env_template.sh b/src/main/resources/scripts/env_template.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/jwt/export-pub-key.sh b/src/main/resources/scripts/jwt/export-pub-key.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/jwt/gen-key-pair.sh b/src/main/resources/scripts/jwt/gen-key-pair.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/jwt/gen-keystore.sh b/src/main/resources/scripts/jwt/gen-keystore.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/run.sh b/src/main/resources/scripts/run.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/start-server-iam.sh b/src/main/resources/scripts/start-server-iam.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/start-server-token.sh b/src/main/resources/scripts/start-server-token.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/start-server.sh b/src/main/resources/scripts/start-server.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/stop-server.sh b/src/main/resources/scripts/stop-server.sh old mode 100755 new mode 100644 diff --git a/src/main/resources/scripts/vault/setup-local-vault.sh b/src/main/resources/scripts/vault/setup-local-vault.sh old mode 100755 new mode 100644 From 735efa97ea769f9b7a18d8bae146e3aba0af9766 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 19 May 2023 04:09:40 -0400 Subject: [PATCH 24/43] Committing changes related to passport permissions --- src/main/bin/ego | 0 src/main/bin/wrapper-macosx-universal-64 | Bin .../java/bio/overture/ego/model/dto/Passport.java | 2 ++ .../bio/overture/ego/service/PassportService.java | 2 +- .../java/bio/overture/ego/service/VisaService.java | 2 +- src/main/resources/application.yml | 11 ++++++----- src/main/resources/dummy-data/reset-dummy-data.sh | 0 src/main/resources/scripts/env_template.sh | 0 src/main/resources/scripts/jwt/export-pub-key.sh | 0 src/main/resources/scripts/jwt/gen-key-pair.sh | 0 src/main/resources/scripts/jwt/gen-keystore.sh | 0 src/main/resources/scripts/run.sh | 0 src/main/resources/scripts/start-server-iam.sh | 0 src/main/resources/scripts/start-server-token.sh | 0 src/main/resources/scripts/start-server.sh | 0 src/main/resources/scripts/stop-server.sh | 0 .../resources/scripts/vault/setup-local-vault.sh | 0 17 files changed, 10 insertions(+), 7 deletions(-) mode change 100644 => 100755 src/main/bin/ego mode change 100644 => 100755 src/main/bin/wrapper-macosx-universal-64 mode change 100644 => 100755 src/main/resources/dummy-data/reset-dummy-data.sh mode change 100644 => 100755 src/main/resources/scripts/env_template.sh mode change 100644 => 100755 src/main/resources/scripts/jwt/export-pub-key.sh mode change 100644 => 100755 src/main/resources/scripts/jwt/gen-key-pair.sh mode change 100644 => 100755 src/main/resources/scripts/jwt/gen-keystore.sh mode change 100644 => 100755 src/main/resources/scripts/run.sh mode change 100644 => 100755 src/main/resources/scripts/start-server-iam.sh mode change 100644 => 100755 src/main/resources/scripts/start-server-token.sh mode change 100644 => 100755 src/main/resources/scripts/start-server.sh mode change 100644 => 100755 src/main/resources/scripts/stop-server.sh mode change 100644 => 100755 src/main/resources/scripts/vault/setup-local-vault.sh diff --git a/src/main/bin/ego b/src/main/bin/ego old mode 100644 new mode 100755 diff --git a/src/main/bin/wrapper-macosx-universal-64 b/src/main/bin/wrapper-macosx-universal-64 old mode 100644 new mode 100755 diff --git a/src/main/java/bio/overture/ego/model/dto/Passport.java b/src/main/java/bio/overture/ego/model/dto/Passport.java index a3bb8211e..154a1cd11 100644 --- a/src/main/java/bio/overture/ego/model/dto/Passport.java +++ b/src/main/java/bio/overture/ego/model/dto/Passport.java @@ -1,5 +1,6 @@ package bio.overture.ego.model.dto; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import java.util.List; @@ -12,6 +13,7 @@ @Builder @AllArgsConstructor @NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) public class Passport { @JsonProperty("sub") diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 226262d03..74b44541e 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -114,7 +114,7 @@ private List getVisaPermissions(List visas) { // Parse Passport token to extract the passport body public Passport parsePassport(@NonNull String passportJwtToken) throws JsonProcessingException { - String[] split_string = passportJwtToken.split("//."); + String[] split_string = passportJwtToken.split("\\."); String base64EncodedHeader = split_string[0]; String base64EncodedBody = split_string[1]; String base64EncodedSignature = split_string[2]; diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 50d1be0fa..b831804fc 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -76,7 +76,7 @@ public void delete(@NonNull UUID id) { // Parses Visa JWT token to convert into Visa Object public Visa parseVisa(@NonNull String visaJwtToken) throws JsonProcessingException { - String[] split_string = visaJwtToken.split("//."); + String[] split_string = visaJwtToken.split("\\."); String base64EncodedHeader = split_string[0]; String base64EncodedBody = split_string[1]; String base64EncodedSignature = split_string[2]; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a32c5810a..dfd99e769 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -184,6 +184,12 @@ token: private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSU6oy48sJW6xzqzOSU1dAvUUeFKQSBHsCf7wGWUGpOxEczhtFiiyx4YUJtg+fyvwWxa4wO3GnQLBPIxBHY8JsnvjQN2lsTUoLqMB9nGpwF617uA/S2igm1u+cDpfi82kbi6SG1Sg30PM047R6oxTRGDLLkeMRF1gRaTBM0HfSL0j6ccU5KPgwYsFLE2We6jeR56iYJGC2KYLH4v8rcc2jRAdMbUntHMtUByF9BPSW7elQnyQH5Qzr/o0b59XLKwnJFn2Bp2yviC8cdyTDyhQGna0e+oESQR1j6u3Ux/mOmm3slRXscA8sH+pHmOEAtjYVf/ww36U8uZv+ctBCJyFVAgMBAAECggEBALrEeJqAFUfWFCkSmdUSFKT0bW/svFUTjXgGnZy1ncz9GpENpMH3lQDQVibteKpYwcom+Cr0XlQ66VUcudPrDjcOY7vhuMfnSh1YWLYyM4IeRHtcUxDVkFoM+vEFNHLf2zIOqqbgmboW3iDVIurT7iRO7KxAe/YtWJL9aVqMtBn7Lu7S7OvAU4ji5iLIBxjl82JYA+9lu/aQ6YGaoZuSO7bcU8Sivi+DKAahqN9XMKiB1XpC+PpaS/aec2S7xIlTdzoDGxEALRGlMe+xBEeQTBVJHBWrRIDPoHLTREeRC/9Pp+1Y4Dz8hd5Bi0n8/5r/q0liD+0vtmjsdU4E2QrktYECgYEA73qWvhCYHPMREAFtwz1mpp9ZhDCW6SF+njG7fBKcjz8OLcy15LXiTGc268ewtQqTMjPQlm1n2C6hGccGAIlMibQJo3KZHlTs125FUzDpTVgdlei6vU7M+gmfRSZed00J6jC04/qMR1tnV3HME3np7eRTKTA6Ts+zBwEvkbCetSkCgYEA4NY5iSBO1ybouIecDdD15uI2ItLPCBNMzu7IiK7IygIzuf+SyKyjhtFSR4vEi0gScOM7UMlwCMOVU10e4nMDknIWCDG9iFvmIEkGHGxgRrN5hX1Wrq74wF212lvvagH1IVWSHa8cVpMe+UwKu5Q1h4yzuYt6Q9wPQ7Qtn5emBE0CgYB2syispMUA9GnsqQii0Xhj9nAEWaEzhOqhtrzbTs5TIkoA4Yr3BkBY5oAOdjhcRBWZuJ0XMrtaKCKqCEAtW+CYEKkGXvMOWcHbNkkeZwv8zkQ73dNRqhFnjgVn3RDNyV20uteueK23YNLkQP+KV89fnuCpdcIw9joiqq/NYuIHoQKBgB5WaZ8KH/lCA8babYEjv/pubZWXUl4plISbja17wBYZ4/bl+F1hhhMr7Wk//743dF2NG7TT6W0VTvHXr9IoaMP65uQmKgfbNpsGn294ZClGEFClz+t0KpZyTpZvL0fjibr8u+GLfkxkP5qt2wjif7KRlrKjklTTva+KAVn2cW1FAoGBAMkX9ekIwhx/7uY6ndxKl8ZMDerjr6MhV0b08hHp3RxHbYVbcpN0UKspoYvZVgHwP18xlDij8yWRE2fapwgi4m82ZmYlg0qqJmyqIU9vBB3Jow903h1KPQrkmQEZxJ/4H8yrbgVf2HT+WUfjTFgaDZRl01bI3YkydCw91/Ub9HU6 public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lOqMuPLCVusc6szklNXQL1FHhSkEgR7An+8BllBqTsRHM4bRYosseGFCbYPn8r8FsWuMDtxp0CwTyMQR2PCbJ740DdpbE1KC6jAfZxqcBete7gP0tooJtbvnA6X4vNpG4ukhtUoN9DzNOO0eqMU0Rgyy5HjERdYEWkwTNB30i9I+nHFOSj4MGLBSxNlnuo3keeomCRgtimCx+L/K3HNo0QHTG1J7RzLVAchfQT0lu3pUJ8kB+UM6/6NG+fVyysJyRZ9gadsr4gvHHckw8oUBp2tHvqBEkEdY+rt1Mf5jppt7JUV7HAPLB/qR5jhALY2FX/8MN+lPLmb/nLQQichVQIDAQAB +broker: + token: + issuer: http://localhost:8081 + private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSU6oy48sJW6xzqzOSU1dAvUUeFKQSBHsCf7wGWUGpOxEczhtFiiyx4YUJtg+fyvwWxa4wO3GnQLBPIxBHY8JsnvjQN2lsTUoLqMB9nGpwF617uA/S2igm1u+cDpfi82kbi6SG1Sg30PM047R6oxTRGDLLkeMRF1gRaTBM0HfSL0j6ccU5KPgwYsFLE2We6jeR56iYJGC2KYLH4v8rcc2jRAdMbUntHMtUByF9BPSW7elQnyQH5Qzr/o0b59XLKwnJFn2Bp2yviC8cdyTDyhQGna0e+oESQR1j6u3Ux/mOmm3slRXscA8sH+pHmOEAtjYVf/ww36U8uZv+ctBCJyFVAgMBAAECggEBALrEeJqAFUfWFCkSmdUSFKT0bW/svFUTjXgGnZy1ncz9GpENpMH3lQDQVibteKpYwcom+Cr0XlQ66VUcudPrDjcOY7vhuMfnSh1YWLYyM4IeRHtcUxDVkFoM+vEFNHLf2zIOqqbgmboW3iDVIurT7iRO7KxAe/YtWJL9aVqMtBn7Lu7S7OvAU4ji5iLIBxjl82JYA+9lu/aQ6YGaoZuSO7bcU8Sivi+DKAahqN9XMKiB1XpC+PpaS/aec2S7xIlTdzoDGxEALRGlMe+xBEeQTBVJHBWrRIDPoHLTREeRC/9Pp+1Y4Dz8hd5Bi0n8/5r/q0liD+0vtmjsdU4E2QrktYECgYEA73qWvhCYHPMREAFtwz1mpp9ZhDCW6SF+njG7fBKcjz8OLcy15LXiTGc268ewtQqTMjPQlm1n2C6hGccGAIlMibQJo3KZHlTs125FUzDpTVgdlei6vU7M+gmfRSZed00J6jC04/qMR1tnV3HME3np7eRTKTA6Ts+zBwEvkbCetSkCgYEA4NY5iSBO1ybouIecDdD15uI2ItLPCBNMzu7IiK7IygIzuf+SyKyjhtFSR4vEi0gScOM7UMlwCMOVU10e4nMDknIWCDG9iFvmIEkGHGxgRrN5hX1Wrq74wF212lvvagH1IVWSHa8cVpMe+UwKu5Q1h4yzuYt6Q9wPQ7Qtn5emBE0CgYB2syispMUA9GnsqQii0Xhj9nAEWaEzhOqhtrzbTs5TIkoA4Yr3BkBY5oAOdjhcRBWZuJ0XMrtaKCKqCEAtW+CYEKkGXvMOWcHbNkkeZwv8zkQ73dNRqhFnjgVn3RDNyV20uteueK23YNLkQP+KV89fnuCpdcIw9joiqq/NYuIHoQKBgB5WaZ8KH/lCA8babYEjv/pubZWXUl4plISbja17wBYZ4/bl+F1hhhMr7Wk//743dF2NG7TT6W0VTvHXr9IoaMP65uQmKgfbNpsGn294ZClGEFClz+t0KpZyTpZvL0fjibr8u+GLfkxkP5qt2wjif7KRlrKjklTTva+KAVn2cW1FAoGBAMkX9ekIwhx/7uY6ndxKl8ZMDerjr6MhV0b08hHp3RxHbYVbcpN0UKspoYvZVgHwP18xlDij8yWRE2fapwgi4m82ZmYlg0qqJmyqIU9vBB3Jow903h1KPQrkmQEZxJ/4H8yrbgVf2HT+WUfjTFgaDZRl01bI3YkydCw91/Ub9HU6 + public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lOqMuPLCVusc6szklNXQL1FHhSkEgR7An+8BllBqTsRHM4bRYosseGFCbYPn8r8FsWuMDtxp0CwTyMQR2PCbJ740DdpbE1KC6jAfZxqcBete7gP0tooJtbvnA6X4vNpG4ukhtUoN9DzNOO0eqMU0Rgyy5HjERdYEWkwTNB30i9I+nHFOSj4MGLBSxNlnuo3keeomCRgtimCx+L/K3HNo0QHTG1J7RzLVAchfQT0lu3pUJ8kB+UM6/6NG+fVyysJyRZ9gadsr4gvHHckw8oUBp2tHvqBEkEdY+rt1Mf5jppt7JUV7HAPLB/qR5jhALY2FX/8MN+lPLmb/nLQQichVQIDAQAB + # Default values available for creation of entities default: user: @@ -202,11 +208,6 @@ initialization: redirectUri: https://example.org # optional description: Some description about this application # optional -broker: - token: - issuer: http://localhost:8081 - private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSU6oy48sJW6xzqzOSU1dAvUUeFKQSBHsCf7wGWUGpOxEczhtFiiyx4YUJtg+fyvwWxa4wO3GnQLBPIxBHY8JsnvjQN2lsTUoLqMB9nGpwF617uA/S2igm1u+cDpfi82kbi6SG1Sg30PM047R6oxTRGDLLkeMRF1gRaTBM0HfSL0j6ccU5KPgwYsFLE2We6jeR56iYJGC2KYLH4v8rcc2jRAdMbUntHMtUByF9BPSW7elQnyQH5Qzr/o0b59XLKwnJFn2Bp2yviC8cdyTDyhQGna0e+oESQR1j6u3Ux/mOmm3slRXscA8sH+pHmOEAtjYVf/ww36U8uZv+ctBCJyFVAgMBAAECggEBALrEeJqAFUfWFCkSmdUSFKT0bW/svFUTjXgGnZy1ncz9GpENpMH3lQDQVibteKpYwcom+Cr0XlQ66VUcudPrDjcOY7vhuMfnSh1YWLYyM4IeRHtcUxDVkFoM+vEFNHLf2zIOqqbgmboW3iDVIurT7iRO7KxAe/YtWJL9aVqMtBn7Lu7S7OvAU4ji5iLIBxjl82JYA+9lu/aQ6YGaoZuSO7bcU8Sivi+DKAahqN9XMKiB1XpC+PpaS/aec2S7xIlTdzoDGxEALRGlMe+xBEeQTBVJHBWrRIDPoHLTREeRC/9Pp+1Y4Dz8hd5Bi0n8/5r/q0liD+0vtmjsdU4E2QrktYECgYEA73qWvhCYHPMREAFtwz1mpp9ZhDCW6SF+njG7fBKcjz8OLcy15LXiTGc268ewtQqTMjPQlm1n2C6hGccGAIlMibQJo3KZHlTs125FUzDpTVgdlei6vU7M+gmfRSZed00J6jC04/qMR1tnV3HME3np7eRTKTA6Ts+zBwEvkbCetSkCgYEA4NY5iSBO1ybouIecDdD15uI2ItLPCBNMzu7IiK7IygIzuf+SyKyjhtFSR4vEi0gScOM7UMlwCMOVU10e4nMDknIWCDG9iFvmIEkGHGxgRrN5hX1Wrq74wF212lvvagH1IVWSHa8cVpMe+UwKu5Q1h4yzuYt6Q9wPQ7Qtn5emBE0CgYB2syispMUA9GnsqQii0Xhj9nAEWaEzhOqhtrzbTs5TIkoA4Yr3BkBY5oAOdjhcRBWZuJ0XMrtaKCKqCEAtW+CYEKkGXvMOWcHbNkkeZwv8zkQ73dNRqhFnjgVn3RDNyV20uteueK23YNLkQP+KV89fnuCpdcIw9joiqq/NYuIHoQKBgB5WaZ8KH/lCA8babYEjv/pubZWXUl4plISbja17wBYZ4/bl+F1hhhMr7Wk//743dF2NG7TT6W0VTvHXr9IoaMP65uQmKgfbNpsGn294ZClGEFClz+t0KpZyTpZvL0fjibr8u+GLfkxkP5qt2wjif7KRlrKjklTTva+KAVn2cW1FAoGBAMkX9ekIwhx/7uY6ndxKl8ZMDerjr6MhV0b08hHp3RxHbYVbcpN0UKspoYvZVgHwP18xlDij8yWRE2fapwgi4m82ZmYlg0qqJmyqIU9vBB3Jow903h1KPQrkmQEZxJ/4H8yrbgVf2HT+WUfjTFgaDZRl01bI3YkydCw91/Ub9HU6 - public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lOqMuPLCVusc6szklNXQL1FHhSkEgR7An+8BllBqTsRHM4bRYosseGFCbYPn8r8FsWuMDtxp0CwTyMQR2PCbJ740DdpbE1KC6jAfZxqcBete7gP0tooJtbvnA6X4vNpG4ukhtUoN9DzNOO0eqMU0Rgyy5HjERdYEWkwTNB30i9I+nHFOSj4MGLBSxNlnuo3keeomCRgtimCx+L/K3HNo0QHTG1J7RzLVAchfQT0lu3pUJ8kB+UM6/6NG+fVyysJyRZ9gadsr4gvHHckw8oUBp2tHvqBEkEdY+rt1Mf5jppt7JUV7HAPLB/qR5jhALY2FX/8MN+lPLmb/nLQQichVQIDAQAB --- ############################################################################### # Profile - "jks" diff --git a/src/main/resources/dummy-data/reset-dummy-data.sh b/src/main/resources/dummy-data/reset-dummy-data.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/env_template.sh b/src/main/resources/scripts/env_template.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/jwt/export-pub-key.sh b/src/main/resources/scripts/jwt/export-pub-key.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/jwt/gen-key-pair.sh b/src/main/resources/scripts/jwt/gen-key-pair.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/jwt/gen-keystore.sh b/src/main/resources/scripts/jwt/gen-keystore.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/run.sh b/src/main/resources/scripts/run.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/start-server-iam.sh b/src/main/resources/scripts/start-server-iam.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/start-server-token.sh b/src/main/resources/scripts/start-server-token.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/start-server.sh b/src/main/resources/scripts/start-server.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/stop-server.sh b/src/main/resources/scripts/stop-server.sh old mode 100644 new mode 100755 diff --git a/src/main/resources/scripts/vault/setup-local-vault.sh b/src/main/resources/scripts/vault/setup-local-vault.sh old mode 100644 new mode 100755 From b10799a672daa68473f7dd20699eddae08618ad4 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 19 May 2023 04:14:32 -0400 Subject: [PATCH 25/43] Committing changes related to passport permissions --- .../ego/controller/PassportController.java | 51 ------------------- 1 file changed, 51 deletions(-) delete mode 100644 src/main/java/bio/overture/ego/controller/PassportController.java diff --git a/src/main/java/bio/overture/ego/controller/PassportController.java b/src/main/java/bio/overture/ego/controller/PassportController.java deleted file mode 100644 index 2af638d89..000000000 --- a/src/main/java/bio/overture/ego/controller/PassportController.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bio.overture.ego.controller; - -import static org.springframework.http.HttpStatus.*; -import static org.springframework.web.bind.annotation.RequestMethod.*; - -import bio.overture.ego.model.entity.VisaPermission; -import bio.overture.ego.service.PassportService; -import io.swagger.v3.oas.annotations.tags.Tag; -import java.util.List; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -@Slf4j -@RestController -@RequestMapping("/passport") -@Tag(name = "Passport", description = "poassport-controller") -public class PassportController { - - private final PassportService passportService; - - @Autowired - public PassportController(@NonNull PassportService passportService) { - this.passportService = passportService; - } - - @RequestMapping(method = POST, value = "/passport/token") - @ResponseStatus(value = OK) - @SneakyThrows - public @ResponseBody List getVisaPermissions(@RequestBody String authToken) { - return passportService.getPermissions(authToken); - } -} From ad7789b05616dd8bdfd9ff8ee80e4369f3c9b25a Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 19 May 2023 05:16:36 -0400 Subject: [PATCH 26/43] Committing changes related to passport visa --- .../ego/controller/PassportController.java | 51 +++++++++++++++++++ .../overture/ego/model/dto/Ga4ghVisaV1.java | 31 +++++++++++ .../bio/overture/ego/model/dto/Passport.java | 9 +--- .../overture/ego/model/dto/PassportVisa.java | 34 +++++++++++++ .../overture/ego/service/PassportService.java | 28 +++++----- .../ego/service/VisaPermissionService.java | 4 -- .../bio/overture/ego/service/VisaService.java | 7 +-- 7 files changed, 134 insertions(+), 30 deletions(-) create mode 100644 src/main/java/bio/overture/ego/controller/PassportController.java create mode 100644 src/main/java/bio/overture/ego/model/dto/Ga4ghVisaV1.java create mode 100644 src/main/java/bio/overture/ego/model/dto/PassportVisa.java diff --git a/src/main/java/bio/overture/ego/controller/PassportController.java b/src/main/java/bio/overture/ego/controller/PassportController.java new file mode 100644 index 000000000..2af638d89 --- /dev/null +++ b/src/main/java/bio/overture/ego/controller/PassportController.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bio.overture.ego.controller; + +import static org.springframework.http.HttpStatus.*; +import static org.springframework.web.bind.annotation.RequestMethod.*; + +import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.service.PassportService; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import lombok.NonNull; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@RestController +@RequestMapping("/passport") +@Tag(name = "Passport", description = "poassport-controller") +public class PassportController { + + private final PassportService passportService; + + @Autowired + public PassportController(@NonNull PassportService passportService) { + this.passportService = passportService; + } + + @RequestMapping(method = POST, value = "/passport/token") + @ResponseStatus(value = OK) + @SneakyThrows + public @ResponseBody List getVisaPermissions(@RequestBody String authToken) { + return passportService.getPermissions(authToken); + } +} diff --git a/src/main/java/bio/overture/ego/model/dto/Ga4ghVisaV1.java b/src/main/java/bio/overture/ego/model/dto/Ga4ghVisaV1.java new file mode 100644 index 000000000..11c1bdc52 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/Ga4ghVisaV1.java @@ -0,0 +1,31 @@ +package bio.overture.ego.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class Ga4ghVisaV1 { + + @JsonProperty("asserted") + private int asserted; + + @JsonProperty("by") + private String by; + + @JsonProperty("source") + private Object source; + + @JsonProperty("type") + private String type; + + @JsonProperty("value") + private String value; +} diff --git a/src/main/java/bio/overture/ego/model/dto/Passport.java b/src/main/java/bio/overture/ego/model/dto/Passport.java index 154a1cd11..36ed9a561 100644 --- a/src/main/java/bio/overture/ego/model/dto/Passport.java +++ b/src/main/java/bio/overture/ego/model/dto/Passport.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotNull; import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; @@ -17,26 +16,20 @@ public class Passport { @JsonProperty("sub") - @NotNull private String sub; @JsonProperty("iss") - @NotNull private String iss; @JsonProperty("exp") - @NotNull - private int exp; + private long exp; @JsonProperty("iat") - @NotNull private int iat; @JsonProperty("ga4gh_passport_v1") - @NotNull private List ga4ghPassportV1; @JsonProperty("jti") - @NotNull private String jti; } diff --git a/src/main/java/bio/overture/ego/model/dto/PassportVisa.java b/src/main/java/bio/overture/ego/model/dto/PassportVisa.java new file mode 100644 index 000000000..3afe19857 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/PassportVisa.java @@ -0,0 +1,34 @@ +package bio.overture.ego.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class PassportVisa { + + @JsonProperty("sub") + private String sub; + + @JsonProperty("ga4gh_visa_v1") + private Ga4ghVisaV1 ga4ghVisaV1; + + @JsonProperty("iss") + private String iss; + + @JsonProperty("exp") + private long exp; + + @JsonProperty("iat") + private int iat; + + @JsonProperty("jti") + private String jti; +} diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 74b44541e..690c04aee 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -1,6 +1,7 @@ package bio.overture.ego.service; import bio.overture.ego.model.dto.Passport; +import bio.overture.ego.model.dto.PassportVisa; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; import bio.overture.ego.model.exceptions.InternalServerException; @@ -10,10 +11,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -52,7 +50,7 @@ public List getPermissions(String authToken) throws JsonProcessi // Parses passport JWT token Passport parsedPassport = parsePassport(authToken); // Fetches visas for parsed passport - List visas = getVisas(parsedPassport); + List visas = getVisas(parsedPassport); // Fetches visa permissions for extracted visas List visaPermissions = getVisaPermissions(visas); // removes deduplicates from visaPermissions @@ -79,17 +77,17 @@ private boolean isValidPassport(@NonNull String authToken) { } // Extracts Visas from parsed passport object - private List getVisas(Passport passport) { - List visas = new ArrayList<>(); + private List getVisas(Passport passport) { + List visas = new ArrayList<>(); passport.getGa4ghPassportV1().stream() .forEach( visaJwt -> { try { if (visaService.isValidVisa(visaJwt)) { - Visa visa = visaService.parseVisa(visaJwt); - if (visa != null) { - visas.add(visa); - } + PassportVisa visa = visaService.parseVisa(visaJwt); + if (visa != null) { + visas.add(visa); + } } } catch (JsonProcessingException e) { e.printStackTrace(); @@ -99,15 +97,15 @@ private List getVisas(Passport passport) { } // Fetches Visa Permissions for extracted Visa list - private List getVisaPermissions(List visas) { + private List getVisaPermissions(List visas) { List visaPermissions = new ArrayList<>(); visas.stream() .distinct() .forEach( visa -> { - if (visaService.getById(visa.getId()) != null) { - visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visa)); - } + Visa visaEntity = new Visa(); + visaEntity.setId(UUID.fromString(visa.getJti())); + visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visaEntity)); }); return visaPermissions; } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 907a833ce..d30d319e5 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -97,10 +97,6 @@ public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { // Fetches visa permissions for given visa request public List getPermissionsForVisa(@NonNull Visa visa) { val result = (List) visaPermissionRepository.findByVisa_Id(visa.getId()); - if (result.isEmpty()) { - throw new NotFoundException( - format("No VisaPermissions exists with visaId '%s'", visa.getId())); - } return result; } diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index b831804fc..b4b003611 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -5,6 +5,7 @@ import static org.mapstruct.factory.Mappers.getMapper; import bio.overture.ego.event.token.ApiKeyEventsPublisher; +import bio.overture.ego.model.dto.PassportVisa; import bio.overture.ego.model.dto.VisaRequest; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.exceptions.InternalServerException; @@ -75,7 +76,7 @@ public void delete(@NonNull UUID id) { } // Parses Visa JWT token to convert into Visa Object - public Visa parseVisa(@NonNull String visaJwtToken) throws JsonProcessingException { + public PassportVisa parseVisa(@NonNull String visaJwtToken) throws JsonProcessingException { String[] split_string = visaJwtToken.split("\\."); String base64EncodedHeader = split_string[0]; String base64EncodedBody = split_string[1]; @@ -83,7 +84,7 @@ public Visa parseVisa(@NonNull String visaJwtToken) throws JsonProcessingExcepti Base64 base64Url = new Base64(true); String header = new String(base64Url.decode(base64EncodedHeader)); String body = new String(base64Url.decode(base64EncodedBody)); - return new ObjectMapper().readValue(body, Visa.class); + return new ObjectMapper().readValue(body, PassportVisa.class); } // Checks if the visa is a valid visa @@ -99,7 +100,7 @@ public boolean isValidVisa(@NonNull String authToken) { return true; } } catch (Exception exception) { - throw new InvalidTokenException("The passport token received from broker is invalid"); + throw new InvalidTokenException("The visa token received from broker is invalid"); } return false; } From 91903192fa1ac57599bed9a7a84286e7cbaf67d3 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 19 May 2023 05:35:42 -0400 Subject: [PATCH 27/43] Committing changes related to passport visa --- pom.xml | 10 +++++----- .../java/bio/overture/ego/service/PassportService.java | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index b97fcaab5..e334304d5 100644 --- a/pom.xml +++ b/pom.xml @@ -401,16 +401,16 @@ protobuf-maven-plugin 0.6.1 - com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} + - + com.google.protobuf:protoc:3.21.7:exe:osx-x86_64 ${basedir}/src/main/proto grpc-java - io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier} + - + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:osx-x86_64 - + compile diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 690c04aee..6fddf92fe 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -44,9 +44,9 @@ public PassportService( public List getPermissions(String authToken) throws JsonProcessingException { // Validates passport auth token - if (!isValidPassport(authToken)) { + /*if (!isValidPassport(authToken)) { throw new InvalidTokenException("The passport token received from broker is invalid"); - } + }*/ // Parses passport JWT token Passport parsedPassport = parsePassport(authToken); // Fetches visas for parsed passport From 4b71a1f8054193094bffdfdc037e62b5ea4ece12 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Fri, 19 May 2023 12:56:43 -0400 Subject: [PATCH 28/43] Update application.yml The private/public key mentioned in the git repo was a dummy one, which was used during testing. As per the requested change, public/private keys are removed from the application.yaml --- src/main/resources/application.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index dfd99e769..27bf7b3f6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -187,9 +187,8 @@ token: broker: token: issuer: http://localhost:8081 - private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSU6oy48sJW6xzqzOSU1dAvUUeFKQSBHsCf7wGWUGpOxEczhtFiiyx4YUJtg+fyvwWxa4wO3GnQLBPIxBHY8JsnvjQN2lsTUoLqMB9nGpwF617uA/S2igm1u+cDpfi82kbi6SG1Sg30PM047R6oxTRGDLLkeMRF1gRaTBM0HfSL0j6ccU5KPgwYsFLE2We6jeR56iYJGC2KYLH4v8rcc2jRAdMbUntHMtUByF9BPSW7elQnyQH5Qzr/o0b59XLKwnJFn2Bp2yviC8cdyTDyhQGna0e+oESQR1j6u3Ux/mOmm3slRXscA8sH+pHmOEAtjYVf/ww36U8uZv+ctBCJyFVAgMBAAECggEBALrEeJqAFUfWFCkSmdUSFKT0bW/svFUTjXgGnZy1ncz9GpENpMH3lQDQVibteKpYwcom+Cr0XlQ66VUcudPrDjcOY7vhuMfnSh1YWLYyM4IeRHtcUxDVkFoM+vEFNHLf2zIOqqbgmboW3iDVIurT7iRO7KxAe/YtWJL9aVqMtBn7Lu7S7OvAU4ji5iLIBxjl82JYA+9lu/aQ6YGaoZuSO7bcU8Sivi+DKAahqN9XMKiB1XpC+PpaS/aec2S7xIlTdzoDGxEALRGlMe+xBEeQTBVJHBWrRIDPoHLTREeRC/9Pp+1Y4Dz8hd5Bi0n8/5r/q0liD+0vtmjsdU4E2QrktYECgYEA73qWvhCYHPMREAFtwz1mpp9ZhDCW6SF+njG7fBKcjz8OLcy15LXiTGc268ewtQqTMjPQlm1n2C6hGccGAIlMibQJo3KZHlTs125FUzDpTVgdlei6vU7M+gmfRSZed00J6jC04/qMR1tnV3HME3np7eRTKTA6Ts+zBwEvkbCetSkCgYEA4NY5iSBO1ybouIecDdD15uI2ItLPCBNMzu7IiK7IygIzuf+SyKyjhtFSR4vEi0gScOM7UMlwCMOVU10e4nMDknIWCDG9iFvmIEkGHGxgRrN5hX1Wrq74wF212lvvagH1IVWSHa8cVpMe+UwKu5Q1h4yzuYt6Q9wPQ7Qtn5emBE0CgYB2syispMUA9GnsqQii0Xhj9nAEWaEzhOqhtrzbTs5TIkoA4Yr3BkBY5oAOdjhcRBWZuJ0XMrtaKCKqCEAtW+CYEKkGXvMOWcHbNkkeZwv8zkQ73dNRqhFnjgVn3RDNyV20uteueK23YNLkQP+KV89fnuCpdcIw9joiqq/NYuIHoQKBgB5WaZ8KH/lCA8babYEjv/pubZWXUl4plISbja17wBYZ4/bl+F1hhhMr7Wk//743dF2NG7TT6W0VTvHXr9IoaMP65uQmKgfbNpsGn294ZClGEFClz+t0KpZyTpZvL0fjibr8u+GLfkxkP5qt2wjif7KRlrKjklTTva+KAVn2cW1FAoGBAMkX9ekIwhx/7uY6ndxKl8ZMDerjr6MhV0b08hHp3RxHbYVbcpN0UKspoYvZVgHwP18xlDij8yWRE2fapwgi4m82ZmYlg0qqJmyqIU9vBB3Jow903h1KPQrkmQEZxJ/4H8yrbgVf2HT+WUfjTFgaDZRl01bI3YkydCw91/Ub9HU6 - public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lOqMuPLCVusc6szklNXQL1FHhSkEgR7An+8BllBqTsRHM4bRYosseGFCbYPn8r8FsWuMDtxp0CwTyMQR2PCbJ740DdpbE1KC6jAfZxqcBete7gP0tooJtbvnA6X4vNpG4ukhtUoN9DzNOO0eqMU0Rgyy5HjERdYEWkwTNB30i9I+nHFOSj4MGLBSxNlnuo3keeomCRgtimCx+L/K3HNo0QHTG1J7RzLVAchfQT0lu3pUJ8kB+UM6/6NG+fVyysJyRZ9gadsr4gvHHckw8oUBp2tHvqBEkEdY+rt1Mf5jppt7JUV7HAPLB/qR5jhALY2FX/8MN+lPLmb/nLQQichVQIDAQAB - + private-key: + public-key: # Default values available for creation of entities default: user: From 029a9ce434bd682ba08abbfadb28a30efdd54412 Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Tue, 23 May 2023 12:18:22 -0400 Subject: [PATCH 29/43] update Spring Cloud Vault dependencies --- pom.xml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b97fcaab5..420023c60 100644 --- a/pom.xml +++ b/pom.xml @@ -239,7 +239,12 @@ org.springframework.cloud spring-cloud-starter-vault-config - 2.1.2.RELEASE + 4.0.1 + + + org.springframework.cloud + spring-cloud-starter-bootstrap + 4.0.1 org.springframework.cloud @@ -448,8 +453,7 @@ org.springframework.cloud spring-cloud-dependencies - - 2021.0.5 + 2022.0.2 pom import From 7b30c9b8ac704c5f4d11e3ae6fd8738fea6de5f0 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Tue, 23 May 2023 16:04:35 -0400 Subject: [PATCH 30/43] Committing changes related to caching broker public key --- pom.xml | 10 +- .../ego/AuthorizationServiceMain.java | 2 + .../ego/controller/PassportController.java | 2 +- .../overture/ego/service/PassportService.java | 258 +++++++++-------- .../ego/service/VisaPermissionService.java | 240 ++++++++-------- .../bio/overture/ego/service/VisaService.java | 260 +++++++++--------- .../ego/token/signer/BrokerTokenSigner.java | 92 ------- .../bio/overture/ego/utils/CacheUtil.java | 48 ++++ src/main/resources/application.yml | 6 +- 9 files changed, 434 insertions(+), 484 deletions(-) delete mode 100644 src/main/java/bio/overture/ego/token/signer/BrokerTokenSigner.java create mode 100644 src/main/java/bio/overture/ego/utils/CacheUtil.java diff --git a/pom.xml b/pom.xml index e334304d5..b97fcaab5 100644 --- a/pom.xml +++ b/pom.xml @@ -401,16 +401,16 @@ protobuf-maven-plugin 0.6.1 - + com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} - com.google.protobuf:protoc:3.21.7:exe:osx-x86_64 + ${basedir}/src/main/proto grpc-java - + io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier} - io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:osx-x86_64 + - + compile diff --git a/src/main/java/bio/overture/ego/AuthorizationServiceMain.java b/src/main/java/bio/overture/ego/AuthorizationServiceMain.java index 1fbc9b94a..9ef972a81 100644 --- a/src/main/java/bio/overture/ego/AuthorizationServiceMain.java +++ b/src/main/java/bio/overture/ego/AuthorizationServiceMain.java @@ -18,8 +18,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication +@EnableCaching public class AuthorizationServiceMain { public static void main(String[] args) { diff --git a/src/main/java/bio/overture/ego/controller/PassportController.java b/src/main/java/bio/overture/ego/controller/PassportController.java index 2af638d89..bb2a042bf 100644 --- a/src/main/java/bio/overture/ego/controller/PassportController.java +++ b/src/main/java/bio/overture/ego/controller/PassportController.java @@ -32,7 +32,7 @@ @Slf4j @RestController @RequestMapping("/passport") -@Tag(name = "Passport", description = "poassport-controller") +@Tag(name = "Passport", description = "passport-controller") public class PassportController { private final PassportService passportService; diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 6fddf92fe..106e79b82 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -1,131 +1,127 @@ -package bio.overture.ego.service; - -import bio.overture.ego.model.dto.Passport; -import bio.overture.ego.model.dto.PassportVisa; -import bio.overture.ego.model.entity.Visa; -import bio.overture.ego.model.entity.VisaPermission; -import bio.overture.ego.model.exceptions.InternalServerException; -import bio.overture.ego.model.exceptions.InvalidTokenException; -import bio.overture.ego.token.signer.BrokerTokenSigner; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import java.util.*; -import java.util.stream.Collectors; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import lombok.val; -import org.apache.commons.codec.binary.Base64; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Slf4j -@Service -@Transactional -public class PassportService { - - private final BrokerTokenSigner tokenSigner; - /** Dependencies */ - @Autowired private VisaService visaService; - - @Autowired private VisaPermissionService visaPermissionService; - - @Autowired - public PassportService( - @NonNull VisaPermissionService visaPermissionService, - @NonNull VisaService visaService, - @NonNull BrokerTokenSigner tokenSigner) { - this.visaService = visaService; - this.visaPermissionService = visaPermissionService; - this.tokenSigner = tokenSigner; - } - - public List getPermissions(String authToken) throws JsonProcessingException { - // Validates passport auth token - /*if (!isValidPassport(authToken)) { - throw new InvalidTokenException("The passport token received from broker is invalid"); - }*/ - // Parses passport JWT token - Passport parsedPassport = parsePassport(authToken); - // Fetches visas for parsed passport - List visas = getVisas(parsedPassport); - // Fetches visa permissions for extracted visas - List visaPermissions = getVisaPermissions(visas); - // removes deduplicates from visaPermissions - visaPermissions = deDupeVisaPermissions(visaPermissions); - return visaPermissions; - } - - // Validates passport token based on public key - private boolean isValidPassport(@NonNull String authToken) { - Claims claims; - val tokenKey = - tokenSigner - .getEncodedPublicKey() - .orElseThrow(() -> new InternalServerException("Internal issue with token signer.")); - try { - claims = Jwts.parser().setSigningKey(tokenKey).parseClaimsJws(authToken).getBody(); - if (claims != null) { - return true; - } - } catch (Exception exception) { - throw new InvalidTokenException("The passport token received from broker is invalid"); - } - return false; - } - - // Extracts Visas from parsed passport object - private List getVisas(Passport passport) { - List visas = new ArrayList<>(); - passport.getGa4ghPassportV1().stream() - .forEach( - visaJwt -> { - try { - if (visaService.isValidVisa(visaJwt)) { - PassportVisa visa = visaService.parseVisa(visaJwt); - if (visa != null) { - visas.add(visa); - } - } - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - }); - return visas; - } - - // Fetches Visa Permissions for extracted Visa list - private List getVisaPermissions(List visas) { - List visaPermissions = new ArrayList<>(); - visas.stream() - .distinct() - .forEach( - visa -> { - Visa visaEntity = new Visa(); - visaEntity.setId(UUID.fromString(visa.getJti())); - visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visaEntity)); - }); - return visaPermissions; - } - - // Parse Passport token to extract the passport body - public Passport parsePassport(@NonNull String passportJwtToken) throws JsonProcessingException { - String[] split_string = passportJwtToken.split("\\."); - String base64EncodedHeader = split_string[0]; - String base64EncodedBody = split_string[1]; - String base64EncodedSignature = split_string[2]; - Base64 base64Url = new Base64(true); - String header = new String(base64Url.decode(base64EncodedHeader)); - String body = new String(base64Url.decode(base64EncodedBody)); - return new ObjectMapper().readValue(body, Passport.class); - } - - // Removes duplicates from the VisaPermissons List - private List deDupeVisaPermissions(List visaPermissions) { - Set permissionsSet = new HashSet(); - permissionsSet.addAll(visaPermissions); - return permissionsSet.stream().collect(Collectors.toList()); - } -} +package bio.overture.ego.service; + +import bio.overture.ego.model.dto.Passport; +import bio.overture.ego.model.dto.PassportVisa; +import bio.overture.ego.model.entity.Visa; +import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.model.exceptions.InvalidTokenException; +import bio.overture.ego.utils.CacheUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import java.util.*; +import java.util.stream.Collectors; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@Transactional +public class PassportService { + + /** Dependencies */ + @Autowired private VisaService visaService; + + @Autowired private VisaPermissionService visaPermissionService; + + @Autowired private CacheUtil cacheUtil; + + @Autowired + public PassportService( + @NonNull VisaPermissionService visaPermissionService, @NonNull VisaService visaService) { + this.visaService = visaService; + this.visaPermissionService = visaPermissionService; + } + + public List getPermissions(String authToken) throws JsonProcessingException { + // Validates passport auth token + if (!isValidPassport(authToken)) { + throw new InvalidTokenException("The passport token received from broker is invalid"); + } + // Parses passport JWT token + Passport parsedPassport = parsePassport(authToken); + // Fetches visas for parsed passport + List visas = getVisas(parsedPassport); + // Fetches visa permissions for extracted visas + List visaPermissions = getVisaPermissions(visas); + // removes deduplicates from visaPermissions + visaPermissions = deDupeVisaPermissions(visaPermissions); + return visaPermissions; + } + + // Validates passport token based on public key + private boolean isValidPassport(@NonNull String authToken) { + Claims claims; + try { + claims = + Jwts.parser() + .setSigningKey(cacheUtil.getPassportBrokerPublicKey()) + .parseClaimsJws(authToken) + .getBody(); + if (claims != null) { + return true; + } + } catch (Exception exception) { + throw new InvalidTokenException("The passport token received from broker is invalid"); + } + return false; + } + + // Extracts Visas from parsed passport object + private List getVisas(Passport passport) { + List visas = new ArrayList<>(); + passport.getGa4ghPassportV1().stream() + .forEach( + visaJwt -> { + try { + if (visaService.isValidVisa(visaJwt)) { + PassportVisa visa = visaService.parseVisa(visaJwt); + if (visa != null) { + visas.add(visa); + } + } + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + }); + return visas; + } + + // Fetches Visa Permissions for extracted Visa list + private List getVisaPermissions(List visas) { + List visaPermissions = new ArrayList<>(); + visas.stream() + .distinct() + .forEach( + visa -> { + Visa visaEntity = new Visa(); + visaEntity.setId(UUID.fromString(visa.getJti())); + visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visaEntity)); + }); + return visaPermissions; + } + + // Parse Passport token to extract the passport body + public Passport parsePassport(@NonNull String passportJwtToken) throws JsonProcessingException { + String[] split_string = passportJwtToken.split("\\."); + String base64EncodedHeader = split_string[0]; + String base64EncodedBody = split_string[1]; + String base64EncodedSignature = split_string[2]; + Base64 base64Url = new Base64(true); + String header = new String(base64Url.decode(base64EncodedHeader)); + String body = new String(base64Url.decode(base64EncodedBody)); + return new ObjectMapper().readValue(body, Passport.class); + } + + // Removes duplicates from the VisaPermissons List + private List deDupeVisaPermissions(List visaPermissions) { + Set permissionsSet = new HashSet(); + permissionsSet.addAll(visaPermissions); + return permissionsSet.stream().collect(Collectors.toList()); + } +} diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index d30d319e5..b381a9e97 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -1,120 +1,120 @@ -package bio.overture.ego.service; - -import static java.lang.String.format; -import static org.mapstruct.factory.Mappers.getMapper; - -import bio.overture.ego.event.token.ApiKeyEventsPublisher; -import bio.overture.ego.model.dto.VisaPermissionRequest; -import bio.overture.ego.model.entity.Visa; -import bio.overture.ego.model.entity.VisaPermission; -import bio.overture.ego.model.exceptions.NotFoundException; -import bio.overture.ego.repository.VisaPermissionRepository; -import jakarta.validation.constraints.NotNull; -import java.util.List; -import java.util.UUID; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import lombok.val; -import org.mapstruct.Mapper; -import org.mapstruct.MappingTarget; -import org.mapstruct.NullValueCheckStrategy; -import org.mapstruct.ReportingPolicy; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Slf4j -@Service -@Transactional -public class VisaPermissionService extends AbstractNamedService { - /** Dependencies */ - @Autowired private VisaService visaService; - - @Autowired private PolicyService policyService; - @Autowired private VisaPermissionRepository visaPermissionRepository; - private final ApiKeyEventsPublisher apiKeyEventsPublisher; - private static final VisaPermissionConverter VISA_PERMISSION_CONVERTER = - getMapper(VisaPermissionConverter.class); - - @Autowired - public VisaPermissionService( - @NonNull VisaPermissionRepository visaPermissionRepository, - @NonNull VisaService visaService, - @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher) { - super(VisaPermission.class, visaPermissionRepository); - this.visaPermissionRepository = visaPermissionRepository; - this.visaService = visaService; - this.apiKeyEventsPublisher = apiKeyEventsPublisher; - } - - public List getPermissionsByVisaId(@NonNull UUID visaId) { - val result = (List) visaPermissionRepository.findByVisa_Id(visaId); - if (result.isEmpty()) { - throw new NotFoundException(format("No VisaPermissions exists with visaId '%s'", visaId)); - } - return result; - } - - public List getPermissionsByPolicyId(@NonNull UUID policyId) { - val result = (List) visaPermissionRepository.findByPolicy_Id(policyId); - if (result.isEmpty()) { - throw new NotFoundException(format("No VisaPermissions exists with policyId '%s'", policyId)); - } - return result; - } - - public VisaPermission createOrUpdatePermissions( - @NonNull VisaPermissionRequest visaPermissionRequest) { - VisaPermission visaPermission = null; - List visaPermissionEntities = - visaPermissionRepository.findByPolicyIdAndVisaId( - visaPermissionRequest.getPolicyId(), visaPermissionRequest.getVisaId()); - if (visaPermissionEntities.isEmpty()) { - visaPermission = new VisaPermission(); - visaPermission.setVisa(visaService.getById(visaPermissionRequest.getVisaId())); - visaPermission.setPolicy(policyService.getById(visaPermissionRequest.getPolicyId())); - visaPermission.setAccessLevel(visaPermissionRequest.getAccessLevel()); - return visaPermissionRepository.save(visaPermission); - } else { - VISA_PERMISSION_CONVERTER.updateVisaPermission( - visaPermissionRequest, visaPermissionEntities.get(0)); - return visaPermissionRepository.save(visaPermissionEntities.get(0)); - } - } - - public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { - VisaPermission visaPermission = null; - List visaPermissionEntities = - visaPermissionRepository.findByPolicyIdAndVisaId(policyId, visaId); - if (!visaPermissionEntities.isEmpty()) { - visaPermissionRepository.deleteById(visaPermissionEntities.get(0).getId()); - } else { - throw new NotFoundException( - format("No VisaPermissions exists with policyId '%s' and visaId '%s'", policyId, visaId)); - } - } - - // Fetches visa permissions for given visa request - public List getPermissionsForVisa(@NonNull Visa visa) { - val result = (List) visaPermissionRepository.findByVisa_Id(visa.getId()); - return result; - } - - @Override - public VisaPermission getById(@NonNull UUID uuid) { - return super.getById(uuid); - } - - @Override - public VisaPermission getWithRelationships(UUID uuid) { - return null; - } - - @Mapper( - nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, - unmappedTargetPolicy = ReportingPolicy.WARN) - public abstract static class VisaPermissionConverter { - public abstract void updateVisaPermission( - VisaPermissionRequest visaPermissionRequest, @MappingTarget VisaPermission visaPermission); - } -} +package bio.overture.ego.service; + +import static java.lang.String.format; +import static org.mapstruct.factory.Mappers.getMapper; + +import bio.overture.ego.event.token.ApiKeyEventsPublisher; +import bio.overture.ego.model.dto.VisaPermissionRequest; +import bio.overture.ego.model.entity.Visa; +import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.model.exceptions.NotFoundException; +import bio.overture.ego.repository.VisaPermissionRepository; +import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.ReportingPolicy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@Transactional +public class VisaPermissionService extends AbstractNamedService { + /** Dependencies */ + @Autowired private VisaService visaService; + + @Autowired private PolicyService policyService; + @Autowired private VisaPermissionRepository visaPermissionRepository; + private final ApiKeyEventsPublisher apiKeyEventsPublisher; + private static final VisaPermissionConverter VISA_PERMISSION_CONVERTER = + getMapper(VisaPermissionConverter.class); + + @Autowired + public VisaPermissionService( + @NonNull VisaPermissionRepository visaPermissionRepository, + @NonNull VisaService visaService, + @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher) { + super(VisaPermission.class, visaPermissionRepository); + this.visaPermissionRepository = visaPermissionRepository; + this.visaService = visaService; + this.apiKeyEventsPublisher = apiKeyEventsPublisher; + } + + public List getPermissionsByVisaId(@NonNull UUID visaId) { + val result = (List) visaPermissionRepository.findByVisa_Id(visaId); + if (result.isEmpty()) { + throw new NotFoundException(format("No VisaPermissions exists with visaId '%s'", visaId)); + } + return result; + } + + public List getPermissionsByPolicyId(@NonNull UUID policyId) { + val result = (List) visaPermissionRepository.findByPolicy_Id(policyId); + if (result.isEmpty()) { + throw new NotFoundException(format("No VisaPermissions exists with policyId '%s'", policyId)); + } + return result; + } + + public VisaPermission createOrUpdatePermissions( + @NonNull VisaPermissionRequest visaPermissionRequest) { + VisaPermission visaPermission = null; + List visaPermissionEntities = + visaPermissionRepository.findByPolicyIdAndVisaId( + visaPermissionRequest.getPolicyId(), visaPermissionRequest.getVisaId()); + if (visaPermissionEntities.isEmpty()) { + visaPermission = new VisaPermission(); + visaPermission.setVisa(visaService.getById(visaPermissionRequest.getVisaId())); + visaPermission.setPolicy(policyService.getById(visaPermissionRequest.getPolicyId())); + visaPermission.setAccessLevel(visaPermissionRequest.getAccessLevel()); + return visaPermissionRepository.save(visaPermission); + } else { + VISA_PERMISSION_CONVERTER.updateVisaPermission( + visaPermissionRequest, visaPermissionEntities.get(0)); + return visaPermissionRepository.save(visaPermissionEntities.get(0)); + } + } + + public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { + VisaPermission visaPermission = null; + List visaPermissionEntities = + visaPermissionRepository.findByPolicyIdAndVisaId(policyId, visaId); + if (!visaPermissionEntities.isEmpty()) { + visaPermissionRepository.deleteById(visaPermissionEntities.get(0).getId()); + } else { + throw new NotFoundException( + format("No VisaPermissions exists with policyId '%s' and visaId '%s'", policyId, visaId)); + } + } + + // Fetches visa permissions for given visa request + public List getPermissionsForVisa(@NonNull Visa visa) { + val result = (List) visaPermissionRepository.findByVisa_Id(visa.getId()); + return result; + } + + @Override + public VisaPermission getById(@NonNull UUID uuid) { + return super.getById(uuid); + } + + @Override + public VisaPermission getWithRelationships(UUID uuid) { + return null; + } + + @Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + unmappedTargetPolicy = ReportingPolicy.WARN) + public abstract static class VisaPermissionConverter { + public abstract void updateVisaPermission( + VisaPermissionRequest visaPermissionRequest, @MappingTarget VisaPermission visaPermission); + } +} diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index b4b003611..c7e651105 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -1,131 +1,129 @@ -package bio.overture.ego.service; - -import static bio.overture.ego.model.exceptions.NotFoundException.checkNotFound; -import static bio.overture.ego.model.exceptions.RequestValidationException.checkRequestValid; -import static org.mapstruct.factory.Mappers.getMapper; - -import bio.overture.ego.event.token.ApiKeyEventsPublisher; -import bio.overture.ego.model.dto.PassportVisa; -import bio.overture.ego.model.dto.VisaRequest; -import bio.overture.ego.model.entity.Visa; -import bio.overture.ego.model.exceptions.InternalServerException; -import bio.overture.ego.model.exceptions.InvalidTokenException; -import bio.overture.ego.repository.VisaRepository; -import bio.overture.ego.token.signer.BrokerTokenSigner; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; -import java.util.UUID; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import lombok.val; -import org.apache.commons.codec.binary.Base64; -import org.mapstruct.Mapper; -import org.mapstruct.MappingTarget; -import org.mapstruct.NullValueCheckStrategy; -import org.mapstruct.ReportingPolicy; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Slf4j -@Service -@Transactional -public class VisaService extends AbstractNamedService { - /** Constants */ - private static final VisaConverter VISA_CONVERTER = getMapper(VisaConverter.class); - - private final BrokerTokenSigner tokenSigner; - /** Dependencies */ - @Autowired private VisaRepository visaRepository; - - private final ApiKeyEventsPublisher apiKeyEventsPublisher; - - @Autowired - public VisaService( - @NonNull VisaRepository visaRepository, - @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher, - @NonNull BrokerTokenSigner tokenSigner) { - super(Visa.class, visaRepository); - this.visaRepository = visaRepository; - this.apiKeyEventsPublisher = apiKeyEventsPublisher; - this.tokenSigner = tokenSigner; - } - - public Visa create(@NonNull VisaRequest createRequest) { - checkRequestValid(createRequest); - val visa = VISA_CONVERTER.convertToVisa(createRequest); - return getRepository().save(visa); - } - - @Override - public Visa getById(@NonNull UUID uuid) { - val result = (Optional) getRepository().findById(uuid); - checkNotFound(result.isPresent(), "The visaId '%s' does not exist", uuid); - return result.get(); - } - - public void delete(@NonNull UUID id) { - checkExistence(id); - super.delete(id); - } - - // Parses Visa JWT token to convert into Visa Object - public PassportVisa parseVisa(@NonNull String visaJwtToken) throws JsonProcessingException { - String[] split_string = visaJwtToken.split("\\."); - String base64EncodedHeader = split_string[0]; - String base64EncodedBody = split_string[1]; - String base64EncodedSignature = split_string[2]; - Base64 base64Url = new Base64(true); - String header = new String(base64Url.decode(base64EncodedHeader)); - String body = new String(base64Url.decode(base64EncodedBody)); - return new ObjectMapper().readValue(body, PassportVisa.class); - } - - // Checks if the visa is a valid visa - public boolean isValidVisa(@NonNull String authToken) { - Claims claims; - val tokenKey = - tokenSigner - .getEncodedPublicKey() - .orElseThrow(() -> new InternalServerException("Internal issue with token signer.")); - try { - claims = Jwts.parser().setSigningKey(tokenKey).parseClaimsJws(authToken).getBody(); - if (claims != null) { - return true; - } - } catch (Exception exception) { - throw new InvalidTokenException("The visa token received from broker is invalid"); - } - return false; - } - - public Page listVisa(@NonNull Pageable pageable) { - return visaRepository.findAll(pageable); - } - - public Visa partialUpdate(@NotNull UUID id, @NonNull VisaRequest updateRequest) { - val visa = getById(id); - VISA_CONVERTER.updateVisa(updateRequest, visa); - return getRepository().save(visa); - } - - @Mapper( - nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, - unmappedTargetPolicy = ReportingPolicy.WARN) - public abstract static class VisaConverter { - public abstract Visa convertToVisa(VisaRequest request); - - public abstract void updateVisa(VisaRequest request, @MappingTarget Visa visaToUpdate); - } - - @Override - public Visa getWithRelationships(UUID uuid) { - return null; - } -} +package bio.overture.ego.service; + +import static bio.overture.ego.model.exceptions.NotFoundException.checkNotFound; +import static bio.overture.ego.model.exceptions.RequestValidationException.checkRequestValid; +import static org.mapstruct.factory.Mappers.getMapper; + +import bio.overture.ego.event.token.ApiKeyEventsPublisher; +import bio.overture.ego.model.dto.PassportVisa; +import bio.overture.ego.model.dto.VisaRequest; +import bio.overture.ego.model.entity.Visa; +import bio.overture.ego.model.exceptions.InvalidTokenException; +import bio.overture.ego.repository.VisaRepository; +import bio.overture.ego.utils.CacheUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; +import java.util.UUID; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.commons.codec.binary.Base64; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.ReportingPolicy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@Transactional +public class VisaService extends AbstractNamedService { + /** Constants */ + private static final VisaConverter VISA_CONVERTER = getMapper(VisaConverter.class); + + /** Dependencies */ + @Autowired private VisaRepository visaRepository; + + @Autowired private CacheUtil cacheUtil; + + private final ApiKeyEventsPublisher apiKeyEventsPublisher; + + @Autowired + public VisaService( + @NonNull VisaRepository visaRepository, + @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher) { + super(Visa.class, visaRepository); + this.visaRepository = visaRepository; + this.apiKeyEventsPublisher = apiKeyEventsPublisher; + } + + public Visa create(@NonNull VisaRequest createRequest) { + checkRequestValid(createRequest); + val visa = VISA_CONVERTER.convertToVisa(createRequest); + return getRepository().save(visa); + } + + @Override + public Visa getById(@NonNull UUID uuid) { + val result = (Optional) getRepository().findById(uuid); + checkNotFound(result.isPresent(), "The visaId '%s' does not exist", uuid); + return result.get(); + } + + public void delete(@NonNull UUID id) { + checkExistence(id); + super.delete(id); + } + + // Parses Visa JWT token to convert into Visa Object + public PassportVisa parseVisa(@NonNull String visaJwtToken) throws JsonProcessingException { + String[] split_string = visaJwtToken.split("\\."); + String base64EncodedHeader = split_string[0]; + String base64EncodedBody = split_string[1]; + String base64EncodedSignature = split_string[2]; + Base64 base64Url = new Base64(true); + String header = new String(base64Url.decode(base64EncodedHeader)); + String body = new String(base64Url.decode(base64EncodedBody)); + return new ObjectMapper().readValue(body, PassportVisa.class); + } + + // Checks if the visa is a valid visa + public boolean isValidVisa(@NonNull String authToken) { + Claims claims; + try { + claims = + Jwts.parser() + .setSigningKey(cacheUtil.getPassportBrokerPublicKey()) + .parseClaimsJws(authToken) + .getBody(); + if (claims != null) { + return true; + } + } catch (Exception exception) { + throw new InvalidTokenException("The visa token received from broker is invalid"); + } + return false; + } + + public Page listVisa(@NonNull Pageable pageable) { + return visaRepository.findAll(pageable); + } + + public Visa partialUpdate(@NotNull UUID id, @NonNull VisaRequest updateRequest) { + val visa = getById(id); + VISA_CONVERTER.updateVisa(updateRequest, visa); + return getRepository().save(visa); + } + + @Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + unmappedTargetPolicy = ReportingPolicy.WARN) + public abstract static class VisaConverter { + public abstract Visa convertToVisa(VisaRequest request); + + public abstract void updateVisa(VisaRequest request, @MappingTarget Visa visaToUpdate); + } + + @Override + public Visa getWithRelationships(UUID uuid) { + return null; + } +} diff --git a/src/main/java/bio/overture/ego/token/signer/BrokerTokenSigner.java b/src/main/java/bio/overture/ego/token/signer/BrokerTokenSigner.java deleted file mode 100644 index e0dfc53f7..000000000 --- a/src/main/java/bio/overture/ego/token/signer/BrokerTokenSigner.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bio.overture.ego.token.signer; - -import jakarta.annotation.PostConstruct; -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.Base64; -import java.util.Optional; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import lombok.val; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@Profile("!jks") -public class BrokerTokenSigner { - - /* - Constants - */ - private static final String KEYFACTORY_TYPE = "RSA"; - /* - Dependencies - */ - @Value("${broker.token.private-key}") - private String encodedPrivKey; - - @Value("${broker.token.public-key}") - private String encodedPubKey; - - /* - Variables - */ - private KeyFactory keyFactory; - private PrivateKey privateKey; - private PublicKey publicKey; - - @PostConstruct - @SneakyThrows - private void init() { - keyFactory = KeyFactory.getInstance(KEYFACTORY_TYPE); - try { - val decodedpriv = Base64.getDecoder().decode(encodedPrivKey); - val decodedPub = Base64.getDecoder().decode(encodedPubKey); - X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(decodedPub); - PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(decodedpriv); - publicKey = keyFactory.generatePublic(pubKeySpec); - privateKey = keyFactory.generatePrivate(privKeySpec); - } catch (InvalidKeySpecException specEx) { - log.error("Error loading keys:{}", specEx); - } - } - - public Optional getKey() { - return Optional.of(privateKey); - } - - public Optional getKeyPair() { - return Optional.of(new KeyPair(publicKey, privateKey)); - } - - public Optional getEncodedPublicKey() { - if (publicKey != null) { - val b64 = Base64.getEncoder(); - String encodedKey = b64.encodeToString(publicKey.getEncoded()); - encodedKey = "-----BEGIN PUBLIC KEY-----\r\n" + encodedKey + "\r\n-----END PUBLIC KEY-----"; - return Optional.of(encodedKey); - } else { - return Optional.empty(); - } - } -} diff --git a/src/main/java/bio/overture/ego/utils/CacheUtil.java b/src/main/java/bio/overture/ego/utils/CacheUtil.java new file mode 100644 index 000000000..f512a6522 --- /dev/null +++ b/src/main/java/bio/overture/ego/utils/CacheUtil.java @@ -0,0 +1,48 @@ +package bio.overture.ego.utils; + +import static bio.overture.ego.model.exceptions.InternalServerException.buildInternalServerException; +import static org.springframework.http.HttpMethod.GET; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Component +public class CacheUtil { + + @Value("${broker.publicKey.url}") + private String brokerPublicKeyUrl; + + private RestTemplate restTemplate; + + @Cacheable("getPassportBrokerPublicKey") + public String getPassportBrokerPublicKey() { + ResponseEntity response; + try { + response = restTemplate.exchange(brokerPublicKeyUrl, GET, null, String.class); + } catch (HttpStatusCodeException err) { + log.error( + "Invalid {} response from passport broker service: {}", + err.getStatusCode().value(), + err.getMessage()); + throw buildInternalServerException( + "Invalid %s response from passport broker service.", err.getStatusCode().value()); + } + return response.getBody(); + } + + @CacheEvict(value = "evictAll", allEntries = true) + public void evictAllCaches() {} + + @Scheduled(fixedRate = 6000) + public void evictAllCachesEveryDay() { + evictAllCaches(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index dfd99e769..cd5e9f76b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -185,10 +185,8 @@ token: public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lOqMuPLCVusc6szklNXQL1FHhSkEgR7An+8BllBqTsRHM4bRYosseGFCbYPn8r8FsWuMDtxp0CwTyMQR2PCbJ740DdpbE1KC6jAfZxqcBete7gP0tooJtbvnA6X4vNpG4ukhtUoN9DzNOO0eqMU0Rgyy5HjERdYEWkwTNB30i9I+nHFOSj4MGLBSxNlnuo3keeomCRgtimCx+L/K3HNo0QHTG1J7RzLVAchfQT0lu3pUJ8kB+UM6/6NG+fVyysJyRZ9gadsr4gvHHckw8oUBp2tHvqBEkEdY+rt1Mf5jppt7JUV7HAPLB/qR5jhALY2FX/8MN+lPLmb/nLQQichVQIDAQAB broker: - token: - issuer: http://localhost:8081 - private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSU6oy48sJW6xzqzOSU1dAvUUeFKQSBHsCf7wGWUGpOxEczhtFiiyx4YUJtg+fyvwWxa4wO3GnQLBPIxBHY8JsnvjQN2lsTUoLqMB9nGpwF617uA/S2igm1u+cDpfi82kbi6SG1Sg30PM047R6oxTRGDLLkeMRF1gRaTBM0HfSL0j6ccU5KPgwYsFLE2We6jeR56iYJGC2KYLH4v8rcc2jRAdMbUntHMtUByF9BPSW7elQnyQH5Qzr/o0b59XLKwnJFn2Bp2yviC8cdyTDyhQGna0e+oESQR1j6u3Ux/mOmm3slRXscA8sH+pHmOEAtjYVf/ww36U8uZv+ctBCJyFVAgMBAAECggEBALrEeJqAFUfWFCkSmdUSFKT0bW/svFUTjXgGnZy1ncz9GpENpMH3lQDQVibteKpYwcom+Cr0XlQ66VUcudPrDjcOY7vhuMfnSh1YWLYyM4IeRHtcUxDVkFoM+vEFNHLf2zIOqqbgmboW3iDVIurT7iRO7KxAe/YtWJL9aVqMtBn7Lu7S7OvAU4ji5iLIBxjl82JYA+9lu/aQ6YGaoZuSO7bcU8Sivi+DKAahqN9XMKiB1XpC+PpaS/aec2S7xIlTdzoDGxEALRGlMe+xBEeQTBVJHBWrRIDPoHLTREeRC/9Pp+1Y4Dz8hd5Bi0n8/5r/q0liD+0vtmjsdU4E2QrktYECgYEA73qWvhCYHPMREAFtwz1mpp9ZhDCW6SF+njG7fBKcjz8OLcy15LXiTGc268ewtQqTMjPQlm1n2C6hGccGAIlMibQJo3KZHlTs125FUzDpTVgdlei6vU7M+gmfRSZed00J6jC04/qMR1tnV3HME3np7eRTKTA6Ts+zBwEvkbCetSkCgYEA4NY5iSBO1ybouIecDdD15uI2ItLPCBNMzu7IiK7IygIzuf+SyKyjhtFSR4vEi0gScOM7UMlwCMOVU10e4nMDknIWCDG9iFvmIEkGHGxgRrN5hX1Wrq74wF212lvvagH1IVWSHa8cVpMe+UwKu5Q1h4yzuYt6Q9wPQ7Qtn5emBE0CgYB2syispMUA9GnsqQii0Xhj9nAEWaEzhOqhtrzbTs5TIkoA4Yr3BkBY5oAOdjhcRBWZuJ0XMrtaKCKqCEAtW+CYEKkGXvMOWcHbNkkeZwv8zkQ73dNRqhFnjgVn3RDNyV20uteueK23YNLkQP+KV89fnuCpdcIw9joiqq/NYuIHoQKBgB5WaZ8KH/lCA8babYEjv/pubZWXUl4plISbja17wBYZ4/bl+F1hhhMr7Wk//743dF2NG7TT6W0VTvHXr9IoaMP65uQmKgfbNpsGn294ZClGEFClz+t0KpZyTpZvL0fjibr8u+GLfkxkP5qt2wjif7KRlrKjklTTva+KAVn2cW1FAoGBAMkX9ekIwhx/7uY6ndxKl8ZMDerjr6MhV0b08hHp3RxHbYVbcpN0UKspoYvZVgHwP18xlDij8yWRE2fapwgi4m82ZmYlg0qqJmyqIU9vBB3Jow903h1KPQrkmQEZxJ/4H8yrbgVf2HT+WUfjTFgaDZRl01bI3YkydCw91/Ub9HU6 - public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lOqMuPLCVusc6szklNXQL1FHhSkEgR7An+8BllBqTsRHM4bRYosseGFCbYPn8r8FsWuMDtxp0CwTyMQR2PCbJ740DdpbE1KC6jAfZxqcBete7gP0tooJtbvnA6X4vNpG4ukhtUoN9DzNOO0eqMU0Rgyy5HjERdYEWkwTNB30i9I+nHFOSj4MGLBSxNlnuo3keeomCRgtimCx+L/K3HNo0QHTG1J7RzLVAchfQT0lu3pUJ8kB+UM6/6NG+fVyysJyRZ9gadsr4gvHHckw8oUBp2tHvqBEkEdY+rt1Mf5jppt7JUV7HAPLB/qR5jhALY2FX/8MN+lPLmb/nLQQichVQIDAQAB + publicKey: + url: http://localhost:8082/token/public_key # Default values available for creation of entities default: From 9cb8e69c05e1e7ec0f75929cf48cc8a89a1d95fa Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Fri, 26 May 2023 12:15:42 -0400 Subject: [PATCH 31/43] Add passport integration --- .../bio/overture/ego/model/enums/ProviderType.java | 8 ++++++-- src/main/resources/application.yml | 13 +++++++++++++ .../sql/V1_24__add_passport_identity_provider.sql | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/flyway/sql/V1_24__add_passport_identity_provider.sql diff --git a/src/main/java/bio/overture/ego/model/enums/ProviderType.java b/src/main/java/bio/overture/ego/model/enums/ProviderType.java index 44e22aa9d..e4b912b73 100644 --- a/src/main/java/bio/overture/ego/model/enums/ProviderType.java +++ b/src/main/java/bio/overture/ego/model/enums/ProviderType.java @@ -15,11 +15,15 @@ public enum ProviderType { LINKEDIN, GITHUB, ORCID, - KEYCLOAK; + KEYCLOAK, + PASSPORT; // TODO: verify these are the correct accessor keys for each provider public static String getIdAccessor(ProviderType provider) { - if (provider.equals(GOOGLE) || provider.equals(ORCID) || provider.equals(KEYCLOAK)) { + if (provider.equals(GOOGLE) + || provider.equals(ORCID) + || provider.equals(KEYCLOAK) + || provider.equals(PASSPORT)) { return "sub"; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index cd5e9f76b..37fa1b354 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -70,6 +70,16 @@ spring: - openid - email - profile + passport: + clientId: ego-client + clientSecret: + redirectUri: "http://localhost:8081/oauth/code/elixir" + authorizationGrantType: authorization_code + scope: + - openid + - email + - profile + - ga4gh_passport_v1 github: clientName: ego @@ -129,6 +139,9 @@ spring: userNameAttribute: sub userRecordUri: https://pub.orcid.org/v2.0 jwkSetUri: https://orcid.org/oauth/jwks + passport: + # OIDC discovery endpoint + issuer-uri: https://login.elixir-czech.org/oidc/ cloud: vault: kv: diff --git a/src/main/resources/flyway/sql/V1_24__add_passport_identity_provider.sql b/src/main/resources/flyway/sql/V1_24__add_passport_identity_provider.sql new file mode 100644 index 000000000..6f107e538 --- /dev/null +++ b/src/main/resources/flyway/sql/V1_24__add_passport_identity_provider.sql @@ -0,0 +1 @@ +ALTER TYPE providertype ADD VALUE 'PASSPORT'; \ No newline at end of file From f5b3bec8dc62ba0edb713de46aabb365673e0a5e Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Mon, 29 May 2023 11:49:57 -0400 Subject: [PATCH 32/43] Changes related to fetching the visas by type and value has been updated by adding new api's --- .../ego/controller/PassportController.java | 5 +- .../ego/controller/VisaController.java | 405 +++++++++--------- .../ego/repository/VisaRepository.java | 34 +- .../overture/ego/service/PassportService.java | 12 +- .../ego/service/VisaPermissionService.java | 13 +- .../bio/overture/ego/service/VisaService.java | 13 + 6 files changed, 258 insertions(+), 224 deletions(-) diff --git a/src/main/java/bio/overture/ego/controller/PassportController.java b/src/main/java/bio/overture/ego/controller/PassportController.java index bb2a042bf..377e711c2 100644 --- a/src/main/java/bio/overture/ego/controller/PassportController.java +++ b/src/main/java/bio/overture/ego/controller/PassportController.java @@ -32,7 +32,10 @@ @Slf4j @RestController @RequestMapping("/passport") -@Tag(name = "Passport", description = "passport-controller") +@Tag( + name = "Passport", + description = + "Passport-Controller (Only for Testing. To be removed post integration with broker service)") public class PassportController { private final PassportService passportService; diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index 03997a974..2ab2453fc 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -1,200 +1,205 @@ -package bio.overture.ego.controller; - -import static org.springframework.web.bind.annotation.RequestMethod.*; - -import bio.overture.ego.model.dto.*; -import bio.overture.ego.model.entity.*; -import bio.overture.ego.security.AdminScoped; -import bio.overture.ego.service.*; -import bio.overture.ego.view.Views; -import com.fasterxml.jackson.annotation.JsonView; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.constraints.NotNull; -import java.util.List; -import java.util.UUID; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Pageable; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.*; - -@Slf4j -@RestController -@RequestMapping("/visa") -@Tag(name = "Visa") -public class VisaController { - - /** Dependencies */ - private final VisaService visaService; - - private final VisaPermissionService visaPermissionService; - - private final UserPermissionService userPermissionService; - private final GroupPermissionService groupPermissionService; - private final ApplicationPermissionService applicationPermissionService; - - @Autowired - public VisaController( - @NonNull VisaService visaService, - @NotNull VisaPermissionService visaPermissionService, - @NonNull UserPermissionService userPermissionService, - @NonNull GroupPermissionService groupPermissionService, - @NonNull ApplicationPermissionService applicationPermissionService) { - this.visaService = visaService; - this.visaPermissionService = visaPermissionService; - this.groupPermissionService = groupPermissionService; - this.userPermissionService = userPermissionService; - this.applicationPermissionService = applicationPermissionService; - } - - /* - * This method is used to fetch visa using id - * @param id UUID - * @return visa Visa - */ - @AdminScoped - @RequestMapping(method = GET, value = "/{id}") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Get Visa by id")}) - @JsonView(Views.REST.class) - public @ResponseBody Visa getVisa( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "id", required = true) UUID id) { - return visaService.getById(id); - } - - /* - * This method is used to list all visas - * @return visas List - */ - @AdminScoped - @RequestMapping(method = GET, value = "") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "All Visas")}) - @JsonView(Views.REST.class) - public @ResponseBody PageDTO listVisa( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @Parameter(hidden = true) Pageable pageable) { - return new PageDTO<>(visaService.listVisa(pageable)); - } - - /* - * This method is used to create visa using visa create request - * @param visaRequest VisaRequest - * @return Visa visa - */ - @AdminScoped - @RequestMapping(method = POST, value = "") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "New Visa"), - }) - public @ResponseBody Visa createVisa( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @RequestBody(required = true) VisaRequest visaRequest) { - return visaService.create(visaRequest); - } - - /* - * This method is used to update visa using visa id and update request - * @param visaId UUID - * @param visaRequest VisaRequest - * @return Visa visa - */ - @AdminScoped - @RequestMapping(method = PUT, value = "/{id}") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Update Visa")}) - public @ResponseBody Visa updateVisa( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "id", required = true) UUID id, - @RequestBody(required = true) VisaRequest visaRequest) { - return visaService.partialUpdate(id, visaRequest); - } - - /* - * This method is used to delete visa using visa id - * @param visaId UUID - */ - @AdminScoped - @RequestMapping(method = DELETE, value = "/{id}") - @ResponseStatus(value = HttpStatus.OK) - public void deleteVisa( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "id", required = true) UUID id) { - visaService.delete(id); - } - - /* - * This method is used to fetch visa permissions using visa id - * @param visaId UUID - * @return visaPermissions List - */ - @AdminScoped - @RequestMapping(method = GET, value = "/permissions/visaId/{id}") - @ApiResponses( - value = {@ApiResponse(responseCode = "200", description = "Get VisaPermissions by visaId")}) - @JsonView(Views.REST.class) - public @ResponseBody List getPermissionsByVisaId( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "id", required = true) UUID id) { - return visaPermissionService.getPermissionsByVisaId(id); - } - - /* - * This method is used to fetch visa permissions using policy id - * @param policyId UUID - * @return visaPermissions List - */ - @AdminScoped - @RequestMapping(method = GET, value = "/permissions/policyId/{id}") - @ApiResponses( - value = {@ApiResponse(responseCode = "200", description = "Get VisaPermissions by policyId")}) - @JsonView(Views.REST.class) - public @ResponseBody List getPermissionsByPolicyId( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "id", required = true) UUID id) { - return visaPermissionService.getPermissionsByPolicyId(id); - } - - /* - * This method is used to create/update visa permissions - * @param visaPermissionRequest VisaPermissionRequest - * @return visaPermission VisaPermission - */ - @AdminScoped - @RequestMapping(method = POST, value = "/permissions") - @ApiResponses( - value = {@ApiResponse(responseCode = "200", description = "Create or Update VisaPermission")}) - @JsonView(Views.REST.class) - public @ResponseBody VisaPermission createOrUpdatePermissions( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @RequestBody(required = true) VisaPermissionRequest visaPermissionRequest) { - return visaPermissionService.createOrUpdatePermissions(visaPermissionRequest); - } - - /* - * This method is used to delete/remove visa permissions - * @param visaPermissionRequest VisaPermissionRequest - */ - @AdminScoped - @RequestMapping(method = DELETE, value = "/permissions/{policyId}/{visaId}") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Remove VisaPermission")}) - @JsonView(Views.REST.class) - public @ResponseBody void removePermissions( - @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "policyId", required = true) UUID policyId, - @PathVariable(value = "visaId", required = true) UUID visaId) { - visaPermissionService.removePermission(policyId, visaId); - } -} +package bio.overture.ego.controller; + +import static org.springframework.web.bind.annotation.RequestMethod.*; + +import bio.overture.ego.model.dto.*; +import bio.overture.ego.model.entity.*; +import bio.overture.ego.security.AdminScoped; +import bio.overture.ego.service.*; +import bio.overture.ego.view.Views; +import com.fasterxml.jackson.annotation.JsonView; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@RestController +@RequestMapping("/visa") +@Tag(name = "Visa") +public class VisaController { + + /** Dependencies */ + private final VisaService visaService; + + private final VisaPermissionService visaPermissionService; + + private final UserPermissionService userPermissionService; + private final GroupPermissionService groupPermissionService; + private final ApplicationPermissionService applicationPermissionService; + + @Autowired + public VisaController( + @NonNull VisaService visaService, + @NotNull VisaPermissionService visaPermissionService, + @NonNull UserPermissionService userPermissionService, + @NonNull GroupPermissionService groupPermissionService, + @NonNull ApplicationPermissionService applicationPermissionService) { + this.visaService = visaService; + this.visaPermissionService = visaPermissionService; + this.groupPermissionService = groupPermissionService; + this.userPermissionService = userPermissionService; + this.applicationPermissionService = applicationPermissionService; + } + + /* + * This method is used to fetch visa using type and value + * @param type String + * @param value String + * @return visas List + */ + @AdminScoped + @RequestMapping(method = GET, value = "/{type}/{value}") + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Get Visa Using Type and Value")}) + @JsonView(Views.REST.class) + public @ResponseBody List getVisaByTypeAndValue( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "type", required = true) String type, + @PathVariable(value = "value", required = true) String value) { + return visaService.getByTypeAndValue(type, value); + } + + /* + * This method is used to list all visas + * @return visas List + */ + @AdminScoped + @RequestMapping(method = GET, value = "") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "All Visas")}) + @JsonView(Views.REST.class) + public @ResponseBody PageDTO listVisa( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @Parameter(hidden = true) Pageable pageable) { + return new PageDTO<>(visaService.listVisa(pageable)); + } + + /* + * This method is used to create visa using visa create request + * @param visaRequest VisaRequest + * @return Visa visa + */ + @AdminScoped + @RequestMapping(method = POST, value = "") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "New Visa"), + }) + public @ResponseBody Visa createVisa( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @RequestBody(required = true) VisaRequest visaRequest) { + return visaService.create(visaRequest); + } + + /* + * This method is used to update visa using visa id and update request + * @param visaId UUID + * @param visaRequest VisaRequest + * @return Visa visa + */ + @AdminScoped + @RequestMapping(method = PUT, value = "/{id}") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Update Visa")}) + public @ResponseBody Visa updateVisa( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "id", required = true) UUID id, + @RequestBody(required = true) VisaRequest visaRequest) { + return visaService.partialUpdate(id, visaRequest); + } + + /* + * This method is used to delete visa using visa id + * @param visaId UUID + */ + @AdminScoped + @RequestMapping(method = DELETE, value = "/{id}") + @ResponseStatus(value = HttpStatus.OK) + public void deleteVisa( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "id", required = true) UUID id) { + visaService.delete(id); + } + + /* + * This method is used to fetch visa permissions using type and value + * @param type String + * @param value String + * @return visas List + */ + @AdminScoped + @RequestMapping(method = GET, value = "/permissions/{type}/{value}") + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Get Visa Using Type and Value")}) + @JsonView(Views.REST.class) + public @ResponseBody List getVisaPermissionsByTypeAndValue( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "type", required = true) String type, + @PathVariable(value = "value", required = true) String value) { + return visaPermissionService.getPermissionsForVisa(visaService.getByTypeAndValue(type, value)); + } + + /* + * This method is used to fetch visa permissions using policy id + * @param policyId UUID + * @return visaPermissions List + */ + @AdminScoped + @RequestMapping(method = GET, value = "/permissions/policyId/{id}") + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Get VisaPermissions by policyId")}) + @JsonView(Views.REST.class) + public @ResponseBody List getPermissionsByPolicyId( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "id", required = true) UUID id) { + return visaPermissionService.getPermissionsByPolicyId(id); + } + + /* + * This method is used to create/update visa permissions + * @param visaPermissionRequest VisaPermissionRequest + * @return visaPermission VisaPermission + */ + @AdminScoped + @RequestMapping(method = POST, value = "/permissions") + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Create or Update VisaPermission")}) + @JsonView(Views.REST.class) + public @ResponseBody VisaPermission createOrUpdatePermissions( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @RequestBody(required = true) VisaPermissionRequest visaPermissionRequest) { + return visaPermissionService.createOrUpdatePermissions(visaPermissionRequest); + } + + /* + * This method is used to delete/remove visa permissions + * @param visaPermissionRequest VisaPermissionRequest + */ + @AdminScoped + @RequestMapping(method = DELETE, value = "/permissions/{policyId}/{visaId}") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Remove VisaPermission")}) + @JsonView(Views.REST.class) + public @ResponseBody void removePermissions( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "policyId", required = true) UUID policyId, + @PathVariable(value = "visaId", required = true) UUID visaId) { + visaPermissionService.removePermission(policyId, visaId); + } +} diff --git a/src/main/java/bio/overture/ego/repository/VisaRepository.java b/src/main/java/bio/overture/ego/repository/VisaRepository.java index 50d1ec130..a9f3de0a7 100644 --- a/src/main/java/bio/overture/ego/repository/VisaRepository.java +++ b/src/main/java/bio/overture/ego/repository/VisaRepository.java @@ -1,16 +1,18 @@ -package bio.overture.ego.repository; - -import bio.overture.ego.model.entity.Visa; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -public interface VisaRepository extends NamedRepository { - @Override - @Deprecated - default Optional findByName(String name) { - return null; - } - - List findAll(); -} +package bio.overture.ego.repository; + +import bio.overture.ego.model.entity.Visa; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface VisaRepository extends NamedRepository { + @Override + @Deprecated + default Optional findByName(String name) { + return null; + } + + List findAll(); + + List getByTypeAndValue(String type, String value); +} diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 106e79b82..8df02148e 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -10,7 +10,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -99,9 +102,10 @@ private List getVisaPermissions(List visas) { .distinct() .forEach( visa -> { - Visa visaEntity = new Visa(); - visaEntity.setId(UUID.fromString(visa.getJti())); - visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visaEntity)); + List visaEntities = + visaService.getByTypeAndValue( + visa.getGa4ghVisaV1().getType(), visa.getGa4ghVisaV1().getValue()); + visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visaEntities)); }); return visaPermissions; } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index b381a9e97..8b1e8e314 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -10,6 +10,7 @@ import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.repository.VisaPermissionRepository; import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import lombok.NonNull; @@ -95,9 +96,15 @@ public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { } // Fetches visa permissions for given visa request - public List getPermissionsForVisa(@NonNull Visa visa) { - val result = (List) visaPermissionRepository.findByVisa_Id(visa.getId()); - return result; + public List getPermissionsForVisa(@NonNull List visas) { + List visaPermissions = new ArrayList<>(); + visas.stream() + .distinct() + .forEach( + visa -> { + visaPermissions.addAll(visaPermissionRepository.findByVisa_Id(visa.getId())); + }); + return visaPermissions; } @Override diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index c7e651105..e4e61f2f0 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -2,6 +2,7 @@ import static bio.overture.ego.model.exceptions.NotFoundException.checkNotFound; import static bio.overture.ego.model.exceptions.RequestValidationException.checkRequestValid; +import static java.lang.String.format; import static org.mapstruct.factory.Mappers.getMapper; import bio.overture.ego.event.token.ApiKeyEventsPublisher; @@ -9,6 +10,7 @@ import bio.overture.ego.model.dto.VisaRequest; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.exceptions.InvalidTokenException; +import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.repository.VisaRepository; import bio.overture.ego.utils.CacheUtil; import com.fasterxml.jackson.core.JsonProcessingException; @@ -16,6 +18,7 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import jakarta.validation.constraints.NotNull; +import java.util.List; import java.util.Optional; import java.util.UUID; import lombok.NonNull; @@ -68,6 +71,16 @@ public Visa getById(@NonNull UUID uuid) { return result.get(); } + public List getByTypeAndValue(@NonNull String type, @NotNull String value) { + val result = visaRepository.getByTypeAndValue(type, value); + if (!result.isEmpty()) { + return result; + } else { + throw new NotFoundException( + format("No Visa exists with type '%s' and value '%s'", type, value)); + } + } + public void delete(@NonNull UUID id) { checkExistence(id); super.delete(id); From c24330977e3c3117bc92c23bf4f1bde71cdbc49f Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Thu, 1 Jun 2023 13:13:36 -0400 Subject: [PATCH 33/43] Changes related to error status 400 and updates to deletion of visa --- .../ego/controller/VisaController.java | 7 +-- .../model/exceptions/ExceptionHandlers.java | 19 +++++++- .../overture/ego/service/PassportService.java | 45 +++++++------------ .../bio/overture/ego/service/VisaService.java | 44 +++++++++--------- src/main/resources/application.yml | 2 +- 5 files changed, 61 insertions(+), 56 deletions(-) diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index 2ab2453fc..a98d6c1b8 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -125,13 +125,14 @@ public VisaController( * @param visaId UUID */ @AdminScoped - @RequestMapping(method = DELETE, value = "/{id}") + @RequestMapping(method = DELETE, value = "/{type}/{value}") @ResponseStatus(value = HttpStatus.OK) public void deleteVisa( @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, - @PathVariable(value = "id", required = true) UUID id) { - visaService.delete(id); + @PathVariable(value = "type", required = true) String type, + @PathVariable(value = "value", required = true) String value) { + visaService.delete(type, value); } /* diff --git a/src/main/java/bio/overture/ego/model/exceptions/ExceptionHandlers.java b/src/main/java/bio/overture/ego/model/exceptions/ExceptionHandlers.java index 0e80a20d0..a2871f1a9 100644 --- a/src/main/java/bio/overture/ego/model/exceptions/ExceptionHandlers.java +++ b/src/main/java/bio/overture/ego/model/exceptions/ExceptionHandlers.java @@ -1,8 +1,7 @@ package bio.overture.ego.model.exceptions; import static java.lang.String.format; -import static org.springframework.http.HttpStatus.BAD_REQUEST; -import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.*; import bio.overture.ego.utils.Joiners; import jakarta.servlet.http.HttpServletRequest; @@ -13,6 +12,7 @@ import lombok.val; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MissingRequestHeaderException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -35,6 +35,21 @@ public ResponseEntity handleConstraintViolationException( NOT_FOUND); } + @ExceptionHandler(MissingRequestHeaderException.class) + public ResponseEntity handleMissingRequestHeaderException( + HttpServletRequest req, MissingRequestHeaderException ex) { + val message = ex.getMessage(); + log.error(message); + return new ResponseEntity( + Map.of( + "message", ex.getMessage(), + "timestamp", new Date(), + "path", req.getServletPath(), + "error", UNAUTHORIZED.getReasonPhrase()), + new HttpHeaders(), + UNAUTHORIZED); + } + @ExceptionHandler(ConstraintViolationException.class) public ResponseEntity handleConstraintViolationException( HttpServletRequest req, ConstraintViolationException ex) { diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 8df02148e..a6f6f607d 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -4,12 +4,9 @@ import bio.overture.ego.model.dto.PassportVisa; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; -import bio.overture.ego.model.exceptions.InvalidTokenException; import bio.overture.ego.utils.CacheUtil; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -43,9 +40,9 @@ public PassportService( public List getPermissions(String authToken) throws JsonProcessingException { // Validates passport auth token - if (!isValidPassport(authToken)) { + /*if (!isValidPassport(authToken)) { throw new InvalidTokenException("The passport token received from broker is invalid"); - } + }*/ // Parses passport JWT token Passport parsedPassport = parsePassport(authToken); // Fetches visas for parsed passport @@ -58,22 +55,12 @@ public List getPermissions(String authToken) throws JsonProcessi } // Validates passport token based on public key - private boolean isValidPassport(@NonNull String authToken) { - Claims claims; - try { - claims = - Jwts.parser() - .setSigningKey(cacheUtil.getPassportBrokerPublicKey()) - .parseClaimsJws(authToken) - .getBody(); - if (claims != null) { - return true; - } - } catch (Exception exception) { - throw new InvalidTokenException("The passport token received from broker is invalid"); - } - return false; - } + /*private void isValidPassport(@NonNull String authToken) throws ParseException, JwkException { + DecodedJWT jwt = JWT.decode(authToken); + Jwk jwk = cacheUtil.getPassportBrokerPublicKey().provider.get(jwt.getKeyId()); + Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); + algorithm.verify(jwt); + }*/ // Extracts Visas from parsed passport object private List getVisas(Passport passport) { @@ -82,12 +69,12 @@ private List getVisas(Passport passport) { .forEach( visaJwt -> { try { - if (visaService.isValidVisa(visaJwt)) { - PassportVisa visa = visaService.parseVisa(visaJwt); - if (visa != null) { - visas.add(visa); - } + // if (visaService.isValidVisa(visaJwt)) { + PassportVisa visa = visaService.parseVisa(visaJwt); + if (visa != null) { + visas.add(visa); } + // } } catch (JsonProcessingException e) { e.printStackTrace(); } @@ -103,9 +90,11 @@ private List getVisaPermissions(List visas) { .forEach( visa -> { List visaEntities = - visaService.getByTypeAndValue( + visaService.getByTypeAndValueForPassport( visa.getGa4ghVisaV1().getType(), visa.getGa4ghVisaV1().getValue()); - visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visaEntities)); + if (visaEntities != null && !visaEntities.isEmpty()) { + visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visaEntities)); + } }); return visaPermissions; } diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index e4e61f2f0..25f0a3c33 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -9,14 +9,11 @@ import bio.overture.ego.model.dto.PassportVisa; import bio.overture.ego.model.dto.VisaRequest; import bio.overture.ego.model.entity.Visa; -import bio.overture.ego.model.exceptions.InvalidTokenException; import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.repository.VisaRepository; import bio.overture.ego.utils.CacheUtil; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; import jakarta.validation.constraints.NotNull; import java.util.List; import java.util.Optional; @@ -81,9 +78,22 @@ public List getByTypeAndValue(@NonNull String type, @NotNull String value) } } - public void delete(@NonNull UUID id) { - checkExistence(id); - super.delete(id); + public List getByTypeAndValueForPassport(@NonNull String type, @NotNull String value) { + val result = visaRepository.getByTypeAndValue(type, value); + if (!result.isEmpty()) { + return result; + } + return null; + } + + public void delete(@NonNull String type, @NotNull String value) { + List visas = getByTypeAndValue(type, value); + if (visas != null && !visas.isEmpty()) { + visas.stream().forEach(visa -> visaRepository.delete(visa)); + } else { + throw new NotFoundException( + format("No Visa exists with type '%s' and value '%s'", type, value)); + } } // Parses Visa JWT token to convert into Visa Object @@ -99,22 +109,12 @@ public PassportVisa parseVisa(@NonNull String visaJwtToken) throws JsonProcessin } // Checks if the visa is a valid visa - public boolean isValidVisa(@NonNull String authToken) { - Claims claims; - try { - claims = - Jwts.parser() - .setSigningKey(cacheUtil.getPassportBrokerPublicKey()) - .parseClaimsJws(authToken) - .getBody(); - if (claims != null) { - return true; - } - } catch (Exception exception) { - throw new InvalidTokenException("The visa token received from broker is invalid"); - } - return false; - } + /*public void isValidVisa(@NonNull String authToken) throws JwkException { + DecodedJWT jwt = JWT.decode(authToken); + Jwk jwk = cacheUtil.getPassportBrokerPublicKey().provider.get(jwt.getKeyId()); + Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); + algorithm.verify(jwt); + }*/ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index cd5e9f76b..544f94170 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -186,7 +186,7 @@ token: broker: publicKey: - url: http://localhost:8082/token/public_key + url: https://login.elixir-czech.org/oidc/jwk # Default values available for creation of entities default: From 2574642f0cfad47c853aa169a0b2d2309ef51cc9 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Mon, 5 Jun 2023 12:02:22 -0400 Subject: [PATCH 34/43] Changes related to updateVisa Controller and adding JWKS token validation implementation( Commented out for fixing the JAR issue) --- pom.xml | 17 +++- .../ego/controller/VisaController.java | 42 ++++---- .../overture/ego/service/PassportService.java | 5 +- .../bio/overture/ego/service/VisaService.java | 34 ++++--- .../bio/overture/ego/utils/CacheUtil.java | 98 ++++++++++--------- 5 files changed, 104 insertions(+), 92 deletions(-) diff --git a/pom.xml b/pom.xml index b97fcaab5..bb8d74739 100644 --- a/pom.xml +++ b/pom.xml @@ -93,7 +93,16 @@ spring-boot-starter-test test - + + + + + + + + + + org.springframework.security spring-security-test @@ -403,12 +412,12 @@ com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} - - ${basedir}/src/main/proto + com.google.protobuf:protoc:3.21.7:exe:osx-x86_64 + ${basedir}/src/main/proto grpc-java io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier} - + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:osx-x86_64 diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index a98d6c1b8..6467edded 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -1,11 +1,17 @@ package bio.overture.ego.controller; +import static java.lang.String.format; import static org.springframework.web.bind.annotation.RequestMethod.*; -import bio.overture.ego.model.dto.*; -import bio.overture.ego.model.entity.*; +import bio.overture.ego.model.dto.PageDTO; +import bio.overture.ego.model.dto.VisaPermissionRequest; +import bio.overture.ego.model.dto.VisaRequest; +import bio.overture.ego.model.entity.Visa; +import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.security.AdminScoped; -import bio.overture.ego.service.*; +import bio.overture.ego.service.VisaPermissionService; +import bio.overture.ego.service.VisaService; import bio.overture.ego.view.Views; import com.fasterxml.jackson.annotation.JsonView; import io.swagger.v3.oas.annotations.Parameter; @@ -33,22 +39,11 @@ public class VisaController { private final VisaPermissionService visaPermissionService; - private final UserPermissionService userPermissionService; - private final GroupPermissionService groupPermissionService; - private final ApplicationPermissionService applicationPermissionService; - @Autowired public VisaController( - @NonNull VisaService visaService, - @NotNull VisaPermissionService visaPermissionService, - @NonNull UserPermissionService userPermissionService, - @NonNull GroupPermissionService groupPermissionService, - @NonNull ApplicationPermissionService applicationPermissionService) { + @NonNull VisaService visaService, @NotNull VisaPermissionService visaPermissionService) { this.visaService = visaService; this.visaPermissionService = visaPermissionService; - this.groupPermissionService = groupPermissionService; - this.userPermissionService = userPermissionService; - this.applicationPermissionService = applicationPermissionService; } /* @@ -67,7 +62,13 @@ public VisaController( final String authorization, @PathVariable(value = "type", required = true) String type, @PathVariable(value = "value", required = true) String value) { - return visaService.getByTypeAndValue(type, value); + List visas = visaService.getByTypeAndValue(type, value); + if (visas != null && !visas.isEmpty()) { + return visas; + } else { + throw new NotFoundException( + format("No Visa exists with type '%s' and value '%s'", type, value)); + } } /* @@ -110,14 +111,13 @@ public VisaController( * @return Visa visa */ @AdminScoped - @RequestMapping(method = PUT, value = "/{id}") + @RequestMapping(method = PUT, value = "/{type}/{value}") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Update Visa")}) - public @ResponseBody Visa updateVisa( + public @ResponseBody List updateVisa( @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, - @PathVariable(value = "id", required = true) UUID id, @RequestBody(required = true) VisaRequest visaRequest) { - return visaService.partialUpdate(id, visaRequest); + return visaService.partialUpdate(visaRequest); } /* @@ -193,7 +193,7 @@ public void deleteVisa( * @param visaPermissionRequest VisaPermissionRequest */ @AdminScoped - @RequestMapping(method = DELETE, value = "/permissions/{policyId}/{visaId}") + @RequestMapping(method = DELETE, value = "/permissions/{policyId}/{type}/{value}") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Remove VisaPermission")}) @JsonView(Views.REST.class) public @ResponseBody void removePermissions( diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index a6f6f607d..0e5624caf 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -4,7 +4,6 @@ import bio.overture.ego.model.dto.PassportVisa; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; -import bio.overture.ego.utils.CacheUtil; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; @@ -29,7 +28,7 @@ public class PassportService { @Autowired private VisaPermissionService visaPermissionService; - @Autowired private CacheUtil cacheUtil; + // @Autowired private CacheUtil cacheUtil; @Autowired public PassportService( @@ -90,7 +89,7 @@ private List getVisaPermissions(List visas) { .forEach( visa -> { List visaEntities = - visaService.getByTypeAndValueForPassport( + visaService.getByTypeAndValue( visa.getGa4ghVisaV1().getType(), visa.getGa4ghVisaV1().getValue()); if (visaEntities != null && !visaEntities.isEmpty()) { visaPermissions.addAll(visaPermissionService.getPermissionsForVisa(visaEntities)); diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 25f0a3c33..6011106af 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -11,10 +11,10 @@ import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.repository.VisaRepository; -import bio.overture.ego.utils.CacheUtil; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -42,7 +42,7 @@ public class VisaService extends AbstractNamedService { /** Dependencies */ @Autowired private VisaRepository visaRepository; - @Autowired private CacheUtil cacheUtil; + // @Autowired private CacheUtil cacheUtil; private final ApiKeyEventsPublisher apiKeyEventsPublisher; @@ -69,16 +69,6 @@ public Visa getById(@NonNull UUID uuid) { } public List getByTypeAndValue(@NonNull String type, @NotNull String value) { - val result = visaRepository.getByTypeAndValue(type, value); - if (!result.isEmpty()) { - return result; - } else { - throw new NotFoundException( - format("No Visa exists with type '%s' and value '%s'", type, value)); - } - } - - public List getByTypeAndValueForPassport(@NonNull String type, @NotNull String value) { val result = visaRepository.getByTypeAndValue(type, value); if (!result.isEmpty()) { return result; @@ -120,10 +110,22 @@ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } - public Visa partialUpdate(@NotNull UUID id, @NonNull VisaRequest updateRequest) { - val visa = getById(id); - VISA_CONVERTER.updateVisa(updateRequest, visa); - return getRepository().save(visa); + public List partialUpdate(@NonNull VisaRequest updateRequest) { + List updatedVisas = new ArrayList<>(); + List visas = getByTypeAndValue(updateRequest.getType(), updateRequest.getValue()); + if (visas != null && !visas.isEmpty()) { + for (Visa visa : visas) { + visa.setBy(updateRequest.getBy()); + visa.setSource(updateRequest.getSource()); + updatedVisas.add(getRepository().save(visa)); + } + } else { + throw new NotFoundException( + format( + "No Visa exists with type '%s' and value '%s'", + updateRequest.getType(), updateRequest.getValue())); + } + return updatedVisas; } @Mapper( diff --git a/src/main/java/bio/overture/ego/utils/CacheUtil.java b/src/main/java/bio/overture/ego/utils/CacheUtil.java index f512a6522..c47a1931a 100644 --- a/src/main/java/bio/overture/ego/utils/CacheUtil.java +++ b/src/main/java/bio/overture/ego/utils/CacheUtil.java @@ -1,48 +1,50 @@ -package bio.overture.ego.utils; - -import static bio.overture.ego.model.exceptions.InternalServerException.buildInternalServerException; -import static org.springframework.http.HttpMethod.GET; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; - -@Slf4j -@Component -public class CacheUtil { - - @Value("${broker.publicKey.url}") - private String brokerPublicKeyUrl; - - private RestTemplate restTemplate; - - @Cacheable("getPassportBrokerPublicKey") - public String getPassportBrokerPublicKey() { - ResponseEntity response; - try { - response = restTemplate.exchange(brokerPublicKeyUrl, GET, null, String.class); - } catch (HttpStatusCodeException err) { - log.error( - "Invalid {} response from passport broker service: {}", - err.getStatusCode().value(), - err.getMessage()); - throw buildInternalServerException( - "Invalid %s response from passport broker service.", err.getStatusCode().value()); - } - return response.getBody(); - } - - @CacheEvict(value = "evictAll", allEntries = true) - public void evictAllCaches() {} - - @Scheduled(fixedRate = 6000) - public void evictAllCachesEveryDay() { - evictAllCaches(); - } -} +// package bio.overture.ego.utils; +// +// import static +// bio.overture.ego.model.exceptions.InternalServerException.buildInternalServerException; +// import static org.springframework.http.HttpMethod.GET; +// +// import com.nimbusds.jose.jwk.JWKSet; +// import lombok.extern.slf4j.Slf4j; +// import org.springframework.beans.factory.annotation.Value; +// import org.springframework.cache.annotation.CacheEvict; +// import org.springframework.cache.annotation.Cacheable; +// import org.springframework.http.ResponseEntity; +// import org.springframework.scheduling.annotation.Scheduled; +// import org.springframework.stereotype.Component; +// import org.springframework.web.client.HttpStatusCodeException; +// import org.springframework.web.client.RestTemplate; +// +// @Slf4j +// @Component +// public class CacheUtil { +// +// @Value("${broker.publicKey.url}") +// private String brokerPublicKeyUrl; +// +// private RestTemplate restTemplate; +// +// @Cacheable("getPassportBrokerPublicKey") +// public JWKSet getPassportBrokerPublicKey() { +// ResponseEntity response; +// try { +// response = restTemplate.exchange(brokerPublicKeyUrl, GET, null, JWKSet.class); +// } catch (HttpStatusCodeException err) { +// log.error( +// "Invalid {} response from passport broker service: {}", +// err.getStatusCode().value(), +// err.getMessage()); +// throw buildInternalServerException( +// "Invalid %s response from passport broker service.", err.getStatusCode().value()); +// } +// return response.getBody(); +// } +// +// @CacheEvict(value = "evictAll", allEntries = true) +// public void evictAllCaches() {} +// +// @Scheduled(fixedRate = 6000) +// public void evictAllCachesEveryDay() { +// evictAllCaches(); +// } +// } From 18d3acf06229503aa1b20161254c0cc135d8047d Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Tue, 6 Jun 2023 14:05:53 -0400 Subject: [PATCH 35/43] Committing changes related to broker verifier for validating passport and visa --- pom.xml | 20 +-- .../overture/ego/service/PassportService.java | 29 +++-- .../bio/overture/ego/service/VisaService.java | 15 ++- .../bio/overture/ego/utils/CacheUtil.java | 115 ++++++++++-------- 4 files changed, 104 insertions(+), 75 deletions(-) diff --git a/pom.xml b/pom.xml index bb8d74739..a9bb2dc18 100644 --- a/pom.xml +++ b/pom.xml @@ -93,16 +93,16 @@ spring-boot-starter-test test - - - - - - - - - - + + com.auth0 + java-jwt + 4.4.0 + + + com.auth0 + jwks-rsa + 0.22.0 + org.springframework.security spring-security-test diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 0e5624caf..a2981d1f1 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -4,8 +4,16 @@ import bio.overture.ego.model.dto.PassportVisa; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; +import bio.overture.ego.utils.CacheUtil; +import com.auth0.jwk.Jwk; +import com.auth0.jwk.JwkException; +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import java.security.interfaces.RSAPublicKey; +import java.text.ParseException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -28,7 +36,7 @@ public class PassportService { @Autowired private VisaPermissionService visaPermissionService; - // @Autowired private CacheUtil cacheUtil; + @Autowired private CacheUtil cacheUtil; @Autowired public PassportService( @@ -37,11 +45,10 @@ public PassportService( this.visaPermissionService = visaPermissionService; } - public List getPermissions(String authToken) throws JsonProcessingException { + public List getPermissions(String authToken) + throws JsonProcessingException, ParseException, JwkException { // Validates passport auth token - /*if (!isValidPassport(authToken)) { - throw new InvalidTokenException("The passport token received from broker is invalid"); - }*/ + isValidPassport(authToken); // Parses passport JWT token Passport parsedPassport = parsePassport(authToken); // Fetches visas for parsed passport @@ -54,12 +61,13 @@ public List getPermissions(String authToken) throws JsonProcessi } // Validates passport token based on public key - /*private void isValidPassport(@NonNull String authToken) throws ParseException, JwkException { + private void isValidPassport(@NonNull String authToken) + throws ParseException, JwkException, JsonProcessingException { DecodedJWT jwt = JWT.decode(authToken); - Jwk jwk = cacheUtil.getPassportBrokerPublicKey().provider.get(jwt.getKeyId()); + Jwk jwk = cacheUtil.getPassportBrokerPublicKey().get(jwt.getKeyId()); Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); algorithm.verify(jwt); - }*/ + } // Extracts Visas from parsed passport object private List getVisas(Passport passport) { @@ -68,13 +76,12 @@ private List getVisas(Passport passport) { .forEach( visaJwt -> { try { - // if (visaService.isValidVisa(visaJwt)) { + visaService.isValidVisa(visaJwt); PassportVisa visa = visaService.parseVisa(visaJwt); if (visa != null) { visas.add(visa); } - // } - } catch (JsonProcessingException e) { + } catch (JsonProcessingException | JwkException e) { e.printStackTrace(); } }); diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 6011106af..df5aac6c2 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -11,9 +11,16 @@ import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.exceptions.NotFoundException; import bio.overture.ego.repository.VisaRepository; +import bio.overture.ego.utils.CacheUtil; +import com.auth0.jwk.Jwk; +import com.auth0.jwk.JwkException; +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.validation.constraints.NotNull; +import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -42,7 +49,7 @@ public class VisaService extends AbstractNamedService { /** Dependencies */ @Autowired private VisaRepository visaRepository; - // @Autowired private CacheUtil cacheUtil; + @Autowired private CacheUtil cacheUtil; private final ApiKeyEventsPublisher apiKeyEventsPublisher; @@ -99,12 +106,12 @@ public PassportVisa parseVisa(@NonNull String visaJwtToken) throws JsonProcessin } // Checks if the visa is a valid visa - /*public void isValidVisa(@NonNull String authToken) throws JwkException { + public void isValidVisa(@NonNull String authToken) throws JwkException, JsonProcessingException { DecodedJWT jwt = JWT.decode(authToken); - Jwk jwk = cacheUtil.getPassportBrokerPublicKey().provider.get(jwt.getKeyId()); + Jwk jwk = cacheUtil.getPassportBrokerPublicKey().get(jwt.getKeyId()); Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); algorithm.verify(jwt); - }*/ + } public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); diff --git a/src/main/java/bio/overture/ego/utils/CacheUtil.java b/src/main/java/bio/overture/ego/utils/CacheUtil.java index c47a1931a..3ea88951d 100644 --- a/src/main/java/bio/overture/ego/utils/CacheUtil.java +++ b/src/main/java/bio/overture/ego/utils/CacheUtil.java @@ -1,50 +1,65 @@ -// package bio.overture.ego.utils; -// -// import static -// bio.overture.ego.model.exceptions.InternalServerException.buildInternalServerException; -// import static org.springframework.http.HttpMethod.GET; -// -// import com.nimbusds.jose.jwk.JWKSet; -// import lombok.extern.slf4j.Slf4j; -// import org.springframework.beans.factory.annotation.Value; -// import org.springframework.cache.annotation.CacheEvict; -// import org.springframework.cache.annotation.Cacheable; -// import org.springframework.http.ResponseEntity; -// import org.springframework.scheduling.annotation.Scheduled; -// import org.springframework.stereotype.Component; -// import org.springframework.web.client.HttpStatusCodeException; -// import org.springframework.web.client.RestTemplate; -// -// @Slf4j -// @Component -// public class CacheUtil { -// -// @Value("${broker.publicKey.url}") -// private String brokerPublicKeyUrl; -// -// private RestTemplate restTemplate; -// -// @Cacheable("getPassportBrokerPublicKey") -// public JWKSet getPassportBrokerPublicKey() { -// ResponseEntity response; -// try { -// response = restTemplate.exchange(brokerPublicKeyUrl, GET, null, JWKSet.class); -// } catch (HttpStatusCodeException err) { -// log.error( -// "Invalid {} response from passport broker service: {}", -// err.getStatusCode().value(), -// err.getMessage()); -// throw buildInternalServerException( -// "Invalid %s response from passport broker service.", err.getStatusCode().value()); -// } -// return response.getBody(); -// } -// -// @CacheEvict(value = "evictAll", allEntries = true) -// public void evictAllCaches() {} -// -// @Scheduled(fixedRate = 6000) -// public void evictAllCachesEveryDay() { -// evictAllCaches(); -// } -// } +package bio.overture.ego.utils; + +import static bio.overture.ego.model.exceptions.InternalServerException.buildInternalServerException; +import static org.springframework.http.HttpMethod.GET; + +import com.auth0.jwk.Jwk; +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Component +public class CacheUtil { + + @Value("${broker.publicKey.url}") + private String brokerPublicKeyUrl; + + private RestTemplate restTemplate; + + @Cacheable("getPassportBrokerPublicKey") + public Map getPassportBrokerPublicKey() throws JsonProcessingException { + ResponseEntity> response; + Map jwkMap = new HashMap(); + try { + restTemplate = new RestTemplate(); + response = + restTemplate.exchange( + brokerPublicKeyUrl, + GET, + null, + new ParameterizedTypeReference>() {}); + } catch (HttpStatusCodeException err) { + log.error( + "Invalid {} response from passport broker config: {}", + err.getStatusCode().value(), + err.getMessage()); + throw buildInternalServerException( + "Invalid %s response from passport broker config.", err.getStatusCode().value()); + } + for (Object obj : response.getBody().get("keys")) { + Jwk jwkObject = Jwk.fromValues((Map) obj); + jwkMap.put(jwkObject.getId(), jwkObject); + } + return jwkMap; + } + + @CacheEvict(value = "evictAll", allEntries = true) + public void evictAllCaches() {} + + @Scheduled(fixedRate = 6000) + public void evictAllCachesEveryDay() { + evictAllCaches(); + } +} From 4f16469e1f1377655718aa6a6cb65466ee1bfa10 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Tue, 6 Jun 2023 14:06:38 -0400 Subject: [PATCH 36/43] Committing changes related to broker verifier for validating passport and visa --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index a9bb2dc18..61c4baece 100644 --- a/pom.xml +++ b/pom.xml @@ -412,12 +412,12 @@ com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} - com.google.protobuf:protoc:3.21.7:exe:osx-x86_64 - ${basedir}/src/main/proto + + ${basedir}/src/main/proto grpc-java io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier} - io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:osx-x86_64 + From bb7b5560c19ec4564a5ded27efba26c6f0f693f3 Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Wed, 7 Jun 2023 10:50:12 -0400 Subject: [PATCH 37/43] add passport permissions to ego token --- .../ego/controller/AuthController.java | 14 ++- .../overture/ego/model/dto/PassportToken.java | 14 +++ .../ego/security/CustomOAuth2User.java | 3 + .../security/CustomOidc2UserInfoService.java | 1 + .../overture/ego/service/PassportService.java | 91 +++++++++++++++++++ .../overture/ego/service/TokenService.java | 35 ++++++- 6 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/main/java/bio/overture/ego/model/dto/PassportToken.java diff --git a/src/main/java/bio/overture/ego/controller/AuthController.java b/src/main/java/bio/overture/ego/controller/AuthController.java index b6b696a4a..b3f311d8a 100644 --- a/src/main/java/bio/overture/ego/controller/AuthController.java +++ b/src/main/java/bio/overture/ego/controller/AuthController.java @@ -27,6 +27,7 @@ import bio.overture.ego.model.exceptions.InvalidTokenException; import bio.overture.ego.provider.google.GoogleTokenService; import bio.overture.ego.security.CustomOAuth2User; +import bio.overture.ego.service.PassportService; import bio.overture.ego.service.RefreshContextService; import bio.overture.ego.service.TokenService; import bio.overture.ego.token.IDToken; @@ -59,17 +60,22 @@ public class AuthController { private String TOKEN_PREFIX; private final TokenService tokenService; + private final PassportService passportService; private final GoogleTokenService googleTokenService; private final TokenSigner tokenSigner; private final RefreshContextService refreshContextService; + private final String PASSPORT_CLIENT_NAME = "passport"; + @Autowired public AuthController( @NonNull TokenService tokenService, + @NonNull PassportService passportService, @NonNull GoogleTokenService googleTokenService, @NonNull TokenSigner tokenSigner, @NonNull RefreshContextService refreshContextService) { this.tokenService = tokenService; + this.passportService = passportService; this.googleTokenService = googleTokenService; this.tokenSigner = tokenSigner; this.refreshContextService = refreshContextService; @@ -121,6 +127,11 @@ public ResponseEntity user( } val user = (CustomOAuth2User) authentication.getPrincipal(); + + val passportJwtToken = (authentication.getAuthorizedClientRegistrationId().equals(PASSPORT_CLIENT_NAME)) ? + passportService.getPassportToken(((CustomOAuth2User) authentication.getPrincipal()).getAccessToken()) : + null; + String token = tokenService.generateUserToken( IDToken.builder() @@ -131,7 +142,8 @@ public ResponseEntity user( .providerType( ProviderType.resolveProviderType( authentication.getAuthorizedClientRegistrationId())) - .build()); + .build(), + passportJwtToken); val outgoingRefreshContext = refreshContextService.createInitialRefreshContext(token); val cookie = diff --git a/src/main/java/bio/overture/ego/model/dto/PassportToken.java b/src/main/java/bio/overture/ego/model/dto/PassportToken.java new file mode 100644 index 000000000..a437c8c16 --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/PassportToken.java @@ -0,0 +1,14 @@ +package bio.overture.ego.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class PassportToken { + + private String access_token; + private String refresh_token; + private Long expires_in; + private String issued_token_type; +} diff --git a/src/main/java/bio/overture/ego/security/CustomOAuth2User.java b/src/main/java/bio/overture/ego/security/CustomOAuth2User.java index 62f2fed67..3c9647c53 100644 --- a/src/main/java/bio/overture/ego/security/CustomOAuth2User.java +++ b/src/main/java/bio/overture/ego/security/CustomOAuth2User.java @@ -23,6 +23,7 @@ public class CustomOAuth2User implements OidcUser { @NonNull private String subjectId; private String email; private OAuth2User oauth2User; + private String accessToken; @Override public Map getAttributes() { @@ -47,6 +48,8 @@ public String getFamilyName() { return this.familyName; } + public String getAccessToken() { return this.accessToken; } + public String getSubjectId() { return oauth2User.getAttributes().containsKey(IdTokenClaimNames.SUB) ? oauth2User.getAttributes().get(IdTokenClaimNames.SUB).toString() diff --git a/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java b/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java index 77dc4d9f4..9ebd55f87 100644 --- a/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java +++ b/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java @@ -53,6 +53,7 @@ public OidcUser loadUser(OidcUserRequest oAuth2UserRequest) throws OAuth2Authent .email(oidcUser.getEmail()) .familyName(oidcUser.getFamilyName()) .givenName(oidcUser.getGivenName()) + .accessToken(oAuth2UserRequest.getAccessToken().getTokenValue()) .build(); } catch (AuthenticationException ex) { throw ex; diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index a2981d1f1..42c1eb7e9 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -1,7 +1,9 @@ package bio.overture.ego.service; import bio.overture.ego.model.dto.Passport; +import bio.overture.ego.model.dto.PassportToken; import bio.overture.ego.model.dto.PassportVisa; +import bio.overture.ego.model.dto.Scope; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; import bio.overture.ego.utils.CacheUtil; @@ -21,14 +23,26 @@ import java.util.stream.Collectors; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; +import lombok.val; import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import static bio.overture.ego.utils.CollectionUtils.mapToSet; @Slf4j @Service @Transactional +@Configuration public class PassportService { /** Dependencies */ @@ -38,6 +52,21 @@ public class PassportService { @Autowired private CacheUtil cacheUtil; + private final String REQUESTED_TOKEN_TYPE = "urn:ga4gh:params:oauth:token-type:passport"; + private final String SUBJECT_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token"; + private final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange"; + + @Value("${spring.security.oauth2.client.registration.passport.clientId}") + private String clientId; + + @Value("${spring.security.oauth2.client.registration.passport.clientSecret}") + private String clientSecret; + + @Value("${spring.security.oauth2.client.provider.passport.issuer-uri}") + private String passportIssuerUri; + + + @Autowired public PassportService( @NonNull VisaPermissionService visaPermissionService, @NonNull VisaService visaService) { @@ -105,6 +134,15 @@ private List getVisaPermissions(List visas) { return visaPermissions; } + public Set extractScopes(@NonNull String passportJwtToken) throws ParseException, JwkException, JsonProcessingException { + val resolvedPermissions = getPermissions(passportJwtToken); + val output = mapToSet(resolvedPermissions, AbstractPermissionService::buildScope); + if (output.isEmpty()) { + output.add(Scope.defaultScope()); + } + return output; + } + // Parse Passport token to extract the passport body public Passport parsePassport(@NonNull String passportJwtToken) throws JsonProcessingException { String[] split_string = passportJwtToken.split("\\."); @@ -123,4 +161,57 @@ private List deDupeVisaPermissions(List visaPerm permissionsSet.addAll(visaPermissions); return permissionsSet.stream().collect(Collectors.toList()); } + + public String getPassportToken(String accessToken) { + + if (accessToken == null || accessToken.isEmpty()) return null; + + val params = passportTokenParams(accessToken); + + val uri = UriComponentsBuilder + .fromUriString(passportIssuerUri) + .path("/token") + .queryParams(params) + .toUriString(); + + val passportToken = getTemplate(clientId, clientSecret) + .exchange(uri, + HttpMethod.POST, + null, + PassportToken.class) + .getBody(); + + return (passportToken != null) ? + passportToken.getAccess_token() : + null; + } + + private RestTemplate getTemplate(String clientId, String clientSecret) { + RestTemplate restTemplate = new RestTemplate(); + restTemplate + .getInterceptors() + .add( + (x, y, z) -> { + x.getHeaders() + .set( + HttpHeaders.AUTHORIZATION, + "Basic " + getBasicAuthHeader(clientId, clientSecret)); + return z.execute(x, y); + }); + return restTemplate; + } + + private String getBasicAuthHeader(String clientId, String clientSecret) { + String credentials = clientId + ":" + clientSecret; + return new String(Base64.encodeBase64(credentials.getBytes())); + } + + private MultiValueMap passportTokenParams(String accessToken){ + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("requested_token_type", REQUESTED_TOKEN_TYPE); + params.add("subject_token", accessToken); + params.add("subject_token_type", SUBJECT_TOKEN_TYPE); + params.add("grant_type", GRANT_TYPE); + return params; + } } diff --git a/src/main/java/bio/overture/ego/service/TokenService.java b/src/main/java/bio/overture/ego/service/TokenService.java index 0ba4162b2..67da32796 100644 --- a/src/main/java/bio/overture/ego/service/TokenService.java +++ b/src/main/java/bio/overture/ego/service/TokenService.java @@ -100,6 +100,7 @@ public class TokenService extends AbstractNamedService { private final ApplicationService applicationService; private final ApiKeyStoreService apiKeyStoreService; private final PolicyService policyService; + private final PassportService passportService; private final UserRepository userRepository; /** Configuration */ @@ -115,6 +116,7 @@ public TokenService( @NonNull ApplicationService applicationService, @NonNull ApiKeyStoreService apiKeyStoreService, @NonNull PolicyService policyService, + @NonNull PassportService passportService, @NonNull TokenStoreRepository tokenStoreRepository, @NonNull UserRepository userRepository, @Value("${jwt.user.durationMs:10800000}") int userJwtDuration, @@ -126,6 +128,7 @@ public TokenService( this.applicationService = applicationService; this.apiKeyStoreService = apiKeyStoreService; this.policyService = policyService; + this.passportService = passportService; this.userRepository = userRepository; this.userJwtDuration = userJwtDuration; this.appJwtDuration = appJwtDuration; @@ -138,8 +141,12 @@ public ApiKey getWithRelationships(@NonNull UUID id) { } public String generateUserToken(IDToken idToken) { + return generateUserToken(idToken, null); + } + + public String generateUserToken(IDToken idToken, String passportJwtToken) { val user = userService.getUserByToken(idToken); - return generateUserToken(user); + return generateUserToken(user, passportJwtToken); } public String updateUserToken(String accessToken) { @@ -167,6 +174,19 @@ public String generateUserToken(User u) { return generateUserToken(u, extractExplicitScopes(u)); } + @SneakyThrows + public String generateUserToken(User u, String passportJwtToken) { + + Set scopes = extractExplicitScopes(u); + + if (passportJwtToken != null){ + Set scopesFromVisas = extractExplicitScopes(passportJwtToken); + scopes = mergeScopes(scopes, scopesFromVisas); + } + + return generateUserToken(u, scopes); + } + @SneakyThrows public String generateUserToken(UUID userId) { val user = userService.findById(userId); @@ -580,6 +600,19 @@ private static Set extractExplicitScopes(Application a) { return mapToSet(explicitScopes(extractScopes(a)), Scope::toString); } + @SneakyThrows + private Set extractExplicitScopes(String passportJwtToken){ + return mapToSet(explicitScopes(passportService.extractScopes(passportJwtToken)), Scope::toString); + } + + private Set mergeScopes(Set scopeSet, Set scopeSetAdditional){ + scopeSet.addAll(scopeSetAdditional); + if(scopeSet.size()>1 && scopeSet.contains(Scope.defaultScope().toString())){ + scopeSet.remove(Scope.defaultScope().toString()); + } + return scopeSet; + } + /** DEPRECATED: To be removed in next major release */ @Deprecated private TokenResponse createTokenResponse(@NonNull ApiKey token) { From 9cebbcfadaa1db55c0d74e986407c7f9a9539ff5 Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Wed, 7 Jun 2023 12:05:52 -0400 Subject: [PATCH 38/43] Committing changes related to update visa and remove permissions path variable --- .../ego/controller/VisaController.java | 9 ++++--- .../ego/service/VisaPermissionService.java | 26 ++++++++++++------- .../bio/overture/ego/service/VisaService.java | 12 ++++----- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index 6467edded..acb102e1b 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -116,8 +116,10 @@ public VisaController( public @ResponseBody List updateVisa( @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, + @PathVariable(value = "type", required = true) String type, + @PathVariable(value = "value", required = true) String value, @RequestBody(required = true) VisaRequest visaRequest) { - return visaService.partialUpdate(visaRequest); + return visaService.partialUpdate(type, value, visaRequest); } /* @@ -200,7 +202,8 @@ public void deleteVisa( @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) final String authorization, @PathVariable(value = "policyId", required = true) UUID policyId, - @PathVariable(value = "visaId", required = true) UUID visaId) { - visaPermissionService.removePermission(policyId, visaId); + @PathVariable(value = "type", required = true) String type, + @PathVariable(value = "value", required = true) String value) { + visaPermissionService.removePermission(policyId, type, value); } } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 8b1e8e314..9eb91096c 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -83,16 +83,22 @@ public VisaPermission createOrUpdatePermissions( } } - public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { - VisaPermission visaPermission = null; - List visaPermissionEntities = - visaPermissionRepository.findByPolicyIdAndVisaId(policyId, visaId); - if (!visaPermissionEntities.isEmpty()) { - visaPermissionRepository.deleteById(visaPermissionEntities.get(0).getId()); - } else { - throw new NotFoundException( - format("No VisaPermissions exists with policyId '%s' and visaId '%s'", policyId, visaId)); - } + public void removePermission( + @NonNull UUID policyId, @NotNull String type, @NotNull String value) { + visaService.getByTypeAndValue(type, value).stream() + .forEach( + visa -> { + List visaPermissionEntities = + visaPermissionRepository.findByPolicyIdAndVisaId(policyId, visa.getId()); + if (!visaPermissionEntities.isEmpty()) { + visaPermissionRepository.deleteById(visaPermissionEntities.get(0).getId()); + } else { + throw new NotFoundException( + format( + "No VisaPermissions exists with policyId '%s' and type '%s' and value '%s'", + policyId, type, value)); + } + }); } // Fetches visa permissions for given visa request diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index df5aac6c2..1638d2aff 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -30,7 +30,6 @@ import lombok.val; import org.apache.commons.codec.binary.Base64; import org.mapstruct.Mapper; -import org.mapstruct.MappingTarget; import org.mapstruct.NullValueCheckStrategy; import org.mapstruct.ReportingPolicy; import org.springframework.beans.factory.annotation.Autowired; @@ -117,11 +116,14 @@ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } - public List partialUpdate(@NonNull VisaRequest updateRequest) { + public List partialUpdate( + @NotNull String type, @NotNull String value, @NonNull VisaRequest updateRequest) { List updatedVisas = new ArrayList<>(); - List visas = getByTypeAndValue(updateRequest.getType(), updateRequest.getValue()); + List visas = getByTypeAndValue(type, value); if (visas != null && !visas.isEmpty()) { for (Visa visa : visas) { + visa.setType(updateRequest.getType()); + visa.setValue(updateRequest.getValue()); visa.setBy(updateRequest.getBy()); visa.setSource(updateRequest.getSource()); updatedVisas.add(getRepository().save(visa)); @@ -130,7 +132,7 @@ public List partialUpdate(@NonNull VisaRequest updateRequest) { throw new NotFoundException( format( "No Visa exists with type '%s' and value '%s'", - updateRequest.getType(), updateRequest.getValue())); + type, value)); } return updatedVisas; } @@ -140,8 +142,6 @@ public List partialUpdate(@NonNull VisaRequest updateRequest) { unmappedTargetPolicy = ReportingPolicy.WARN) public abstract static class VisaConverter { public abstract Visa convertToVisa(VisaRequest request); - - public abstract void updateVisa(VisaRequest request, @MappingTarget Visa visaToUpdate); } @Override From 10949a328dbd72cc53af311f6f79a7541d4d44ef Mon Sep 17 00:00:00 2001 From: Azher2Ali <121898125+Azher2Ali@users.noreply.github.com> Date: Thu, 8 Jun 2023 07:49:18 -0400 Subject: [PATCH 39/43] Committing changes related to removal passport controller --- .../ego/controller/PassportController.java | 54 ------------------- 1 file changed, 54 deletions(-) delete mode 100644 src/main/java/bio/overture/ego/controller/PassportController.java diff --git a/src/main/java/bio/overture/ego/controller/PassportController.java b/src/main/java/bio/overture/ego/controller/PassportController.java deleted file mode 100644 index 377e711c2..000000000 --- a/src/main/java/bio/overture/ego/controller/PassportController.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2017. The Ontario Institute for Cancer Research. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bio.overture.ego.controller; - -import static org.springframework.http.HttpStatus.*; -import static org.springframework.web.bind.annotation.RequestMethod.*; - -import bio.overture.ego.model.entity.VisaPermission; -import bio.overture.ego.service.PassportService; -import io.swagger.v3.oas.annotations.tags.Tag; -import java.util.List; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -@Slf4j -@RestController -@RequestMapping("/passport") -@Tag( - name = "Passport", - description = - "Passport-Controller (Only for Testing. To be removed post integration with broker service)") -public class PassportController { - - private final PassportService passportService; - - @Autowired - public PassportController(@NonNull PassportService passportService) { - this.passportService = passportService; - } - - @RequestMapping(method = POST, value = "/passport/token") - @ResponseStatus(value = OK) - @SneakyThrows - public @ResponseBody List getVisaPermissions(@RequestBody String authToken) { - return passportService.getPermissions(authToken); - } -} From b2ccb871bb90c819536f844be852244571a794f8 Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Tue, 13 Jun 2023 09:20:03 -0400 Subject: [PATCH 40/43] multiple passport brokers --- .../ego/controller/AuthController.java | 13 +++-- .../overture/ego/service/PassportService.java | 50 ++++++++----------- .../overture/ego/service/TokenService.java | 16 +++--- .../bio/overture/ego/service/VisaService.java | 4 +- .../bio/overture/ego/utils/CacheUtil.java | 15 +++--- src/main/resources/application.yml | 5 +- 6 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/main/java/bio/overture/ego/controller/AuthController.java b/src/main/java/bio/overture/ego/controller/AuthController.java index b3f311d8a..006834b0c 100644 --- a/src/main/java/bio/overture/ego/controller/AuthController.java +++ b/src/main/java/bio/overture/ego/controller/AuthController.java @@ -64,8 +64,7 @@ public class AuthController { private final GoogleTokenService googleTokenService; private final TokenSigner tokenSigner; private final RefreshContextService refreshContextService; - - private final String PASSPORT_CLIENT_NAME = "passport"; + private final String GA4GH_PASSPORT_SCOPE = "ga4gh_passport_v1"; @Autowired public AuthController( @@ -128,8 +127,11 @@ public ResponseEntity user( val user = (CustomOAuth2User) authentication.getPrincipal(); - val passportJwtToken = (authentication.getAuthorizedClientRegistrationId().equals(PASSPORT_CLIENT_NAME)) ? - passportService.getPassportToken(((CustomOAuth2User) authentication.getPrincipal()).getAccessToken()) : + + val passportJwtToken = (user.getClaim(GA4GH_PASSPORT_SCOPE) != null) ? + passportService.getPassportToken( + authentication.getAuthorizedClientRegistrationId(), + user.getAccessToken()) : null; String token = @@ -143,7 +145,8 @@ public ResponseEntity user( ProviderType.resolveProviderType( authentication.getAuthorizedClientRegistrationId())) .build(), - passportJwtToken); + passportJwtToken, + authentication.getAuthorizedClientRegistrationId()); val outgoingRefreshContext = refreshContextService.createInitialRefreshContext(token); val cookie = diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index 42c1eb7e9..a32237ec9 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -26,10 +26,11 @@ import lombok.val; import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.LinkedMultiValueMap; @@ -52,20 +53,12 @@ public class PassportService { @Autowired private CacheUtil cacheUtil; + @Autowired private ClientRegistrationRepository clientRegistrationRepository; + private final String REQUESTED_TOKEN_TYPE = "urn:ga4gh:params:oauth:token-type:passport"; private final String SUBJECT_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token"; private final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange"; - @Value("${spring.security.oauth2.client.registration.passport.clientId}") - private String clientId; - - @Value("${spring.security.oauth2.client.registration.passport.clientSecret}") - private String clientSecret; - - @Value("${spring.security.oauth2.client.provider.passport.issuer-uri}") - private String passportIssuerUri; - - @Autowired public PassportService( @@ -74,14 +67,14 @@ public PassportService( this.visaPermissionService = visaPermissionService; } - public List getPermissions(String authToken) + public List getPermissions(String authToken, String providerType) throws JsonProcessingException, ParseException, JwkException { // Validates passport auth token - isValidPassport(authToken); + isValidPassport(authToken, providerType); // Parses passport JWT token Passport parsedPassport = parsePassport(authToken); // Fetches visas for parsed passport - List visas = getVisas(parsedPassport); + List visas = getVisas(parsedPassport, providerType); // Fetches visa permissions for extracted visas List visaPermissions = getVisaPermissions(visas); // removes deduplicates from visaPermissions @@ -90,22 +83,22 @@ public List getPermissions(String authToken) } // Validates passport token based on public key - private void isValidPassport(@NonNull String authToken) - throws ParseException, JwkException, JsonProcessingException { + private void isValidPassport(@NonNull String authToken, @NonNull String providerType) + throws JwkException { DecodedJWT jwt = JWT.decode(authToken); - Jwk jwk = cacheUtil.getPassportBrokerPublicKey().get(jwt.getKeyId()); + Jwk jwk = cacheUtil.getPassportBrokerPublicKey(providerType).get(jwt.getKeyId()); Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); algorithm.verify(jwt); } // Extracts Visas from parsed passport object - private List getVisas(Passport passport) { + private List getVisas(Passport passport, @NonNull String providerType) { List visas = new ArrayList<>(); passport.getGa4ghPassportV1().stream() .forEach( visaJwt -> { try { - visaService.isValidVisa(visaJwt); + visaService.isValidVisa(visaJwt, providerType); PassportVisa visa = visaService.parseVisa(visaJwt); if (visa != null) { visas.add(visa); @@ -134,8 +127,8 @@ private List getVisaPermissions(List visas) { return visaPermissions; } - public Set extractScopes(@NonNull String passportJwtToken) throws ParseException, JwkException, JsonProcessingException { - val resolvedPermissions = getPermissions(passportJwtToken); + public Set extractScopes(@NonNull String passportJwtToken, @NonNull String providerType) throws ParseException, JwkException, JsonProcessingException { + val resolvedPermissions = getPermissions(passportJwtToken, providerType); val output = mapToSet(resolvedPermissions, AbstractPermissionService::buildScope); if (output.isEmpty()) { output.add(Scope.defaultScope()); @@ -162,19 +155,18 @@ private List deDupeVisaPermissions(List visaPerm return permissionsSet.stream().collect(Collectors.toList()); } - public String getPassportToken(String accessToken) { + public String getPassportToken(String providerId, String accessToken) { if (accessToken == null || accessToken.isEmpty()) return null; - val params = passportTokenParams(accessToken); + val clientRegistration = clientRegistrationRepository.findByRegistrationId(providerId); val uri = UriComponentsBuilder - .fromUriString(passportIssuerUri) - .path("/token") - .queryParams(params) + .fromUriString(clientRegistration.getProviderDetails().getTokenUri()) + .queryParams(passportTokenParams(accessToken)) .toUriString(); - val passportToken = getTemplate(clientId, clientSecret) + val passportToken = getTemplate(clientRegistration) .exchange(uri, HttpMethod.POST, null, @@ -186,7 +178,7 @@ public String getPassportToken(String accessToken) { null; } - private RestTemplate getTemplate(String clientId, String clientSecret) { + private RestTemplate getTemplate(ClientRegistration clientRegistration) { RestTemplate restTemplate = new RestTemplate(); restTemplate .getInterceptors() @@ -195,7 +187,7 @@ private RestTemplate getTemplate(String clientId, String clientSecret) { x.getHeaders() .set( HttpHeaders.AUTHORIZATION, - "Basic " + getBasicAuthHeader(clientId, clientSecret)); + "Basic " + getBasicAuthHeader(clientRegistration.getClientId(), clientRegistration.getClientSecret())); return z.execute(x, y); }); return restTemplate; diff --git a/src/main/java/bio/overture/ego/service/TokenService.java b/src/main/java/bio/overture/ego/service/TokenService.java index 67da32796..66feb55be 100644 --- a/src/main/java/bio/overture/ego/service/TokenService.java +++ b/src/main/java/bio/overture/ego/service/TokenService.java @@ -141,12 +141,12 @@ public ApiKey getWithRelationships(@NonNull UUID id) { } public String generateUserToken(IDToken idToken) { - return generateUserToken(idToken, null); + return generateUserToken(idToken, null, null); } - public String generateUserToken(IDToken idToken, String passportJwtToken) { + public String generateUserToken(IDToken idToken, String passportJwtToken, String providerType) { val user = userService.getUserByToken(idToken); - return generateUserToken(user, passportJwtToken); + return generateUserToken(user, passportJwtToken, providerType); } public String updateUserToken(String accessToken) { @@ -175,12 +175,12 @@ public String generateUserToken(User u) { } @SneakyThrows - public String generateUserToken(User u, String passportJwtToken) { + public String generateUserToken(User u, String passportJwtToken, String providerType) { Set scopes = extractExplicitScopes(u); - if (passportJwtToken != null){ - Set scopesFromVisas = extractExplicitScopes(passportJwtToken); + if (passportJwtToken != null && providerType != null){ + Set scopesFromVisas = extractExplicitScopes(passportJwtToken, providerType); scopes = mergeScopes(scopes, scopesFromVisas); } @@ -601,8 +601,8 @@ private static Set extractExplicitScopes(Application a) { } @SneakyThrows - private Set extractExplicitScopes(String passportJwtToken){ - return mapToSet(explicitScopes(passportService.extractScopes(passportJwtToken)), Scope::toString); + private Set extractExplicitScopes(String passportJwtToken, String providerType){ + return mapToSet(explicitScopes(passportService.extractScopes(passportJwtToken, providerType)), Scope::toString); } private Set mergeScopes(Set scopeSet, Set scopeSetAdditional){ diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 1638d2aff..8a26ad186 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -105,9 +105,9 @@ public PassportVisa parseVisa(@NonNull String visaJwtToken) throws JsonProcessin } // Checks if the visa is a valid visa - public void isValidVisa(@NonNull String authToken) throws JwkException, JsonProcessingException { + public void isValidVisa(@NonNull String authToken, @NonNull String providerType) throws JwkException, JsonProcessingException { DecodedJWT jwt = JWT.decode(authToken); - Jwk jwk = cacheUtil.getPassportBrokerPublicKey().get(jwt.getKeyId()); + Jwk jwk = cacheUtil.getPassportBrokerPublicKey(providerType).get(jwt.getKeyId()); Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); algorithm.verify(jwt); } diff --git a/src/main/java/bio/overture/ego/utils/CacheUtil.java b/src/main/java/bio/overture/ego/utils/CacheUtil.java index 3ea88951d..ac9d43b9c 100644 --- a/src/main/java/bio/overture/ego/utils/CacheUtil.java +++ b/src/main/java/bio/overture/ego/utils/CacheUtil.java @@ -4,17 +4,18 @@ import static org.springframework.http.HttpMethod.GET; import com.auth0.jwk.Jwk; -import com.fasterxml.jackson.core.JsonProcessingException; import java.util.HashMap; import java.util.List; import java.util.Map; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; +import lombok.val; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.ResponseEntity; import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.RestTemplate; @@ -23,20 +24,22 @@ @Component public class CacheUtil { - @Value("${broker.publicKey.url}") - private String brokerPublicKeyUrl; + @Autowired + private ClientRegistrationRepository clientRegistrationRepository; private RestTemplate restTemplate; @Cacheable("getPassportBrokerPublicKey") - public Map getPassportBrokerPublicKey() throws JsonProcessingException { + public Map getPassportBrokerPublicKey(String providerType) { ResponseEntity> response; Map jwkMap = new HashMap(); + + val clientRegistration = clientRegistrationRepository.findByRegistrationId(providerType); try { restTemplate = new RestTemplate(); response = restTemplate.exchange( - brokerPublicKeyUrl, + clientRegistration.getProviderDetails().getJwkSetUri(), GET, null, new ParameterizedTypeReference>() {}); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3a45ac08a..b2757b4a0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -70,6 +70,8 @@ spring: - openid - email - profile + + # Passport brokers must have ga4gh_passport_v1 scope passport: clientId: ego-client clientSecret: @@ -197,9 +199,6 @@ token: private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSU6oy48sJW6xzqzOSU1dAvUUeFKQSBHsCf7wGWUGpOxEczhtFiiyx4YUJtg+fyvwWxa4wO3GnQLBPIxBHY8JsnvjQN2lsTUoLqMB9nGpwF617uA/S2igm1u+cDpfi82kbi6SG1Sg30PM047R6oxTRGDLLkeMRF1gRaTBM0HfSL0j6ccU5KPgwYsFLE2We6jeR56iYJGC2KYLH4v8rcc2jRAdMbUntHMtUByF9BPSW7elQnyQH5Qzr/o0b59XLKwnJFn2Bp2yviC8cdyTDyhQGna0e+oESQR1j6u3Ux/mOmm3slRXscA8sH+pHmOEAtjYVf/ww36U8uZv+ctBCJyFVAgMBAAECggEBALrEeJqAFUfWFCkSmdUSFKT0bW/svFUTjXgGnZy1ncz9GpENpMH3lQDQVibteKpYwcom+Cr0XlQ66VUcudPrDjcOY7vhuMfnSh1YWLYyM4IeRHtcUxDVkFoM+vEFNHLf2zIOqqbgmboW3iDVIurT7iRO7KxAe/YtWJL9aVqMtBn7Lu7S7OvAU4ji5iLIBxjl82JYA+9lu/aQ6YGaoZuSO7bcU8Sivi+DKAahqN9XMKiB1XpC+PpaS/aec2S7xIlTdzoDGxEALRGlMe+xBEeQTBVJHBWrRIDPoHLTREeRC/9Pp+1Y4Dz8hd5Bi0n8/5r/q0liD+0vtmjsdU4E2QrktYECgYEA73qWvhCYHPMREAFtwz1mpp9ZhDCW6SF+njG7fBKcjz8OLcy15LXiTGc268ewtQqTMjPQlm1n2C6hGccGAIlMibQJo3KZHlTs125FUzDpTVgdlei6vU7M+gmfRSZed00J6jC04/qMR1tnV3HME3np7eRTKTA6Ts+zBwEvkbCetSkCgYEA4NY5iSBO1ybouIecDdD15uI2ItLPCBNMzu7IiK7IygIzuf+SyKyjhtFSR4vEi0gScOM7UMlwCMOVU10e4nMDknIWCDG9iFvmIEkGHGxgRrN5hX1Wrq74wF212lvvagH1IVWSHa8cVpMe+UwKu5Q1h4yzuYt6Q9wPQ7Qtn5emBE0CgYB2syispMUA9GnsqQii0Xhj9nAEWaEzhOqhtrzbTs5TIkoA4Yr3BkBY5oAOdjhcRBWZuJ0XMrtaKCKqCEAtW+CYEKkGXvMOWcHbNkkeZwv8zkQ73dNRqhFnjgVn3RDNyV20uteueK23YNLkQP+KV89fnuCpdcIw9joiqq/NYuIHoQKBgB5WaZ8KH/lCA8babYEjv/pubZWXUl4plISbja17wBYZ4/bl+F1hhhMr7Wk//743dF2NG7TT6W0VTvHXr9IoaMP65uQmKgfbNpsGn294ZClGEFClz+t0KpZyTpZvL0fjibr8u+GLfkxkP5qt2wjif7KRlrKjklTTva+KAVn2cW1FAoGBAMkX9ekIwhx/7uY6ndxKl8ZMDerjr6MhV0b08hHp3RxHbYVbcpN0UKspoYvZVgHwP18xlDij8yWRE2fapwgi4m82ZmYlg0qqJmyqIU9vBB3Jow903h1KPQrkmQEZxJ/4H8yrbgVf2HT+WUfjTFgaDZRl01bI3YkydCw91/Ub9HU6 public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lOqMuPLCVusc6szklNXQL1FHhSkEgR7An+8BllBqTsRHM4bRYosseGFCbYPn8r8FsWuMDtxp0CwTyMQR2PCbJ740DdpbE1KC6jAfZxqcBete7gP0tooJtbvnA6X4vNpG4ukhtUoN9DzNOO0eqMU0Rgyy5HjERdYEWkwTNB30i9I+nHFOSj4MGLBSxNlnuo3keeomCRgtimCx+L/K3HNo0QHTG1J7RzLVAchfQT0lu3pUJ8kB+UM6/6NG+fVyysJyRZ9gadsr4gvHHckw8oUBp2tHvqBEkEdY+rt1Mf5jppt7JUV7HAPLB/qR5jhALY2FX/8MN+lPLmb/nLQQichVQIDAQAB -broker: - publicKey: - url: https://login.elixir-czech.org/oidc/jwk # Default values available for creation of entities default: From 002742fe791b29b186e371185e2f0c9136239c52 Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Thu, 15 Jun 2023 13:15:52 -0400 Subject: [PATCH 41/43] add column providerissueruri --- .../bio/overture/ego/controller/AuthController.java | 13 ++++++++++--- .../overture/ego/model/dto/CreateUserRequest.java | 2 ++ .../java/bio/overture/ego/model/entity/User.java | 4 ++++ .../bio/overture/ego/model/enums/ProviderType.java | 8 ++++++++ .../bio/overture/ego/model/enums/SqlFields.java | 1 + .../ego/security/CustomOidc2UserInfoService.java | 2 +- .../java/bio/overture/ego/service/UserService.java | 1 + src/main/java/bio/overture/ego/token/IDToken.java | 2 ++ .../flyway/sql/V1_25__add_provider_issuer_uri.sql | 1 + 9 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 src/main/resources/flyway/sql/V1_25__add_provider_issuer_uri.sql diff --git a/src/main/java/bio/overture/ego/controller/AuthController.java b/src/main/java/bio/overture/ego/controller/AuthController.java index 006834b0c..c8b463a80 100644 --- a/src/main/java/bio/overture/ego/controller/AuthController.java +++ b/src/main/java/bio/overture/ego/controller/AuthController.java @@ -37,6 +37,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import java.util.Objects; +import java.util.Optional; import lombok.NonNull; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -134,6 +135,13 @@ public ResponseEntity user( user.getAccessToken()) : null; + Optional providerType = ProviderType + .findIfExist(authentication.getAuthorizedClientRegistrationId()); + + if(user.getClaim(GA4GH_PASSPORT_SCOPE) != null && providerType.isEmpty()){ + providerType = Optional.of(ProviderType.PASSPORT); + } + String token = tokenService.generateUserToken( IDToken.builder() @@ -141,9 +149,8 @@ public ResponseEntity user( .email(user.getEmail()) .familyName(user.getFamilyName()) .givenName(user.getGivenName()) - .providerType( - ProviderType.resolveProviderType( - authentication.getAuthorizedClientRegistrationId())) + .providerType(providerType.get()) + .providerIssuerUri(user.getIssuer().toString()) .build(), passportJwtToken, authentication.getAuthorizedClientRegistrationId()); diff --git a/src/main/java/bio/overture/ego/model/dto/CreateUserRequest.java b/src/main/java/bio/overture/ego/model/dto/CreateUserRequest.java index f0ffc790a..1c88eb928 100644 --- a/src/main/java/bio/overture/ego/model/dto/CreateUserRequest.java +++ b/src/main/java/bio/overture/ego/model/dto/CreateUserRequest.java @@ -47,4 +47,6 @@ public class CreateUserRequest { @NotNull ProviderType providerType; @NotNull String providerSubjectId; + + private String providerIssuerUri; } diff --git a/src/main/java/bio/overture/ego/model/entity/User.java b/src/main/java/bio/overture/ego/model/entity/User.java index 88f5d7fe8..9af3163a6 100644 --- a/src/main/java/bio/overture/ego/model/entity/User.java +++ b/src/main/java/bio/overture/ego/model/entity/User.java @@ -148,6 +148,10 @@ public class User implements PolicyOwner, Identifiable { @Column(name = SqlFields.PROVIDERSUBJECTID, nullable = false) private String providerSubjectId; + @JsonView({Views.JWTAccessToken.class, Views.REST.class}) + @Column(name = SqlFields.PROVIDERISSUERURI) + private String providerIssuerUri; + @JsonIgnore @OneToMany( mappedBy = JavaFields.OWNER, diff --git a/src/main/java/bio/overture/ego/model/enums/ProviderType.java b/src/main/java/bio/overture/ego/model/enums/ProviderType.java index e4b912b73..fc6f531a8 100644 --- a/src/main/java/bio/overture/ego/model/enums/ProviderType.java +++ b/src/main/java/bio/overture/ego/model/enums/ProviderType.java @@ -8,6 +8,8 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import java.util.Optional; + @RequiredArgsConstructor public enum ProviderType { GOOGLE, @@ -53,6 +55,12 @@ public static ProviderType resolveProviderType(@NonNull String providerType) { providerType, COMMA.join(values())))); } + public static Optional findIfExist(@NonNull String providerType) { + return stream(values()) + .filter(x -> x.toString().equalsIgnoreCase(providerType)) + .findFirst(); + } + @Override public String toString() { return this.name(); diff --git a/src/main/java/bio/overture/ego/model/enums/SqlFields.java b/src/main/java/bio/overture/ego/model/enums/SqlFields.java index dfdf0a5fb..a00a6820f 100644 --- a/src/main/java/bio/overture/ego/model/enums/SqlFields.java +++ b/src/main/java/bio/overture/ego/model/enums/SqlFields.java @@ -36,6 +36,7 @@ public class SqlFields { public static final String USER_ID = "user_id"; public static final String PROVIDERTYPE = "providertype"; public static final String PROVIDERSUBJECTID = "providersubjectid"; + public static final String PROVIDERISSUERURI = "providerissueruri"; public static final String INITIALIZED = "initialized"; public static final String ERRORREDIRECTURI = "errorredirecturi"; public static final String SOURCE = "source"; diff --git a/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java b/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java index 9ebd55f87..c7a405cdf 100644 --- a/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java +++ b/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java @@ -36,9 +36,9 @@ public OidcUser loadUser(OidcUserRequest oAuth2UserRequest) throws OAuth2Authent OidcUser oidcUser = super.loadUser(oAuth2UserRequest); try { String provider = oAuth2UserRequest.getClientRegistration().getRegistrationId(); - val idName = ProviderType.getIdAccessor(ProviderType.resolveProviderType(provider)); if (provider.equalsIgnoreCase(ProviderType.ORCID.toString())) { val info = getOrcidUserInfo(oidcUser, oAuth2UserRequest); + val idName = ProviderType.getIdAccessor(ProviderType.resolveProviderType(provider)); return CustomOAuth2User.builder() .oauth2User(new DefaultOAuth2User(oidcUser.getAuthorities(), info, idName)) .subjectId(info.get(idName).toString()) diff --git a/src/main/java/bio/overture/ego/service/UserService.java b/src/main/java/bio/overture/ego/service/UserService.java index 894a394a3..c6141bc9d 100644 --- a/src/main/java/bio/overture/ego/service/UserService.java +++ b/src/main/java/bio/overture/ego/service/UserService.java @@ -175,6 +175,7 @@ public User createFromIDToken(IDToken idToken) { .type(userDefaultsConfig.getDefaultUserType()) .providerType(idToken.getProviderType()) .providerSubjectId(idToken.getProviderSubjectId()) + .providerIssuerUri(idToken.getProviderIssuerUri()) .build()); } diff --git a/src/main/java/bio/overture/ego/token/IDToken.java b/src/main/java/bio/overture/ego/token/IDToken.java index 8a0eca68c..92ce43686 100644 --- a/src/main/java/bio/overture/ego/token/IDToken.java +++ b/src/main/java/bio/overture/ego/token/IDToken.java @@ -43,4 +43,6 @@ public class IDToken { @JsonProperty("provider_subject_id") @NonNull String providerSubjectId; + + private String providerIssuerUri; } diff --git a/src/main/resources/flyway/sql/V1_25__add_provider_issuer_uri.sql b/src/main/resources/flyway/sql/V1_25__add_provider_issuer_uri.sql new file mode 100644 index 000000000..b9a55f3b8 --- /dev/null +++ b/src/main/resources/flyway/sql/V1_25__add_provider_issuer_uri.sql @@ -0,0 +1 @@ +ALTER TABLE egouser ADD COLUMN providerissueruri VARCHAR(255); \ No newline at end of file From 34831a4a63c4d913ca9646c92bd0e586c498dcdf Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Thu, 29 Jun 2023 14:30:55 -0400 Subject: [PATCH 42/43] Passport refresh token Ego issue #723 --- ...essTokenResponseConverterWithDefaults.java | 1 - .../ego/controller/AuthController.java | 117 +++++++++----- .../ego/model/dto/PassportRefreshToken.java | 21 +++ .../dto/PassportRefreshTokenResponse.java | 15 ++ .../ego/security/CustomOAuth2User.java | 3 + .../security/CustomOidc2UserInfoService.java | 11 ++ .../overture/ego/service/PassportService.java | 149 ++++++++++++------ .../ego/service/RefreshContextService.java | 31 ++++ .../overture/ego/service/TokenService.java | 56 ++++--- .../bio/overture/ego/service/VisaService.java | 7 +- .../bio/overture/ego/utils/TypeUtils.java | 11 ++ src/main/resources/application.yml | 1 + 12 files changed, 310 insertions(+), 113 deletions(-) create mode 100644 src/main/java/bio/overture/ego/model/dto/PassportRefreshToken.java create mode 100644 src/main/java/bio/overture/ego/model/dto/PassportRefreshTokenResponse.java diff --git a/src/main/java/bio/overture/ego/config/OAuth2AccessTokenResponseConverterWithDefaults.java b/src/main/java/bio/overture/ego/config/OAuth2AccessTokenResponseConverterWithDefaults.java index 1901176b1..f6d2bd7d8 100644 --- a/src/main/java/bio/overture/ego/config/OAuth2AccessTokenResponseConverterWithDefaults.java +++ b/src/main/java/bio/overture/ego/config/OAuth2AccessTokenResponseConverterWithDefaults.java @@ -20,7 +20,6 @@ public class OAuth2AccessTokenResponseConverterWithDefaults OAuth2ParameterNames.ACCESS_TOKEN, OAuth2ParameterNames.TOKEN_TYPE, OAuth2ParameterNames.EXPIRES_IN, - OAuth2ParameterNames.REFRESH_TOKEN, OAuth2ParameterNames.SCOPE) .collect(Collectors.toSet()); diff --git a/src/main/java/bio/overture/ego/controller/AuthController.java b/src/main/java/bio/overture/ego/controller/AuthController.java index c8b463a80..ae538af37 100644 --- a/src/main/java/bio/overture/ego/controller/AuthController.java +++ b/src/main/java/bio/overture/ego/controller/AuthController.java @@ -18,6 +18,7 @@ import static bio.overture.ego.model.enums.JavaFields.REFRESH_ID; import static bio.overture.ego.utils.SwaggerConstants.AUTH_CONTROLLER; +import static bio.overture.ego.utils.TypeUtils.isValidUUID; import static org.springframework.http.HttpStatus.*; import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; import static org.springframework.web.bind.annotation.RequestMethod.*; @@ -27,9 +28,7 @@ import bio.overture.ego.model.exceptions.InvalidTokenException; import bio.overture.ego.provider.google.GoogleTokenService; import bio.overture.ego.security.CustomOAuth2User; -import bio.overture.ego.service.PassportService; -import bio.overture.ego.service.RefreshContextService; -import bio.overture.ego.service.TokenService; +import bio.overture.ego.service.*; import bio.overture.ego.token.IDToken; import bio.overture.ego.token.signer.TokenSigner; import bio.overture.ego.utils.Tokens; @@ -50,6 +49,7 @@ import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.HttpClientErrorException; @Slf4j @RestController @@ -65,6 +65,7 @@ public class AuthController { private final GoogleTokenService googleTokenService; private final TokenSigner tokenSigner; private final RefreshContextService refreshContextService; + private final UserService userService; private final String GA4GH_PASSPORT_SCOPE = "ga4gh_passport_v1"; @Autowired @@ -73,12 +74,14 @@ public AuthController( @NonNull PassportService passportService, @NonNull GoogleTokenService googleTokenService, @NonNull TokenSigner tokenSigner, - @NonNull RefreshContextService refreshContextService) { + @NonNull RefreshContextService refreshContextService, + @NonNull UserService userService) { this.tokenService = tokenService; this.passportService = passportService; this.googleTokenService = googleTokenService; this.tokenSigner = tokenSigner; this.refreshContextService = refreshContextService; + this.userService = userService; } @RequestMapping(method = GET, value = "/google/token") @@ -126,42 +129,54 @@ public ResponseEntity user( throw new RuntimeException("no user"); } - val user = (CustomOAuth2User) authentication.getPrincipal(); + val oAuth2User = (CustomOAuth2User) authentication.getPrincipal(); + val passportJwtToken = + (oAuth2User.getClaim(GA4GH_PASSPORT_SCOPE) != null) + ? passportService.getPassportToken( + authentication.getAuthorizedClientRegistrationId(), oAuth2User.getAccessToken()) + : null; - val passportJwtToken = (user.getClaim(GA4GH_PASSPORT_SCOPE) != null) ? - passportService.getPassportToken( - authentication.getAuthorizedClientRegistrationId(), - user.getAccessToken()) : - null; + Optional providerType = + ProviderType.findIfExist(authentication.getAuthorizedClientRegistrationId()); - Optional providerType = ProviderType - .findIfExist(authentication.getAuthorizedClientRegistrationId()); - - if(user.getClaim(GA4GH_PASSPORT_SCOPE) != null && providerType.isEmpty()){ + if (oAuth2User.getClaim(GA4GH_PASSPORT_SCOPE) != null && providerType.isEmpty()) { providerType = Optional.of(ProviderType.PASSPORT); } - String token = + val idToken = + IDToken.builder() + .providerSubjectId(oAuth2User.getSubjectId()) + .email(oAuth2User.getEmail()) + .familyName(oAuth2User.getFamilyName()) + .givenName(oAuth2User.getGivenName()) + .providerType(providerType.get()) + .providerIssuerUri(oAuth2User.getIssuer().toString()) + .build(); + + val egoToken = tokenService.generateUserToken( - IDToken.builder() - .providerSubjectId(user.getSubjectId()) - .email(user.getEmail()) - .familyName(user.getFamilyName()) - .givenName(user.getGivenName()) - .providerType(providerType.get()) - .providerIssuerUri(user.getIssuer().toString()) - .build(), - passportJwtToken, - authentication.getAuthorizedClientRegistrationId()); - - val outgoingRefreshContext = refreshContextService.createInitialRefreshContext(token); - val cookie = - refreshContextService.createRefreshCookie(outgoingRefreshContext.getRefreshToken()); - response.addCookie(cookie); + idToken, passportJwtToken, authentication.getAuthorizedClientRegistrationId()); + + if (oAuth2User.getClaim(GA4GH_PASSPORT_SCOPE) != null && oAuth2User.getRefreshToken() != null) { + // create a cookie with passport refresh token + val user = userService.getUserByToken(idToken); + val outgoingRefreshContext = + refreshContextService.createPassportRefreshToken(user, oAuth2User.getRefreshToken()); + val cookie = + refreshContextService.createPassportRefreshCookie( + outgoingRefreshContext, oAuth2User.getRefreshToken()); + response.addCookie(cookie); + } else { + // create a cookie with refreshId + val outgoingRefreshContext = refreshContextService.createInitialRefreshContext(egoToken); + val cookie = + refreshContextService.createRefreshCookie(outgoingRefreshContext.getRefreshToken()); + response.addCookie(cookie); + } SecurityContextHolder.getContext().setAuthentication(null); - return new ResponseEntity<>(token, OK); + return new ResponseEntity<>(egoToken, OK); } @RequestMapping( @@ -200,15 +215,41 @@ public ResponseEntity refreshEgoToken( return new ResponseEntity<>("Please login", UNAUTHORIZED); } val currentToken = Tokens.removeTokenPrefix(authorization, TOKEN_PREFIX); - // TODO: [anncatton] validate jwt before proceeding to service call. - val outboundUserToken = - refreshContextService.validateAndReturnNewUserToken(refreshId, currentToken); - val newRefreshToken = tokenService.getTokenUserInfo(outboundUserToken).getRefreshToken(); - val newCookie = refreshContextService.createRefreshCookie(newRefreshToken); - response.addCookie(newCookie); + try { + if (isValidUUID(refreshId)) { + val outboundUserToken = + refreshContextService.validateAndReturnNewUserToken(refreshId, currentToken); + val newRefreshToken = tokenService.getTokenUserInfo(outboundUserToken).getRefreshToken(); + val newCookie = refreshContextService.createRefreshCookie(newRefreshToken); + response.addCookie(newCookie); + + return new ResponseEntity<>(outboundUserToken, OK); + } else { + + val user = tokenService.getTokenUserInfo(currentToken); - return new ResponseEntity<>(outboundUserToken, OK); + val clientRegistration = + passportService.getPassportClientRegistrations().get(user.getProviderIssuerUri()); + + val passportResponse = + passportService.refreshToken(clientRegistration.getRegistrationId(), refreshId); + + val egoToken = tokenService.generatePassportEgoToken(user, passportResponse.getAccess_token(), clientRegistration.getRegistrationId()); + + val outgoingRefreshContext = + refreshContextService.createPassportRefreshToken( + user, passportResponse.getRefresh_token()); + val newCookie = + refreshContextService.createPassportRefreshCookie( + outgoingRefreshContext, passportResponse.getRefresh_token()); + response.addCookie(newCookie); + + return new ResponseEntity<>(egoToken, OK); + } + }catch (HttpClientErrorException e){ + return new ResponseEntity<>(e.getResponseBodyAsString(), e.getStatusCode()); + } } @ExceptionHandler({InvalidTokenException.class}) diff --git a/src/main/java/bio/overture/ego/model/dto/PassportRefreshToken.java b/src/main/java/bio/overture/ego/model/dto/PassportRefreshToken.java new file mode 100644 index 000000000..09f625bfc --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/PassportRefreshToken.java @@ -0,0 +1,21 @@ +package bio.overture.ego.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; +import lombok.val; + +import java.util.Calendar; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class PassportRefreshToken { + private String iss; + private String aud; + private Long exp; // in seconds + private String jti; + + public Long getSecondsUntilExpiry() { + val seconds = this.exp - Calendar.getInstance().getTime().getTime() / 1000L; + return seconds > 0 ? seconds : 0; + } +} diff --git a/src/main/java/bio/overture/ego/model/dto/PassportRefreshTokenResponse.java b/src/main/java/bio/overture/ego/model/dto/PassportRefreshTokenResponse.java new file mode 100644 index 000000000..5bf77f2ea --- /dev/null +++ b/src/main/java/bio/overture/ego/model/dto/PassportRefreshTokenResponse.java @@ -0,0 +1,15 @@ +package bio.overture.ego.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class PassportRefreshTokenResponse { + private String access_token; + private String token_type; + private String refresh_token; + private Long expires_in; + private String scope; + private String id_token; +} diff --git a/src/main/java/bio/overture/ego/security/CustomOAuth2User.java b/src/main/java/bio/overture/ego/security/CustomOAuth2User.java index 3c9647c53..1bb4fb7eb 100644 --- a/src/main/java/bio/overture/ego/security/CustomOAuth2User.java +++ b/src/main/java/bio/overture/ego/security/CustomOAuth2User.java @@ -24,6 +24,7 @@ public class CustomOAuth2User implements OidcUser { private String email; private OAuth2User oauth2User; private String accessToken; + private String refreshToken; @Override public Map getAttributes() { @@ -50,6 +51,8 @@ public String getFamilyName() { public String getAccessToken() { return this.accessToken; } + public String getRefreshToken() {return this.refreshToken; } + public String getSubjectId() { return oauth2User.getAttributes().containsKey(IdTokenClaimNames.SUB) ? oauth2User.getAttributes().get(IdTokenClaimNames.SUB).toString() diff --git a/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java b/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java index c7a405cdf..ae8974a2b 100644 --- a/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java +++ b/src/main/java/bio/overture/ego/security/CustomOidc2UserInfoService.java @@ -15,6 +15,7 @@ import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.security.oauth2.core.user.DefaultOAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User; @@ -47,6 +48,8 @@ public OidcUser loadUser(OidcUserRequest oAuth2UserRequest) throws OAuth2Authent .givenName(info.getOrDefault(GIVEN_NAME, "").toString()) .build(); } + + val refreshToken = getRefreshToken(oAuth2UserRequest); return CustomOAuth2User.builder() .oauth2User(oidcUser) .subjectId(oidcUser.getSubject()) @@ -54,6 +57,7 @@ public OidcUser loadUser(OidcUserRequest oAuth2UserRequest) throws OAuth2Authent .familyName(oidcUser.getFamilyName()) .givenName(oidcUser.getGivenName()) .accessToken(oAuth2UserRequest.getAccessToken().getTokenValue()) + .refreshToken(refreshToken) .build(); } catch (AuthenticationException ex) { throw ex; @@ -87,4 +91,11 @@ private RestTemplate getTemplate(OAuth2UserRequest oAuth2UserRequest) { }); return restTemplate; } + + private String getRefreshToken(OAuth2UserRequest oAuth2UserRequest) { + val refreshToken = + (String) + oAuth2UserRequest.getAdditionalParameters().get(OAuth2ParameterNames.REFRESH_TOKEN); + return refreshToken; + } } diff --git a/src/main/java/bio/overture/ego/service/PassportService.java b/src/main/java/bio/overture/ego/service/PassportService.java index a32237ec9..43c521ad1 100644 --- a/src/main/java/bio/overture/ego/service/PassportService.java +++ b/src/main/java/bio/overture/ego/service/PassportService.java @@ -1,9 +1,9 @@ package bio.overture.ego.service; -import bio.overture.ego.model.dto.Passport; -import bio.overture.ego.model.dto.PassportToken; -import bio.overture.ego.model.dto.PassportVisa; -import bio.overture.ego.model.dto.Scope; +import static bio.overture.ego.utils.CollectionUtils.mapToSet; + +import bio.overture.ego.model.dto.*; +import bio.overture.ego.model.entity.User; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; import bio.overture.ego.utils.CacheUtil; @@ -16,12 +16,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.security.interfaces.RSAPublicKey; import java.text.ParseException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import lombok.NonNull; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.apache.commons.codec.binary.Base64; @@ -31,6 +29,7 @@ import org.springframework.http.HttpMethod; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.LinkedMultiValueMap; @@ -38,8 +37,6 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; -import static bio.overture.ego.utils.CollectionUtils.mapToSet; - @Slf4j @Service @Transactional @@ -55,10 +52,14 @@ public class PassportService { @Autowired private ClientRegistrationRepository clientRegistrationRepository; - private final String REQUESTED_TOKEN_TYPE = "urn:ga4gh:params:oauth:token-type:passport"; - private final String SUBJECT_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token"; - private final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange"; + @Autowired private InMemoryClientRegistrationRepository inMemoryClientRegistrationRepository; + private final String TOKEN_TYPE_PASSPORT = "urn:ga4gh:params:oauth:token-type:passport"; + private final String TOKEN_TYPE_ACCESS_TOKEN = "urn:ietf:params:oauth:token-type:access_token"; + private final String GRANT_TYPE_TOKEN_EXCHANGE = + "urn:ietf:params:oauth:grant-type:token-exchange"; + private final String REFRESH_TOKEN = "refresh_token"; + private final String GA4GH_PASSPORT_SCOPE = "ga4gh_passport_v1"; @Autowired public PassportService( @@ -127,27 +128,36 @@ private List getVisaPermissions(List visas) { return visaPermissions; } - public Set extractScopes(@NonNull String passportJwtToken, @NonNull String providerType) throws ParseException, JwkException, JsonProcessingException { - val resolvedPermissions = getPermissions(passportJwtToken, providerType); - val output = mapToSet(resolvedPermissions, AbstractPermissionService::buildScope); - if (output.isEmpty()) { - output.add(Scope.defaultScope()); - } - return output; + public Set extractScopes(@NonNull String passportJwtToken, @NonNull String providerType) + throws ParseException, JwkException, JsonProcessingException { + val resolvedPermissions = getPermissions(passportJwtToken, providerType); + val output = mapToSet(resolvedPermissions, AbstractPermissionService::buildScope); + if (output.isEmpty()) { + output.add(Scope.defaultScope()); + } + return output; } // Parse Passport token to extract the passport body - public Passport parsePassport(@NonNull String passportJwtToken) throws JsonProcessingException { - String[] split_string = passportJwtToken.split("\\."); - String base64EncodedHeader = split_string[0]; - String base64EncodedBody = split_string[1]; - String base64EncodedSignature = split_string[2]; - Base64 base64Url = new Base64(true); - String header = new String(base64Url.decode(base64EncodedHeader)); - String body = new String(base64Url.decode(base64EncodedBody)); + @SneakyThrows + private Passport parsePassport(@NonNull String passportJwtToken) { + val body = decodeJwtBody(passportJwtToken); return new ObjectMapper().readValue(body, Passport.class); } + @SneakyThrows + private PassportRefreshToken parseRefreshToken(@NonNull String jwtRefreshToken) { + val body = decodeJwtBody(jwtRefreshToken); + return new ObjectMapper().readValue(body, PassportRefreshToken.class); + } + + private String decodeJwtBody(@NonNull String jwtToken){ + val split_string = jwtToken.split("\\."); + val base64EncodedBody = split_string[1]; + val base64Url = new Base64(true); + return new String(base64Url.decode(base64EncodedBody)); + } + // Removes duplicates from the VisaPermissons List private List deDupeVisaPermissions(List visaPermissions) { Set permissionsSet = new HashSet(); @@ -161,21 +171,46 @@ public String getPassportToken(String providerId, String accessToken) { val clientRegistration = clientRegistrationRepository.findByRegistrationId(providerId); - val uri = UriComponentsBuilder - .fromUriString(clientRegistration.getProviderDetails().getTokenUri()) - .queryParams(passportTokenParams(accessToken)) - .toUriString(); + val uri = + UriComponentsBuilder.fromUriString(clientRegistration.getProviderDetails().getTokenUri()) + .queryParams(passportTokenParams(accessToken)) + .toUriString(); - val passportToken = getTemplate(clientRegistration) - .exchange(uri, - HttpMethod.POST, - null, - PassportToken.class) - .getBody(); + val passportToken = + getTemplate(clientRegistration) + .exchange(uri, HttpMethod.POST, null, PassportToken.class) + .getBody(); - return (passportToken != null) ? - passportToken.getAccess_token() : - null; + return (passportToken != null) ? passportToken.getAccess_token() : null; + } + + + public PassportRefreshTokenResponse refreshToken(String providerId, String refreshJwtToken) { + if (refreshJwtToken == null || refreshJwtToken.isEmpty()) return null; + + val clientRegistration = clientRegistrationRepository.findByRegistrationId(providerId); + + val uri = + UriComponentsBuilder.fromUriString(clientRegistration.getProviderDetails().getTokenUri()) + .queryParams(refreshPassportTokenParams(clientRegistration, refreshJwtToken)) + .toUriString(); + + return getTemplate(clientRegistration) + .exchange(uri, HttpMethod.POST, null, PassportRefreshTokenResponse.class) + .getBody(); + } + + public Map getPassportClientRegistrations() { + Map passportProviderDetails = new HashMap<>(); + + inMemoryClientRegistrationRepository.forEach( + clientRegistration -> { + if (clientRegistration.getScopes().contains(GA4GH_PASSPORT_SCOPE)) { + passportProviderDetails.put( + clientRegistration.getProviderDetails().getIssuerUri(), clientRegistration); + } + }); + return passportProviderDetails; } private RestTemplate getTemplate(ClientRegistration clientRegistration) { @@ -187,7 +222,10 @@ private RestTemplate getTemplate(ClientRegistration clientRegistration) { x.getHeaders() .set( HttpHeaders.AUTHORIZATION, - "Basic " + getBasicAuthHeader(clientRegistration.getClientId(), clientRegistration.getClientSecret())); + "Basic " + + getBasicAuthHeader( + clientRegistration.getClientId(), + clientRegistration.getClientSecret())); return z.execute(x, y); }); return restTemplate; @@ -198,12 +236,31 @@ private String getBasicAuthHeader(String clientId, String clientSecret) { return new String(Base64.encodeBase64(credentials.getBytes())); } - private MultiValueMap passportTokenParams(String accessToken){ + private MultiValueMap passportTokenParams(String accessToken) { MultiValueMap params = new LinkedMultiValueMap<>(); - params.add("requested_token_type", REQUESTED_TOKEN_TYPE); + params.add("requested_token_type", TOKEN_TYPE_PASSPORT); params.add("subject_token", accessToken); - params.add("subject_token_type", SUBJECT_TOKEN_TYPE); - params.add("grant_type", GRANT_TYPE); + params.add("subject_token_type", TOKEN_TYPE_ACCESS_TOKEN); + params.add("grant_type", GRANT_TYPE_TOKEN_EXCHANGE); + return params; + } + + private MultiValueMap refreshPassportTokenParams( + ClientRegistration clientRegistration, String refreshJwtToken) { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("client_id", clientRegistration.getClientId()); + params.add("client_secret", clientRegistration.getClientSecret()); + params.add("refresh_token", refreshJwtToken); + params.add("grant_type", REFRESH_TOKEN); return params; } + + @SneakyThrows + public PassportRefreshToken getRefreshTokenClaims(String jwtToken, User user) { + isValidPassport( + jwtToken, + this.getPassportClientRegistrations().get(user.getProviderIssuerUri()).getRegistrationId()); + + return parseRefreshToken(jwtToken); + } } diff --git a/src/main/java/bio/overture/ego/service/RefreshContextService.java b/src/main/java/bio/overture/ego/service/RefreshContextService.java index 419700067..72fdbdd97 100644 --- a/src/main/java/bio/overture/ego/service/RefreshContextService.java +++ b/src/main/java/bio/overture/ego/service/RefreshContextService.java @@ -6,9 +6,11 @@ import static bio.overture.ego.model.exceptions.UniqueViolationException.checkUnique; import bio.overture.ego.model.domain.RefreshContext; +import bio.overture.ego.model.dto.PassportRefreshToken; import bio.overture.ego.model.entity.RefreshToken; import bio.overture.ego.model.entity.User; import bio.overture.ego.model.exceptions.ForbiddenException; +import bio.overture.ego.model.exceptions.UnauthorizedException; import bio.overture.ego.repository.RefreshTokenRepository; import bio.overture.ego.repository.queryspecification.builder.RefreshTokenSpecificationBuilder; import jakarta.servlet.http.Cookie; @@ -18,6 +20,7 @@ import java.util.Optional; import java.util.UUID; import lombok.NonNull; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +33,7 @@ public class RefreshContextService extends AbstractBaseService decodedToken = validateAndReturn(accessToken); @@ -179,7 +195,7 @@ public String generateUserToken(User u, String passportJwtToken, String provider Set scopes = extractExplicitScopes(u); - if (passportJwtToken != null && providerType != null){ + if (passportJwtToken != null && providerType != null) { Set scopesFromVisas = extractExplicitScopes(passportJwtToken, providerType); scopes = mergeScopes(scopes, scopesFromVisas); } @@ -187,16 +203,6 @@ public String generateUserToken(User u, String passportJwtToken, String provider return generateUserToken(u, scopes); } - @SneakyThrows - public String generateUserToken(UUID userId) { - val user = userService.findById(userId); - if (user.isEmpty()) { - throw new NotFoundException("user not found"); - } - val u = user.get(); - return generateUserToken(u, extractExplicitScopes(u)); - } - public Set getScopes(Set scopeNames) { return mapToSet(scopeNames, this::getScope); } @@ -286,7 +292,7 @@ public String generateApiKeyString() { return UUID.randomUUID().toString(); } - public String generateUserToken(@NonNull User u, @NonNull Set scope) { + private String generateUserToken(@NonNull User u, @NonNull Set scope) { val tokenClaims = generateUserTokenClaims(u, scope); return getSignedToken(tokenClaims); } @@ -601,13 +607,15 @@ private static Set extractExplicitScopes(Application a) { } @SneakyThrows - private Set extractExplicitScopes(String passportJwtToken, String providerType){ - return mapToSet(explicitScopes(passportService.extractScopes(passportJwtToken, providerType)), Scope::toString); + private Set extractExplicitScopes(String passportJwtToken, String providerType) { + return mapToSet( + explicitScopes(passportService.extractScopes(passportJwtToken, providerType)), + Scope::toString); } - private Set mergeScopes(Set scopeSet, Set scopeSetAdditional){ + private Set mergeScopes(Set scopeSet, Set scopeSetAdditional) { scopeSet.addAll(scopeSetAdditional); - if(scopeSet.size()>1 && scopeSet.contains(Scope.defaultScope().toString())){ + if (scopeSet.size() > 1 && scopeSet.contains(Scope.defaultScope().toString())) { scopeSet.remove(Scope.defaultScope().toString()); } return scopeSet; diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index 8a26ad186..c090dfb12 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -105,7 +105,8 @@ public PassportVisa parseVisa(@NonNull String visaJwtToken) throws JsonProcessin } // Checks if the visa is a valid visa - public void isValidVisa(@NonNull String authToken, @NonNull String providerType) throws JwkException, JsonProcessingException { + public void isValidVisa(@NonNull String authToken, @NonNull String providerType) + throws JwkException, JsonProcessingException { DecodedJWT jwt = JWT.decode(authToken); Jwk jwk = cacheUtil.getPassportBrokerPublicKey(providerType).get(jwt.getKeyId()); Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); @@ -130,9 +131,7 @@ public List partialUpdate( } } else { throw new NotFoundException( - format( - "No Visa exists with type '%s' and value '%s'", - type, value)); + format("No Visa exists with type '%s' and value '%s'", type, value)); } return updatedVisas; } diff --git a/src/main/java/bio/overture/ego/utils/TypeUtils.java b/src/main/java/bio/overture/ego/utils/TypeUtils.java index 1ac2575d8..6ecff3bed 100644 --- a/src/main/java/bio/overture/ego/utils/TypeUtils.java +++ b/src/main/java/bio/overture/ego/utils/TypeUtils.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; +import java.util.regex.Pattern; import lombok.val; public class TypeUtils { @@ -40,4 +41,14 @@ public static T convertToAnotherType(Object fromObject, Class tClass) { mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return mapper.convertValue(fromObject, tClass); } + + private static final Pattern UUID_REGEX_PATTERN = + Pattern.compile("^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$"); + + public static boolean isValidUUID(String str) { + if (str == null) { + return false; + } + return UUID_REGEX_PATTERN.matcher(str).matches(); + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b2757b4a0..cdbf3906c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -81,6 +81,7 @@ spring: - openid - email - profile + - offline_access - ga4gh_passport_v1 github: From 055c87223855bc1e560de2070442c40eb5fde085 Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Thu, 6 Jul 2023 17:00:48 -0400 Subject: [PATCH 43/43] visas controllers by id --- .../ego/controller/VisaController.java | 73 +++++++++++++------ .../ego/service/VisaPermissionService.java | 46 +++++------- .../bio/overture/ego/service/VisaService.java | 32 +++----- 3 files changed, 81 insertions(+), 70 deletions(-) diff --git a/src/main/java/bio/overture/ego/controller/VisaController.java b/src/main/java/bio/overture/ego/controller/VisaController.java index acb102e1b..0217dd9b0 100644 --- a/src/main/java/bio/overture/ego/controller/VisaController.java +++ b/src/main/java/bio/overture/ego/controller/VisaController.java @@ -19,10 +19,12 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; +import java.util.Arrays; import java.util.List; import java.util.UUID; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; +import lombok.val; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -30,8 +32,8 @@ @Slf4j @RestController -@RequestMapping("/visa") -@Tag(name = "Visa") +@RequestMapping("/visas") +@Tag(name = "Visas") public class VisaController { /** Dependencies */ @@ -71,6 +73,24 @@ public VisaController( } } + @AdminScoped + @RequestMapping(method = GET, value = "/{visaId}") + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Get Visa Using visa Id")}) + @JsonView(Views.REST.class) + public @ResponseBody Visa getVisaByTypeAndValue( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "visaId", required = true) UUID visaId) { + val visa = visaService.getById(visaId); + if (visa != null) { + return visa; + } else { + throw new NotFoundException( + format("No Visa exists with id '%s'", visaId)); + } + } + /* * This method is used to list all visas * @return visas List @@ -111,15 +131,14 @@ public VisaController( * @return Visa visa */ @AdminScoped - @RequestMapping(method = PUT, value = "/{type}/{value}") + @RequestMapping(method = PUT, value = "/{visaId}") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Update Visa")}) - public @ResponseBody List updateVisa( + public @ResponseBody Visa updateVisa( @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "type", required = true) String type, - @PathVariable(value = "value", required = true) String value, + final String authorization, + @PathVariable(value = "visaId", required = true) UUID visaId, @RequestBody(required = true) VisaRequest visaRequest) { - return visaService.partialUpdate(type, value, visaRequest); + return visaService.update(visaId, visaRequest); } /* @@ -127,14 +146,13 @@ public VisaController( * @param visaId UUID */ @AdminScoped - @RequestMapping(method = DELETE, value = "/{type}/{value}") + @RequestMapping(method = DELETE, value = "/{visaId}") @ResponseStatus(value = HttpStatus.OK) public void deleteVisa( @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "type", required = true) String type, - @PathVariable(value = "value", required = true) String value) { - visaService.delete(type, value); + final String authorization, + @PathVariable(value = "visaId", required = true) UUID visaId) { + visaService.delete(visaId); } /* @@ -156,6 +174,19 @@ public void deleteVisa( return visaPermissionService.getPermissionsForVisa(visaService.getByTypeAndValue(type, value)); } + @AdminScoped + @RequestMapping(method = GET, value = "/permissions/{visaId}") + @ApiResponses( + value = {@ApiResponse(responseCode = "200", description = "Get Visa using visa id")}) + @JsonView(Views.REST.class) + public @ResponseBody List getVisaPermissionsByVisaId( + @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) + final String authorization, + @PathVariable(value = "visaId", required = true) UUID visaId) { + val visa = visaService.getById(visaId); + return visaPermissionService.getPermissionsForVisa(Arrays.asList(visa)); + } + /* * This method is used to fetch visa permissions using policy id * @param policyId UUID @@ -192,18 +223,18 @@ public void deleteVisa( /* * This method is used to delete/remove visa permissions - * @param visaPermissionRequest VisaPermissionRequest + * @param visaId UUID + * @param policyId UUID */ @AdminScoped - @RequestMapping(method = DELETE, value = "/permissions/{policyId}/{type}/{value}") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Remove VisaPermission")}) + @RequestMapping(method = DELETE, value = "/{visaId}/permissions/{policyId}") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Remove Visa Permission")}) @JsonView(Views.REST.class) public @ResponseBody void removePermissions( @Parameter(hidden = true) @RequestHeader(value = "Authorization", required = true) - final String authorization, - @PathVariable(value = "policyId", required = true) UUID policyId, - @PathVariable(value = "type", required = true) String type, - @PathVariable(value = "value", required = true) String value) { - visaPermissionService.removePermission(policyId, type, value); + final String authorization, + @PathVariable(value = "visaId", required = true) UUID visaId, + @PathVariable(value = "policyId", required = true) UUID policyId) { + visaPermissionService.removePermission(policyId, visaId); } } diff --git a/src/main/java/bio/overture/ego/service/VisaPermissionService.java b/src/main/java/bio/overture/ego/service/VisaPermissionService.java index 9eb91096c..b75b48735 100644 --- a/src/main/java/bio/overture/ego/service/VisaPermissionService.java +++ b/src/main/java/bio/overture/ego/service/VisaPermissionService.java @@ -3,7 +3,6 @@ import static java.lang.String.format; import static org.mapstruct.factory.Mappers.getMapper; -import bio.overture.ego.event.token.ApiKeyEventsPublisher; import bio.overture.ego.model.dto.VisaPermissionRequest; import bio.overture.ego.model.entity.Visa; import bio.overture.ego.model.entity.VisaPermission; @@ -33,27 +32,16 @@ public class VisaPermissionService extends AbstractNamedService getPermissionsByVisaId(@NonNull UUID visaId) { - val result = (List) visaPermissionRepository.findByVisa_Id(visaId); - if (result.isEmpty()) { - throw new NotFoundException(format("No VisaPermissions exists with visaId '%s'", visaId)); - } - return result; } public List getPermissionsByPolicyId(@NonNull UUID policyId) { @@ -83,22 +71,22 @@ public VisaPermission createOrUpdatePermissions( } } - public void removePermission( - @NonNull UUID policyId, @NotNull String type, @NotNull String value) { - visaService.getByTypeAndValue(type, value).stream() - .forEach( - visa -> { - List visaPermissionEntities = - visaPermissionRepository.findByPolicyIdAndVisaId(policyId, visa.getId()); - if (!visaPermissionEntities.isEmpty()) { - visaPermissionRepository.deleteById(visaPermissionEntities.get(0).getId()); - } else { - throw new NotFoundException( - format( - "No VisaPermissions exists with policyId '%s' and type '%s' and value '%s'", - policyId, type, value)); - } - }); + public void removePermission(@NonNull UUID policyId, @NotNull UUID visaId) { + + val visa = visaService.getById(visaId); + + if(visa == null) { + throw new NotFoundException(format("No Visa exists with id '%s'", visaId)); + } + + val visaPermissionEntities = visaPermissionRepository.findByPolicyIdAndVisaId(policyId, visa.getId()); + + if(visaPermissionEntities.isEmpty()){ + throw new NotFoundException(format("No VisaPermissions exists with policyId '%s'", policyId)); + } + + visaPermissionRepository.deleteById(visaPermissionEntities.get(0).getId()); + } // Fetches visa permissions for given visa request diff --git a/src/main/java/bio/overture/ego/service/VisaService.java b/src/main/java/bio/overture/ego/service/VisaService.java index c090dfb12..dab688d71 100644 --- a/src/main/java/bio/overture/ego/service/VisaService.java +++ b/src/main/java/bio/overture/ego/service/VisaService.java @@ -5,7 +5,6 @@ import static java.lang.String.format; import static org.mapstruct.factory.Mappers.getMapper; -import bio.overture.ego.event.token.ApiKeyEventsPublisher; import bio.overture.ego.model.dto.PassportVisa; import bio.overture.ego.model.dto.VisaRequest; import bio.overture.ego.model.entity.Visa; @@ -21,7 +20,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.validation.constraints.NotNull; import java.security.interfaces.RSAPublicKey; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -50,15 +48,12 @@ public class VisaService extends AbstractNamedService { @Autowired private CacheUtil cacheUtil; - private final ApiKeyEventsPublisher apiKeyEventsPublisher; @Autowired public VisaService( - @NonNull VisaRepository visaRepository, - @NonNull ApiKeyEventsPublisher apiKeyEventsPublisher) { + @NonNull VisaRepository visaRepository) { super(Visa.class, visaRepository); this.visaRepository = visaRepository; - this.apiKeyEventsPublisher = apiKeyEventsPublisher; } public Visa create(@NonNull VisaRequest createRequest) { @@ -117,23 +112,20 @@ public Page listVisa(@NonNull Pageable pageable) { return visaRepository.findAll(pageable); } - public List partialUpdate( - @NotNull String type, @NotNull String value, @NonNull VisaRequest updateRequest) { - List updatedVisas = new ArrayList<>(); - List visas = getByTypeAndValue(type, value); - if (visas != null && !visas.isEmpty()) { - for (Visa visa : visas) { - visa.setType(updateRequest.getType()); - visa.setValue(updateRequest.getValue()); - visa.setBy(updateRequest.getBy()); - visa.setSource(updateRequest.getSource()); - updatedVisas.add(getRepository().save(visa)); - } + public Visa update( + @NotNull UUID visaId, @NonNull VisaRequest updateRequest) { + Visa updateVisa = getById(visaId); + if (updateVisa != null) { + updateVisa.setType(updateRequest.getType()); + updateVisa.setValue(updateRequest.getValue()); + updateVisa.setBy(updateRequest.getBy()); + updateVisa.setSource(updateRequest.getSource()); + return getRepository().save(updateVisa); + } else { throw new NotFoundException( - format("No Visa exists with type '%s' and value '%s'", type, value)); + format("No Visa exists with id '%s'", visaId)); } - return updatedVisas; } @Mapper(