Skip to content

Commit 6fd3c28

Browse files
committed
Add controller for validate-endpoint
1 parent 5ab3c55 commit 6fd3c28

File tree

4 files changed

+228
-121
lines changed

4 files changed

+228
-121
lines changed

public/validate.php

Lines changed: 0 additions & 121 deletions
This file was deleted.

routing/routes/routes.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
casserver-cas10-validate:
2+
path: /validate
3+
defaults: { _controller: 'SimpleSAML\Module\casserver\Controller\Cas10::validate' }

src/Controller/Cas10.php

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Module\casserver\Controller;
6+
7+
use Exception;
8+
use SimpleSAML\Configuration;
9+
use SimpleSAML\Logger;
10+
use SimpleSAML\Module;
11+
use SimpleSAML\Module\casserver\Utils\Url as UrlUtils;
12+
use Symfony\Component\HttpFoundation\Request;
13+
use Symfony\Component\HttpFoundation\StreamedResponse;
14+
15+
use function array_key_exist;
16+
use function is_null;
17+
use function var_export;
18+
19+
/**
20+
* Controller class for the casserver module.
21+
*
22+
* This class serves the different views available in the module.
23+
*
24+
* @package SimpleSAML\Module\casserver
25+
*/
26+
class Cas10
27+
{
28+
/** @var \SimpleSAML\Configuration */
29+
protected Configuration $config;
30+
31+
/** @var \SimpleSAML\Module\casserver\Utils\Url */
32+
protected UrlUtils $urlUtils;
33+
34+
35+
/**
36+
* Controller constructor.
37+
*
38+
* It initializes the global configuration for the controllers implemented here.
39+
*
40+
* @param \SimpleSAML\Configuration $config The configuration to use by the controllers.
41+
*/
42+
public function __construct(
43+
Configuration $config
44+
) {
45+
$this->config = $config;
46+
$this->urlUtils = new UrlUtils();
47+
}
48+
49+
50+
/**
51+
* @param \Symfony\Component\HttpFoundation\Request $request
52+
* @return \Symfony\Component\HttpFoundation\StreamedResponse
53+
*/
54+
public function validate(Request $request): StreamedResponse
55+
{
56+
/* Load simpleSAMLphp, configuration and metadata */
57+
$casconfig = Configuration::getConfig('module_casserver.php');
58+
59+
/* Instantiate protocol handler */
60+
$protocolClass = Module::resolveClass('casserver:Cas10', 'Cas\Protocol');
61+
62+
/** @psalm-suppress InvalidStringClass */
63+
$protocol = new $protocolClass($casconfig);
64+
65+
$response = new StreamedResponse();
66+
if ($request->query->has('service') && $request->query->has('ticket')) {
67+
$forceAuthn = $request->query->has('renew') && !!$request->query->get('renew');
68+
69+
try {
70+
/* Instantiate ticket store */
71+
$ticketStoreConfig = $casconfig->getOptionalValue(
72+
'ticketstore',
73+
['class' => 'casserver:FileSystemTicketStore']
74+
);
75+
76+
$ticketStoreClass = Module::resolveClass($ticketStoreConfig['class'], 'Cas\Ticket');
77+
78+
/** @psalm-suppress InvalidStringClass */
79+
$ticketStore = new $ticketStoreClass($casconfig);
80+
81+
$ticketFactoryClass = Module::resolveClass('casserver:TicketFactory', 'Cas\Ticket');
82+
83+
/** @psalm-suppress InvalidStringClass */
84+
$ticketFactory = new $ticketFactoryClass($casconfig);
85+
86+
$ticket = $request->query->get('ticket');
87+
$serviceTicket = $ticketStore->getTicket($ticket);
88+
89+
if (!is_null($serviceTicket) && $ticketFactory->isServiceTicket($serviceTicket)) {
90+
$service = $request->query->get('service');
91+
$ticketStore->deleteTicket($ticket);
92+
$usernameField = $casconfig->getOptionalValue('attrname', 'eduPersonPrincipalName');
93+
94+
if (
95+
!$ticketFactory->isExpired($serviceTicket) &&
96+
$this->urlUtils->sanitize($serviceTicket['service']) === $this->urlUtils->sanitize($service) &&
97+
(!$forceAuthn || $serviceTicket['forceAuthn']) &&
98+
array_key_exists($usernameField, $serviceTicket['attributes'])
99+
) {
100+
$response->setCallback(function() use ($protocol, $serviceTicket, $usernameField) {
101+
echo $protocol->getValidateSuccessResponse($serviceTicket['attributes'][$usernameField][0]);
102+
});
103+
} else {
104+
if (!array_key_exists($usernameField, $serviceTicket['attributes'])) {
105+
Logger::error(sprintf(
106+
'casserver:validate: internal server error. Missing user name attribute: %s',
107+
var_export($usernameField, true)
108+
));
109+
110+
$response->setCallback(function() use ($protocol) {
111+
echo $protocol->getValidateFailureResponse();
112+
});
113+
} else {
114+
if ($ticketFactory->isExpired($serviceTicket)) {
115+
$message = 'Ticket has ' . var_export($ticket, true) . ' expired';
116+
} else {
117+
if ($this->urlUtils->sanitize($serviceTicket['service']) === $this->urlUtils->sanitize($service)) {
118+
$message = 'Mismatching service parameters: expected ' .
119+
var_export($serviceTicket['service'], true) .
120+
' but was: ' . var_export($service, true);
121+
} else {
122+
$message = 'Ticket was issue from single sign on session';
123+
}
124+
}
125+
Logger::debug('casserver:' . $message);
126+
127+
$response->setCallback(function() use ($protocol) {
128+
echo $protocol->getValidateFailureResponse();
129+
});
130+
}
131+
}
132+
} else {
133+
if (is_null($serviceTicket)) {
134+
$message = 'ticket: ' . var_export($ticket, true) . ' not recognized';
135+
} else {
136+
$message = 'ticket: ' . var_export($ticket, true) . ' is not a service ticket';
137+
}
138+
139+
Logger::debug('casserver:' . $message);
140+
141+
$response->setCallback(function() use ($protocol) {
142+
echo $protocol->getValidateFailureResponse();
143+
});
144+
}
145+
} catch (Exception $e) {
146+
Logger::error('casserver:validate: internal server error. ' . var_export($e->getMessage(), true));
147+
148+
$response->setCallback(function() use ($protocol) {
149+
echo $protocol->getValidateFailureResponse();
150+
});
151+
}
152+
} else {
153+
if (!$request->query->has('service')) {
154+
$message = 'Missing service parameter: [service]';
155+
} else {
156+
$message = 'Missing ticket parameter: [ticket]';
157+
}
158+
159+
Logger::debug('casserver:' . $message);
160+
$response->setCallback(function() use ($protocol) {
161+
echo $protocol->getValidateFailureResponse();
162+
});
163+
}
164+
165+
return $response;
166+
}
167+
}

src/Utils/Url.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
*/
23+
24+
declare(strict_types=1);
25+
26+
namespace SimpleSAML\Module\casserver\Utils;
27+
28+
use SimpleSAML\Configuration;
29+
use SimpleSAML\Module\casserver\Cas\ServiceValidator;
30+
use SimpleSAML\Module\casserver\Cas\TicketValidator;
31+
32+
class Url
33+
{
34+
/**
35+
* @deprecated
36+
* @see ServiceValidator
37+
* @param string $service
38+
* @param array $legal_service_urls
39+
* @return bool
40+
*/
41+
public function checkServiceURL(string $service, array $legal_service_urls): bool
42+
{
43+
//delegate to ServiceValidator until all references to this can be cleaned up
44+
$config = Configuration::loadFromArray(['legal_service_urls' => $legal_service_urls]);
45+
$serviceValidator = new ServiceValidator($config);
46+
return $serviceValidator->checkServiceURL($service) !== null;
47+
}
48+
49+
50+
/**
51+
* @param string $parameter
52+
* @return string
53+
*/
54+
public function sanitize(string $parameter): string
55+
{
56+
return TicketValidator::sanitize($parameter);
57+
}
58+
}

0 commit comments

Comments
 (0)