Giter VIP home page Giter VIP logo

diga-api-service's People

Contributors

bokchan avatar gtuk avatar icemac avatar jakob-p avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

diga-api-service's Issues

Handling of requests containing test codes

Sending test codes using this service makes sense to me to try out the different api endpoints and also to test integrations of this service. However, in production setups it might be better to disallow sending requests with test codes. Potential solutions:

  • have a setting which disables sending requests for test codes
  • returning is_test_code in the api responses so it can be handled at caller side.

Include diga error code for code validation requests in response

If a code validation request fails the service returns a generic response with http status 400, e.g.:

{
    "timestamp": "2021-08-11T14:39:16.682+00:00",
    "status": 400,
    "error": "Bad Request",
    "path": "/validate/AAAAAAAAAAAAAAAA"
}

In the case where the request to diga-api-client succeeds but response.isHasError() == true it would be helpful if the original errors from the DigaCodeValidationResponse could be included in the response from the diga-api-service as well.

  • It will allow the client/us to determine which error message to show to the user
  • Being able to store the response with the original diga error code directly in our db backend makes it easier to integrate it with our internal monitoring systems.

Using the numeric error codes seems more consistent as they are language independent and also found in official DiGA documentation.

A possible response format could be:

{
    "timestamp": "2021-08-11T14:39:16.682+00:00",
    "status": 400,
    "error": "Bad Request",
    "digaErrorCode": 102, 
    "digaErrorText": "Freischaltcode / Rezeptcode nicht gefunden: AAAA AAAA AAAA AAAA",  // optional
    "path": "/validate/AAAAAAAAAAAAAAAA"
}

One complication is that AbstractDigaApiResponse defines errors as a List so it might be that the response format should reflect this.

{
  "timestamp":"2021-08-11T14:39:16.682+00:00",
  "status":400,
  "error":"Bad Request",
  "digaErrors":[
    {
      "errorCode":102,
      "errorText":"Freischaltcode / Rezeptcode nicht gefunden: AAAA AAAA AAAA AAAA" // optional
    }
  ],
  "path":"/validate/AAAAAAAAAAAAAAAA"
}

Return 403 for diga test code requests when DISABLE_TESTCODES=true

Currently the response for a diga test code when DISABLE_TESTCODES=true is:

{
    "timestamp": "2021-08-23T07:15:50.545+00:00",
    "status": 400,
    "error": "Bad Request",
    "message": "Testcodes are not allowed",
    "path": "/validate/77AAAAAAAAAAAGIS"
}

It could make sense to use return 403 Forbidden to denote this. It fits the semantics of the status code:

The HTTP 403 Forbidden client error status response code indicates that the server understood the request but refuses to authorize it.

And it is clear(er) that the error is different from the normal code validation error.

The proposed response would instead be:

{
    "timestamp": "2021-08-23T10:14:44.185+00:00",
    "status": 403,
    "error": "Forbidden",
    "message": "Testcodes are not allowed",
    "path": "/validate/77AAAAAAAAAAAGIS"
}

Using the service for two DiGAs

Hi!
First of all thanks for this project, it helped us a lot.

We would like to use the service to validate the codes for two DiGAs in the future. As far as I see this might not be possible with the current implementation. I see two possible ways at this point:

  1. Run a separate instance of this service with a different configuration.
  2. Add two additional endpoints (e.g. validate_diga2 and bill_diga2) for the second DiGA and implement some way to switch between the configurations.

Am I going in the right direction or am I missing something?
Thanks!

Extend code validation response with the xml file from diga api response

We have noticed in section 4.4 - Protokollierung here that it is required to log the interactions with the DiGA api.

Die Protokollierung muss die folgenden Mindestinhalte umfassen:
- Eindeutige Bezeichnung der Kommunikationspartner (Institutionskennzeichen)
- Zeitstempel im Format „yyyy-MM-dd HH:mm:ss“, basierend auf deutscher Zeit
- Prozesskennzeichen (Prüfung Freischaltcode / Rezeptcode / Abrechnung)
- Freischaltcode / Rezeptcode
- Verarbeitungskennzeichen (fehlerfrei/fehlerhaft)

Translated fields:

- ik numbers
- timestamp in German timezone
- value for `verfahren`
- prescription code
- flag if valid or not

In the current json response of this service we only get parts of this data. Also it might be a good idea to store the response xml (on caller-side) after making the validation request. Therefore, it would be great if this service could return the xml file in addition to the existing response format. In its' simplest form the xml could just be returned as text string.

Current Response

{
    "code": "77AAAAAAAAAAAAAX",
    "digavId": "00451000",
    "dayOfServiceProvision": "2021-06-02"
}

Proposed Change

{
    "code": "77AAAAAAAAAAAAAX",
    "digavId": "00451000",
    "dayOfServiceProvision": "2021-06-02",
    "xmlResponse": "<?xml version="1.0" ...>..."
}

All the required data for logging can be extracted from the xml_response on the caller-side. Additionally, it could make sense to return a boolean field isTestCode which denotes if the code was a test code or not.

What do you think @gtuk ?

Java 17: JCE cannot authenticate the provider BC

Using Java 17 and the new 2.0.0 release I seem to run into spring-projects/spring-boot#28837:

Local traceback for validation
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.0)

2023-11-14 15:46:05.429 INFO 76200 --- [ main] dev.gtuk.diga.ApplicationKt : Starting ApplicationKt vv2.0.0 using Java 17.0.9 on echo with PID 76200 (/.../digaapibuildout/diga-api-service-v2.0.0.jar started by icemac in /.../digaapibuildout)
2023-11-14 15:46:05.430 INFO 76200 --- [ main] dev.gtuk.diga.ApplicationKt : No active profile set, falling back to default profiles: default
2023-11-14 15:46:06.045 INFO 76200 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 6000 (http)
2023-11-14 15:46:06.050 INFO 76200 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-11-14 15:46:06.050 INFO 76200 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.46]
2023-11-14 15:46:06.079 INFO 76200 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-11-14 15:46:06.079 INFO 76200 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 618 ms
2023-11-14 15:46:07.082 INFO 76200 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 6000 (http) with context path ''
2023-11-14 15:46:07.088 INFO 76200 --- [ main] dev.gtuk.diga.ApplicationKt : Started ApplicationKt in 1.87 seconds (JVM running for 2.091)
2023-11-14 15:46:07.088 INFO 76200 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state LivenessState changed to CORRECT
2023-11-14 15:46:07.089 INFO 76200 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state ReadinessState changed to ACCEPTING_TRAFFIC
2023-11-14 15:46:10.161 INFO 76200 --- [nio-6000-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-11-14 15:46:10.161 INFO 76200 --- [nio-6000-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2023-11-14 15:46:10.162 INFO 76200 --- [nio-6000-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2023-11-14 15:46:10.596 ERROR 76200 --- [nio-6000-exec-1] com.alextherapeutics.diga.DigaApiClient : Failed to validate DiGA code 77AAAAAAAAAAAAAX

com.alextherapeutics.diga.DigaEncryptionException: Diga encryption failed due to exception
at com.alextherapeutics.diga.model.DigaEncryption.encrypt(DigaEncryption.java:61) ~[diga-api-client-2.0.0.jar!/:na]
at com.alextherapeutics.diga.DigaApiClient.performCodeValidation(DigaApiClient.java:213) ~[diga-api-client-2.0.0.jar!/:na]
at com.alextherapeutics.diga.DigaApiClient.sendTestCodeValidationRequest(DigaApiClient.java:152) ~[diga-api-client-2.0.0.jar!/:na]
at dev.gtuk.diga.DigaService.verify(DigaService.kt:75) ~[classes!/:v2.0.0]
at dev.gtuk.diga.AppController.verify(AppController.kt:18) ~[classes!/:v2.0.0]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.7.jar!/:5.3.7]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.7.jar!/:5.3.7]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.7.jar!/:5.3.7]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.46.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.7.jar!/:5.3.7]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar!/:5.3.7]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.7.jar!/:5.3.7]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar!/:5.3.7]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.7.jar!/:5.3.7]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.7.jar!/:5.3.7]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707) ~[tomcat-embed-core-9.0.46.jar!/:na]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.46.jar!/:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.46.jar!/:na]
at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]
Caused by: de.tk.opensource.secon.SeconException: org.bouncycastle.cms.CMSException: cannot create key generator: JCE cannot authenticate the provider BC
at de.tk.opensource.secon.SECON.lambda$callable$4(SECON.java:268) ~[secon-tool-1.2.0.jar!/:na]
at global.namespace.fun.io.api.Socket.accept(Socket.java:109) ~[fun-io-api-2.4.0.jar!/:2.4.0]
at global.namespace.fun.io.spi.Copy.lambda$copy$3(Copy.java:91) ~[fun-io-spi-2.4.0.jar!/:2.4.0]
at global.namespace.fun.io.api.Socket.accept(Socket.java:110) ~[fun-io-api-2.4.0.jar!/:2.4.0]
at global.namespace.fun.io.spi.Copy.copy(Copy.java:91) ~[fun-io-spi-2.4.0.jar!/:2.4.0]
at global.namespace.fun.io.bios.BIOS.copy(BIOS.java:537) ~[fun-io-bios-2.4.0.jar!/:2.4.0]
at de.tk.opensource.secon.SECON.lambda$copy$3(SECON.java:246) ~[secon-tool-1.2.0.jar!/:na]
at de.tk.opensource.secon.SECON.lambda$callable$4(SECON.java:262) ~[secon-tool-1.2.0.jar!/:na]
at de.tk.opensource.secon.SECON.call(SECON.java:256) ~[secon-tool-1.2.0.jar!/:na]
at de.tk.opensource.secon.SECON.copy(SECON.java:245) ~[secon-tool-1.2.0.jar!/:na]
at com.alextherapeutics.diga.model.DigaEncryption.encrypt(DigaEncryption.java:54) ~[diga-api-client-2.0.0.jar!/:na]
... 54 common frames omitted
Caused by: org.bouncycastle.cms.CMSException: cannot create key generator: JCE cannot authenticate the provider BC
at org.bouncycastle.cms.jcajce.EnvelopedDataHelper.createKeyGenerator(Unknown Source) ~[bcpkix-jdk15on-1.70.jar!/:1.70.00.0]
at org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder$CMSOutputEncryptor.(Unknown Source) ~[bcpkix-jdk15on-1.70.jar!/:1.70.00.0]
at org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder.build(Unknown Source) ~[bcpkix-jdk15on-1.70.jar!/:1.70.00.0]
at de.tk.opensource.secon.DefaultSubscriber.encrypt(DefaultSubscriber.java:215) ~[secon-tool-1.2.0.jar!/:na]
at de.tk.opensource.secon.DefaultSubscriber.lambda$encrypt$2(DefaultSubscriber.java:220) ~[secon-tool-1.2.0.jar!/:na]
at de.tk.opensource.secon.Streams.lambda$fixOutputstreamClose$1(Streams.java:48) ~[secon-tool-1.2.0.jar!/:na]
at global.namespace.fun.io.api.function.XFunction.lambda$compose$0(XFunction.java:32) ~[fun-io-api-2.4.0.jar!/:2.4.0]
at global.namespace.fun.io.api.Socket.lambda$map$0(Socket.java:138) ~[fun-io-api-2.4.0.jar!/:2.4.0]
at de.tk.opensource.secon.SECON.lambda$callable$4(SECON.java:262) ~[secon-tool-1.2.0.jar!/:na]
... 64 common frames omitted
Caused by: java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
at java.base/javax.crypto.JceSecurity.getInstance(JceSecurity.java:131) ~[na:na]
at java.base/javax.crypto.KeyGenerator.getInstance(KeyGenerator.java:286) ~[na:na]
at org.bouncycastle.jcajce.util.NamedJcaJceHelper.createKeyGenerator(Unknown Source) ~[bcprov-jdk15on-1.70.jar!/:1.70.0]
... 73 common frames omitted
Caused by: java.lang.IllegalStateException: zip file closed
at java.base/java.util.zip.ZipFile.ensureOpen(ZipFile.java:840) ~[na:na]
at java.base/java.util.zip.ZipFile.getManifestName(ZipFile.java:1066) ~[na:na]
at java.base/java.util.zip.ZipFile$1.getManifestName(ZipFile.java:1125) ~[na:na]
at java.base/javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:464) ~[na:na]
at java.base/javax.crypto.JarVerifier.verifyJars(JarVerifier.java:320) ~[na:na]
at java.base/javax.crypto.JarVerifier.verify(JarVerifier.java:263) ~[na:na]
at java.base/javax.crypto.ProviderVerifier.verify(ProviderVerifier.java:130) ~[na:na]
at java.base/javax.crypto.JceSecurity.verifyProvider(JceSecurity.java:190) ~[na:na]
at java.base/javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:218) ~[na:na]
at java.base/javax.crypto.JceSecurity.getInstance(JceSecurity.java:128) ~[na:na]
... 75 common frames omitted

According to spring-projects/spring-boot@33c5e12 this issue was fixed in 3.2.0rc1.

Do you think it is possible to try out the latest version (currently 3.2.0rc2) to get rid of this error? It currently prevents from using the new release and Java 17.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.