diff --git a/README.md b/README.md index f0bbeef..ffe9e4a 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ Use environment variables to configure the relying party server. | `EHEALTHID_RP_HOST` | Host to bind to. | `0.0.0.0` | | `EHEALTHID_RP_PORT` | Port to bind to. | `1234` | | `EHEALTHID_RP_ES_TTL` | The time to live for the entity statement. In ISO8601 format. | `PT12H` | -| `EHEALTHID_RP_SCOPES` | The comma separated list of scopes requested in the federation. This __MUST__ match what was registered with the federation master. | `openid,urn:telematik:email,urn:telematik:display_name` | +| `EHEALTHID_RP_SCOPES` | The comma separated list of scopes requested in the federation. This __MUST__ match what was registered with the federation master. | `openid,urn:telematik:versicherter` | | `EHEALTHID_RP_SESSION_STORE_TTL` | The time to live for sessions. In ISO8601 format. | `PT20M` | | `EHEALTHID_RP_SESSION_STORE_MAX_ENTRIES` | The maximum number of sessions to store. Keeps memory bounded. | `1000` | | `EHEALTHID_RP_CODE_STORE_TTL` | The time to live for codes, i.e. successful logins where the code is not redeemed yet. In ISO8601 format. | `PT5M` | diff --git a/ehealthid-cli/src/main/java/com/oviva/ehealthid/cli/FedRegistrationCommand.java b/ehealthid-cli/src/main/java/com/oviva/ehealthid/cli/FedRegistrationCommand.java index ee61a09..fe48a13 100755 --- a/ehealthid-cli/src/main/java/com/oviva/ehealthid/cli/FedRegistrationCommand.java +++ b/ehealthid-cli/src/main/java/com/oviva/ehealthid/cli/FedRegistrationCommand.java @@ -64,9 +64,13 @@ public class FedRegistrationCommand implements Callable { @Option( names = {"-c", "--contact-email"}, - description = "the technical contact email for the IdP", - required = true) - private String email; + description = "the technical contact email for the IdP") + private String contactEmail; + + @Option( + names = {"--vfs-confirmation"}, + description = "gematik-Verfahrensschlüssel (starts with VFS_DiGA_...)") + private String vfsConfirmation; public static void main(String[] args) { @@ -83,6 +87,8 @@ public static void main(String[] args) { public Integer call() throws Exception { + parameterValidation(); + var entityConfiguration = fetchEntityConfiguration(); for (var key : entityConfiguration.jwks().getKeys()) { validateKey(key, KeyUse.SIGNATURE); @@ -97,28 +103,43 @@ public Integer call() throws Exception { return 0; } + private void printRegistrationForm(EntityConfiguration entityConfiguration) { + var registrationForm = renderRegistrationForm(entityConfiguration); + System.out.println(registrationForm); + } + + private void writeRegistrationForm(EntityConfiguration entityConfiguration) throws IOException { + var registrationForm = renderRegistrationForm(entityConfiguration); + + logger.atInfo().log("writing registration form to '{}'", file); + Files.writeString(file, registrationForm); + } + private String renderRegistrationForm(EntityConfiguration entityConfiguration) { return RegistratonFormRenderer.render( new Model( + vfsConfirmation, memberId, entityConfiguration.orgName(), - email, + contactEmail, issuerUri, environment, entityConfiguration.scopes(), entityConfiguration.jwks())); } - private void printRegistrationForm(EntityConfiguration entityConfiguration) { - var registrationForm = renderRegistrationForm(entityConfiguration); - System.out.println(registrationForm); - } - - private void writeRegistrationForm(EntityConfiguration entityConfiguration) throws IOException { - var registrationForm = renderRegistrationForm(entityConfiguration); - - logger.atInfo().log("writing registration form to '{}'", file); - Files.writeString(file, registrationForm); + private void parameterValidation() { + if (environment == Environment.PU) { + if (vfsConfirmation == null || vfsConfirmation.isBlank()) { + logger.atError().log("Verfahrensschlüssel is required for production (PU) environment"); + throw new RuntimeException(); + } + } else { + if (contactEmail == null || contactEmail.isBlank()) { + logger.atError().log("contact email is required for test environments"); + throw new RuntimeException(); + } + } } private EntityConfiguration fetchEntityConfiguration() { diff --git a/ehealthid-cli/src/main/java/com/oviva/ehealthid/cli/RegistratonFormRenderer.java b/ehealthid-cli/src/main/java/com/oviva/ehealthid/cli/RegistratonFormRenderer.java index abc79b1..c9cc822 100644 --- a/ehealthid-cli/src/main/java/com/oviva/ehealthid/cli/RegistratonFormRenderer.java +++ b/ehealthid-cli/src/main/java/com/oviva/ehealthid/cli/RegistratonFormRenderer.java @@ -14,7 +14,39 @@ public class RegistratonFormRenderer { - private static final String XML_TEMPLATE = + private static final String XML_TEMPLATE_PROD = + """ + + + + {{vfsConfirmation}} + Fachdienst + {{organisationName}} + {{memberId}} + ORG-0001:BT-0144 + {{issuerUri}} + + {{scopeAge}} + {{scopeDisplayName}} + {{scopeEmail}} + {{scopeGender}} + {{scopeDateOfBirth}} + {{scopeFirstName}} + {{scopeLastName}} + {{scopeInsuredPerson}} + + {{#publicKeys}} + + {{kid}} + {{pem}} + {{environment}} + + {{/publicKeys}} + + + """; + + private static final String XML_TEMPLATE_TEST = """ @@ -48,17 +80,34 @@ public class RegistratonFormRenderer { public static String render(Model m) { + return switch (m.environment()) { + case PU -> renderProductive(m); + default -> renderTestEnvironment(m); + }; + } + + private static String renderProductive(Model m) { + return renderTemplate(XML_TEMPLATE_PROD, m); + } + + private static String renderTestEnvironment(Model m) { + return renderTemplate(XML_TEMPLATE_TEST, m); + } + + private static String renderTemplate(String template, Model m) { + var mf = new DefaultMustacheFactory(); - var template = mf.compile(new StringReader(XML_TEMPLATE), "entity-statement-registration"); + var compiledTemplate = mf.compile(new StringReader(template), "entity-statement-registration"); var w = new StringWriter(); var rm = RenderModel.fromModel(m); - template.execute(w, rm); + compiledTemplate.execute(w, rm); return w.toString(); } public record Model( + String vfsConfirmation, String memberId, String organisationName, String contactEmail, @@ -87,6 +136,7 @@ enum Scope { } record RenderModel( + String vfsConfirmation, String memberId, String organisationName, String issuerUri, @@ -105,6 +155,7 @@ record RenderModel( public static RenderModel fromModel(Model m) { return new RenderModel( + m.vfsConfirmation(), m.memberId(), m.organisationName(), m.issuerUri().toString(), diff --git a/ehealthid-cli/src/test/java/com/oviva/ehealthid/cli/RegistratonFormRendererTest.java b/ehealthid-cli/src/test/java/com/oviva/ehealthid/cli/RegistratonFormRendererTest.java index 873edee..e02c1ea 100644 --- a/ehealthid-cli/src/test/java/com/oviva/ehealthid/cli/RegistratonFormRendererTest.java +++ b/ehealthid-cli/src/test/java/com/oviva/ehealthid/cli/RegistratonFormRendererTest.java @@ -25,6 +25,7 @@ void render() throws JOSEException { var xml = RegistratonFormRenderer.render( new Model( + "VFS_DiGA_Test", "FDmyDiGAMemb", "My DiGA", "bobby.tables@example.com", diff --git a/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/ConfigReader.java b/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/ConfigReader.java index e0800b0..2dce252 100644 --- a/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/ConfigReader.java +++ b/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/ConfigReader.java @@ -140,10 +140,7 @@ private List getScopes() { return configProvider .get(CONFIG_SCOPES) - .or( - () -> - Optional.of( - "openid,urn:telematik:email,urn:telematik:versicherter,urn:telematik:display_name")) + .or(() -> Optional.of("openid,urn:telematik:versicherter")) .stream() .flatMap(Strings::mustParseCommaList) .toList(); diff --git a/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/poc/GematikHeaderDecoratorHttpClient.java b/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/poc/GematikHeaderDecoratorHttpClient.java index 3236174..72b8893 100644 --- a/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/poc/GematikHeaderDecoratorHttpClient.java +++ b/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/poc/GematikHeaderDecoratorHttpClient.java @@ -12,6 +12,7 @@ public class GematikHeaderDecoratorHttpClient implements HttpClient { LoggerFactory.getLogger(GematikHeaderDecoratorHttpClient.class); // RU: https://gsi-ref.dev.gematik.solutions/.well-known/openid-federation + // RU PAR mTLS: https://gsi-ref-mtls.dev.gematik.solutions/PAR_Auth // TU: https://gsi.dev.gematik.solutions/.well-known/openid-federation private static final Pattern HOST_GEMATIK_IDP = Pattern.compile("gsi(-[-a-z0-9]+)?.dev.gematik.solutions");