Rev 1278 | Rev 1305 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1278 | Rev 1293 | ||
---|---|---|---|
1 | <?php |
1 | <?php |
2 | 2 | ||
3 | /* |
3 | /* |
4 | * OIDplus 2.0 |
4 | * OIDplus 2.0 |
5 | * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft |
5 | * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft |
6 | * |
6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * you may not use this file except in compliance with the License. |
8 | * you may not use this file except in compliance with the License. |
9 | * You may obtain a copy of the License at |
9 | * You may obtain a copy of the License at |
10 | * |
10 | * |
11 | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | * |
12 | * |
13 | * Unless required by applicable law or agreed to in writing, software |
13 | * Unless required by applicable law or agreed to in writing, software |
14 | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | * See the License for the specific language governing permissions and |
16 | * See the License for the specific language governing permissions and |
17 | * limitations under the License. |
17 | * limitations under the License. |
18 | */ |
18 | */ |
19 | 19 | ||
20 | // ATTENTION: If you change something, please make sure that the changes |
20 | // ATTENTION: If you change something, please make sure that the changes |
21 | // are synchronous with OIDplusPageRaRestApi |
21 | // are synchronous with OIDplusPageRaRestApi |
22 | 22 | ||
23 | namespace ViaThinkSoft\OIDplus; |
23 | namespace ViaThinkSoft\OIDplus; |
24 | 24 | ||
25 | // phpcs:disable PSR1.Files.SideEffects |
25 | // phpcs:disable PSR1.Files.SideEffects |
26 | \defined('INSIDE_OIDPLUS') or die; |
26 | \defined('INSIDE_OIDPLUS') or die; |
27 | // phpcs:enable PSR1.Files.SideEffects |
27 | // phpcs:enable PSR1.Files.SideEffects |
28 | 28 | ||
29 | class OIDplusPageAdminRestApi extends OIDplusPagePluginAdmin { |
29 | class OIDplusPageAdminRestApi extends OIDplusPagePluginAdmin { |
30 | 30 | ||
31 | /** |
31 | /** |
32 | * @param string $actionID |
- | |
33 | * @param array $params |
32 | * @param array $params |
34 | * @return array |
33 | * @return array |
35 | * @throws OIDplusException |
34 | * @throws OIDplusException |
36 | */ |
35 | */ |
37 | public function action(string $actionID, array $params): array { |
36 | private function action_Blacklist(array $params): array { |
38 | if ($actionID == 'blacklistJWT') { |
- | |
39 | if (!OIDplus::authUtils()->isAdminLoggedIn()) { |
37 | if (!OIDplus::authUtils()->isAdminLoggedIn()) { |
40 | throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), null, 401); |
38 | throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), null, 401); |
41 | } |
39 | } |
42 | 40 | ||
43 | if (!OIDplus::baseConfig()->getValue('JWT_ALLOW_REST_ADMIN', true)) { |
41 | if (!OIDplus::baseConfig()->getValue('JWT_ALLOW_REST_ADMIN', true)) { |
44 | throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_REST_ADMIN')); |
42 | throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_REST_ADMIN')); |
45 | } |
43 | } |
46 | 44 | ||
47 | $gen = OIDplusAuthContentStoreJWT::JWT_GENERATOR_REST; |
45 | $gen = OIDplusAuthContentStoreJWT::JWT_GENERATOR_REST; |
48 | $sub = 'admin'; |
46 | $sub = 'admin'; |
49 | 47 | ||
50 | OIDplusAuthContentStoreJWT::jwtBlacklist($gen, $sub); |
48 | OIDplusAuthContentStoreJWT::jwtBlacklist($gen, $sub); |
51 | 49 | ||
52 | return array("status" => 0); |
50 | return array("status" => 0); |
- | 51 | } |
|
- | 52 | ||
- | 53 | /** |
|
- | 54 | * @param string $actionID |
|
- | 55 | * @param array $params |
|
- | 56 | * @return array |
|
- | 57 | * @throws OIDplusException |
|
- | 58 | */ |
|
- | 59 | public function action(string $actionID, array $params): array { |
|
- | 60 | if ($actionID == 'blacklistJWT') { |
|
- | 61 | return $this->action_Blacklist($params); |
|
53 | } else { |
62 | } else { |
54 | return parent::action($actionID, $params); |
63 | return parent::action($actionID, $params); |
55 | } |
64 | } |
56 | } |
65 | } |
57 | 66 | ||
58 | /** |
67 | /** |
59 | * @param string $id |
68 | * @param string $id |
60 | * @param array $out |
69 | * @param array $out |
61 | * @param bool $handled |
70 | * @param bool $handled |
62 | * @return void |
71 | * @return void |
63 | * @throws OIDplusException |
72 | * @throws OIDplusException |
64 | */ |
73 | */ |
65 | public function gui(string $id, array &$out, bool &$handled) { |
74 | public function gui(string $id, array &$out, bool &$handled) { |
66 | $parts = explode('$',$id,2); |
75 | $parts = explode('$',$id,2); |
67 | $subpage = $parts[1] ?? ''; |
76 | $subpage = $parts[1] ?? ''; |
68 | 77 | ||
69 | if ($parts[0] == 'oidplus:rest_api_information_admin') { |
78 | if ($parts[0] == 'oidplus:rest_api_information_admin') { |
70 | $handled = true; |
79 | $handled = true; |
71 | 80 | ||
72 | if (str_starts_with($subpage, 'endpoints:')) { |
81 | if (str_starts_with($subpage, 'endpoints:')) { |
73 | // Note: This page can be accessed WITHOUT login! |
82 | // Note: This page can be accessed WITHOUT login! |
74 | $plugin = OIDplus::getPluginByOid(explode(':',$subpage)[1]); |
83 | $plugin = OIDplus::getPluginByOid(explode(':',$subpage)[1]); |
75 | if (!$plugin || !($plugin instanceof INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_9)) throw new OIDplusException(_L("No endpoints for this plugin found"), null, 404); |
84 | if (!$plugin || !($plugin instanceof INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_9)) throw new OIDplusException(_L("No endpoints for this plugin found"), null, 404); |
76 | $out['title'] = _L('REST API').' - '.$plugin->getManifest()->getName() . ' ' . _L('Endpoints'); |
85 | $out['title'] = _L('REST API').' - '.$plugin->getManifest()->getName() . ' ' . _L('Endpoints'); |
77 | $out['icon'] = file_exists(__DIR__.'/img/endpoints_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/endpoints_icon.png' : ''; |
86 | $out['icon'] = file_exists(__DIR__.'/img/endpoints_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/endpoints_icon.png' : ''; |
78 | $out['text'] = ''; |
87 | $out['text'] = ''; |
79 | if (OIDplus::authUtils()->isAdminLoggedIn()) { |
88 | if (OIDplus::authUtils()->isAdminLoggedIn()) { |
80 | $out['text'] .= '<p><a '.OIDplus::gui()->link('oidplus:rest_api_information_admin').'><img src="img/arrow_back.png" width="16" alt="'._L('Go back').'"> '._L('Go back').'</a></p>'; |
89 | $out['text'] .= '<p><a '.OIDplus::gui()->link('oidplus:rest_api_information_admin').'><img src="img/arrow_back.png" width="16" alt="'._L('Go back').'"> '._L('Go back').'</a></p>'; |
81 | } |
90 | } |
82 | $out['text'] .= $plugin->restApiInfo('html'); |
91 | $out['text'] .= $plugin->restApiInfo('html'); |
83 | } else { |
92 | } else { |
84 | $out['title'] = _L('REST API'); |
93 | $out['title'] = _L('REST API'); |
85 | $out['icon'] = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : ''; |
94 | $out['icon'] = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : ''; |
86 | 95 | ||
87 | if (!OIDplus::authUtils()->isAdminLoggedIn()) { |
96 | if (!OIDplus::authUtils()->isAdminLoggedIn()) { |
88 | throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), $out['title'], 401); |
97 | throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), $out['title'], 401); |
89 | } |
98 | } |
90 | 99 | ||
91 | if (!OIDplus::baseConfig()->getValue('JWT_ALLOW_REST_ADMIN', true)) { |
100 | if (!OIDplus::baseConfig()->getValue('JWT_ALLOW_REST_ADMIN', true)) { |
92 | throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_REST_ADMIN'), $out['title']); |
101 | throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_REST_ADMIN'), $out['title']); |
93 | } |
102 | } |
94 | 103 | ||
95 | if (is_null(OIDplus::getPluginByOid("1.3.6.1.4.1.37476.2.5.2.4.1.2"))) { // OIDplusPagePublicRestApi |
104 | if (is_null(OIDplus::getPluginByOid("1.3.6.1.4.1.37476.2.5.2.4.1.2"))) { // OIDplusPagePublicRestApi |
96 | throw new OIDplusException(_L('The administrator has disabled this feature. (Plugin %1).','OIDplusPagePublicRestApi'), $out['title']); |
105 | throw new OIDplusException(_L('The administrator has disabled this feature. (Plugin %1).','OIDplusPagePublicRestApi'), $out['title']); |
97 | } |
106 | } |
98 | 107 | ||
99 | $gen = OIDplusAuthContentStoreJWT::JWT_GENERATOR_REST; |
108 | $gen = OIDplusAuthContentStoreJWT::JWT_GENERATOR_REST; |
100 | $sub = 'admin'; |
109 | $sub = 'admin'; |
101 | 110 | ||
102 | $authSimulation = new OIDplusAuthContentStoreJWT(); |
111 | $authSimulation = new OIDplusAuthContentStoreJWT(); |
103 | $authSimulation->adminLogin(); |
112 | $authSimulation->adminLogin(); |
104 | $authSimulation->setValue('oidplus_generator', $gen); |
113 | $authSimulation->setValue('oidplus_generator', $gen); |
105 | $token = $authSimulation->getJWTToken(); |
114 | $token = $authSimulation->getJWTToken(); |
106 | 115 | ||
107 | $out['text'] .= '<p>'._L('You can make automated calls to your OIDplus account by calling an REST API.').'</p>'; |
116 | $out['text'] .= '<p>'._L('You can make automated calls to your OIDplus account by calling an REST API.').'</p>'; |
108 | $out['text'] .= '<h2>'._L('Endpoints').'</h2>'; |
117 | $out['text'] .= '<h2>'._L('Endpoints').'</h2>'; |
109 | $endpoints = ''; |
118 | $endpoints = ''; |
110 | foreach (OIDplus::getAllPlugins() as $plugin) { |
119 | foreach (OIDplus::getAllPlugins() as $plugin) { |
111 | if ($plugin instanceof INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_9) { |
120 | if ($plugin instanceof INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_9) { |
112 | $link = 'oidplus:rest_api_information_admin$endpoints:'.$plugin->getManifest()->getOid(); |
121 | $link = 'oidplus:rest_api_information_admin$endpoints:'.$plugin->getManifest()->getOid(); |
113 | $endpoints .= '<li><a '.OIDplus::gui()->link($link).'>'.htmlentities($plugin->getManifest()->getName()).'</a></li>'; |
122 | $endpoints .= '<li><a '.OIDplus::gui()->link($link).'>'.htmlentities($plugin->getManifest()->getName()).'</a></li>'; |
114 | } |
123 | } |
115 | } |
124 | } |
116 | if ($endpoints) { |
125 | if ($endpoints) { |
117 | $out['text'] .= '<p>'._L('The following installed plugins are offering REST endpoints:').'</p>'; |
126 | $out['text'] .= '<p>'._L('The following installed plugins are offering REST endpoints:').'</p>'; |
118 | $out['text'] .= '<p><ul>'.$endpoints.'</ul></p>'; |
127 | $out['text'] .= '<p><ul>'.$endpoints.'</ul></p>'; |
119 | } else { |
128 | } else { |
120 | $out['text'] .= '<p>'._L('No installed plugin offers a REST functionality').'</p>'; |
129 | $out['text'] .= '<p>'._L('No installed plugin offers a REST functionality').'</p>'; |
121 | } |
130 | } |
122 | $out['text'] .= '<h2>'._L('Authentication').'</h2>'; |
131 | $out['text'] .= '<h2>'._L('Authentication').'</h2>'; |
123 | $out['text'] .= '<p>'._L('The authentication is done via the following HTTP header:').'</p>'; |
132 | $out['text'] .= '<p>'._L('The authentication is done via the following HTTP header:').'</p>'; |
124 | $out['text'] .= '<p><pre id="oidplus_auth_jwt">'; |
133 | $out['text'] .= '<p><pre id="oidplus_auth_jwt">'; |
125 | $out['text'] .= 'Authentication: Bearer '.htmlentities($token)."\n"; |
134 | $out['text'] .= 'Authentication: Bearer '.htmlentities($token)."\n"; |
126 | $out['text'] .= '</pre></p>'; |
135 | $out['text'] .= '</pre></p>'; |
127 | $out['text'] .= '<p><input type="button" value="'._L('Copy to clipboard').'" onClick="copyToClipboard(oidplus_auth_jwt)"></p>'; |
136 | $out['text'] .= '<p><input type="button" value="'._L('Copy to clipboard').'" onClick="copyToClipboard(oidplus_auth_jwt)"></p>'; |
128 | $out['text'] .= '<p>'._L('Please keep this information confidential!').'</p>'; |
137 | $out['text'] .= '<p>'._L('Please keep this information confidential!').'</p>'; |
129 | $out['text'] .= '<p>'._L('The JWT-token (secret!) will automatically perform a one-time-login to fulfill the request. The other fields are the normal fields which are called during the usual operation of OIDplus.').'</p>'; |
138 | $out['text'] .= '<p>'._L('The JWT-token (secret!) will automatically perform a one-time-login to fulfill the request. The other fields are the normal fields which are called during the usual operation of OIDplus.').'</p>'; |
130 | 139 | ||
131 | $out['text'] .= '<h2>'._L('Blacklisted tokens').'</h2>'; |
140 | $out['text'] .= '<h2>'._L('Blacklisted tokens').'</h2>'; |
132 | $bl_time = OIDplusAuthContentStoreJWT::jwtGetBlacklistTime($gen, $sub); |
141 | $bl_time = OIDplusAuthContentStoreJWT::jwtGetBlacklistTime($gen, $sub); |
133 | if ($bl_time == 0) { |
142 | if ($bl_time == 0) { |
134 | $out['text'] .= '<p>'._L('None of the previously generated JWT tokens have been blacklisted.').'</p>'; |
143 | $out['text'] .= '<p>'._L('None of the previously generated JWT tokens have been blacklisted.').'</p>'; |
135 | } else { |
144 | } else { |
136 | $out['text'] .= '<p>'._L('All tokens generated before %1 have been blacklisted.',date('d F Y, H:i:s',$bl_time+1)).'</p>'; |
145 | $out['text'] .= '<p>'._L('All tokens generated before %1 have been blacklisted.',date('d F Y, H:i:s',$bl_time+1)).'</p>'; |
137 | } |
146 | } |
138 | $out['text'] .= '<button type="button" name="btn_blacklist_jwt" id="btn_blacklist_jwt" class="btn btn-danger btn-xs" onclick="OIDplusPageAdminRestApi.blacklistJWT()">'._L('Blacklist all previously generated tokens').'</button>'; |
147 | $out['text'] .= '<button type="button" name="btn_blacklist_jwt" id="btn_blacklist_jwt" class="btn btn-danger btn-xs" onclick="OIDplusPageAdminRestApi.blacklistJWT()">'._L('Blacklist all previously generated tokens').'</button>'; |
139 | } |
148 | } |
140 | } |
149 | } |
141 | } |
150 | } |
142 | 151 | ||
143 | /** |
152 | /** |
144 | * @param array $json |
153 | * @param array $json |
145 | * @param string|null $ra_email |
154 | * @param string|null $ra_email |
146 | * @param bool $nonjs |
155 | * @param bool $nonjs |
147 | * @param string $req_goto |
156 | * @param string $req_goto |
148 | * @return bool |
157 | * @return bool |
149 | * @throws OIDplusException |
158 | * @throws OIDplusException |
150 | */ |
159 | */ |
151 | public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool { |
160 | public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool { |
152 | if (!OIDplus::authUtils()->isAdminLoggedIn()) return false; |
161 | if (!OIDplus::authUtils()->isAdminLoggedIn()) return false; |
153 | 162 | ||
154 | if (file_exists(__DIR__.'/img/main_icon16.png')) { |
163 | if (file_exists(__DIR__.'/img/main_icon16.png')) { |
155 | $tree_icon = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon16.png'; |
164 | $tree_icon = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon16.png'; |
156 | } else { |
165 | } else { |
157 | $tree_icon = null; // default icon (folder) |
166 | $tree_icon = null; // default icon (folder) |
158 | } |
167 | } |
159 | 168 | ||
160 | if (file_exists(__DIR__.'/img/endpoints_icon16.png')) { |
169 | if (file_exists(__DIR__.'/img/endpoints_icon16.png')) { |
161 | $tree_icon_endpoints = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/endpoints_icon16.png'; |
170 | $tree_icon_endpoints = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/endpoints_icon16.png'; |
162 | } else { |
171 | } else { |
163 | $tree_icon_endpoints = null; // default icon (folder) |
172 | $tree_icon_endpoints = null; // default icon (folder) |
164 | } |
173 | } |
165 | 174 | ||
166 | $submenu = array(); |
175 | $submenu = array(); |
167 | foreach (OIDplus::getAllPlugins() as $plugin) { |
176 | foreach (OIDplus::getAllPlugins() as $plugin) { |
168 | if ($plugin instanceof INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_9) { |
177 | if ($plugin instanceof INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_9) { |
169 | $submenu[] = [ |
178 | $submenu[] = [ |
170 | 'id' => 'oidplus:rest_api_information_admin$endpoints:'.$plugin->getManifest()->getOid(), |
179 | 'id' => 'oidplus:rest_api_information_admin$endpoints:'.$plugin->getManifest()->getOid(), |
171 | 'icon' => $tree_icon_endpoints, |
180 | 'icon' => $tree_icon_endpoints, |
172 | 'text' => $plugin->getManifest()->getName() . ' ' . _L('Endpoints') |
181 | 'text' => $plugin->getManifest()->getName() . ' ' . _L('Endpoints') |
173 | ]; |
182 | ]; |
174 | } |
183 | } |
175 | } |
184 | } |
176 | 185 | ||
177 | $json[] = array( |
186 | $json[] = array( |
178 | 'id' => 'oidplus:rest_api_information_admin', |
187 | 'id' => 'oidplus:rest_api_information_admin', |
179 | 'icon' => $tree_icon, |
188 | 'icon' => $tree_icon, |
180 | 'text' => _L('REST API'), |
189 | 'text' => _L('REST API'), |
181 | 'children' => $submenu |
190 | 'children' => $submenu |
182 | ); |
191 | ); |
183 | 192 | ||
184 | return true; |
193 | return true; |
185 | } |
194 | } |
186 | 195 | ||
187 | /** |
196 | /** |
188 | * @param string $request |
197 | * @param string $request |
189 | * @return array|false |
198 | * @return array|false |
190 | */ |
199 | */ |
191 | public function tree_search(string $request) { |
200 | public function tree_search(string $request) { |
192 | return false; |
201 | return false; |
193 | } |
202 | } |
194 | } |
203 | } |
195 | 204 |