From b17e5ca8eeeec81330a8edad11da9e0334645006 Mon Sep 17 00:00:00 2001 From: Vihang Patil Date: Tue, 5 Nov 2019 11:43:14 +0100 Subject: [PATCH] Removed deprecated MyInfo API v2 --- .circleci/prime-canary-values.yaml | 3 +- .circleci/prime-dev-values.yaml | 2 - .circleci/prime-prod-values.yaml | 2 - .../kotlin/org/ostelco/at/common/TestUser.kt | 2 +- .../kotlin/org/ostelco/at/jersey/Tests.kt | 80 ------ .../kotlin/org/ostelco/at/okhttp/Tests.kt | 72 ------ .../endpoint/resources/KycResources.kt | 31 --- .../endpoint/resources/KycResourcesTest.kt | 19 +- .../org.ostelco.prime.ekyc.MyInfoKycService | 1 + ...co.prime.paymentprocessor.PaymentProcessor | 2 +- .../org/ostelco/prime/ekyc/KycModule.kt | 15 -- .../prime/ekyc/myinfo/v2/MyInfoClient.kt | 239 ------------------ .../org.ostelco.prime.ekyc.MyInfoKycService | 1 - .../prime/ekyc/myinfo/v2/MyInfoClientTest.kt | 213 ---------------- .../prime/ekyc/myinfo/v3/MyInfoClientTest.kt | 9 +- .../ostelco/ext/myinfo/MyInfoEmulatorApp.kt | 3 - .../org/ostelco/ext/myinfo/v2/Resources.kt | 186 -------------- .../org/ostelco/prime/model/Entities.kt | 1 - .../ostelco/prime/storage/graph/Neo4jStore.kt | 2 - prime/config/config.yaml | 8 - prime/config/test.yaml | 8 - prime/infra/dev/prime-customer-api.yaml | 36 --- prime/infra/prime-direct-values.yaml | 2 - 23 files changed, 21 insertions(+), 916 deletions(-) create mode 100644 customer-endpoint/src/test/resources/META-INF/services/org.ostelco.prime.ekyc.MyInfoKycService delete mode 100644 ekyc/src/main/kotlin/org/ostelco/prime/ekyc/myinfo/v2/MyInfoClient.kt delete mode 100644 ekyc/src/test/kotlin/org/ostelco/prime/ekyc/myinfo/v2/MyInfoClientTest.kt delete mode 100644 ext-myinfo-emulator/src/main/kotlin/org/ostelco/ext/myinfo/v2/Resources.kt diff --git a/.circleci/prime-canary-values.yaml b/.circleci/prime-canary-values.yaml index 5fc606a9c..f6ad0a7d6 100644 --- a/.circleci/prime-canary-values.yaml +++ b/.circleci/prime-canary-values.yaml @@ -40,8 +40,7 @@ prime: ACTIVATE_TOPIC_ID: ocs-activate CCR_SUBSCRIPTION_ID: ocs-ccr-sub GOOGLE_APPLICATION_CREDENTIALS: /secret/prime-service-account.json - MY_INFO_API_URI: https://myinfosg.api.gov.sg/v2 - MY_INFO_API_REALM: prod + MY_INFO_V3_API_URI: https://api.myinfo.gov.sg/com/v3 MY_INFO_REDIRECT_URI: https://dl.oya.world/links/myinfo secretVolumes: diff --git a/.circleci/prime-dev-values.yaml b/.circleci/prime-dev-values.yaml index a8f090b2c..5a595e8b8 100644 --- a/.circleci/prime-dev-values.yaml +++ b/.circleci/prime-dev-values.yaml @@ -48,9 +48,7 @@ prime: ACTIVATE_TOPIC_ID: ocs-activate CCR_SUBSCRIPTION_ID: ocs-ccr-sub GOOGLE_APPLICATION_CREDENTIALS: /secret/prime-service-account.json - MY_INFO_V2_API_URI: https://myinfosgstg.api.gov.sg/test/v2 MY_INFO_V3_API_URI: https://test.api.myinfo.gov.sg/com/v3 - MY_INFO_API_REALM: dev MY_INFO_REDIRECT_URI: https://dl-dev.oya.world/links/myinfo secretVolumes: diff --git a/.circleci/prime-prod-values.yaml b/.circleci/prime-prod-values.yaml index ac6da9416..e5d018b90 100644 --- a/.circleci/prime-prod-values.yaml +++ b/.circleci/prime-prod-values.yaml @@ -48,9 +48,7 @@ prime: ACTIVATE_TOPIC_ID: ocs-activate CCR_SUBSCRIPTION_ID: ocs-ccr-sub GOOGLE_APPLICATION_CREDENTIALS: /secret/prime-service-account.json - MY_INFO_V2_API_URI: https://myinfosg.api.gov.sg/v2 MY_INFO_V3_API_URI: https://api.myinfo.gov.sg/com/v3 - MY_INFO_API_REALM: prod MY_INFO_REDIRECT_URI: https://dl.oya.world/links/myinfo secretVolumes: diff --git a/acceptance-tests/src/main/kotlin/org/ostelco/at/common/TestUser.kt b/acceptance-tests/src/main/kotlin/org/ostelco/at/common/TestUser.kt index 5f554678b..31b361cdd 100644 --- a/acceptance-tests/src/main/kotlin/org/ostelco/at/common/TestUser.kt +++ b/acceptance-tests/src/main/kotlin/org/ostelco/at/common/TestUser.kt @@ -41,7 +41,7 @@ fun enableRegion(email: String, region: String = "no") { when (region) { "sg" -> { get { - path = "/regions/sg/kyc/myInfo/activation-code" + path = "/regions/sg/kyc/myInfo/v3/personData/activation-code" this.email = email } put(expectedResultCode = 204) { diff --git a/acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt b/acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt index 72cdaad53..39930fc73 100644 --- a/acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt +++ b/acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt @@ -1433,32 +1433,6 @@ class JumioKycTest { class SingaporeKycTest { - @Test - fun `jersey test - GET myinfoConfig v2`() { - - val email = "myinfo-v2-${randomInt()}@test.com" - var customerId = "" - try { - - customerId = createCustomer(name = "Test MyInfoConfig v2 Customer", email = email).id - - val myInfoConfig = get { - path = "/regions/sg/kyc/myInfoConfig" - this.email = email - } - - assertEquals( - "http://ext-myinfo-emulator:8080/v2/authorise" + - "?client_id=STG2-MYINFO-SELF-TEST" + - "&attributes=name,sex,dob,residentialstatus,nationality,mobileno,email,mailadd" + - "&redirect_uri=http://localhost:3001/callback", - myInfoConfig.url) - - } finally { - StripePayment.deleteCustomer(customerId = customerId) - } - } - @Test fun `jersey test - GET myinfoConfig v3`() { @@ -1485,60 +1459,6 @@ class SingaporeKycTest { } } - @Test - fun `jersey test - GET myinfo v2`() { - - val email = "myinfo-v2-${randomInt()}@test.com" - var customerId = "" - try { - - customerId = createCustomer(name = "Test MyInfo v2 Customer", email = email).id - - run { - val regionDetailsList = get { - path = "/regions" - this.email = email - } - regionDetailsList.forEach { - assertTrue(it.status == AVAILABLE, "All regions should be in available state") - assertTrue(it.simProfiles.isEmpty(), "All regions should have empty Sim profile list") - } - } - - val personData: String = get { - path = "/regions/sg/kyc/myInfo/authCode" - this.email = email - } - - val expectedPersonData = """{"name":{"lastupdated":"2018-03-20","source":"1","classification":"C","value":"TAN XIAO HUI"},"sex":{"lastupdated":"2018-03-20","source":"1","classification":"C","value":"F"},"nationality":{"lastupdated":"2018-03-20","source":"1","classification":"C","value":"SG"},"dob":{"lastupdated":"2018-03-20","source":"1","classification":"C","value":"1970-05-17"},"email":{"lastupdated":"2018-08-23","source":"4","classification":"C","value":"myinfotesting@gmail.com"},"mobileno":{"lastupdated":"2018-08-23","code":"65","source":"4","classification":"C","prefix":"+","nbr":"97399245"},"mailadd":{"country":"SG","unit":"128","street":"BEDOK NORTH AVENUE 4","lastupdated":"2018-03-20","block":"102","postal":"460102","source":"1","classification":"C","floor":"09","building":"PEARL GARDEN"},"uinfin":"S9812381D"}""" - assertEquals(expectedPersonData, personData, "MyInfo PersonData do not match") - - run { - val regionDetailsList = get { - path = "/regions" - this.email = email - } - - val sgRegionDetails = regionDetailsList.singleOrNull { it.region.id == "sg" } - assertTrue(sgRegionDetails != null, "regionDetailsList should contain sg region") - - val regionDetails = RegionDetails() - .region(Region().id("sg").name("Singapore")) - .status(PENDING) - .kycStatusMap(mutableMapOf( - KycType.JUMIO.name to KycStatus.PENDING, - KycType.MY_INFO.name to KycStatus.APPROVED, - KycType.ADDRESS.name to KycStatus.PENDING, - KycType.NRIC_FIN.name to KycStatus.PENDING)) - .simProfiles(SimProfileList()) - - assertEquals(regionDetails, sgRegionDetails, "RegionDetails do not match") - } - } finally { - StripePayment.deleteCustomer(customerId = customerId) - } - } - @Test fun `jersey test - GET myinfo v3`() { diff --git a/acceptance-tests/src/main/kotlin/org/ostelco/at/okhttp/Tests.kt b/acceptance-tests/src/main/kotlin/org/ostelco/at/okhttp/Tests.kt index d79a4e7d4..ed85cfbb6 100644 --- a/acceptance-tests/src/main/kotlin/org/ostelco/at/okhttp/Tests.kt +++ b/acceptance-tests/src/main/kotlin/org/ostelco/at/okhttp/Tests.kt @@ -605,31 +605,6 @@ class PurchaseTest { class SingaporeKycTest { - @Test - fun `okhttp test - GET myinfoConfig v2`() { - - val email = "myinfo-${randomInt()}@test.com" - var customerId = "" - try { - - customerId = createCustomer(name = "Test MyInfoConfig v2 Customer", email = email).id - - val client = clientForSubject(subject = email) - - val myInfoConfig = client.myInfoV2Config - - assertEquals( - "http://ext-myinfo-emulator:8080/v2/authorise" + - "?client_id=STG2-MYINFO-SELF-TEST" + - "&attributes=name,sex,dob,residentialstatus,nationality,mobileno,email,mailadd" + - "&redirect_uri=http://localhost:3001/callback", - myInfoConfig.url) - - } finally { - StripePayment.deleteCustomer(customerId = customerId) - } - } - @Test fun `okhttp test - GET myinfoConfig v3`() { @@ -655,53 +630,6 @@ class SingaporeKycTest { } } - @Test - fun `okhttp test - GET myinfo v2`() { - - val email = "myinfo-v2-${randomInt()}@test.com" - var customerId = "" - try { - - customerId = createCustomer(name = "Test MyInfo v2 Customer", email = email).id - - val client = clientForSubject(subject = email) - - run { - val regionDetailsList = client.allRegions - - regionDetailsList.forEach { - assertTrue(it.status == AVAILABLE, "All regions should be in available state") - } - } - - val personData: String = jacksonObjectMapper().writeValueAsString(client.getCustomerMyInfoV2Data("authCode")) - - val expectedPersonData = """{"name":{"lastupdated":"2018-03-20","source":"1","classification":"C","value":"TAN XIAO HUI"},"sex":{"lastupdated":"2018-03-20","source":"1","classification":"C","value":"F"},"nationality":{"lastupdated":"2018-03-20","source":"1","classification":"C","value":"SG"},"dob":{"lastupdated":"2018-03-20","source":"1","classification":"C","value":"1970-05-17"},"email":{"lastupdated":"2018-08-23","source":"4","classification":"C","value":"myinfotesting@gmail.com"},"mobileno":{"lastupdated":"2018-08-23","code":"65","source":"4","classification":"C","prefix":"+","nbr":"97399245"},"mailadd":{"country":"SG","unit":"128","street":"BEDOK NORTH AVENUE 4","lastupdated":"2018-03-20","block":"102","postal":"460102","source":"1","classification":"C","floor":"09","building":"PEARL GARDEN"},"uinfin":"S9812381D"}""" - assertEquals(expectedPersonData, personData, "MyInfo PersonData do not match") - - run { - val regionDetailsList = client.allRegions - - val sgRegionIndex = regionDetailsList.indexOfFirst { it.region.id == "sg" } - assertTrue(sgRegionIndex != -1, "regionDetailsList should contain sg region") - - val regionDetails = RegionDetails() - .region(Region().id("sg").name("Singapore")) - .status(PENDING) - .kycStatusMap(mutableMapOf( - KycType.JUMIO.name to KycStatus.PENDING, - KycType.MY_INFO.name to KycStatus.APPROVED, - KycType.ADDRESS.name to KycStatus.PENDING, - KycType.NRIC_FIN.name to KycStatus.PENDING)) - .simProfiles(SimProfileList()) - - assertEquals(regionDetails, regionDetailsList[sgRegionIndex], "RegionDetails do not match") - } - } finally { - StripePayment.deleteCustomer(customerId = customerId) - } - } - @Test fun `okhttp test - GET myinfo v3`() { diff --git a/customer-endpoint/src/main/kotlin/org/ostelco/prime/customer/endpoint/resources/KycResources.kt b/customer-endpoint/src/main/kotlin/org/ostelco/prime/customer/endpoint/resources/KycResources.kt index a97959a39..915990e48 100644 --- a/customer-endpoint/src/main/kotlin/org/ostelco/prime/customer/endpoint/resources/KycResources.kt +++ b/customer-endpoint/src/main/kotlin/org/ostelco/prime/customer/endpoint/resources/KycResources.kt @@ -7,7 +7,6 @@ import org.ostelco.prime.customer.endpoint.store.SubscriberDAO import org.ostelco.prime.ekyc.MyInfoKycService import org.ostelco.prime.getLogger import org.ostelco.prime.model.MyInfoApiVersion -import org.ostelco.prime.model.MyInfoApiVersion.V2 import org.ostelco.prime.model.MyInfoApiVersion.V3 import org.ostelco.prime.module.getResource import org.ostelco.prime.tracing.EnableTracing @@ -48,36 +47,6 @@ class SingaporeKycResource(private val dao: SubscriberDAO): KycResource(regionCo private val logger by getLogger() - // MyInfo v2 - private val myInfoKycService by lazy { getResource("v2") } - - @GET - @Path("/myInfo/{authorisationCode}") - @Produces(MediaType.APPLICATION_JSON) - fun getCustomerMyInfoData(@Auth token: AccessTokenPrincipal?, - @NotNull - @PathParam("authorisationCode") - authorisationCode: String): Response = - if (token == null) { - Response.status(Response.Status.UNAUTHORIZED) - } else { - dao.getCustomerMyInfoData( - identity = token.identity, - version = V2, - authorisationCode = authorisationCode) - .responseBuilder(jsonEncode = false) - }.build() - - @GET - @Path("/myInfoConfig") - @Produces(MediaType.APPLICATION_JSON) - fun getMyInfoConfig(@Auth token: AccessTokenPrincipal?): Response = - if (token == null) { - Response.status(Response.Status.UNAUTHORIZED) - } else { - Response.status(Response.Status.OK).entity(myInfoKycService.getConfig()) - }.build() - // MyInfo v3 @Path("/myInfo/v3") diff --git a/customer-endpoint/src/test/kotlin/org/ostelco/prime/customer/endpoint/resources/KycResourcesTest.kt b/customer-endpoint/src/test/kotlin/org/ostelco/prime/customer/endpoint/resources/KycResourcesTest.kt index 5a914deb5..d636cde68 100644 --- a/customer-endpoint/src/test/kotlin/org/ostelco/prime/customer/endpoint/resources/KycResourcesTest.kt +++ b/customer-endpoint/src/test/kotlin/org/ostelco/prime/customer/endpoint/resources/KycResourcesTest.kt @@ -20,15 +20,22 @@ import org.ostelco.prime.auth.AccessTokenPrincipal import org.ostelco.prime.auth.OAuthAuthenticator import org.ostelco.prime.customer.endpoint.store.SubscriberDAO import org.ostelco.prime.customer.endpoint.util.AccessToken +import org.ostelco.prime.ekyc.MyInfoKycService import org.ostelco.prime.jsonmapper.objectMapper import org.ostelco.prime.model.Identity -import org.ostelco.prime.model.MyInfoApiVersion.V2 +import org.ostelco.prime.model.MyInfoApiVersion.V3 import org.ostelco.prime.model.ScanInformation import org.ostelco.prime.model.ScanStatus import java.util.* +import javax.inject.Named import javax.ws.rs.core.MediaType import javax.ws.rs.core.Response +private val MOCK_MY_INFO_KYC_SERVICE: MyInfoKycService = Mockito.mock(MyInfoKycService::class.java) + +@Named("v3") +class MockMyInfoKycService : MyInfoKycService by MOCK_MY_INFO_KYC_SERVICE + class KycResourcesTest { private val email = "mw@internet.org" @@ -99,10 +106,10 @@ class KycResourcesTest { val identityCaptor = argumentCaptor() val authorisationCodeCaptor = argumentCaptor() - `when`>(DAO.getCustomerMyInfoData(identityCaptor.capture(), eq(V2), authorisationCodeCaptor.capture())) + `when`>(DAO.getCustomerMyInfoData(identityCaptor.capture(), eq(V3), authorisationCodeCaptor.capture())) .thenReturn("{}".right()) - val resp = RULE.target("regions/sg/kyc/myInfo/code123") + val resp = RULE.target("regions/sg/kyc/myInfo/v3/personData/code123") .request() .header("Authorization", "Bearer ${AccessToken.withEmail(email)}") .get(Response::class.java) @@ -123,10 +130,10 @@ class KycResourcesTest { val identityCaptor = argumentCaptor() val authorisationCodeCaptor = argumentCaptor() - `when`>(DAO.getCustomerMyInfoData(identityCaptor.capture(), eq(V2), authorisationCodeCaptor.capture())) + `when`>(DAO.getCustomerMyInfoData(identityCaptor.capture(), eq(V3), authorisationCodeCaptor.capture())) .thenReturn("{}".right()) - val resp = RULE.target("regions/no/kyc/myInfo/code123") + val resp = RULE.target("regions/no/kyc/myInfo/v3/personData/code123") .request() .header("Authorization", "Bearer ${AccessToken.withEmail(email)}") .get(Response::class.java) @@ -137,7 +144,7 @@ class KycResourcesTest { @Before fun setUp() { - Mockito.`when`(AUTHENTICATOR.authenticate(ArgumentMatchers.anyString())) + `when`(AUTHENTICATOR.authenticate(ArgumentMatchers.anyString())) .thenReturn(Optional.of(AccessTokenPrincipal(Identity(email, "EMAIL","email")))) } diff --git a/customer-endpoint/src/test/resources/META-INF/services/org.ostelco.prime.ekyc.MyInfoKycService b/customer-endpoint/src/test/resources/META-INF/services/org.ostelco.prime.ekyc.MyInfoKycService new file mode 100644 index 000000000..4d0e4b83d --- /dev/null +++ b/customer-endpoint/src/test/resources/META-INF/services/org.ostelco.prime.ekyc.MyInfoKycService @@ -0,0 +1 @@ +org.ostelco.prime.customer.endpoint.resources.MockMyInfoKycService \ No newline at end of file diff --git a/customer-endpoint/src/test/resources/META-INF/services/org.ostelco.prime.paymentprocessor.PaymentProcessor b/customer-endpoint/src/test/resources/META-INF/services/org.ostelco.prime.paymentprocessor.PaymentProcessor index 14b9531c5..491bc3ed7 100644 --- a/customer-endpoint/src/test/resources/META-INF/services/org.ostelco.prime.paymentprocessor.PaymentProcessor +++ b/customer-endpoint/src/test/resources/META-INF/services/org.ostelco.prime.paymentprocessor.PaymentProcessor @@ -1 +1 @@ -org.ostelco.prime.client.api.resources.MockPaymentProcessor +org.ostelco.prime.customer.endpoint.resources.MockPaymentProcessor diff --git a/ekyc/src/main/kotlin/org/ostelco/prime/ekyc/KycModule.kt b/ekyc/src/main/kotlin/org/ostelco/prime/ekyc/KycModule.kt index 202c76336..c778f6eed 100644 --- a/ekyc/src/main/kotlin/org/ostelco/prime/ekyc/KycModule.kt +++ b/ekyc/src/main/kotlin/org/ostelco/prime/ekyc/KycModule.kt @@ -14,7 +14,6 @@ class KycModule : PrimeModule { @JsonProperty fun setConfig(config: Config) { - ConfigRegistry.myInfoV2 = config.myInfoV2 ConfigRegistry.myInfoV3 = config.myInfoV3 } @@ -36,22 +35,9 @@ class KycModule : PrimeModule { } data class Config( - val myInfoV2: MyInfoV2Config, val myInfoV3: MyInfoV3Config ) -data class MyInfoV2Config( - val myInfoApiUri: String, - val myInfoApiClientId: String, - val myInfoApiClientSecret: String, - val myInfoApiEnableSecurity: Boolean = true, - val myInfoApiRealm: String, - val myInfoRedirectUri: String, - val myInfoServerPublicKey: String, - val myInfoClientPrivateKey: String, - val myInfoPersonDataAttributes: String = "name,sex,dob,residentialstatus,nationality,mobileno,email,mailadd" -) - data class MyInfoV3Config( val myInfoApiUri: String, val myInfoApiClientId: String, @@ -64,7 +50,6 @@ data class MyInfoV3Config( ) object ConfigRegistry { - lateinit var myInfoV2: MyInfoV2Config lateinit var myInfoV3: MyInfoV3Config } diff --git a/ekyc/src/main/kotlin/org/ostelco/prime/ekyc/myinfo/v2/MyInfoClient.kt b/ekyc/src/main/kotlin/org/ostelco/prime/ekyc/myinfo/v2/MyInfoClient.kt deleted file mode 100644 index b7e815f7e..000000000 --- a/ekyc/src/main/kotlin/org/ostelco/prime/ekyc/myinfo/v2/MyInfoClient.kt +++ /dev/null @@ -1,239 +0,0 @@ -package org.ostelco.prime.ekyc.myinfo.v2 - -import io.jsonwebtoken.Jwts -import org.apache.cxf.rs.security.jose.jwe.JweCompactConsumer -import org.apache.cxf.rs.security.jose.jwe.JweUtils -import org.apache.http.HttpResponse -import org.apache.http.client.methods.HttpGet -import org.apache.http.client.methods.HttpPost -import org.apache.http.entity.StringEntity -import org.ostelco.prime.ekyc.MyInfoData -import org.ostelco.prime.ekyc.MyInfoKycService -import org.ostelco.prime.ekyc.Registry.myInfoClient -import org.ostelco.prime.ekyc.myinfo.ExtendedCompressionCodecResolver -import org.ostelco.prime.ekyc.myinfo.HttpMethod -import org.ostelco.prime.ekyc.myinfo.HttpMethod.GET -import org.ostelco.prime.ekyc.myinfo.HttpMethod.POST -import org.ostelco.prime.ekyc.myinfo.TokenApiResponse -import org.ostelco.prime.getLogger -import org.ostelco.prime.jsonmapper.objectMapper -import org.ostelco.prime.model.MyInfoConfig -import java.net.URLEncoder -import java.nio.charset.StandardCharsets -import java.security.KeyFactory -import java.security.SecureRandom -import java.security.Signature -import java.security.spec.PKCS8EncodedKeySpec -import java.security.spec.X509EncodedKeySpec -import java.time.Instant -import java.util.* -import javax.inject.Named -import javax.ws.rs.core.MediaType -import kotlin.system.measureTimeMillis -import org.ostelco.prime.ekyc.ConfigRegistry.myInfoV2 as config - -@Named("v2") -class MyInfoClient : MyInfoKycService by MyInfoClientSingleton - -object MyInfoClientSingleton : MyInfoKycService { - - private val logger by getLogger() - - override fun getConfig(): MyInfoConfig = MyInfoConfig( - url = "${config.myInfoApiUri}/authorise" + - "?client_id=${config.myInfoApiClientId}" + - "&attributes=${config.myInfoPersonDataAttributes}" + - "&redirect_uri=${config.myInfoRedirectUri}") - - override fun getPersonData(authorisationCode: String): MyInfoData? { - - // Call /token API to get access_token - val tokenApiResponse = getToken(authorisationCode = authorisationCode) - ?.let { content -> - objectMapper.readValue(content, TokenApiResponse::class.java) - } - ?: return null - - // extract uin_fin out of "subject" of claims of access_token - val claims = getClaims(tokenApiResponse.accessToken) - val uinFin = claims.body.subject - - // Using access_token and uin_fin, call /person API to get Person Data - val personData = getPersonData( - uinFin = uinFin, - accessToken = tokenApiResponse.accessToken) - - return MyInfoData(uinFin = uinFin, personData = personData) - } - - private fun getToken(authorisationCode: String): String? = - sendSignedRequest( - httpMethod = POST, - path = "/token", - queryParams = mapOf( - "grant_type" to "authorization_code", - "code" to authorisationCode, - "redirect_uri" to config.myInfoRedirectUri, - "client_id" to config.myInfoApiClientId, - "client_secret" to config.myInfoApiClientSecret)) - - - private fun getClaims(accessToken: String) = Jwts.parser() - .setCompressionCodecResolver(ExtendedCompressionCodecResolver) - .setSigningKey(KeyFactory - .getInstance("RSA") - .generatePublic(X509EncodedKeySpec(Base64 - .getDecoder() - .decode(config.myInfoServerPublicKey)))) - .parseClaimsJws(accessToken) - - - private fun getPersonData(uinFin: String, accessToken: String): String? = - sendSignedRequest( - httpMethod = GET, - path = "/person/$uinFin", - queryParams = mapOf( - "client_id" to config.myInfoApiClientId, - "attributes" to config.myInfoPersonDataAttributes), - accessToken = accessToken) - - /** - * Ref: https://www.ndi-api.gov.sg/library/trusted-data/myinfo/tutorial3 - */ - private fun sendSignedRequest( - httpMethod: HttpMethod, - path: String, - queryParams: Map, - accessToken: String? = null): String? { - - val queryParamsString = queryParams.entries.joinToString("&") { """${it.key}=${URLEncoder.encode(it.value, StandardCharsets.US_ASCII)}""" } - - val requestUrl = "${config.myInfoApiUri}$path" - - // Create HTTP request - val request = when (httpMethod) { - GET -> HttpGet("$requestUrl?$queryParamsString") - POST -> HttpPost(requestUrl).also { - it.entity = StringEntity(queryParamsString) - } - } - - if (config.myInfoApiEnableSecurity) { - - val nonce = SecureRandom.getInstance("SHA1PRNG").nextLong() - val timestamp = Instant.now().toEpochMilli() - - // A) Construct the Authorisation Token Parameter - val defaultAuthHeaders = mapOf( - "apex_l2_eg_timestamp" to "$timestamp", - "apex_l2_eg_nonce" to "$nonce", - "apex_l2_eg_app_id" to config.myInfoApiClientId, - "apex_l2_eg_signature_method" to "SHA256withRSA", - "apex_l2_eg_version" to "1.0") - - // B) Forming the Base String - // Base String is a representation of the entire request (ensures message integrity) - - val baseStringParams = defaultAuthHeaders + queryParams - - // i) Normalize request parameters - val baseParamString = baseStringParams.entries - .sortedBy { it.key } - .joinToString("&") { "${it.key}=${it.value}" } - - // ii) construct request URL ---> url is passed in to this function - // NOTE: need to include the ".e." in order for the security authorisation header to work - //myinfosgstg.api.gov.sg -> myinfosgstg.e.api.gov.sg - - val url = "${config.myInfoApiUri.toLowerCase().replace(".api.gov.sg", ".e.api.gov.sg")}$path" - - // iii) concatenate request elements (HTTP method + url + base string parameters) - val baseString = "$httpMethod&$url&$baseParamString" - - // C) Signing Base String to get Digital Signature - // Load pem file containing the x509 cert & private key & sign the base string with it to produce the Digital Signature - val signature = Signature.getInstance("SHA256withRSA") - .also { sign -> - sign.initSign(KeyFactory - .getInstance("RSA") - .generatePrivate(PKCS8EncodedKeySpec( - Base64.getDecoder().decode(config.myInfoClientPrivateKey)))) - } - .also { sign -> sign.update(baseString.toByteArray()) } - .let(Signature::sign) - .let(Base64.getEncoder()::encodeToString) - - // D) Assembling the Authorization Header - - val authHeaders = mapOf("realm" to config.myInfoApiRealm) + - defaultAuthHeaders + - mapOf("apex_l2_eg_signature" to signature) - - var authHeaderString = "apex_l2_eg " + - authHeaders.entries - .joinToString(",") { """${it.key}="${it.value}"""" } - - if (accessToken != null) { - authHeaderString = "$authHeaderString,Bearer $accessToken" - } - - request.addHeader("Authorization", authHeaderString) - - } else if (accessToken != null) { - request.addHeader("Authorization", "Bearer $accessToken") - } - - request.addHeader("Cache-Control", "no-cache") - request.addHeader("Accept", MediaType.APPLICATION_JSON) - - if (httpMethod == POST) { - request.addHeader("Content-Type", MediaType.APPLICATION_FORM_URLENCODED) - } - - var response: HttpResponse? = null - - val latency = measureTimeMillis { - response = myInfoClient.execute(request) - } - - logger.info("Latency is $latency ms for MyInfo $httpMethod") - - val statusCode = response?.statusLine?.statusCode - if (statusCode != 200) { - logger.info("response: $httpMethod status: ${response?.statusLine}") - } - - val content = response - ?.entity - ?.content - ?.readAllBytes() - ?.let { String(it) } - - if (content == null || statusCode != 200) { - logger.info("$httpMethod Response content: $content") - return null - } - - if (config.myInfoApiEnableSecurity && httpMethod == GET) { - return decodeJweCompact(content) - } - - return content - } - - private fun decodeJweCompact(jwePayload: String): String { - - val privateKey = KeyFactory - .getInstance("RSA") - .generatePrivate(PKCS8EncodedKeySpec( - Base64.getDecoder().decode(config.myInfoClientPrivateKey))) - - val jweHeaders = JweCompactConsumer(jwePayload).jweHeaders - - return String(JweUtils.decrypt( - privateKey, - jweHeaders.keyEncryptionAlgorithm, - jweHeaders.contentEncryptionAlgorithm, - jwePayload)) - } -} diff --git a/ekyc/src/main/resources/META-INF/services/org.ostelco.prime.ekyc.MyInfoKycService b/ekyc/src/main/resources/META-INF/services/org.ostelco.prime.ekyc.MyInfoKycService index 7682c967a..29ce9e4ab 100644 --- a/ekyc/src/main/resources/META-INF/services/org.ostelco.prime.ekyc.MyInfoKycService +++ b/ekyc/src/main/resources/META-INF/services/org.ostelco.prime.ekyc.MyInfoKycService @@ -1,2 +1 @@ -org.ostelco.prime.ekyc.myinfo.v2.MyInfoClient org.ostelco.prime.ekyc.myinfo.v3.MyInfoClient \ No newline at end of file diff --git a/ekyc/src/test/kotlin/org/ostelco/prime/ekyc/myinfo/v2/MyInfoClientTest.kt b/ekyc/src/test/kotlin/org/ostelco/prime/ekyc/myinfo/v2/MyInfoClientTest.kt deleted file mode 100644 index ce59f8b33..000000000 --- a/ekyc/src/test/kotlin/org/ostelco/prime/ekyc/myinfo/v2/MyInfoClientTest.kt +++ /dev/null @@ -1,213 +0,0 @@ -package org.ostelco.prime.ekyc.myinfo.v2 - -import io.dropwizard.testing.ConfigOverride -import io.dropwizard.testing.DropwizardTestSupport -import io.dropwizard.testing.ResourceHelpers -import org.apache.http.impl.client.HttpClientBuilder -import org.junit.AfterClass -import org.junit.Assert.assertArrayEquals -import org.junit.Assert.assertEquals -import org.junit.Before -import org.junit.BeforeClass -import org.junit.Test -import org.ostelco.ext.myinfo.MyInfoEmulatorApp -import org.ostelco.ext.myinfo.MyInfoEmulatorConfig -import org.ostelco.prime.ekyc.ConfigRegistry -import org.ostelco.prime.ekyc.MyInfoV2Config -import org.ostelco.prime.ekyc.Registry -import org.ostelco.prime.getLogger -import java.io.File -import java.io.FileInputStream -import java.security.KeyFactory -import java.security.KeyPair -import java.security.KeyPairGenerator -import java.security.PrivateKey -import java.security.cert.CertificateFactory -import java.security.spec.PKCS8EncodedKeySpec -import java.security.spec.X509EncodedKeySpec -import java.util.* -import kotlin.system.measureTimeMillis - -/** - * Ref: https://www.ndi-api.gov.sg/assets/lib/trusted-data/myinfo/specs/myinfo-kyc-v2.1.1.yaml.html#section/Environments - * - * https://{ENV_DOMAIN_NAME}/{VERSION}/{RESOURCE} - * - * ENV_DOMAIN_NAME: - * - Sandbox/Dev: https://myinfosgstg.api.gov.sg/dev/ - * - Staging: https://myinfosgstg.api.gov.sg/test/ - * - Production: https://myinfosg.api.gov.sg/ - * - * VERSION: `/v2` - */ -// Using certs from https://github.com/jamesleegovtech/myinfo-demo-app/tree/master/ssl -private val templateTestConfig = String(File("src/test/resources/stg-demoapp-client-privatekey-2018.pem").readBytes()) - .replace("\n","") - .removePrefix("-----BEGIN PRIVATE KEY-----") - .removeSuffix("-----END PRIVATE KEY-----") - .let { base64Encoded -> PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64Encoded)) } - .let { keySpec -> KeyFactory.getInstance("RSA").generatePrivate(keySpec) } - .let { clientPrivateKey: PrivateKey -> - MyInfoV2Config( - myInfoApiUri = "https://myinfosgstg.api.gov.sg/test/v2", - myInfoApiClientId = "STG2-MYINFO-SELF-TEST", - myInfoApiClientSecret = "44d953c796cccebcec9bdc826852857ab412fbe2", - myInfoRedirectUri = "http://localhost:3001/callback", - myInfoApiRealm = "http://localhost:3001", - myInfoPersonDataAttributes = "name,sex,race,nationality,dob,email,mobileno,regadd,housingtype,hdbtype,marital,edulevel,ownerprivate,cpfcontributions,cpfbalances", - myInfoServerPublicKey = "", - myInfoClientPrivateKey = Base64.getEncoder().encodeToString(clientPrivateKey.encoded) - ) - } - -class MyInfoClientTest { - - private val logger by getLogger() - - @Before - fun setupUnitTest() { - ConfigRegistry.myInfoV2 = templateTestConfig.copy( - myInfoApiUri = "http://localhost:8080", - myInfoServerPublicKey = Base64.getEncoder().encodeToString(myInfoServerKeyPair.public.encoded)) - - Registry.myInfoClient = HttpClientBuilder.create().build() - } - - /** - * This test to send request to real staging server of MyInfo API. - * - * Some setup is needed to run this test. - * - * 1. Checkout the forked repo: https://github.com/ostelco/myinfo-demo-app - * 2. npm install - * 3. ./start.sh - * 4. Open web browser with Developer console open. - * 5. Goto http://localhost:3001 - * 6. Click button "RETRIEVE INFO" - * 7. Login to SingPass using username: S9812381D and password: MyInfo2o15 - * 8. Click on "Accept" button. - * 9. Copy authorisationCode from developer console of web browser. - * 10. Use this value in `test myInfo client` test. - * 11. Set @Before annotation on 'setupRealStaging()' instead of 'setupUnitTest()'. - * - */ - // @Before - fun setupRealStaging() { - // Using certs from https://github.com/jamesleegovtech/myinfo-demo-app/tree/master/ssl - // server public key - val certificateFactory = CertificateFactory.getInstance("X.509") - val certificate= certificateFactory.generateCertificate(FileInputStream("src/test/resources/stg-auth-signing-public.pem")) - - ConfigRegistry.myInfoV2 = templateTestConfig.copy( - myInfoPersonDataAttributes = "name,sex,race,nationality,dob,email,mobileno,regadd,housingtype,hdbtype,marital,edulevel,assessableincome,ownerprivate,assessyear,cpfcontributions,cpfbalances", - myInfoServerPublicKey = Base64.getEncoder().encodeToString(certificate.publicKey.encoded)) - - Registry.myInfoClient = HttpClientBuilder.create().build() - } - - @Test - fun `test myInfo client`() { - val durationInMilliSec = measureTimeMillis { - val myInfoData = MyInfoClientSingleton.getPersonData(authorisationCode = "authorisation-code") - logger.info("MyInfo - UIN/FIN: {}", myInfoData?.uinFin) - logger.info("MyInfo - PersonData: {}", myInfoData?.personData) - } - logger.info("Time taken to fetch personData: {} sec", durationInMilliSec / 1000) - } - - companion object { - - val myInfoServerKeyPair: KeyPair = KeyPairGenerator.getInstance("RSA") - .apply { this.initialize(2048) } - .genKeyPair() - - @JvmStatic - val SUPPORT: DropwizardTestSupport = CertificateFactory - .getInstance("X.509") - .generateCertificate(FileInputStream("src/test/resources/stg-demoapp-client-publiccert-2018.pem")) - .let { certificate -> - DropwizardTestSupport( - MyInfoEmulatorApp::class.java, - ResourceHelpers.resourceFilePath("myinfo-emulator-config.yaml"), - ConfigOverride.config("myInfoApiClientId", templateTestConfig.myInfoApiClientId), - ConfigOverride.config("myInfoApiClientSecret", templateTestConfig.myInfoApiClientSecret), - ConfigOverride.config("myInfoRedirectUri", templateTestConfig.myInfoRedirectUri), - ConfigOverride.config("myInfoServerPublicKey", Base64.getEncoder().encodeToString(myInfoServerKeyPair.public.encoded)), - ConfigOverride.config("myInfoServerPrivateKey", Base64.getEncoder().encodeToString(myInfoServerKeyPair.private.encoded)), - ConfigOverride.config("myInfoClientPublicKey", Base64.getEncoder().encodeToString(certificate.publicKey.encoded))) - } - - @JvmStatic - @BeforeClass - fun beforeClass() = SUPPORT.before() - - @JvmStatic - @AfterClass - fun afterClass() = SUPPORT.after() - } -} - -class RSAKeyTest { - - @Test - fun `test encode and decode`() { - val keyPair: KeyPair = KeyPairGenerator.getInstance("RSA") - .apply { this.initialize(2048) } - .genKeyPair() - - val encodedPublicKey = keyPair.public.encoded - - val base64PublicKey = Base64.getEncoder().encodeToString(encodedPublicKey) - val decodedPublicKey = Base64.getDecoder().decode(base64PublicKey) - - assertArrayEquals(encodedPublicKey, decodedPublicKey) - - assertEquals(keyPair.public, KeyFactory - .getInstance("RSA") - .generatePublic(X509EncodedKeySpec(Base64 - .getDecoder() - .decode(base64PublicKey)))) - - val encodedPrivateKey = keyPair.private.encoded - val base64PrivateKey = Base64.getEncoder().encodeToString(encodedPrivateKey) - val decodedPrivateKey = Base64.getDecoder().decode(base64PrivateKey) - - assertArrayEquals(encodedPrivateKey, decodedPrivateKey) - - assertEquals(keyPair.private, KeyFactory - .getInstance("RSA") - .generatePrivate(PKCS8EncodedKeySpec(Base64 - .getDecoder() - .decode(base64PrivateKey)))) - } - - @Test - fun `test loading MyInfo Staging Key`() { - - // Using public cert from https://github.com/jamesleegovtech/myinfo-demo-app/tree/master/ssl - val certificateFactory = CertificateFactory.getInstance("X.509") - val certificate= certificateFactory.generateCertificate(FileInputStream("src/test/resources/stg-auth-signing-public.pem")) - certificate.publicKey - } - - @Test - fun `test loading MyInfo Staging client private key`() { - - // Using cert from https://github.com/jamesleegovtech/myinfo-demo-app/tree/master/ssl - val base64Encoded = String(File("src/test/resources/stg-demoapp-client-privatekey-2018.pem").readBytes()) - .replace("\n","") - .removePrefix("-----BEGIN PRIVATE KEY-----") - .removeSuffix("-----END PRIVATE KEY-----") - val keySpec = PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64Encoded)) - val clientPrivateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec) - } - - @Test - fun `test MyInfo Staging client public key`() { - - // Using public cert from https://github.com/jamesleegovtech/myinfo-demo-app/tree/master/ssl - val certificateFactory = CertificateFactory.getInstance("X.509") - val certificate= certificateFactory.generateCertificate(FileInputStream("src/test/resources/stg-demoapp-client-publiccert-2018.pem")) - certificate.publicKey - } -} \ No newline at end of file diff --git a/ekyc/src/test/kotlin/org/ostelco/prime/ekyc/myinfo/v3/MyInfoClientTest.kt b/ekyc/src/test/kotlin/org/ostelco/prime/ekyc/myinfo/v3/MyInfoClientTest.kt index c79fe1fad..8dd182e2d 100644 --- a/ekyc/src/test/kotlin/org/ostelco/prime/ekyc/myinfo/v3/MyInfoClientTest.kt +++ b/ekyc/src/test/kotlin/org/ostelco/prime/ekyc/myinfo/v3/MyInfoClientTest.kt @@ -15,7 +15,6 @@ import org.ostelco.ext.myinfo.MyInfoEmulatorConfig import org.ostelco.prime.ekyc.ConfigRegistry import org.ostelco.prime.ekyc.MyInfoV3Config import org.ostelco.prime.ekyc.Registry -import org.ostelco.prime.ekyc.myinfo.v2.MyInfoClientSingleton import org.ostelco.prime.getLogger import java.io.File import java.io.FileInputStream @@ -30,14 +29,14 @@ import java.util.* import kotlin.system.measureTimeMillis /** - * Ref: https://www.ndi-api.gov.sg/assets/lib/trusted-data/myinfo/specs/myinfo-kyc-v2.1.1.yaml.html#section/Environments + * Ref: https://www.ndi-api.gov.sg/assets/lib/trusted-data/myinfo/specs/myinfo-kyc-v3.0.2.html#section/Environments * * https://{ENV_DOMAIN_NAME}/{VERSION}/{RESOURCE} * * ENV_DOMAIN_NAME: - * - Sandbox/Dev: https://myinfosgstg.api.gov.sg/dev/ - * - Staging: https://myinfosgstg.api.gov.sg/test/ - * - Production: https://myinfosg.api.gov.sg/ + * - Sandbox/Dev: https://sandbox.api.myinfo.gov.sg/com/v3 + * - Staging: https://test.api.myinfo.gov.sg/com/v3 + * - Production: https://api.myinfo.gov.sg/com/v3 * * VERSION: `/v2` */ diff --git a/ext-myinfo-emulator/src/main/kotlin/org/ostelco/ext/myinfo/MyInfoEmulatorApp.kt b/ext-myinfo-emulator/src/main/kotlin/org/ostelco/ext/myinfo/MyInfoEmulatorApp.kt index f4fe45fa8..28452afa4 100644 --- a/ext-myinfo-emulator/src/main/kotlin/org/ostelco/ext/myinfo/MyInfoEmulatorApp.kt +++ b/ext-myinfo-emulator/src/main/kotlin/org/ostelco/ext/myinfo/MyInfoEmulatorApp.kt @@ -31,9 +31,6 @@ class MyInfoEmulatorApp : Application() { Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), PAYLOAD_ANY)) - env.jersey().register(org.ostelco.ext.myinfo.v2.TokenResource(config)) - env.jersey().register(org.ostelco.ext.myinfo.v2.PersonResource(config)) - env.jersey().register(org.ostelco.ext.myinfo.v3.TokenResource(config)) env.jersey().register(org.ostelco.ext.myinfo.v3.PersonResource(config)) } diff --git a/ext-myinfo-emulator/src/main/kotlin/org/ostelco/ext/myinfo/v2/Resources.kt b/ext-myinfo-emulator/src/main/kotlin/org/ostelco/ext/myinfo/v2/Resources.kt deleted file mode 100644 index 88bf0e34e..000000000 --- a/ext-myinfo-emulator/src/main/kotlin/org/ostelco/ext/myinfo/v2/Resources.kt +++ /dev/null @@ -1,186 +0,0 @@ -package org.ostelco.ext.myinfo.v2 - -import org.ostelco.ext.myinfo.JsonUtils.compactJson -import org.ostelco.ext.myinfo.JweCompactUtils -import org.ostelco.ext.myinfo.JwtUtils.createAccessToken -import org.ostelco.ext.myinfo.JwtUtils.getClaims -import org.ostelco.ext.myinfo.MyInfoEmulatorConfig -import org.ostelco.prime.getLogger -import javax.ws.rs.Consumes -import javax.ws.rs.FormParam -import javax.ws.rs.GET -import javax.ws.rs.HeaderParam -import javax.ws.rs.POST -import javax.ws.rs.Path -import javax.ws.rs.PathParam -import javax.ws.rs.Produces -import javax.ws.rs.QueryParam -import javax.ws.rs.core.Context -import javax.ws.rs.core.HttpHeaders -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response - -@Path("/v2/token") -class TokenResource(private val config: MyInfoEmulatorConfig) { - - private val logger by getLogger() - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.APPLICATION_JSON) - fun getToken( - @FormParam("grant_type") grantType: String?, - @FormParam("code") authorisationCode: String?, - @FormParam("redirect_uri") redirectUri: String?, - @FormParam("client_id") clientId: String?, - @FormParam("client_secret") clientSecret: String?, - @HeaderParam("Authorization") authHeaderString: String?, - @Context headers: HttpHeaders, - body: String): Response { - - logger.debug("Content-Type: ${headers.mediaType}") - logger.debug("Headers >>>\n${headers.requestHeaders.entries.joinToString("\n")}\n<<< End of Headers") - logger.debug("Body >>>\n$body\n<<< End of Body") - - return when { - - headers.mediaType != MediaType.APPLICATION_FORM_URLENCODED_TYPE -> - Response.status(Response.Status.BAD_REQUEST) - .entity("""{reason: "Invalid Content-Type - ${headers.mediaType}"}""") - .build() - - grantType != "authorization_code" -> - Response.status(Response.Status.BAD_REQUEST) - .entity("""{reason: "Invalid grant_type"}""") - .build() - - redirectUri != config.myInfoRedirectUri -> - Response.status(Response.Status.FORBIDDEN) - .entity("""{reason: "Invalid redirect_uri"}""") - .build() - - clientId != config.myInfoApiClientId -> - Response.status(Response.Status.FORBIDDEN) - .entity("""{reason: "Invalid client_id"}""") - .build() - - clientSecret != config.myInfoApiClientSecret -> - Response.status(Response.Status.FORBIDDEN) - .entity("""{reason: "Invalid client_secret"}""") - .build() - - else -> - Response.status(Response.Status.OK).entity(""" - { - "access_token":"${createAccessToken(config.myInfoServerPrivateKey)}", - "scope":"mobileno nationality dob name mailadd email sex residentialstatus", - "token_type":"Bearer", - "expires_in":1799 - }""".trimIndent()) - .build() - } - } -} - -@Path("/v2/person") -class PersonResource(private val config: MyInfoEmulatorConfig) { - - private val logger by getLogger() - - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("/{uinFin}") - fun getToken( - @PathParam("uinFin") uinFin: String, - @QueryParam("client_id") clientId: String, - @QueryParam("attributes") attributes: String, - @HeaderParam("Authorization") authHeaderString: String, - @Context headers: HttpHeaders, - body: String): Response { - - logger.debug("Content-Type: ${headers.mediaType}") - logger.debug("Headers >>>\n${headers.requestHeaders.entries.joinToString("\n")}\n<<< End of Headers") - logger.debug("Body >>>\n$body\n<<< End of Body") - - if (!authHeaderString.contains("Bearer ")) { - return Response.status(Response.Status.FORBIDDEN) - .entity("""{reason: "Missing JWT Access Token"}""") - .build() - } - - val claims = getClaims(authHeaderString.substringAfter("Bearer "), config.myInfoServerPublicKey) - - if (claims.body.subject != uinFin) { - return Response.status(Response.Status.FORBIDDEN) - .entity("""{reason: "Invalid Subject in Access Token"}""") - .build() - } - - if (authHeaderString.startsWith("Bearer ")) { - return Response - .status(Response.Status.OK) - .entity(getPersonData(uinFin = uinFin)) - .build() - } - - return Response - .status(Response.Status.OK) - .entity(JweCompactUtils.encrypt(config.myInfoClientPublicKey, getPersonData(uinFin = uinFin))) - .build() - } - - private fun getPersonData(uinFin: String): String = compactJson(""" -{ - "name": { - "lastupdated": "2018-03-20", - "source": "1", - "classification": "C", - "value": "TAN XIAO HUI" - }, - "sex": { - "lastupdated": "2018-03-20", - "source": "1", - "classification": "C", - "value": "F" - }, - "nationality": { - "lastupdated": "2018-03-20", - "source": "1", - "classification": "C", - "value": "SG" - }, - "dob": { - "lastupdated": "2018-03-20", - "source": "1", - "classification": "C", - "value": "1970-05-17" - }, - "email": { - "lastupdated": "2018-08-23", - "source": "4", - "classification": "C", - "value": "myinfotesting@gmail.com" - }, - "mobileno": { - "lastupdated": "2018-08-23", - "code": "65", - "source": "4", - "classification": "C", - "prefix": "+", - "nbr": "97399245" - }, - "mailadd": { - "country": "SG", - "unit": "128", - "street": "BEDOK NORTH AVENUE 4", - "lastupdated": "2018-03-20", - "block": "102", - "postal": "460102", - "source": "1", - "classification": "C", - "floor": "09", - "building": "PEARL GARDEN" - }, - "uinfin": "$uinFin" -}""") -} \ No newline at end of file diff --git a/model/src/main/kotlin/org/ostelco/prime/model/Entities.kt b/model/src/main/kotlin/org/ostelco/prime/model/Entities.kt index 39853d77b..d343361b4 100644 --- a/model/src/main/kotlin/org/ostelco/prime/model/Entities.kt +++ b/model/src/main/kotlin/org/ostelco/prime/model/Entities.kt @@ -82,7 +82,6 @@ enum class KycStatus { data class MyInfoConfig(val url: String) enum class MyInfoApiVersion { - V2, V3 } diff --git a/neo4j-store/src/main/kotlin/org/ostelco/prime/storage/graph/Neo4jStore.kt b/neo4j-store/src/main/kotlin/org/ostelco/prime/storage/graph/Neo4jStore.kt index afa915d55..ca7cb1d5f 100644 --- a/neo4j-store/src/main/kotlin/org/ostelco/prime/storage/graph/Neo4jStore.kt +++ b/neo4j-store/src/main/kotlin/org/ostelco/prime/storage/graph/Neo4jStore.kt @@ -53,7 +53,6 @@ import org.ostelco.prime.model.KycType.JUMIO import org.ostelco.prime.model.KycType.MY_INFO import org.ostelco.prime.model.KycType.NRIC_FIN import org.ostelco.prime.model.MyInfoApiVersion -import org.ostelco.prime.model.MyInfoApiVersion.V2 import org.ostelco.prime.model.MyInfoApiVersion.V3 import org.ostelco.prime.model.PaymentType.SUBSCRIPTION import org.ostelco.prime.model.Plan @@ -1808,7 +1807,6 @@ object Neo4jStoreSingleton : GraphStore { val myInfoData = try { when (version) { - V2 -> myInfoKycV2Service V3 -> myInfoKycV3Service }.getPersonData(authorisationCode) } catch (e: Exception) { diff --git a/prime/config/config.yaml b/prime/config/config.yaml index f61971804..3d3319586 100644 --- a/prime/config/config.yaml +++ b/prime/config/config.yaml @@ -41,14 +41,6 @@ modules: connectionRequestTimeout: 1s - type: kyc config: - myInfoV2: - myInfoApiUri: ${MY_INFO_V2_API_URI} - myInfoApiClientId: ${MY_INFO_API_CLIENT_ID} - myInfoApiClientSecret: ${MY_INFO_API_CLIENT_SECRET} - myInfoApiRealm: ${MY_INFO_API_REALM} - myInfoRedirectUri: ${MY_INFO_REDIRECT_URI} - myInfoServerPublicKey: ${MY_INFO_SERVER_PUBLIC_KEY} - myInfoClientPrivateKey: ${MY_INFO_CLIENT_PRIVATE_KEY} myInfoV3: myInfoApiUri: ${MY_INFO_V3_API_URI} myInfoApiClientId: ${MY_INFO_API_CLIENT_ID} diff --git a/prime/config/test.yaml b/prime/config/test.yaml index 3cc7467b6..ab8887d25 100644 --- a/prime/config/test.yaml +++ b/prime/config/test.yaml @@ -19,14 +19,6 @@ modules: csvFile: /config-data/imeiDb.csv - type: kyc config: - myInfoV2: - myInfoApiUri: http://ext-myinfo-emulator:8080/v2 - myInfoApiClientId: STG2-MYINFO-SELF-TEST - myInfoApiClientSecret: 44d953c796cccebcec9bdc826852857ab412fbe2 - myInfoApiRealm: http://localhost:3001 - myInfoRedirectUri: http://localhost:3001/callback - myInfoServerPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqWWA2rH1wuBkd1zp0uOh+dnCRRcQWiI89ildk9UGSd3kgzPx1mYEL40cBOBVpSIkbRp65fJDjBm+MhzlHBgWZ1q27S30nczwnzAUJqUfJvLeCW7HLwqwPVSQlqby/n4MV2AKUu0jMacOeXE3Bevm92BEOH9wQhv81Rd7HZXRJGgMecqmVehMT7Mk88xHJvvWD1bYSQL5ADnNz1v0wq/afOVYPWAOl7xYoIgokYJQD3WwnKHVcotZcP8B5mu0AuMnP71JnzjVsRpwuO8N/m28fmzXCY7ARwRpz20Q6oOq09+ZMiJkpdT5TTqEF1u3FxTq5TY8CY60q9L5RqEUNJA9fQIDAQAB - myInfoClientPrivateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGBRdsiDqKPGyHgOpzxmSU2EQkm+zYZLvlPlwkwyfFWLndFLZ3saxJS+LIixsFhunrrUT9ZZ0x+bB6MV55o70z4ABOJRFNWx1wbMGqdiC0Fyfpwad3iYpRVjZO+5etHA9JEoaTPoFxv+ktd8kVAL9P5I7/Pi6g1R+B2t2lsaE2bMSwtZqgs55gb7fsCR3Z4nQi7BddYR7MZ2lAMWf7h7Dkm6uRlGhl2RvtmYa6dXFnK3RhIpdQOUT3quyhweMGspowC/tYSG+BNhy1WukbwhIP5vTAvv1WbHTg+WaUUV+pP0TjPQcY73clHxNpI5zrNqDmwD2rogNfePKRUI63yBUfAgMBAAECggEAGy/7xVT25J/jLr+OcRLeIGmJAZW+8P7zpUfoksuQnFHQQwBjBRAJ3Y5jtrESprGdUFRb0oavDHuBtWUt2XmXspWgtRn1xC8sXZExDdxmJRPA0SFbgtgJe51gm3uDmarullPK0lCUqS92Ll3x58ZQfgGdeIHrGP3p84Q/Rk6bGcObcPhDYWSOYKm4i2DPM01bnZG2z4BcrWSseOmeWUxqZcMlGz9GAyepUU/EoqRIHxw/2Y+TGus1JSy5DdhPE0HAEWKZH729ZdoyikOZCMxApQglUkRwkwhtXzVAemm6OSoy3BEWvSEJh/F82tFrmquUoe/xd5JastlBHyD78RAakQKBgQDkHAzo1fowRI19tk7VCPn0zMdF/UTRghtLywc/4xnw1Nd13m+orArOdVzPlQokLVNL81dIVKXnId0Hw/kX8CRyRYz8tkL81spc39DfalZW7QI7Fschfq1Htgkxd/QEjBlIaqjkOjGSbX9xYjYU1Db8PuGoGXWOsYiv9PCsKR056wKBgQDeOzfZSpV5kX8SECJXRA+emyCnO9S29p0W+5BCTQp3OPnmbL7b/mGqBVJ0DC+IiN67Lu8xxzejswqLZqaRvmQuioqH+8mOGpXYZwhShAif2AuixxvL7OK6dvDmMqoKhBI9nZ9+XI60Cd/LjnWgyFO04uq4otnTukmYsSP+fp6wnQKBgEopYH0WjFfDAelcKzcRywouxZ7Yn9Ypoaw7nujDcfydhktY/R5uiLjk6T7H6tsmLU2lGLx4YNPLa6wJp+ODfKX2PMcwjojbYEFftu3cCaQLPE1vs2ANalLFOSnvINOVpOapXq2Mye8cUHHRh1mwQQwzeXQIivLQf2sNjG28lDbvAoGACsh80UJZNmjk7Y9y2yEmUN/eGb9Bdw9IWBEk0tLCKz7MgW3NZQdW3dUcRx1AQTPC+vowCQ5NmNfbLyBv/KpsWgXG6wpAoXCQzMtTEA3wDTGCfweCRcbcyYdz8PeMYK4/5FV9o7gCBKJmBY6IDqEpzqEkGolsYGWtpIcT5Alo0dECgYEA3hzC9NLwumi/1JWm+ASSADTO3rrGo9hicG/WKGzSHD5l1f+IO1SfmUN/6i2JjcnE07eYArNrCfbMgkFavj502ne2fSaYM4p0o147O9Ty8jCyY9vuh/ZGid6qUe3TBI6/okWfmYw6FVbRpNfVEeG7kPfkDW/JdH7qkWTFbh3eH1k= myInfoV3: myInfoApiUri: http://ext-myinfo-emulator:8080/v3 myInfoApiClientId: STG2-MYINFO-SELF-TEST diff --git a/prime/infra/dev/prime-customer-api.yaml b/prime/infra/dev/prime-customer-api.yaml index 6dff36ed3..25d247190 100644 --- a/prime/infra/dev/prime-customer-api.yaml +++ b/prime/infra/dev/prime-customer-api.yaml @@ -257,42 +257,6 @@ paths: description: "Region or Scan not found." security: - firebase: [] - "/regions/sg/kyc/myInfoConfig": - get: - description: "Get Singapore MyInfo v2 service config (deprecated)." - produces: - - application/json - operationId: "getMyInfoV2Config" - responses: - 200: - description: "MyInfo service config." - schema: - $ref: "#/definitions/MyInfoConfig" - 404: - description: "Config not found." - security: - - firebase: [] - "/regions/sg/kyc/myInfo/{authorisationCode}": - get: - description: "Get Customer Data from Singapore MyInfo v2 service (deprecated)." - produces: - - application/json - operationId: "getCustomerMyInfoV2Data" - parameters: - - name: authorisationCode - in: path - description: "Authorisation Code" - required: true - type: string - responses: - 200: - description: "Successfully retrieved Customer Data from MyInfo v2 service." - schema: - type: object - 404: - description: "Person Data not found." - security: - - firebase: [] "/regions/sg/kyc/myInfo/v3/config": get: description: "Get Singapore MyInfo v3 service config." diff --git a/prime/infra/prime-direct-values.yaml b/prime/infra/prime-direct-values.yaml index 731194964..65b8e9210 100644 --- a/prime/infra/prime-direct-values.yaml +++ b/prime/infra/prime-direct-values.yaml @@ -33,9 +33,7 @@ prime: ACTIVATE_TOPIC_ID: ocs-activate CCR_SUBSCRIPTION_ID: ocs-ccr-prime-direct-sub GOOGLE_APPLICATION_CREDENTIALS: /secret/prime-service-account.json - MY_INFO_V2_API_URI: https://myinfosgstg.api.gov.sg/test/v2 MY_INFO_V3_API_URI: https://test.api.myinfo.gov.sg/com/v3 - MY_INFO_API_REALM: direct MY_INFO_REDIRECT_URI: https://dl-dev.oya.world/links/myinfo secretVolumes: