Mercurial > hg > orthanc-authorization
annotate Plugin/PermissionParser.cpp @ 196:55760c465c3a
Fix wrong access to POST /instances that was considered as a resource list
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Mon, 24 Jun 2024 18:28:16 +0200 |
parents | 2f1e872e8eaa |
children |
rev | line source |
---|---|
71 | 1 /** |
2 * Advanced authorization plugin for Orthanc | |
3 * Copyright (C) 2017-2023 Osimis S.A., Belgium | |
150 | 4 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium |
188
c4b908970ae4
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
150
diff
changeset
|
5 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
71 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 #include "PermissionParser.h" | |
22 | |
23 #include <Toolbox.h> | |
24 #include <OrthancException.h> | |
25 #include <Logging.h> | |
26 | |
27 namespace OrthancPlugins | |
28 { | |
191 | 29 PermissionPattern::PermissionPattern(const OrthancPluginHttpMethod& method, |
30 const std::string& patternRegex, | |
31 const std::string& permissions) : | |
32 method_(method), | |
33 pattern_(patternRegex) | |
71 | 34 { |
74 | 35 if (!permissions.empty()) |
36 { | |
37 std::vector<std::string> permissionsVector; | |
38 Orthanc::Toolbox::TokenizeString(permissionsVector, permissions, '|'); | |
71 | 39 |
74 | 40 for (size_t i = 0; i < permissionsVector.size(); ++i) |
41 { | |
191 | 42 permissions_.insert(permissionsVector[i]); |
74 | 43 } |
71 | 44 } |
45 } | |
46 | |
47 | |
48 static void Replace(std::string& text, const std::string& findText, const std::string& replaceText) | |
49 { | |
50 size_t pos = text.find(findText); | |
51 if (pos != std::string::npos) | |
52 { | |
53 text = text.replace(pos, findText.size(), replaceText); | |
54 } | |
55 } | |
56 | |
57 | |
58 static void StripLeadingAndTrailingSlashes(std::string& text) | |
59 { | |
60 if (text.size() > 1 && text[0] == '/') | |
61 { | |
62 text = text.substr(1, text.size() -1); | |
63 } | |
64 if (text.size() > 1 && text[text.size() - 1] == '/') | |
65 { | |
66 text = text.substr(0, text.size() -1); | |
67 } | |
68 } | |
69 | |
70 | |
71 PermissionParser::PermissionParser(const std::string& dicomWebRoot, const std::string& oe2Root) : | |
72 dicomWebRoot_(dicomWebRoot), | |
73 oe2Root_(oe2Root) | |
74 { | |
75 } | |
76 | |
191 | 77 PermissionParser::~PermissionParser() |
78 { | |
79 for (std::list<PermissionPattern*>::iterator it = permissionsPattern_.begin(); | |
80 it != permissionsPattern_.begin(); ++it) | |
81 { | |
82 assert(*it != NULL); | |
83 delete *it; | |
84 } | |
85 } | |
86 | |
149
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
87 void PermissionParser::Add(const Json::Value& configuration, const IAuthorizationParser* authorizationParser) |
71 | 88 { |
89 if (configuration.type() != Json::arrayValue) | |
90 { | |
91 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType, "Permissions should be an array."); | |
92 } | |
93 | |
94 for (Json::ArrayIndex i = 0; i < configuration.size(); ++i) | |
95 { | |
96 const Json::Value& permission = configuration[i]; | |
97 if (permission.type() != Json::arrayValue || permission.size() < 3) | |
98 { | |
99 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType, "Permissions elements should be an array of min size 3."); | |
100 } | |
101 | |
149
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
102 if (permission[1].asString() == "SINGLE_RESOURCE_PATTERNS") |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
103 { |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
104 std::vector<boost::regex> singleResourcePatterns; |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
105 authorizationParser->GetSingleResourcePatterns(singleResourcePatterns); |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
106 |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
107 for (std::vector<boost::regex>::const_iterator it = singleResourcePatterns.begin(); it != singleResourcePatterns.end(); ++it) |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
108 { |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
109 Add(permission[0].asString(), // 0 = HTTP method |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
110 it->str(), // 1 = pattern |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
111 permission[2].asString() // 2 = list of | separated permissions (no space) |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
112 // 3 = optional comment |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
113 ); |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
114 } |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
115 } |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
116 else |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
117 { |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
118 Add(permission[0].asString(), // 0 = HTTP method |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
119 permission[1].asString(), // 1 = pattern |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
120 permission[2].asString() // 2 = list of | separated permissions (no space) |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
121 // 3 = optional comment |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
122 ); |
423531fb1200
SINGLE_RESOURCE_PATTERNS to facilitate api-key support
Alain Mazy <am@osimis.io>
parents:
74
diff
changeset
|
123 } |
71 | 124 } |
125 | |
126 } | |
127 | |
128 void PermissionParser::Add(const std::string& method, | |
129 const std::string& patternRegex, | |
130 const std::string& permission) | |
131 { | |
132 std::string lowerCaseMethod; | |
133 Orthanc::Toolbox::ToLowerCase(lowerCaseMethod, method); | |
134 OrthancPluginHttpMethod parsedMethod = OrthancPluginHttpMethod_Get; | |
135 | |
136 if (lowerCaseMethod == "post") | |
137 { | |
138 parsedMethod = OrthancPluginHttpMethod_Post; | |
139 } | |
140 else if (lowerCaseMethod == "put") | |
141 { | |
142 parsedMethod = OrthancPluginHttpMethod_Put; | |
143 } | |
144 else if (lowerCaseMethod == "delete") | |
145 { | |
146 parsedMethod = OrthancPluginHttpMethod_Delete; | |
147 } | |
148 else if (lowerCaseMethod == "get") | |
149 { | |
150 parsedMethod = OrthancPluginHttpMethod_Get; | |
151 } | |
152 else | |
153 { | |
154 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, std::string("Invalid HTTP method ") + method); | |
155 } | |
156 | |
157 std::string regex = patternRegex; | |
158 std::string strippedDicomWebRoot = dicomWebRoot_; | |
159 | |
160 StripLeadingAndTrailingSlashes(strippedDicomWebRoot); | |
161 Replace(regex, "DICOM_WEB_ROOT", strippedDicomWebRoot); | |
162 | |
163 LOG(WARNING) << "Authorization plugin: adding a new permission pattern: " << lowerCaseMethod << " " << regex << " - " << permission; | |
164 | |
191 | 165 permissionsPattern_.push_back(new PermissionPattern(parsedMethod, regex, permission)); |
194
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
166 |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
167 { // extract individual permissions |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
168 std::set<std::string> permissions; |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
169 Orthanc::Toolbox::SplitString(permissions, permission, '|'); |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
170 |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
171 for (std::set<std::string>::const_iterator it = permissions.begin(); it != permissions.end(); ++it) |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
172 { |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
173 if (!it->empty()) |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
174 { |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
175 permissionsList_.insert(*it); |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
176 } |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
177 } |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
178 |
85859ec3aa7e
added support for roles/permissions edition
Alain Mazy <am@orthanc.team>
parents:
188
diff
changeset
|
179 } |
71 | 180 } |
181 | |
182 bool PermissionParser::Parse(std::set<std::string>& permissions, | |
183 std::string& matchedPattern, | |
184 const OrthancPluginHttpMethod& method, | |
185 const std::string& uri) const | |
186 { | |
187 // The mutex below should not be necessary, but we prefer to | |
188 // ensure thread safety in boost::regex | |
189 boost::mutex::scoped_lock lock(mutex_); | |
190 | |
191 | |
191 | 192 for (std::list<PermissionPattern*>::const_iterator it = permissionsPattern_.begin(); |
193 it != permissionsPattern_.end(); ++it) | |
71 | 194 { |
191 | 195 if (method == (*it)->GetMethod()) |
71 | 196 { |
197 boost::smatch what; | |
191 | 198 if (boost::regex_match(uri, what, (*it)->GetPattern())) |
71 | 199 { |
191 | 200 matchedPattern = (*it)->GetPattern().expression(); |
201 permissions = (*it)->GetPermissions(); | |
71 | 202 return true; |
203 } | |
204 } | |
205 } | |
206 | |
207 return false; | |
208 } | |
209 } |