1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22require_once __DIR__.'/include/config.inc.php'; 23 24$redirect_to = (new CUrl('index.php'))->setArgument('form', 'default'); 25 26$request = CSessionHelper::get('request'); 27CSessionHelper::unset(['request']); 28 29if (hasRequest('request')) { 30 $request = getRequest('request'); 31 preg_match('/^\/?(?<filename>[a-z0-9_.]+\.php)(\?.*)?$/i', $request, $test_request); 32 33 if (!array_key_exists('filename', $test_request) || !file_exists('./'.$test_request['filename']) 34 || $test_request['filename'] === basename(__FILE__)) { 35 $request = ''; 36 } 37 38 if ($request !== '') { 39 $redirect_to->setArgument('request', $request); 40 CSessionHelper::set('request', $request); 41 } 42} 43 44if (CAuthenticationHelper::get(CAuthenticationHelper::SAML_AUTH_ENABLED) == ZBX_AUTH_SAML_DISABLED) { 45 CSessionHelper::unset(['request']); 46 47 redirect($redirect_to->toString()); 48} 49 50require_once __DIR__.'/vendor/php-saml/_toolkit_loader.php'; 51require_once __DIR__.'/vendor/xmlseclibs/xmlseclibs.php'; 52 53use OneLogin\Saml2\Auth; 54use OneLogin\Saml2\Utils; 55 56global $SSO; 57 58$sp_key = ''; 59$sp_cert = ''; 60$idp_cert = ''; 61 62if (is_array($SSO) && array_key_exists('SP_KEY', $SSO)) { 63 if (is_readable($SSO['SP_KEY'])) { 64 $sp_key = file_get_contents($SSO['SP_KEY']); 65 } 66} 67elseif (is_readable('conf/certs/sp.key')) { 68 $sp_key = file_get_contents('conf/certs/sp.key'); 69} 70 71if (is_array($SSO) && array_key_exists('SP_CERT', $SSO)) { 72 if (is_readable($SSO['SP_CERT'])) { 73 $sp_cert = file_get_contents($SSO['SP_CERT']); 74 } 75} 76elseif (is_readable('conf/certs/sp.crt')) { 77 $sp_cert = file_get_contents('conf/certs/sp.crt'); 78} 79 80if (is_array($SSO) && array_key_exists('IDP_CERT', $SSO)) { 81 if (is_readable($SSO['IDP_CERT'])) { 82 $idp_cert = file_get_contents($SSO['IDP_CERT']); 83 } 84} 85elseif (is_readable('conf/certs/idp.crt')) { 86 $idp_cert = file_get_contents('conf/certs/idp.crt'); 87} 88 89if (is_array($SSO) && array_key_exists('SETTINGS', $SSO)) { 90 if (array_key_exists('baseurl', $SSO['SETTINGS']) && !is_array($SSO['SETTINGS']['baseurl']) 91 && $SSO['SETTINGS']['baseurl'] !== '') { 92 Utils::setBaseURL((string) $SSO['SETTINGS']['baseurl']); 93 } 94 95 if (array_key_exists('use_proxy_headers', $SSO['SETTINGS']) && (bool) $SSO['SETTINGS']['use_proxy_headers']) { 96 Utils::setProxyVars(true); 97 } 98} 99 100$baseurl = Utils::getSelfURLNoQuery(); 101$relay_state = null; 102$settings = [ 103 'sp' => [ 104 'entityId' => CAuthenticationHelper::get(CAuthenticationHelper::SAML_SP_ENTITYID), 105 'assertionConsumerService' => [ 106 'url' => $baseurl.'?acs' 107 ], 108 'singleLogoutService' => [ 109 'url' => $baseurl.'?sls' 110 ], 111 'NameIDFormat' => CAuthenticationHelper::get(CAuthenticationHelper::SAML_NAMEID_FORMAT), 112 'x509cert' => $sp_cert, 113 'privateKey' => $sp_key 114 ], 115 'idp' => [ 116 'entityId' => CAuthenticationHelper::get(CAuthenticationHelper::SAML_IDP_ENTITYID), 117 'singleSignOnService' => [ 118 'url' => CAuthenticationHelper::get(CAuthenticationHelper::SAML_SSO_URL) 119 ], 120 'singleLogoutService' => [ 121 'url' => CAuthenticationHelper::get(CAuthenticationHelper::SAML_SLO_URL) 122 ], 123 'x509cert' => $idp_cert 124 ], 125 'security' => [ 126 'nameIdEncrypted' => (bool) CAuthenticationHelper::get(CAuthenticationHelper::SAML_ENCRYPT_NAMEID), 127 'authnRequestsSigned' => (bool) CAuthenticationHelper::get(CAuthenticationHelper::SAML_SIGN_AUTHN_REQUESTS), 128 'logoutRequestSigned' => (bool) CAuthenticationHelper::get(CAuthenticationHelper::SAML_SIGN_LOGOUT_REQUESTS), 129 'logoutResponseSigned' => (bool) CAuthenticationHelper::get(CAuthenticationHelper::SAML_SIGN_LOGOUT_RESPONSES), 130 'wantMessagesSigned' => (bool) CAuthenticationHelper::get(CAuthenticationHelper::SAML_SIGN_MESSAGES), 131 'wantAssertionsEncrypted' => (bool) CAuthenticationHelper::get(CAuthenticationHelper::SAML_ENCRYPT_ASSERTIONS), 132 'wantAssertionsSigned' => (bool) CAuthenticationHelper::get(CAuthenticationHelper::SAML_SIGN_ASSERTIONS), 133 'wantNameIdEncrypted' => (bool) CAuthenticationHelper::get(CAuthenticationHelper::SAML_ENCRYPT_NAMEID) 134 ] 135]; 136 137if (is_array($SSO) && array_key_exists('SETTINGS', $SSO)) { 138 foreach (['strict', 'compress', 'contactPerson', 'organization'] as $option) { 139 if (array_key_exists($option, $SSO['SETTINGS'])) { 140 $settings[$option] = $SSO['SETTINGS'][$option]; 141 } 142 } 143 144 if (array_key_exists('sp', $SSO['SETTINGS'])) { 145 foreach (['attributeConsumingService', 'x509certNew'] as $option) { 146 if (array_key_exists($option, $SSO['SETTINGS']['sp'])) { 147 $settings['sp'][$option] = $SSO['SETTINGS']['sp'][$option]; 148 } 149 } 150 } 151 152 if (array_key_exists('idp', $SSO['SETTINGS'])) { 153 if (array_key_exists('singleLogoutService', $SSO['SETTINGS']['idp']) 154 && array_key_exists('responseUrl', $SSO['SETTINGS']['idp']['singleLogoutService'])) { 155 $settings['idp']['singleLogoutService']['responseUrl'] = 156 $SSO['SETTINGS']['idp']['singleLogoutService']['responseUrl']; 157 } 158 159 foreach (['certFingerprint', 'certFingerprintAlgorithm', 'x509certMulti'] as $option) { 160 if (array_key_exists($option, $SSO['SETTINGS']['idp'])) { 161 $settings['idp'][$option] = $SSO['SETTINGS']['idp'][$option]; 162 } 163 } 164 } 165 166 if (array_key_exists('security', $SSO['SETTINGS'])) { 167 foreach (['signMetadata', 'wantNameId', 'requestedAuthnContext', 'requestedAuthnContextComparison', 168 'wantXMLValidation', 'relaxDestinationValidation', 'destinationStrictlyMatches', 'lowercaseUrlencoding', 169 'rejectUnsolicitedResponsesWithInResponseTo', 'signatureAlgorithm', 'digestAlgorithm'] as $option) { 170 if (array_key_exists($option, $SSO['SETTINGS']['security'])) { 171 $settings['security'][$option] = $SSO['SETTINGS']['security'][$option]; 172 } 173 } 174 } 175} 176 177try { 178 $auth = new Auth($settings); 179 180 if (hasRequest('acs') && !CSessionHelper::has('saml_data')) { 181 $auth->processResponse(); 182 183 if (!$auth->isAuthenticated()) { 184 throw new Exception($auth->getLastErrorReason()); 185 } 186 187 $user_attributes = $auth->getAttributes(); 188 189 if (!array_key_exists(CAuthenticationHelper::get(CAuthenticationHelper::SAML_USERNAME_ATTRIBUTE), 190 $user_attributes 191 )) { 192 throw new Exception( 193 _s('The parameter "%1$s" is missing from the user attributes.', CAuthenticationHelper::get(CAuthenticationHelper::SAML_USERNAME_ATTRIBUTE)) 194 ); 195 } 196 197 $saml_data = [ 198 'username_attribute' => reset( 199 $user_attributes[CAuthenticationHelper::get(CAuthenticationHelper::SAML_USERNAME_ATTRIBUTE)] 200 ), 201 'nameid' => $auth->getNameId(), 202 'nameid_format' => $auth->getNameIdFormat(), 203 'nameid_name_qualifier' => $auth->getNameIdNameQualifier(), 204 'nameid_sp_name_qualifier' => $auth->getNameIdSPNameQualifier(), 205 'session_index' => $auth->getSessionIndex() 206 ]; 207 $saml_data['sign'] = CEncryptHelper::sign(json_encode($saml_data)); 208 209 CSessionHelper::set('saml_data', $saml_data); 210 211 if (hasRequest('RelayState') && strpos(getRequest('RelayState'), $baseurl) === false) { 212 $relay_state = getRequest('RelayState'); 213 } 214 } 215 216 if (CAuthenticationHelper::get(CAuthenticationHelper::SAML_SLO_URL) !== '') { 217 if (hasRequest('slo') && CSessionHelper::has('saml_data')) { 218 $saml_data = CSessionHelper::get('saml_data'); 219 220 CWebUser::logout(); 221 222 $auth->logout(null, [], $saml_data['nameid'], $saml_data['session_index'], false, 223 $saml_data['nameid_format'], $saml_data['nameid_name_qualifier'], $saml_data['nameid_sp_name_qualifier'] 224 ); 225 } 226 227 if (hasRequest('sls')) { 228 $auth->processSLO(); 229 230 redirect('index.php'); 231 } 232 } 233 234 if (CWebUser::isLoggedIn() && !CWebUser::isGuest()) { 235 redirect($redirect_to->toString()); 236 } 237 238 if (CSessionHelper::has('saml_data')) { 239 $saml_data = CSessionHelper::get('saml_data'); 240 241 if (!array_key_exists('sign', $saml_data)) { 242 throw new Exception(_('Session initialization error.')); 243 } 244 245 $saml_data_sign = $saml_data['sign']; 246 $saml_data_sign_check = CEncryptHelper::sign(json_encode(array_diff_key($saml_data, array_flip(['sign'])))); 247 248 if (!CEncryptHelper::checkSign($saml_data_sign, $saml_data_sign_check)) { 249 throw new Exception(_('Session initialization error.')); 250 } 251 252 CWebUser::$data = API::getApiService('user')->loginByUsername($saml_data['username_attribute'], 253 (CAuthenticationHelper::get(CAuthenticationHelper::SAML_CASE_SENSITIVE) == ZBX_AUTH_CASE_SENSITIVE), 254 CAuthenticationHelper::get(CAuthenticationHelper::AUTHENTICATION_TYPE) 255 ); 256 257 if (CWebUser::$data['gui_access'] == GROUP_GUI_ACCESS_DISABLED) { 258 CSessionHelper::unset(['saml_data']); 259 260 throw new Exception(_('GUI access disabled.')); 261 } 262 263 CSessionHelper::set('sessionid', CWebUser::$data['sessionid']); 264 API::getWrapper()->auth = CWebUser::$data['sessionid']; 265 266 $redirect = array_filter([$request, CWebUser::$data['url'], $relay_state, CMenuHelper::getFirstUrl()]); 267 redirect(reset($redirect)); 268 } 269 270 $auth->login(); 271} 272catch (Exception $e) { 273 error($e->getMessage()); 274} 275 276echo (new CView('general.warning', [ 277 'header' => _('You are not logged in'), 278 'messages' => array_column(get_and_clear_messages(), 'message'), 279 'buttons' => [ 280 (new CButton('login', _('Login')))->onClick( 281 'document.location = '.json_encode( 282 $redirect_to 283 ->setArgument('request', $request) 284 ->getUrl() 285 ).';' 286 ) 287 ], 288 'theme' => getUserTheme(CWebUser::$data) 289]))->getOutput(); 290 291session_write_close(); 292