Mercurial > hg > orthanc
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.cpp Fri Apr 14 11:49:24 2023 +0200 @@ -0,0 +1,209 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#include "DicomFilter.h" + +#include "PluginToolbox.h" + +#include "../../../../OrthancFramework/Sources/Logging.h" +#include "../../../../OrthancFramework/Sources/OrthancException.h" + +#include "../Common/OrthancPluginCppWrapper.h" + + +DicomFilter::DicomFilter() : + hasAcceptedTransferSyntaxes_(false) +{ + { + OrthancPlugins::OrthancConfiguration config; + alwaysAllowEcho_ = config.GetBooleanValue("DicomAlwaysAllowEcho", true); + alwaysAllowFind_ = config.GetBooleanValue("DicomAlwaysAllowFind", false); + alwaysAllowMove_ = config.GetBooleanValue("DicomAlwaysAllowMove", false); + alwaysAllowStore_ = config.GetBooleanValue("DicomAlwaysAllowStore", true); + unknownSopClassAccepted_ = config.GetBooleanValue("UnknownSopClassAccepted", false); + isStrict_ = config.GetBooleanValue("StrictAetComparison", false); + checkModalityHost_ = config.GetBooleanValue("DicomCheckModalityHost", false); + } +} + + +bool DicomFilter::IsAllowedConnection(const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) +{ + boost::shared_lock<boost::shared_mutex> lock(mutex_); + + LOG(INFO) << "Incoming connection from AET " << remoteAet + << " on IP " << remoteIp << ", calling AET " << calledAet; + + if (alwaysAllowEcho_ || + alwaysAllowFind_ || + alwaysAllowMove_ || + alwaysAllowStore_) + { + return true; + } + else + { + std::string name; + Orthanc::RemoteModalityParameters parameters; + + if (!PluginToolbox::LookupAETitle(name, parameters, isStrict_, remoteAet)) + { + LOG(WARNING) << "Modality \"" << remoteAet + << "\" is not listed in the \"DicomModalities\" configuration option"; + return false; + } + else if (!checkModalityHost_ || + remoteIp == parameters.GetHost()) + { + return true; + } + else + { + LOG(WARNING) << "Forbidding access from AET \"" << remoteAet + << "\" given its hostname (" << remoteIp << ") does not match " + << "the \"DicomModalities\" configuration option (" + << parameters.GetHost() << " was expected)"; + return false; + } + } +} + + +bool DicomFilter::IsAllowedRequest(const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet, + Orthanc::DicomRequestType type) +{ + boost::shared_lock<boost::shared_mutex> lock(mutex_); + + LOG(INFO) << "Incoming " << EnumerationToString(type) << " request from AET " + << remoteAet << " on IP " << remoteIp << ", calling AET " << calledAet; + + if (type == Orthanc::DicomRequestType_Echo && + alwaysAllowEcho_) + { + // Incoming C-Echo requests are always accepted, even from unknown AET + return true; + } + else if (type == Orthanc::DicomRequestType_Find && + alwaysAllowFind_) + { + // Incoming C-Find requests are always accepted, even from unknown AET + return true; + } + else if (type == Orthanc::DicomRequestType_Store && + alwaysAllowStore_) + { + // Incoming C-Store requests are always accepted, even from unknown AET + return true; + } + else if (type == Orthanc::DicomRequestType_Move && + alwaysAllowMove_) + { + // Incoming C-Move requests are always accepted, even from unknown AET + return true; + } + else + { + std::string name; + Orthanc::RemoteModalityParameters parameters; + + if (!PluginToolbox::LookupAETitle(name, parameters, isStrict_, remoteAet)) + { + LOG(WARNING) << "DICOM authorization rejected for AET " << remoteAet + << " on IP " << remoteIp << ": This AET is not listed in " + << "configuration option \"DicomModalities\""; + return false; + } + else + { + if (parameters.IsRequestAllowed(type)) + { + return true; + } + else + { + LOG(WARNING) << "DICOM authorization rejected for AET " << remoteAet + << " on IP " << remoteIp << ": The DICOM command " + << EnumerationToString(type) << " is not allowed for this modality " + << "according to configuration option \"DicomModalities\""; + return false; + } + } + } +} + + +void DicomFilter::GetAcceptedTransferSyntaxes(std::set<Orthanc::DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) +{ + boost::unique_lock<boost::shared_mutex> lock(mutex_); + + if (!hasAcceptedTransferSyntaxes_) + { + Json::Value syntaxes; + + if (!OrthancPlugins::RestApiGet(syntaxes, "/tools/accepted-transfer-syntaxes", false) || + syntaxes.type() != Json::arrayValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else + { + for (Json::Value::ArrayIndex i = 0; i < syntaxes.size(); i++) + { + Orthanc::DicomTransferSyntax syntax; + + if (syntaxes[i].type() != Json::stringValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else if (Orthanc::LookupTransferSyntax(syntax, syntaxes[i].asString())) + { + acceptedTransferSyntaxes_.insert(syntax); + } + else + { + LOG(WARNING) << "Unknown transfer syntax: " << syntaxes[i].asString(); + } + } + } + + hasAcceptedTransferSyntaxes_ = true; + } + + target = acceptedTransferSyntaxes_; +} + + +bool DicomFilter::IsUnknownSopClassAccepted(const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) +{ + boost::shared_lock<boost::shared_mutex> lock(mutex_); + return unknownSopClassAccepted_; +}