Skip to content

Commit

Permalink
#424: improve audit trail
Browse files Browse the repository at this point in the history
  • Loading branch information
unixoid committed Nov 27, 2023
1 parent ff42542 commit 4220eff
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 136 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.openehealth.ipf.commons.ihe.xacml20;

import org.apache.commons.lang3.StringUtils;
import org.herasaf.xacml.core.context.impl.AttributeType;
import org.herasaf.xacml.core.context.impl.RequestType;
import org.herasaf.xacml.core.policy.Evaluatable;
import org.herasaf.xacml.core.policy.impl.IdReferenceType;
Expand All @@ -25,10 +26,12 @@
import org.openehealth.ipf.commons.ihe.xacml20.herasaf.Hl7v3FunctionsInitializer;
import org.openehealth.ipf.commons.ihe.xacml20.herasaf.types.IiDataTypeAttribute;
import org.openehealth.ipf.commons.ihe.xacml20.stub.ehealthswiss.*;
import org.openehealth.ipf.commons.ihe.xacml20.stub.hl7v3.CV;
import org.openehealth.ipf.commons.ihe.xacml20.stub.hl7v3.II;
import org.openehealth.ipf.commons.ihe.xacml20.stub.saml20.assertion.AssertionType;
import org.openehealth.ipf.commons.ihe.xacml20.stub.saml20.protocol.ResponseType;
import org.openehealth.ipf.commons.ihe.xacml20.stub.xacml20.saml.assertion.XACMLPolicyStatementType;
import org.openehealth.ipf.commons.ihe.xacml20.stub.xacml20.saml.protocol.XACMLAuthzDecisionQueryType;
import org.openehealth.ipf.commons.ihe.xacml20.stub.xacml20.saml.protocol.XACMLPolicyQueryType;

import javax.xml.bind.JAXBContext;
Expand Down Expand Up @@ -206,4 +209,37 @@ public static Optional<IdReferenceType> extractPolicyId(XACMLPolicyQueryType req
return Optional.empty();
}

public static RequestType extractAuthzRequest(XACMLAuthzDecisionQueryType query) {
for (JAXBElement<?> jaxbElement : query.getRest()) {
if (jaxbElement.getValue() instanceof RequestType) {
return (RequestType) jaxbElement.getValue();
}
}
throw new IllegalArgumentException("Could not extract authorization request");
}

public static String extractStringAttributeValue(AttributeType attribute) {
try {
return (String) attribute.getAttributeValues().get(0).getContent().get(0);
} catch (Exception e) {
return null;
}
}

