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$config = select_config(); 25$redirect_to = (new CUrl('index.php'))->setArgument('form', 'default'); 26 27$request = CSession::getValue('request'); 28CSession::unsetValue(['request']); 29 30if (hasRequest('request')) { 31 $request = getRequest('request'); 32 preg_match('/^\/?(?<filename>[a-z0-9_.]+\.php)(\?.*)?$/i', $request, $test_request); 33 34 if (!array_key_exists('filename', $test_request) || !file_exists('./'.$test_request['filename']) 35 || $test_request['filename'] === basename(__FILE__)) { 36 $request = ''; 37 } 38 39 if ($request !== '') { 40 $redirect_to->setArgument('request', $request); 41 CSession::setValue('request', $request); 42 } 43} 44 45if ($config['saml_auth_enabled'] == ZBX_AUTH_SAML_DISABLED) { 46 CSession::unsetValue(['request']); 47 48 redirect($redirect_to->toString()); 49} 50 51require_once __DIR__.'/vendor/php-saml/_toolkit_loader.php'; 52require_once __DIR__.'/vendor/xmlseclibs/xmlseclibs.php'; 53 54use OneLogin\Saml2\Auth; 55use OneLogin\Saml2\Utils; 56 57global $SSO; 58 59$sp_key = ''; 60$sp_cert = ''; 61$idp_cert = ''; 62 63if (is_array($SSO) && array_key_exists('SP_KEY', $SSO)) { 64 if (is_readable($SSO['SP_KEY'])) { 65 $sp_key = file_get_contents($SSO['SP_KEY']); 66 } 67} 68elseif (is_readable('conf/certs/sp.key')) { 69 $sp_key = file_get_contents('conf/certs/sp.key'); 70} 71 72if (is_array($SSO) && array_key_exists('SP_CERT', $SSO)) { 73 if (is_readable($SSO['SP_CERT'])) { 74 $sp_cert = file_get_contents($SSO['SP_CERT']); 75 } 76} 77elseif (is_readable('conf/certs/sp.crt')) { 78 $sp_cert = file_get_contents('conf/certs/sp.crt'); 79} 80 81if (is_array($SSO) && array_key_exists('IDP_CERT', $SSO)) { 82 if (is_readable($SSO['IDP_CERT'])) { 83 $idp_cert = file_get_contents($SSO['IDP_CERT']); 84 } 85} 86elseif (is_readable('conf/certs/idp.crt')) { 87 $idp_cert = file_get_contents('conf/certs/idp.crt'); 88} 89 90if (is_array($SSO) && array_key_exists('SETTINGS', $SSO)) { 91 if (array_key_exists('baseurl', $SSO['SETTINGS']) && !is_array($SSO['SETTINGS']['baseurl']) 92 && $SSO['SETTINGS']['baseurl'] !== '') { 93 Utils::setBaseURL((string) $SSO['SETTINGS']['baseurl']); 94 } 95 96 if (array_key_exists('use_proxy_headers', $SSO['SETTINGS']) && (bool) $SSO['SETTINGS']['use_proxy_headers']) { 97 Utils::setProxyVars(true); 98 } 99} 100 101$baseurl = Utils::getSelfURLNoQuery(); 102$relay_state = null; 103$settings = [ 104 'sp' => [ 105 'entityId' => $config['saml_sp_entityid'], 106 'assertionConsumerService' => [ 107 'url' => $baseurl.'?acs' 108 ], 109 'singleLogoutService' => [ 110 'url' => $baseurl.'?sls' 111 ], 112 'NameIDFormat' => $config['saml_nameid_format'], 113 'x509cert' => $sp_cert, 114 'privateKey' => $sp_key 115 ], 116 'idp' => [ 117 'entityId' => $config['saml_idp_entityid'], 118 'singleSignOnService' => [ 119 'url' => $config['saml_sso_url'] 120 ], 121 'singleLogoutService' => [ 122 'url' => $config['saml_slo_url'] 123 ], 124 'x509cert' => $idp_cert 125 ], 126 'security' => [ 127 'nameIdEncrypted' => (bool) $config['saml_encrypt_nameid'], 128 'authnRequestsSigned' => (bool) $config['saml_sign_authn_requests'], 129 'logoutRequestSigned' => (bool) $config['saml_sign_logout_requests'], 130 'logoutResponseSigned' => (bool) $config['saml_sign_logout_responses'], 131 'wantMessagesSigned' => (bool) $config['saml_sign_messages'], 132 'wantAssertionsEncrypted' => (bool) $config['saml_encrypt_assertions'], 133 'wantAssertionsSigned' => (bool) $config['saml_sign_assertions'], 134 'wantNameIdEncrypted' => (bool) $config['saml_encrypt_nameid'] 135 ] 136]; 137 138if (is_array($SSO) && array_key_exists('SETTINGS', $SSO)) { 139 foreach (['strict', 'compress', 'contactPerson', 'organization'] as $option) { 140 if (array_key_exists($option, $SSO['SETTINGS'])) { 141 $settings[$option] = $SSO['SETTINGS'][$option]; 142 } 143 } 144 145 if (array_key_exists('sp', $SSO['SETTINGS'])) { 146 foreach (['attributeConsumingService', 'x509certNew'] as $option) { 147 if (array_key_exists($option, $SSO['SETTINGS']['sp'])) { 148 $settings['sp'][$option] = $SSO['SETTINGS']['sp'][$option]; 149 } 150 } 151 } 152 153 if (array_key_exists('idp', $SSO['SETTINGS'])) { 154 if (array_key_exists('singleLogoutService', $SSO['SETTINGS']['idp']) 155 && array_key_exists('responseUrl', $SSO['SETTINGS']['idp']['singleLogoutService'])) { 156 $settings['idp']['singleLogoutService']['responseUrl'] = 157 $SSO['SETTINGS']['idp']['singleLogoutService']['responseUrl']; 158 } 159 160 foreach (['certFingerprint', 'certFingerprintAlgorithm', 'x509certMulti'] as $option) { 161 if (array_key_exists($option, $SSO['SETTINGS']['idp'])) { 162 $settings['idp'][$option] = $SSO['SETTINGS']['idp'][$option]; 163 } 164 } 165 } 166 167 if (array_key_exists('security', $SSO['SETTINGS'])) { 168 foreach (['signMetadata', 'wantNameId', 'requestedAuthnContext', 'requestedAuthnContextComparison', 169 'wantXMLValidation', 'relaxDestinationValidation', 'destinationStrictlyMatches', 'lowercaseUrlencoding', 170 'rejectUnsolicitedResponsesWithInResponseTo', 'signatureAlgorithm', 'digestAlgorithm'] as $option) { 171 if (array_key_exists($option, $SSO['SETTINGS']['security'])) { 172 $settings['security'][$option] = $SSO['SETTINGS']['security'][$option]; 173 } 174 } 175 } 176} 177 178try { 179 $auth = new Auth($settings); 180 181 if (hasRequest('acs') && !CSession::keyExists('saml_data')) { 182 $auth->processResponse(); 183 184 if (!$auth->isAuthenticated()) { 185 throw new Exception($auth->getLastErrorReason()); 186 } 187 188 $user_attributes = $auth->getAttributes(); 189 190 if (!array_key_exists($config['saml_username_attribute'], $user_attributes)) { 191 throw new Exception( 192 _s('The parameter "%1$s" is missing from the user attributes.', $config['saml_username_attribute']) 193 ); 194 } 195 196 CSession::setValue('saml_data', [ 197 'username_attribute' => reset($user_attributes[$config['saml_username_attribute']]), 198 'nameid' => $auth->getNameId(), 199 'nameid_format' => $auth->getNameIdFormat(), 200 'nameid_name_qualifier' => $auth->getNameIdNameQualifier(), 201 'nameid_sp_name_qualifier' => $auth->getNameIdSPNameQualifier(), 202 'session_index' => $auth->getSessionIndex() 203 ]); 204 205 if (hasRequest('RelayState') && strpos(getRequest('RelayState'), $baseurl) === false) { 206 $relay_state = getRequest('RelayState'); 207 } 208 } 209 210 if ($config['saml_slo_url'] !== '') { 211 if (hasRequest('slo') && CSession::keyExists('saml_data')) { 212 $saml_data = CSession::getValue('saml_data'); 213 214 CWebUser::logout(); 215 216 $auth->logout(null, [], $saml_data['nameid'], $saml_data['session_index'], false, 217 $saml_data['nameid_format'], $saml_data['nameid_name_qualifier'], $saml_data['nameid_sp_name_qualifier'] 218 ); 219 } 220 221 if (hasRequest('sls')) { 222 $auth->processSLO(); 223 224 redirect('index.php'); 225 } 226 } 227 228 if (CWebUser::isLoggedIn() && !CWebUser::isGuest()) { 229 redirect($redirect_to->toString()); 230 } 231 232 if (CSession::keyExists('saml_data')) { 233 $saml_data = CSession::getValue('saml_data'); 234 $user = API::getApiService('user')->loginByAlias($saml_data['username_attribute'], 235 ($config['saml_case_sensitive'] == ZBX_AUTH_CASE_SENSITIVE), $config['authentication_type'] 236 ); 237 238 if ($user['gui_access'] == GROUP_GUI_ACCESS_DISABLED) { 239 CSession::unsetValue(['saml_data']); 240 241 throw new Exception(_('GUI access disabled.')); 242 } 243 244 CWebUser::setSessionCookie($user['sessionid']); 245 246 $redirect = array_filter([$request, $user['url'], $relay_state, ZBX_DEFAULT_URL]); 247 redirect(reset($redirect)); 248 } 249 250 $auth->login(); 251} 252catch (Exception $e) { 253 error($e->getMessage()); 254} 255 256echo (new CView('general.warning', [ 257 'header' => _('You are not logged in'), 258 'messages' => array_column(clear_messages(), 'message'), 259 'buttons' => [ 260 (new CButton('login', _('Login')))->onClick( 261 'document.location = '.json_encode( 262 $redirect_to 263 ->setArgument('request', $request) 264 ->getUrl() 265 ).';' 266 ) 267 ], 268 'theme' => getUserTheme(CWebUser::$data) 269]))->getOutput(); 270