1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.openehealth.ipf.commons.ihe.ws.cxf.audit;
17
18 import lombok.Getter;
19 import lombok.Setter;
20 import org.apache.cxf.binding.soap.SoapMessage;
21 import org.apache.cxf.headers.Header;
22 import org.apache.cxf.message.Message;
23 import org.apache.cxf.security.transport.TLSSessionInfo;
24 import org.apache.cxf.transport.http.AbstractHTTPDestination;
25 import org.apache.cxf.ws.addressing.AddressingProperties;
26 import org.apache.cxf.ws.addressing.AttributedURIType;
27 import org.apache.cxf.ws.addressing.EndpointReferenceType;
28 import org.apache.cxf.ws.addressing.JAXWSAConstants;
29 import org.openehealth.ipf.commons.audit.AuditContext;
30 import org.openehealth.ipf.commons.core.config.Lookup;
31 import org.openehealth.ipf.commons.ihe.core.atna.AuditStrategy;
32 import org.openehealth.ipf.commons.ihe.ws.InterceptorUtils;
33 import org.openehealth.ipf.commons.ihe.ws.cxf.AbstractSafeInterceptor;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import javax.naming.ldap.LdapName;
38 import javax.naming.ldap.Rdn;
39 import javax.servlet.http.HttpServletRequest;
40 import java.security.Principal;
41 import java.security.cert.Certificate;
42 import java.security.cert.X509Certificate;
43 import java.util.List;
44
45 import static java.util.Objects.requireNonNull;
46
47
48
49
50
51
52 abstract public class AbstractAuditInterceptor<T extends WsAuditDataset> extends AbstractSafeInterceptor {
53
54 private static final transient Logger LOG = LoggerFactory.getLogger(AbstractAuditInterceptor.class);
55
56
57
58
59
60 public static final String DATASET_CONTEXT_KEY = AbstractAuditInterceptor.class.getName() + ".DATASET";
61
62
63
64
65 @Getter
66 @Setter
67 private static XuaProcessor xuaProcessor = Lookup.lookup(XuaProcessor.class).orElse(XuaProcessor.NOOP);
68
69
70
71
72 private final AuditStrategy<T> auditStrategy;
73
74 @Getter
75 private final AuditContext auditContext;
76
77
78
79
80
81
82
83
84 protected AbstractAuditInterceptor(String phase, AuditStrategy<T> auditStrategy, AuditContext auditContext) {
85 super(phase);
86 this.auditStrategy = requireNonNull(auditStrategy);
87 this.auditContext = requireNonNull(auditContext);
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102 protected T getAuditDataset(SoapMessage message) {
103 T auditDataset = InterceptorUtils.findContextualProperty(message, DATASET_CONTEXT_KEY);
104 if (auditDataset == null) {
105 auditDataset = getAuditStrategy().createAuditDataset();
106 if (auditDataset == null) {
107 LOG.warn("Cannot obtain audit dataset instance, NPE is pending");
108 return null;
109 }
110 message.getExchange().put(DATASET_CONTEXT_KEY, auditDataset);
111 }
112 return auditDataset;
113 }
114
115
116
117
118
119
120
121 protected AuditStrategy<T> getAuditStrategy() {
122 return auditStrategy;
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 protected static void extractUserIdFromWSAddressing(
140 SoapMessage message,
141 boolean isInbound,
142 boolean inverseWsaDirection,
143 WsAuditDataset auditDataset) {
144 AddressingProperties wsaProperties = (AddressingProperties) message.get(isInbound ?
145 JAXWSAConstants.ADDRESSING_PROPERTIES_INBOUND :
146 JAXWSAConstants.ADDRESSING_PROPERTIES_OUTBOUND);
147
148 if (wsaProperties != null) {
149 AttributedURIType address = null;
150 if (inverseWsaDirection) {
151 address = wsaProperties.getTo();
152 } else {
153 EndpointReferenceType replyTo = wsaProperties.getReplyTo();
154 if (replyTo != null) {
155 address = replyTo.getAddress();
156 }
157 }
158
159 if (address != null) {
160 auditDataset.setSourceUserId(address.getValue());
161 }
162 }
163 if (auditDataset.getSourceUserId() == null) {
164 LOG.info("Missing WS-Addressing headers");
165 auditDataset.setSourceUserId("unknown");
166 }
167 }
168
169
170
171
172
173
174
175
176
177
178 protected static void extractXuaUserNameFromSaml2Assertion(
179 SoapMessage message,
180 Header.Direction headerDirection,
181 WsAuditDataset auditDataset) {
182 xuaProcessor.extractXuaUserNameFromSaml2Assertion(message, headerDirection, auditDataset);
183 }
184
185
186
187
188
189 protected static void extractAddressesFromServletRequest(
190 SoapMessage message,
191 WsAuditDataset auditDataset) {
192 HttpServletRequest request =
193 (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
194 auditDataset.setRemoteAddress(request.getRemoteAddr());
195 auditDataset.setLocalAddress(request.getRequestURL().toString());
196 auditDataset.setDestinationUserId(request.getRequestURL().toString());
197 }
198
199
200
201
202 protected static void extractClientCertificateCommonName(
203 SoapMessage message,
204 WsAuditDataset auditDataset) {
205 TLSSessionInfo request = message.get(TLSSessionInfo.class);
206 if (request != null) {
207 Certificate[] certificates = request.getPeerCertificates();
208 if (certificates != null && certificates.length > 0) {
209 try {
210 X509Certificate certificate = (X509Certificate) certificates[0];
211 Principal principal = certificate.getSubjectDN();
212 String dn = principal.getName();
213 LdapName ldapDN = new LdapName(dn);
214 for (Rdn rdn : ldapDN.getRdns()) {
215 if (rdn.getType().equalsIgnoreCase("CN")) {
216 auditDataset.setSourceUserName((String) rdn.getValue());
217 break;
218 }
219 }
220 } catch (Exception e) {
221 LOG.info("Could not extract CN from client certificate", e);
222 }
223 }
224 }
225 }
226
227
228
229
230
231
232 protected static Object extractPojo(Message message) {
233 List<?> list = message.getContent(List.class);
234 return ((list == null) || list.isEmpty()) ? null : list.get(0);
235 }
236 }