1 | <?php |
||
2 | |||
3 | /* |
||
4 | * simpleSAMLphp-casserver is a CAS 1.0 and 2.0 compliant CAS server in the form of a simpleSAMLphp module |
||
5 | * |
||
6 | * Copyright (C) 2013 Bjorn R. Jensen |
||
7 | * |
||
8 | * This library is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of the GNU Lesser General Public |
||
10 | * License as published by the Free Software Foundation; either |
||
11 | * version 2.1 of the License, or (at your option) any later version. |
||
12 | * |
||
13 | * This library is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
16 | * Lesser General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU Lesser General Public |
||
19 | * License along with this library; if not, write to the Free Software |
||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
21 | * |
||
22 | * Incoming parameters: |
||
23 | * service |
||
24 | * renew |
||
25 | * gateway |
||
26 | * entityId |
||
27 | * scope |
||
28 | * language |
||
29 | */ |
||
30 | |||
31 | use SimpleSAML\Module\casserver\Cas\AttributeExtractor; |
||
32 | use SimpleSAML\Module\casserver\Cas\Protocol\SamlValidateResponder; |
||
33 | use SimpleSAML\Module\casserver\Cas\ServiceValidator; |
||
34 | use SimpleSAML\Module\casserver\Cas\Ticket\TicketFactory; |
||
35 | use SimpleSAML\Module\casserver\Cas\Ticket\TicketStore; |
||
36 | use SimpleSAML\Configuration; |
||
37 | use SimpleSAML\Locale\Language; |
||
38 | use SimpleSAML\Logger; |
||
39 | use SimpleSAML\Module; |
||
40 | use SimpleSAML\Session; |
||
41 | use SimpleSAML\Utils\HTTP; |
||
42 | |||
43 | require_once('utility/urlUtils.php'); |
||
44 | |||
45 | $forceAuthn = isset($_GET['renew']) && $_GET['renew']; |
||
46 | $isPassive = isset($_GET['gateway']) && $_GET['gateway']; |
||
47 | // Determine if client wants us to post or redirect the response. Default is redirect. |
||
48 | $redirect = !(isset($_GET['method']) && 'POST' === $_GET['method']); |
||
49 | |||
50 | $casconfig = Configuration::getConfig('module_casserver.php'); |
||
51 | $serviceValidator = new ServiceValidator($casconfig); |
||
52 | |||
53 | $serviceUrl = $_GET['service'] ?? $_GET['TARGET'] ?? null; |
||
54 | |||
55 | if (isset($serviceUrl)) { |
||
56 | $serviceCasConfig = $serviceValidator->checkServiceURL(sanitize($serviceUrl)); |
||
57 | if (isset($serviceCasConfig)) { |
||
58 | // Override the cas configuration to use for this service |
||
59 | $casconfig = $serviceCasConfig; |
||
60 | } else { |
||
61 | $message = 'Service parameter provided to CAS server is not listed as a legal service: [service] = ' . |
||
62 | var_export($serviceUrl, true); |
||
63 | Logger::debug('casserver:' . $message); |
||
64 | |||
65 | throw new \Exception($message); |
||
66 | } |
||
67 | } |
||
68 | |||
69 | |||
70 | $as = new \SimpleSAML\Auth\Simple($casconfig->getValue('authsource')); |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
71 | |||
72 | if (array_key_exists('scope', $_GET) && is_string($_GET['scope'])) { |
||
73 | $scopes = $casconfig->getValue('scopes', []); |
||
74 | |||
75 | if (array_key_exists($_GET['scope'], $scopes)) { |
||
76 | $idpList = $scopes[$_GET['scope']]; |
||
77 | } else { |
||
78 | $message = 'Scope parameter provided to CAS server is not listed as legal scope: [scope] = ' . |
||
79 | var_export($_GET['scope'], true); |
||
80 | Logger::debug('casserver:' . $message); |
||
81 | |||
82 | throw new \Exception($message); |
||
83 | } |
||
84 | } |
||
85 | |||
86 | if (array_key_exists('language', $_GET) && is_string($_GET['language'])) { |
||
87 | Language::setLanguageCookie($_GET['language']); |
||
88 | } |
||
89 | |||
90 | $ticketStoreConfig = $casconfig->getValue('ticketstore', ['class' => 'casserver:FileSystemTicketStore']); |
||
91 | $ticketStoreClass = Module::resolveClass($ticketStoreConfig['class'], 'Cas_Ticket'); |
||
92 | /** @var $ticketStore TicketStore */ |
||
93 | /** @psalm-suppress InvalidStringClass */ |
||
94 | $ticketStore = new $ticketStoreClass($casconfig); |
||
95 | |||
96 | $ticketFactoryClass = Module::resolveClass('casserver:TicketFactory', 'Cas_Ticket'); |
||
97 | /** @var $ticketFactory TicketFactory */ |
||
98 | /** @psalm-suppress InvalidStringClass */ |
||
99 | $ticketFactory = new $ticketFactoryClass($casconfig); |
||
100 | |||
101 | $session = Session::getSessionFromRequest(); |
||
102 | |||
103 | $sessionTicket = $ticketStore->getTicket($session->getSessionId()); |
||
104 | $sessionRenewId = $sessionTicket ? $sessionTicket['renewId'] : null; |
||
105 | $requestRenewId = isset($_REQUEST['renewId']) ? $_REQUEST['renewId'] : null; |
||
106 | |||
107 | if (!$as->isAuthenticated() || ($forceAuthn && $sessionRenewId != $requestRenewId)) { |
||
108 | $query = []; |
||
109 | |||
110 | if ($sessionRenewId && $forceAuthn) { |
||
111 | $query['renewId'] = $sessionRenewId; |
||
112 | } |
||
113 | |||
114 | if (isset($_REQUEST['service'])) { |
||
115 | $query['service'] = $_REQUEST['service']; |
||
116 | } |
||
117 | |||
118 | if (isset($_REQUEST['TARGET'])) { |
||
119 | $query['TARGET'] = $_REQUEST['TARGET']; |
||
120 | } |
||
121 | |||
122 | if (isset($_REQUEST['method'])) { |
||
123 | $query['method'] = $_REQUEST['method']; |
||
124 | } |
||
125 | |||
126 | if (isset($_REQUEST['renew'])) { |
||
127 | $query['renew'] = $_REQUEST['renew']; |
||
128 | } |
||
129 | |||
130 | if (isset($_REQUEST['gateway'])) { |
||
131 | $query['gateway'] = $_REQUEST['gateway']; |
||
132 | } |
||
133 | |||
134 | if (array_key_exists('language', $_GET)) { |
||
135 | $query['language'] = is_string($_GET['language']) ? $_GET['language'] : null; |
||
136 | } |
||
137 | |||
138 | if (isset($_REQUEST['debugMode'])) { |
||
139 | $query['debugMode'] = $_REQUEST['debugMode']; |
||
140 | } |
||
141 | |||
142 | $returnUrl = HTTP::getSelfURLNoQuery() . '?' . http_build_query($query); |
||
143 | |||
144 | $params = [ |
||
145 | 'ForceAuthn' => $forceAuthn, |
||
146 | 'isPassive' => $isPassive, |
||
147 | 'ReturnTo' => $returnUrl, |
||
148 | ]; |
||
149 | |||
150 | if (isset($_GET['entityId'])) { |
||
151 | $params['saml:idp'] = $_GET['entityId']; |
||
152 | } |
||
153 | |||
154 | if (isset($idpList)) { |
||
155 | if (sizeof($idpList) > 1) { |
||
156 | $params['saml:IDPList'] = $idpList; |
||
157 | } else { |
||
158 | $params['saml:idp'] = $idpList[0]; |
||
159 | } |
||
160 | } |
||
161 | |||
162 | $as->login($params); |
||
163 | } |
||
164 | |||
165 | $sessionExpiry = $as->getAuthData('Expire'); |
||
166 | |||
167 | if (!is_array($sessionTicket) || $forceAuthn) { |
||
168 | $sessionTicket = $ticketFactory->createSessionTicket($session->getSessionId(), $sessionExpiry); |
||
169 | |||
170 | $ticketStore->addTicket($sessionTicket); |
||
171 | } |
||
172 | |||
173 | $parameters = []; |
||
174 | |||
175 | if (array_key_exists('language', $_GET)) { |
||
176 | $oldLanguagePreferred = Language::getLanguageCookie(); |
||
177 | |||
178 | if (isset($oldLanguagePreferred)) { |
||
179 | $parameters['language'] = $oldLanguagePreferred; |
||
180 | } else { |
||
181 | if (is_string($_GET['language'])) { |
||
182 | $parameters['language'] = $_GET['language']; |
||
183 | } |
||
184 | } |
||
185 | } |
||
186 | |||
187 | if (isset($serviceUrl)) { |
||
188 | $defaultTicketName = isset($_GET['service']) ? 'ticket' : 'SAMLart'; |
||
189 | $ticketName = $casconfig->getValue('ticketName', $defaultTicketName); |
||
190 | |||
191 | $attributeExtractor = new AttributeExtractor(); |
||
192 | $mappedAttributes = $attributeExtractor->extractUserAndAttributes($as->getAttributes(), $casconfig); |
||
193 | |||
194 | $serviceTicket = $ticketFactory->createServiceTicket([ |
||
195 | 'service' => $serviceUrl, |
||
196 | 'forceAuthn' => $forceAuthn, |
||
197 | 'userName' => $mappedAttributes['user'], |
||
198 | 'attributes' => $mappedAttributes['attributes'], |
||
199 | 'proxies' => [], |
||
200 | 'sessionId' => $sessionTicket['id'] |
||
201 | ]); |
||
202 | |||
203 | $ticketStore->addTicket($serviceTicket); |
||
204 | |||
205 | $parameters[$ticketName] = $serviceTicket['id']; |
||
206 | |||
207 | $validDebugModes = ['true', 'samlValidate']; |
||
208 | if ( |
||
209 | array_key_exists('debugMode', $_GET) && |
||
210 | in_array($_GET['debugMode'], $validDebugModes) && |
||
211 | $casconfig->getBoolean('debugMode', false) |
||
212 | ) { |
||
213 | if ($_GET['debugMode'] === 'samlValidate') { |
||
214 | $samlValidate = new SamlValidateResponder(); |
||
215 | $samlResponse = $samlValidate->convertToSaml($serviceTicket); |
||
216 | $soap = $samlValidate->wrapInSoap($samlResponse); |
||
217 | echo '<pre>' . htmlspecialchars($soap) . '</pre>'; |
||
218 | } else { |
||
219 | $method = 'serviceValidate'; |
||
220 | // Fake some options for validateTicket |
||
221 | $_GET[$ticketName] = $serviceTicket['id']; |
||
222 | // We want to capture the output from echo used in validateTicket |
||
223 | ob_start(); |
||
224 | require_once 'utility/validateTicket.php'; |
||
225 | $casResponse = ob_get_contents(); |
||
226 | ob_end_clean(); |
||
227 | echo '<pre>' . htmlspecialchars($casResponse) . '</pre>'; |
||
228 | } |
||
229 | } elseif ($redirect) { |
||
230 | HTTP::redirectTrustedURL(HTTP::addURLParameters($serviceUrl, $parameters)); |
||
231 | } else { |
||
232 | HTTP::submitPOSTData($serviceUrl, $parameters); |
||
233 | } |
||
234 | } else { |
||
235 | HTTP::redirectTrustedURL( |
||
236 | HTTP::addURLParameters(Module::getModuleURL('casserver/loggedIn.php'), $parameters) |
||
237 | ); |
||
238 | } |
||
239 |