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 01/10] 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 b6b696a4..2dfb2c6a 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 00000000..c228ac82 --- /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 88f5d7fe..157d4f11 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 00000000..a8f44277 --- /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 ee273dfd..3dbe2621 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 00000000..be145ba0 --- /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 02/10] 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 2dfb2c6a..b6b696a4 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 c228ac82..a3bb8211 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 157d4f11..88f5d7fe 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 a8f44277..7a5fac08 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 6057ce5b..0afe23ba 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 9e65f8db..e91c1b09 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 be145ba0..00000000 --- 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 03/10] 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 3dbe2621..9714fe86 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 04/10] 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 f45ee953..00000000 --- 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 00000000..2af638d8 --- /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 7a5fac08..226262d0 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 0afe23ba..907a833c 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 00000000..e0dfc53f --- /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 9714fe86..a32c5810 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 05/10] 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 a3bb8211..154a1cd1 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 226262d0..74b44541 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 50d1be0f..b831804f 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 a32c5810..dfd99e76 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 06/10] 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 2af638d8..00000000 --- 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 07/10] 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 00000000..2af638d8 --- /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 00000000..11c1bdc5 --- /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 154a1cd1..36ed9a56 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 00000000..3afe1985 --- /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 74b44541..690c04ae 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 907a833c..d30d319e 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 b831804f..b4b00361 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 08/10] 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 b97fcaab..e334304d 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 690c04ae..6fddf92f 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 09/10] 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 dfd99e76..27bf7b3f 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 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 10/10] 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 e334304d..b97fcaab 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 1fbc9b94..9ef972a8 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 2af638d8..bb2a042b 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 6fddf92f..106e79b8 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 d30d319e..b381a9e9 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 b4b00361..c7e65110 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 e0dfc53f..00000000 --- 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 00000000..f512a652 --- /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 dfd99e76..cd5e9f76 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: