View Javadoc
1   /*
2    * Copyright 2018 the original author or authors.
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package org.openehealth.ipf.platform.camel.ihe.fhir.iti68;
18  
19  import org.apache.camel.Exchange;
20  import org.openehealth.ipf.commons.audit.AuditContext;
21  import org.openehealth.ipf.commons.audit.codes.EventOutcomeIndicator;
22  import org.openehealth.ipf.commons.ihe.core.atna.AuditStrategy;
23  import org.openehealth.ipf.commons.ihe.fhir.iti68.Iti68AuditDataset;
24  import org.openehealth.ipf.platform.camel.ihe.atna.interceptor.AuditInterceptor;
25  import org.openehealth.ipf.platform.camel.ihe.core.InterceptorSupport;
26  import org.openehealth.ipf.platform.camel.ihe.fhir.core.intercept.consumer.AuditInterceptorUtils;
27  import org.slf4j.Logger;
28  import org.slf4j.LoggerFactory;
29  
30  import javax.servlet.http.HttpServletRequest;
31  
32  /**
33   * Audit Interceptor for ITI-68. Note that the ParticipantObjectIdentificationType for the document
34   * is not populated automatically, because the location of the parametzers depends upon the actual
35   * implementation. The AuditDataset is forwarded in the Camel message header "AuditDataset" so that
36   * at least {@link Iti68AuditDataset#documentUniqueId} can be set.
37   *
38   * @author Christian Ohr
39   * @since 3.5
40   */
41  class Iti68ConsumerAuditInterceptor
42          extends InterceptorSupport<Iti68Endpoint>
43          implements AuditInterceptor<Iti68AuditDataset, Iti68Endpoint> {
44  
45      private static final Logger LOG = LoggerFactory.getLogger(Iti68ConsumerAuditInterceptor.class);
46  
47      private final AuditContext auditContext;
48  
49      Iti68ConsumerAuditInterceptor(AuditContext auditContext) {
50          this.auditContext = auditContext;
51      }
52  
53      @Override
54      public AuditStrategy<Iti68AuditDataset> getAuditStrategy() {
55          return getEndpoint().getServerAuditStrategy();
56      }
57  
58      @Override
59      public void determineParticipantsAddresses(Exchange exchange, Iti68AuditDataset auditDataset) {
60      }
61  
62      @Override
63      public void process(Exchange exchange) throws Exception {
64          Iti68AuditDataset auditDataset = createAndEnrichAuditDatasetFromRequest(getAuditStrategy(), exchange, exchange.getIn().getBody());
65          determineParticipantsAddresses(exchange, auditDataset);
66  
67          // Add audit dataset to the exchange headers so that a processing route could add things like
68          // document id, repository id etc. This is because this information may be present (in case of
69          // FHIR/XDS bridges) in the request URI, but there is no definition HOW.
70          exchange.getIn().setHeader(AUDIT_DATASET_HEADER, auditDataset);
71  
72          boolean failed = false;
73          try {
74              getWrappedProcessor().process(exchange);
75              failed = exchange.isFailed();
76              // Do not check the body, because it's a stream
77          } catch (Exception e) {
78              if (auditDataset != null) {
79                  auditDataset.setEventOutcomeDescription(e.getMessage());
80              }
81              throw e;
82          } finally {
83              if (auditDataset != null) {
84                  auditDataset.setEventOutcomeIndicator(failed ?
85                          EventOutcomeIndicator.MajorFailure :
86                          EventOutcomeIndicator.Success);
87                  getAuditStrategy().doAudit(auditContext, auditDataset);
88              }
89          }
90      }
91  
92      /**
93       * Creates a new audit dataset and enriches it with data from the request
94       * message.  All exception are ignored.
95       *
96       * @return newly created audit dataset or <code>null</code> when creation failed.
97       */
98      private Iti68AuditDataset createAndEnrichAuditDatasetFromRequest(AuditStrategy<Iti68AuditDataset> strategy, Exchange exchange, Object msg) {
99          try {
100             Iti68AuditDataset auditDataset = strategy.createAuditDataset();
101 
102             HttpServletRequest request = exchange.getIn().getHeader(Exchange.HTTP_SERVLET_REQUEST, HttpServletRequest.class);
103             auditDataset.setSourceUserId("unknown");
104             auditDataset.setDestinationUserId(request.getRequestURL().toString());
105             auditDataset.setRemoteAddress(request.getRemoteAddr());
106 
107             // TODO Also extract basic auth user?
108             AuditInterceptorUtils.extractClientCertificateCommonName(exchange, auditDataset);
109 
110             return strategy.enrichAuditDatasetFromRequest(auditDataset, msg, exchange.getIn().getHeaders());
111         } catch (Exception e) {
112             LOG.error("Exception when enriching audit dataset from request", e);
113             return null;
114         }
115     }
116 
117 }