Skip to content

Commit

Permalink
Merge pull request #439 from oehf/feature/433-balp-audit
Browse files Browse the repository at this point in the history
Feature/433 balp audit
  • Loading branch information
stanojevic-boris authored Feb 1, 2024
2 parents 4766c2a + 68b7dfa commit a8bbb28
Show file tree
Hide file tree
Showing 97 changed files with 3,379 additions and 125 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ work
/commons/ihe/xds/generated-stubs
generated-stubs
/commons/audit/.vertx
/local_history.patch
4 changes: 4 additions & 0 deletions boot/ipf-atna-spring-boot-starter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
<groupId>org.openehealth.ipf.commons</groupId>
<artifactId>ipf-commons-audit</artifactId>
</dependency>
<dependency>
<groupId>org.openehealth.ipf.commons</groupId>
<artifactId>ipf-commons-ihe-fhir-r4-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@

package org.openehealth.ipf.boot.atna;

import org.openehealth.ipf.commons.audit.*;
import org.openehealth.ipf.commons.audit.AuditContext;
import org.openehealth.ipf.commons.audit.AuditMessagePostProcessor;
import org.openehealth.ipf.commons.audit.AuditMetadataProvider;
import org.openehealth.ipf.commons.audit.DefaultAuditContext;
import org.openehealth.ipf.commons.audit.DefaultAuditMetadataProvider;
import org.openehealth.ipf.commons.audit.DefaultBalpAuditContext;
import org.openehealth.ipf.commons.audit.TlsParameters;
import org.openehealth.ipf.commons.audit.handler.AuditExceptionHandler;
import org.openehealth.ipf.commons.audit.handler.LoggingAuditExceptionHandler;
import org.openehealth.ipf.commons.audit.protocol.AuditTransmissionChannel;
import org.openehealth.ipf.commons.audit.protocol.AuditTransmissionProtocol;
import org.openehealth.ipf.commons.audit.queue.AuditMessageQueue;
import org.openehealth.ipf.commons.ihe.fhir.support.audit.marshal.BalpJsonSerializationStrategy;
import org.openehealth.ipf.commons.ihe.fhir.support.audit.marshal.BalpXmlSerializationStrategy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Expand All @@ -31,6 +39,8 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static org.apache.commons.lang3.StringUtils.isNotBlank;

/**
*
*/
Expand All @@ -48,7 +58,27 @@ public AuditContext auditContext(IpfAtnaConfigurationProperties config,
AuditExceptionHandler auditExceptionHandler,
AuditMessagePostProcessor auditMessagePostProcessor,
@Value("${spring.application.name}") String appName) {
var auditContext = new DefaultAuditContext();
if (config.getBalp() != null) {
return balpConfiguration(defaultContextConfiguration(new DefaultBalpAuditContext(), config,
auditTransmissionProtocol, auditMessageQueue, tlsParameters, auditMetadataProvider,
auditExceptionHandler, auditMessagePostProcessor, appName), config);
} else {
return defaultContextConfiguration(new DefaultAuditContext(), config, auditTransmissionProtocol,
auditMessageQueue, tlsParameters, auditMetadataProvider, auditExceptionHandler,
auditMessagePostProcessor, appName);
}
}

