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 }