public static CV extractCodeAttributeValue(AttributeType attribute) {
try {
for (Object o : attribute.getAttributeValues().get(0).getContent()) {
if (o instanceof JAXBElement) {
var value = ((JAXBElement<?>) o).getValue();
if (value instanceof CV) {
return (CV) value;
}
}
}
} catch (Exception e) {
// nop
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import org.openehealth.ipf.commons.audit.types.ParticipantObjectIdType;
import org.openehealth.ipf.commons.ihe.ws.cxf.audit.WsAuditDataset;

import java.util.HashMap;
import java.util.Map;

/**
* @author Dmytro Rud
* @since 4.8.0
Expand All @@ -30,11 +33,12 @@ public class ChAdrAuditDataset extends WsAuditDataset {
private static final String UNKNOWN = "[unknown]";

@Getter @Setter private String subjectId = UNKNOWN;
@Getter @Setter private String resourceId = UNKNOWN;
@Getter @Setter private String decision = UNKNOWN;
@Getter @Setter private ParticipantObjectTypeCodeRole objectRole;
@Getter @Setter private ParticipantObjectIdType subjectRole = ParticipantObjectIdType.of(UNKNOWN, UNKNOWN, UNKNOWN);

// map from resource ID to decision
@Getter @Setter private Map<String, String> decisionsByResourceIds = new HashMap<>();

public ChAdrAuditDataset(boolean serverSide) {
super(serverSide);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@

import lombok.extern.slf4j.Slf4j;
import org.herasaf.xacml.core.context.impl.AttributeType;
import org.herasaf.xacml.core.context.impl.ResourceType;
import org.herasaf.xacml.core.context.impl.ResultType;
import org.openehealth.ipf.commons.audit.AuditContext;
import org.openehealth.ipf.commons.audit.codes.EventOutcomeIndicator;
import org.openehealth.ipf.commons.audit.codes.ParticipantObjectTypeCode;
import org.openehealth.ipf.commons.audit.codes.ParticipantObjectTypeCodeRole;
import org.openehealth.ipf.commons.audit.model.AuditMessage;
import org.openehealth.ipf.commons.audit.model.TypeValuePairType;
import org.openehealth.ipf.commons.audit.types.ParticipantObjectIdType;
import org.openehealth.ipf.commons.ihe.core.atna.AuditStrategySupport;
import org.openehealth.ipf.commons.ihe.core.atna.event.QueryInformationBuilder;
import org.openehealth.ipf.commons.ihe.xacml20.Xacml20AuditUtils;
import org.openehealth.ipf.commons.ihe.xacml20.Xacml20Status;
import org.openehealth.ipf.commons.ihe.xacml20.Xacml20Utils;
import org.openehealth.ipf.commons.ihe.xacml20.audit.codes.Xacml20EventTypeCodes;
import org.openehealth.ipf.commons.ihe.xacml20.audit.codes.Xacml20ParticipantIdType;
import org.openehealth.ipf.commons.ihe.xacml20.model.PpqConstants;
Expand All @@ -36,9 +39,7 @@
import org.openehealth.ipf.commons.ihe.xacml20.stub.xacml20.saml.protocol.XACMLAuthzDecisionQueryType;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author Dmytro Rud
Expand All @@ -59,48 +60,58 @@ public ChAdrAuditDataset createAuditDataset() {
@Override
public AuditMessage[] makeAuditMessage(AuditContext auditContext, ChAdrAuditDataset auditDataset) {
var builder = new QueryInformationBuilder<>(auditContext, auditDataset, Xacml20EventTypeCodes.AuthorizationDecisionsQueryAdr, auditDataset.getPurposesOfUse());
return builder
.setQueryParameters(
builder.setQueryParameters(
auditDataset.getSubjectId(),
auditDataset.getSubjectRole(),
null,
ParticipantObjectTypeCode.Person,
ParticipantObjectTypeCodeRole.SecurityUserEntity,
Collections.emptyList())
.setQueryParameters(
auditDataset.getResourceId(),
Collections.emptyList());

for (Map.Entry<String, String> entry : auditDataset.getDecisionsByResourceIds().entrySet()) {
builder.setQueryParameters(
entry.getKey(),
Xacml20ParticipantIdType.AuthorizationDecisionsQueryAdr,
null,
ParticipantObjectTypeCode.System,
auditDataset.getObjectRole(),
(auditDataset.getDecision() != null)
? Collections.singletonList(new TypeValuePairType("decision", auditDataset.getDecision()))
: Collections.emptyList())
.getMessages();
(entry.getValue() != null)
? Collections.singletonList(new TypeValuePairType("decision", entry.getValue()))
: Collections.emptyList());
}

return builder.getMessages();
}

@Override
public ChAdrAuditDataset enrichAuditDatasetFromRequest(ChAdrAuditDataset auditDataset, Object requestObject, Map<String, Object> parameters) {
var query = (XACMLAuthzDecisionQueryType) requestObject;
for (AttributeType attribute : Xacml20AuditUtils.extractSubjectAttributes(query)) {
var authzRequest = Xacml20Utils.extractAuthzRequest(query);
for (AttributeType attribute : authzRequest.getSubjects().get(0).getAttributes()) {
switch (attribute.getAttributeId()) {
case PpqConstants.AttributeIds.XACML_1_0_SUBJECT_ID:
auditDataset.setSubjectId(Xacml20AuditUtils.extractStringAttributeValue(attribute));
auditDataset.setSubjectId(Xacml20Utils.extractStringAttributeValue(attribute));
break;
case PpqConstants.AttributeIds.XACML_2_0_SUBJECT_ROLE:
auditDataset.setSubjectRole(Xacml20AuditUtils.extractCodeAttributeValue(attribute));
var cv = Xacml20Utils.extractCodeAttributeValue(attribute);
if (cv != null) {
auditDataset.setSubjectRole(ParticipantObjectIdType.of(cv.getCode(), cv.getCodeSystem(), cv.getDisplayName()));
}
break;
}
}
for (AttributeType attribute : Xacml20AuditUtils.extractResourceAttributes(query)) {
if (PpqConstants.AttributeIds.XACML_1_0_RESOURCE_ID.equals(attribute.getAttributeId())) {
auditDataset.setResourceId(Xacml20AuditUtils.extractStringAttributeValue(attribute));
break;
for (ResourceType resource : authzRequest.getResources()) {
for (AttributeType attribute : resource.getAttributes()) {
if (PpqConstants.AttributeIds.XACML_1_0_RESOURCE_ID.equals(attribute.getAttributeId())) {
String resourceId = Xacml20Utils.extractStringAttributeValue(attribute);
auditDataset.getDecisionsByResourceIds().put(resourceId, null);
break;
}
}
}
for (AttributeType attribute : Xacml20AuditUtils.extractActionAttributes(query)) {
for (AttributeType attribute : authzRequest.getAction().getAttributes()) {
if (PpqConstants.AttributeIds.XACML_1_0_ACTION_ID.equals(attribute.getAttributeId())) {
String action = Xacml20AuditUtils.extractStringAttributeValue(attribute);
String action = Xacml20Utils.extractStringAttributeValue(attribute);
if (action != null) {
switch (action) {
case PpqConstants.ActionIds.ITI_18:
Expand Down Expand Up @@ -135,15 +146,8 @@ public boolean enrichAuditDatasetFromResponse(ChAdrAuditDataset auditDataset, Ob
auditDataset.setEventOutcomeIndicator(EventOutcomeIndicator.Success);
var assertion = (AssertionType) response.getAssertionOrEncryptedAssertion().get(0);
var statement = (XACMLAuthzDecisionStatementType) assertion.getStatementOrAuthnStatementOrAuthzDecisionStatement().get(0);
var decisions = statement.getResponse().getResults().stream()
.map(result -> result.getDecision().value())
.collect(Collectors.toSet());
// the order matters, the first one who is present wins
for (String decision : List.of("Deny", "Permit", "NotApplicable", "Indeterminate")) {
if (decisions.contains(decision)) {
auditDataset.setDecision(decision);
break;
}
for (ResultType result : statement.getResponse().getResults()) {
auditDataset.getDecisionsByResourceIds().put(result.getResourceId(), result.getDecision().value());
}
} else {
auditDataset.setEventOutcomeIndicator(EventOutcomeIndicator.SeriousFailure);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import org.openehealth.ipf.commons.audit.model.AuditMessage;
import org.openehealth.ipf.commons.ihe.core.atna.AuditStrategySupport;
import org.openehealth.ipf.commons.ihe.core.atna.event.QueryInformationBuilder;
import org.openehealth.ipf.commons.ihe.xacml20.Xacml20AuditUtils;
import org.openehealth.ipf.commons.ihe.xacml20.Xacml20Status;
import org.openehealth.ipf.commons.ihe.xacml20.Xacml20Utils;
import org.openehealth.ipf.commons.ihe.xacml20.audit.codes.Xacml20EventTypeCodes;
import org.openehealth.ipf.commons.ihe.xacml20.audit.codes.Xacml20ParticipantIdType;
import org.openehealth.ipf.commons.ihe.xacml20.model.PpqConstants;
Expand Down Expand Up @@ -77,9 +77,10 @@ public AuditMessage[] makeAuditMessage(AuditContext auditContext, Iti79AuditData
@Override
public Iti79AuditDataset enrichAuditDatasetFromRequest(Iti79AuditDataset auditDataset, Object requestObject, Map<String, Object> parameters) {
var query = (XACMLAuthzDecisionQueryType) requestObject;
for (AttributeType attribute : Xacml20AuditUtils.extractSubjectAttributes(query)) {
var request = Xacml20Utils.extractAuthzRequest(query);
for (AttributeType attribute : request.getSubjects().get(0).getAttributes()) {
if (PpqConstants.AttributeIds.XACML_1_0_SUBJECT_ID.equals(attribute.getAttributeId())) {
auditDataset.setRequesterId(Xacml20AuditUtils.extractStringAttributeValue(attribute));
auditDataset.setRequesterId(Xacml20Utils.extractStringAttributeValue(attribute));
}
}
auditDataset.setQueryId(query.getID());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,24 @@
<ns3:Statement xsi:type="ns9:XACMLAuthzDecisionStatementType"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Response>
<Result ResourceId="urn:uuid:a928a3d3-bf47-4d29-9526-b1fe886c0184">
<Result ResourceId="urn:uuid:5a478b92-0b20-40a9-9bee-30ce7d831ca2">
<Decision>Permit</Decision>
<Status>
<StatusCode Value="urn:oasis:names:tc:xacml:1.0:status:ok"/>
</Status>
</Result>
<Result ResourceId="urn:uuid:a43e8041-5afd-40bf-9c7c-9d9fc6f8c1a8">
<Decision>Permit</Decision>
<Status>
<StatusCode Value="urn:oasis:names:tc:xacml:1.0:status:ok"/>
</Status>
</Result>
<Result ResourceId="urn:uuid:1d78d91d-73c9-49b7-94f5-76b2a44e1c9c">
<Decision>NotApplicable</Decision>
<Status>
<StatusCode Value="urn:oasis:names:tc:xacml:1.0:status:ok"/>
</Status>
</Result>
</Response>
</ns3:Statement>
</ns3:Assertion>
Expand Down
Loading

0 comments on commit 4220eff

Please sign in to comment.