private <T extends DefaultAuditContext> T defaultContextConfiguration(T auditContext,
IpfAtnaConfigurationProperties config,
AuditTransmissionProtocol auditTransmissionProtocol,
AuditMessageQueue auditMessageQueue,
TlsParameters tlsParameters,
AuditMetadataProvider auditMetadataProvider,
AuditExceptionHandler auditExceptionHandler,
AuditMessagePostProcessor auditMessagePostProcessor,
@Value("${spring.application.name}") String appName) {

auditContext.setAuditEnabled(config.isAuditEnabled());

// Simple properties
Expand All @@ -67,7 +97,63 @@ public AuditContext auditContext(IpfAtnaConfigurationProperties config,
auditContext.setAuditMessageQueue(auditMessageQueue);
auditContext.setAuditExceptionHandler(auditExceptionHandler);
auditContext.setAuditMessagePostProcessor(auditMessagePostProcessor);
return auditContext;
}

private DefaultBalpAuditContext balpConfiguration(DefaultBalpAuditContext auditContext, IpfAtnaConfigurationProperties config) {
if (config.getBalp() != null) {
auditContext.setAuditRepositoryContextPath(config.getBalp().getAuditRepositoryContextPath());

if (isNotBlank(config.getBalp().getAuditEventSerializationType())) {
auditContext.setSerializationStrategy(
config.getBalp().getAuditEventSerializationType().equalsIgnoreCase("json") ?
new BalpJsonSerializationStrategy() : new BalpXmlSerializationStrategy());
}
if (config.getBalp().getOauth() != null) {
if (config.getBalp().getOauth().getIdPath() != null) {
auditContext.getBalpJwtExtractorProperties().setIdPath(config.getBalp().getOauth().getIdPath());
}
if (config.getBalp().getOauth().getClientIdPath() != null) {
auditContext.getBalpJwtExtractorProperties().setClientIdPath(config.getBalp().getOauth().getClientIdPath());
}
if (config.getBalp().getOauth().getIssuerPath() != null) {
auditContext.getBalpJwtExtractorProperties().setIssuerPath(config.getBalp().getOauth().getIssuerPath());
}
if (config.getBalp().getOauth().getSubjectPath() != null) {
auditContext.getBalpJwtExtractorProperties().setSubjectPath(config.getBalp().getOauth().getSubjectPath());
}
if (config.getBalp().getOauth().getSubjectNamePath() != null) {
auditContext.getBalpJwtExtractorProperties().setSubjectNamePath(config.getBalp().getOauth().getSubjectNamePath());
}
if (config.getBalp().getOauth().getSubjectRolePath() != null) {
auditContext.getBalpJwtExtractorProperties().setSubjectRolePath(config.getBalp().getOauth().getSubjectRolePath());
}
if (config.getBalp().getOauth().getSubjectOrganizationIdPath() != null) {
auditContext.getBalpJwtExtractorProperties().setSubjectOrganizationIdPath(config.getBalp().getOauth().getSubjectOrganizationIdPath());
}
if (config.getBalp().getOauth().getPurposeOfUsePath() != null) {
auditContext.getBalpJwtExtractorProperties().setPurposeOfUsePath(config.getBalp().getOauth().getPurposeOfUsePath());
}
if (config.getBalp().getOauth().getHomeCommunityIdPath() != null) {
auditContext.getBalpJwtExtractorProperties().setHomeCommunityIdPath(config.getBalp().getOauth().getHomeCommunityIdPath());
}
if (config.getBalp().getOauth().getNationalProviderIdPath() != null) {
auditContext.getBalpJwtExtractorProperties().setNationalProviderIdPath(config.getBalp().getOauth().getNationalProviderIdPath());
}
if (config.getBalp().getOauth().getDocIdPath() != null) {
auditContext.getBalpJwtExtractorProperties().setDocIdPath(config.getBalp().getOauth().getDocIdPath());
}
if (config.getBalp().getOauth().getPatientIdPath() != null) {
auditContext.getBalpJwtExtractorProperties().setPatientIdPath(config.getBalp().getOauth().getPatientIdPath());
}
if (config.getBalp().getOauth().getPersonIdPath() != null) {
auditContext.getBalpJwtExtractorProperties().setPersonIdPath(config.getBalp().getOauth().getPersonIdPath());
}
if (config.getBalp().getOauth().getAcpPath() != null) {
auditContext.getBalpJwtExtractorProperties().setAcpPath(config.getBalp().getOauth().getAcpPath());
}
}
}
return auditContext;
}

Expand Down Expand Up @@ -95,10 +181,10 @@ public AuditTransmissionProtocol auditTransmissionProtocol(IpfAtnaConfigurationP
TlsParameters tlsParameters) throws Exception {
if (config.getAuditSenderClass() != null) {
return config.getAuditSenderClass().getConstructor(TlsParameters.class)
.newInstance(tlsParameters);
.newInstance(tlsParameters);
}
return AuditTransmissionChannel.fromProtocolName(config.getAuditRepositoryTransport())
.makeInstance(tlsParameters);
.makeInstance(tlsParameters);
}

@Bean
Expand All @@ -107,8 +193,8 @@ public AuditMetadataProvider auditMetadataProvider(IpfAtnaConfigurationPropertie
@Value("${spring.application.name}") String appName) {
var auditMetadataProvider = new DefaultAuditMetadataProvider();
auditMetadataProvider.setSendingApplication(config.getAuditSendingApplication() != null ?
config.getAuditSendingApplication() :
appName);
config.getAuditSendingApplication() :
appName);
return auditMetadataProvider;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,88 @@ public class IpfAtnaConfigurationProperties {

@Getter @Setter
private String auditValueIfMissing = "UNKNOWN";

@Getter @Setter
private Balp balp;

public static class Balp {

/**
* Sets the context-path of the BALP audit record repository.
*/
@Getter
@Setter
private String auditRepositoryContextPath = "";

@Getter
@Setter
private String auditEventSerializationType = "json";

@Getter
@Setter
private OAuth oauth;

public static class OAuth {

@Getter
@Setter
private String[] idPath;

@Getter
@Setter
private String[] issuerPath;

@Getter
@Setter
private String[] clientIdPath;

@Getter
@Setter
private String[] subjectPath;

@Getter
@Setter
private String[] subjectNamePath;

@Getter
@Setter
private String[] subjectOrganizationPath;

@Getter
@Setter
private String[] subjectOrganizationIdPath;

@Getter
@Setter
private String[] subjectRolePath;

@Getter
@Setter
private String[] purposeOfUsePath;

@Getter
@Setter
private String[] homeCommunityIdPath;

@Getter
@Setter
private String[] nationalProviderIdPath;

@Getter
@Setter
private String[] personIdPath;

@Getter
@Setter
private String[] patientIdPath;

@Getter
@Setter
private String[] docIdPath;

@Getter
@Setter
private String[] acpPath;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2017 the original author or authors.
*
* 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 org.openehealth.ipf.boot.atna;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openehealth.ipf.commons.audit.AuditContext;
import org.openehealth.ipf.commons.audit.BalpAuditContext;
import org.openehealth.ipf.commons.audit.queue.AsynchronousAuditMessageQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;


/**
*
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = { TestApplication.class })
@ActiveProfiles("balp")
public class IpfAtnaBalpAutoConfigurationTest {

@Autowired
private AuditContext auditContext;

@Test
public void testAtnaWithBalpSettings() throws Exception {
assertTrue(auditContext instanceof BalpAuditContext);

assertEquals("atna-test", auditContext.getAuditSourceId());
assertEquals("mysite", auditContext.getAuditEnterpriseSiteId());
assertEquals("localhost", auditContext.getAuditRepositoryHostName());
assertEquals(1342, auditContext.getAuditRepositoryPort());
assertEquals("FHIR-REST-TLS", auditContext.getAuditTransmissionProtocol().getTransportName());
assertTrue(auditContext.getAuditMessageQueue() instanceof AsynchronousAuditMessageQueue);

assertEquals("fhir", ((BalpAuditContext)auditContext).getAuditRepositoryContextPath());
assertArrayEquals(new String[]{"cid","client-id","my-client-id-path"},
((BalpAuditContext) auditContext).getBalpJwtExtractorProperties().getClientIdPath());
assertArrayEquals(new String[]{},
((BalpAuditContext) auditContext).getBalpJwtExtractorProperties().getIdPath());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ipf:
atna:
audit-repository-transport: FHIR-REST-TLS
balp:
audit-repository-context-path: fhir
oauth:
clientIdPath: cid,client-id,my-client-id-path
idPath:
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ ipf:
audit-enterprise-site-id: mysite
audit-queue-class: org.openehealth.ipf.commons.audit.queue.AsynchronousAuditMessageQueue
security-domain-name: mydomain

4 changes: 4 additions & 0 deletions commons/audit/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
<artifactId>jakarta.jms-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ default SerializationStrategy getSerializationStrategy() {
default void audit(AuditMessage... messages) {
if (isAuditEnabled() && messages != null) {
getAuditMessageQueue().audit(this, Stream.of(messages)
.map(getAuditMessagePostProcessor())
.toArray(AuditMessage[]::new));
.map(getAuditMessagePostProcessor())
.toArray(AuditMessage[]::new));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2024 the original author or authors.
*
* 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 org.openehealth.ipf.commons.audit;

/**
* @author Boris Stanojevic
* @since 4.8
*/
public interface BalpAuditContext extends AuditContext {

String getAuditRepositoryContextPath();

BalpJwtExtractorProperties getBalpJwtExtractorProperties();
}
Loading

0 comments on commit a8bbb28

Please sign in to comment.