Mercurial > hg > orthanc
comparison OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.cpp @ 5273:7cb1b851f5c8
Added a sample plugin bringing multitenant DICOM support through labels
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 14 Apr 2023 11:49:24 +0200 |
parents | |
children | a8385880902f |
comparison
equal
deleted
inserted
replaced
5272:a45e8b6115f6 | 5273:7cb1b851f5c8 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2023 Osimis S.A., Belgium | |
6 * Copyright (C) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium | |
7 * | |
8 * This program is free software: you can redistribute it and/or | |
9 * modify it under the terms of the GNU Lesser General Public License | |
10 * as published by the Free Software Foundation, either version 3 of | |
11 * the License, or (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, but | |
14 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Lesser General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Lesser General Public | |
19 * License along with this program. If not, see | |
20 * <http://www.gnu.org/licenses/>. | |
21 **/ | |
22 | |
23 | |
24 #include "DicomFilter.h" | |
25 | |
26 #include "PluginToolbox.h" | |
27 | |
28 #include "../../../../OrthancFramework/Sources/Logging.h" | |
29 #include "../../../../OrthancFramework/Sources/OrthancException.h" | |
30 | |
31 #include "../Common/OrthancPluginCppWrapper.h" | |
32 | |
33 | |
34 DicomFilter::DicomFilter() : | |
35 hasAcceptedTransferSyntaxes_(false) | |
36 { | |
37 { | |
38 OrthancPlugins::OrthancConfiguration config; | |
39 alwaysAllowEcho_ = config.GetBooleanValue("DicomAlwaysAllowEcho", true); | |
40 alwaysAllowFind_ = config.GetBooleanValue("DicomAlwaysAllowFind", false); | |
41 alwaysAllowMove_ = config.GetBooleanValue("DicomAlwaysAllowMove", false); | |
42 alwaysAllowStore_ = config.GetBooleanValue("DicomAlwaysAllowStore", true); | |
43 unknownSopClassAccepted_ = config.GetBooleanValue("UnknownSopClassAccepted", false); | |
44 isStrict_ = config.GetBooleanValue("StrictAetComparison", false); | |
45 checkModalityHost_ = config.GetBooleanValue("DicomCheckModalityHost", false); | |
46 } | |
47 } | |
48 | |
49 | |
50 bool DicomFilter::IsAllowedConnection(const std::string& remoteIp, | |
51 const std::string& remoteAet, | |
52 const std::string& calledAet) | |
53 { | |
54 boost::shared_lock<boost::shared_mutex> lock(mutex_); | |
55 | |
56 LOG(INFO) << "Incoming connection from AET " << remoteAet | |
57 << " on IP " << remoteIp << ", calling AET " << calledAet; | |
58 | |
59 if (alwaysAllowEcho_ || | |
60 alwaysAllowFind_ || | |
61 alwaysAllowMove_ || | |
62 alwaysAllowStore_) | |
63 { | |
64 return true; | |
65 } | |
66 else | |
67 { | |
68 std::string name; | |
69 Orthanc::RemoteModalityParameters parameters; | |
70 | |
71 if (!PluginToolbox::LookupAETitle(name, parameters, isStrict_, remoteAet)) | |
72 { | |
73 LOG(WARNING) << "Modality \"" << remoteAet | |
74 << "\" is not listed in the \"DicomModalities\" configuration option"; | |
75 return false; | |
76 } | |
77 else if (!checkModalityHost_ || | |
78 remoteIp == parameters.GetHost()) | |
79 { | |
80 return true; | |
81 } | |
82 else | |
83 { | |
84 LOG(WARNING) << "Forbidding access from AET \"" << remoteAet | |
85 << "\" given its hostname (" << remoteIp << ") does not match " | |
86 << "the \"DicomModalities\" configuration option (" | |
87 << parameters.GetHost() << " was expected)"; | |
88 return false; | |
89 } | |
90 } | |
91 } | |
92 | |
93 | |
94 bool DicomFilter::IsAllowedRequest(const std::string& remoteIp, | |
95 const std::string& remoteAet, | |
96 const std::string& calledAet, | |
97 Orthanc::DicomRequestType type) | |
98 { | |
99 boost::shared_lock<boost::shared_mutex> lock(mutex_); | |
100 | |
101 LOG(INFO) << "Incoming " << EnumerationToString(type) << " request from AET " | |
102 << remoteAet << " on IP " << remoteIp << ", calling AET " << calledAet; | |
103 | |
104 if (type == Orthanc::DicomRequestType_Echo && | |
105 alwaysAllowEcho_) | |
106 { | |
107 // Incoming C-Echo requests are always accepted, even from unknown AET | |
108 return true; | |
109 } | |
110 else if (type == Orthanc::DicomRequestType_Find && | |
111 alwaysAllowFind_) | |
112 { | |
113 // Incoming C-Find requests are always accepted, even from unknown AET | |
114 return true; | |
115 } | |
116 else if (type == Orthanc::DicomRequestType_Store && | |
117 alwaysAllowStore_) | |
118 { | |
119 // Incoming C-Store requests are always accepted, even from unknown AET | |
120 return true; | |
121 } | |
122 else if (type == Orthanc::DicomRequestType_Move && | |
123 alwaysAllowMove_) | |
124 { | |
125 // Incoming C-Move requests are always accepted, even from unknown AET | |
126 return true; | |
127 } | |
128 else | |
129 { | |
130 std::string name; | |
131 Orthanc::RemoteModalityParameters parameters; | |
132 | |
133 if (!PluginToolbox::LookupAETitle(name, parameters, isStrict_, remoteAet)) | |
134 { | |
135 LOG(WARNING) << "DICOM authorization rejected for AET " << remoteAet | |
136 << " on IP " << remoteIp << ": This AET is not listed in " | |
137 << "configuration option \"DicomModalities\""; | |
138 return false; | |
139 } | |
140 else | |
141 { | |
142 if (parameters.IsRequestAllowed(type)) | |
143 { | |
144 return true; | |
145 } | |
146 else | |
147 { | |
148 LOG(WARNING) << "DICOM authorization rejected for AET " << remoteAet | |
149 << " on IP " << remoteIp << ": The DICOM command " | |
150 << EnumerationToString(type) << " is not allowed for this modality " | |
151 << "according to configuration option \"DicomModalities\""; | |
152 return false; | |
153 } | |
154 } | |
155 } | |
156 } | |
157 | |
158 | |
159 void DicomFilter::GetAcceptedTransferSyntaxes(std::set<Orthanc::DicomTransferSyntax>& target, | |
160 const std::string& remoteIp, | |
161 const std::string& remoteAet, | |
162 const std::string& calledAet) | |
163 { | |
164 boost::unique_lock<boost::shared_mutex> lock(mutex_); | |
165 | |
166 if (!hasAcceptedTransferSyntaxes_) | |
167 { | |
168 Json::Value syntaxes; | |
169 | |
170 if (!OrthancPlugins::RestApiGet(syntaxes, "/tools/accepted-transfer-syntaxes", false) || | |
171 syntaxes.type() != Json::arrayValue) | |
172 { | |
173 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
174 } | |
175 else | |
176 { | |
177 for (Json::Value::ArrayIndex i = 0; i < syntaxes.size(); i++) | |
178 { | |
179 Orthanc::DicomTransferSyntax syntax; | |
180 | |
181 if (syntaxes[i].type() != Json::stringValue) | |
182 { | |
183 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
184 } | |
185 else if (Orthanc::LookupTransferSyntax(syntax, syntaxes[i].asString())) | |
186 { | |
187 acceptedTransferSyntaxes_.insert(syntax); | |
188 } | |
189 else | |
190 { | |
191 LOG(WARNING) << "Unknown transfer syntax: " << syntaxes[i].asString(); | |
192 } | |
193 } | |
194 } | |
195 | |
196 hasAcceptedTransferSyntaxes_ = true; | |
197 } | |
198 | |
199 target = acceptedTransferSyntaxes_; | |
200 } | |
201 | |
202 | |
203 bool DicomFilter::IsUnknownSopClassAccepted(const std::string& remoteIp, | |
204 const std::string& remoteAet, | |
205 const std::string& calledAet) | |
206 { | |
207 boost::shared_lock<boost::shared_mutex> lock(mutex_); | |
208 return unknownSopClassAccepted_; | |
209 } |