Skip to content

Commit edb1bbc

Browse files
authored
Create controller, cleanup old www-files (#2)
* Create controller, cleanup old www-files
1 parent db6d4a3 commit edb1bbc

File tree

4 files changed

+309
-199
lines changed

4 files changed

+309
-199
lines changed

lib/AdfsController.php

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
<?php
2+
3+
namespace SimpleSAML\Module\adfs;
4+
5+
use SAML2\Constants;
6+
use SimpleSAML\Configuration;
7+
use SimpleSAML\Error as SspError;
8+
use SimpleSAML\IdP;
9+
use SimpleSAML\Locale\Translate;
10+
use SimpleSAML\Logger;
11+
use SimpleSAML\Module;
12+
use SimpleSAML\Module\adfs\IdP\ADFS;
13+
use SimpleSAML\Metadata;
14+
use SimpleSAML\Session;
15+
use SimpleSAML\Utils;
16+
use SimpleSAML\XHTML\Template;
17+
use Symfony\Component\HttpFoundation\Request;
18+
use Symfony\Component\HttpFoundation\Response;
19+
use Symfony\Component\HttpFoundation\StreamedResponse;
20+
use Webmozart\Assert\Assert;
21+
22+
/**
23+
* Controller class for the adfs module.
24+
*
25+
* This class serves the adfs views available in the module.
26+
*
27+
* @package SimpleSAML\Module\adfs
28+
*/
29+
class AdfsController
30+
{
31+
/** @var \SimpleSAML\Configuration */
32+
protected $config;
33+
34+
/** @var \SimpleSAML\Metadata\MetaDataStorageHandler */
35+
protected $metadata;
36+
37+
/** @var \SimpleSAML\Session */
38+
protected $session;
39+
40+
/**
41+
* AdfsController constructor.
42+
*
43+
* @param \SimpleSAML\Configuration $config The configuration to use.
44+
* @param \SimpleSAML\Session $session The current user session.
45+
*/
46+
public function __construct(Configuration $config, Session $session)
47+
{
48+
$this->config = $config;
49+
$this->metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
50+
$this->session = $session;
51+
}
52+
53+
54+
/**
55+
* @param \Symfony\Component\HttpFoundation\Request $request
56+
* @return \Symfony\Component\HttpFoundation\Response|\SimpleSAML\XHTML\Template
57+
*/
58+
public function metadata(Request $request)
59+
{
60+
if (!$this->config->getBoolean('enable.adfs-idp', false)) {
61+
throw new SspError\Error('NOACCESS');
62+
}
63+
64+
// check if valid local session exists
65+
if ($this->config->getBoolean('admin.protectmetadata', false)) {
66+
Utils\Auth::requireAdmin();
67+
}
68+
69+
try {
70+
$idpentityid = isset($_GET['idpentityid']) ?
71+
$_GET['idpentityid'] : $this->metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
72+
$idpmeta = $this->metadata->getMetaDataConfig($idpentityid, 'adfs-idp-hosted');
73+
74+
$availableCerts = [];
75+
$keys = [];
76+
$certInfo = Utils\Crypto::loadPublicKey($idpmeta, false, 'new_');
77+
78+
if ($certInfo !== null) {
79+
$availableCerts['new_idp.crt'] = $certInfo;
80+
$keys[] = [
81+
'type' => 'X509Certificate',
82+
'signing' => true,
83+
'encryption' => true,
84+
'X509Certificate' => $certInfo['certData'],
85+
];
86+
$hasNewCert = true;
87+
} else {
88+
$hasNewCert = false;
89+
}
90+
91+
/** @var array $certInfo */
92+
$certInfo = Utils\Crypto::loadPublicKey($idpmeta, true);
93+
$availableCerts['idp.crt'] = $certInfo;
94+
$keys[] = [
95+
'type' => 'X509Certificate',
96+
'signing' => true,
97+
'encryption' => ($hasNewCert ? false : true),
98+
'X509Certificate' => $certInfo['certData'],
99+
];
100+
101+
if ($idpmeta->hasValue('https.certificate')) {
102+
/** @var array $httpsCert */
103+
$httpsCert = Utils\Crypto::loadPublicKey($idpmeta, true, 'https.');
104+
Assert::keyExists($httpsCert, 'certData');
105+
$availableCerts['https.crt'] = $httpsCert;
106+
$keys[] = [
107+
'type' => 'X509Certificate',
108+
'signing' => true,
109+
'encryption' => false,
110+
'X509Certificate' => $httpsCert['certData'],
111+
];
112+
}
113+
114+
$adfs_service_location = Module::getModuleURL('adfs').'/idp/prp.php';
115+
$metaArray = [
116+
'metadata-set' => 'adfs-idp-remote',
117+
'entityid' => $idpentityid,
118+
'SingleSignOnService' => [
119+
0 => [
120+
'Binding' => Constants::BINDING_HTTP_REDIRECT,
121+
'Location' => $adfs_service_location
122+
]
123+
],
124+
'SingleLogoutService' => [
125+
0 => [
126+
'Binding' => Constants::BINDING_HTTP_REDIRECT,
127+
'Location' => $adfs_service_location
128+
]
129+
],
130+
];
131+
132+
if (count($keys) === 1) {
133+
$metaArray['certData'] = $keys[0]['X509Certificate'];
134+
} else {
135+
$metaArray['keys'] = $keys;
136+
}
137+
138+
$metaArray['NameIDFormat'] = $idpmeta->getString(
139+
'NameIDFormat',
140+
Constants::NAMEID_TRANSIENT
141+
);
142+
143+
if ($idpmeta->hasValue('OrganizationName')) {
144+
$metaArray['OrganizationName'] = $idpmeta->getLocalizedString('OrganizationName');
145+
$metaArray['OrganizationDisplayName'] = $idpmeta->getLocalizedString(
146+
'OrganizationDisplayName',
147+
$metaArray['OrganizationName']
148+
);
149+
150+
if (!$idpmeta->hasValue('OrganizationURL')) {
151+
throw new SspError\Exception('If OrganizationName is set, OrganizationURL must also be set.');
152+
}
153+
$metaArray['OrganizationURL'] = $idpmeta->getLocalizedString('OrganizationURL');
154+
}
155+
156+
if ($idpmeta->hasValue('scope')) {
157+
$metaArray['scope'] = $idpmeta->getArray('scope');
158+
}
159+
160+
if ($idpmeta->hasValue('EntityAttributes')) {
161+
$metaArray['EntityAttributes'] = $idpmeta->getArray('EntityAttributes');
162+
}
163+
164+
if ($idpmeta->hasValue('UIInfo')) {
165+
$metaArray['UIInfo'] = $idpmeta->getArray('UIInfo');
166+
}
167+
168+
if ($idpmeta->hasValue('DiscoHints')) {
169+
$metaArray['DiscoHints'] = $idpmeta->getArray('DiscoHints');
170+
}
171+
172+
if ($idpmeta->hasValue('RegistrationInfo')) {
173+
$metaArray['RegistrationInfo'] = $idpmeta->getArray('RegistrationInfo');
174+
}
175+
176+
$metaflat = '$metadata['.var_export($idpentityid, true).'] = '.var_export($metaArray, true).';';
177+
178+
$metaBuilder = new Metadata\SAMLBuilder($idpentityid);
179+
$metaBuilder->addSecurityTokenServiceType($metaArray);
180+
$metaBuilder->addOrganizationInfo($metaArray);
181+
$technicalContactEmail = $this->config->getString('technicalcontact_email', null);
182+
if ($technicalContactEmail && $technicalContactEmail !== 'na@example.org') {
183+
$metaBuilder->addContact('technical', Utils\Config\Metadata::getContact([
184+
'emailAddress' => $technicalContactEmail,
185+
'name' => $this->config->getString('technicalcontact_name', null),
186+
'contactType' => 'technical',
187+
]));
188+
}
189+
$output_xhtml = array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml';
190+
$metaxml = $metaBuilder->getEntityDescriptorText($output_xhtml);
191+
if (!$output_xhtml) {
192+
$metaxml = str_replace("\n", '', $metaxml);
193+
}
194+
195+
// sign the metadata if enabled
196+
$metaxml = Metadata\Signer::sign($metaxml, $idpmeta->toArray(), 'ADFS IdP');
197+
198+
if ($output_xhtml) {
199+
$t = new Template($this->config, 'metadata.php', 'admin');
200+
201+
$t->data['clipboard.js'] = true;
202+
$t->data['available_certs'] = $availableCerts;
203+
$certdata = [];
204+
foreach (array_keys($availableCerts) as $availableCert) {
205+
$certdata[$availableCert]['name'] = $availableCert;
206+
$certdata[$availableCert]['url'] = Module::getModuleURL('saml/idp/certs.php').
207+
'/'.$availableCert;
208+
209+
$certdata[$availableCert]['comment'] = '';
210+
if ($availableCerts[$availableCert]['certFingerprint'][0] === 'afe71c28ef740bc87425be13a2263d37971da1f9') {
211+
$certdata[$availableCert]['comment'] = 'This is the default certificate.'.
212+
' Generate a new certificate if this is a production system.';
213+
}
214+
}
215+
$t->data['certdata'] = $certdata;
216+
$t->data['header'] = 'adfs-idp'; // TODO: Replace with headerString in 2.0
217+
$t->data['headerString'] = Translate::noop('metadata_adfs-idp');
218+
$t->data['metaurl'] = Utils\HTTP::getSelfURLNoQuery();
219+
$t->data['metadata'] = htmlspecialchars($metaxml);
220+
$t->data['metadataflat'] = htmlspecialchars($metaflat);
221+
222+
return $t;
223+
} else {
224+
// make sure to export only the md:EntityDescriptor
225+
$i = strpos($metaxml, '<md:EntityDescriptor');
226+
$metaxml = substr($metaxml, $i ? $i : 0);
227+
228+
// 22 = strlen('</md:EntityDescriptor>')
229+
$i = strrpos($metaxml, '</md:EntityDescriptor>');
230+
$metaxml = substr($metaxml, 0, $i ? $i + 22 : 0);
231+
232+
$response = new Response();
233+
$response->headers->set('Content-Type', 'application/xml');
234+
$response->setContent($metaxml);
235+
236+
return $response;
237+
}
238+
} catch (\Exception $exception) {
239+
throw new SspError\Error('METADATA', $exception);
240+
}
241+
}
242+
243+
244+
/**
245+
* @param \Symfony\Component\HttpFoundation\Request $request
246+
* @return \Symfony\Component\HttpFoundation\Response
247+
*/
248+
public function prp(Request $request)
249+
{
250+
Logger::info('ADFS - IdP.prp: Accessing ADFS IdP endpoint prp');
251+
252+
$idpEntityId = $this->metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
253+
$idp = IdP::getById('adfs:'.$idpEntityId);
254+
255+
if (isset($_GET['wa'])) {
256+
if ($_GET['wa'] === 'wsignout1.0') {
257+
return new StreamedResponse(
258+
/** @return void */
259+
function () use ($idp) {
260+
ADFS::receiveLogoutMessage($idp);
261+
}
262+
);
263+
} elseif ($_GET['wa'] === 'wsignin1.0') {
264+
return new StreamedResponse(
265+
/** @return void */
266+
function () use ($idp) {
267+
ADFS::receiveAuthnRequest($idp);
268+
}
269+
);
270+
}
271+
throw new SspError\BadRequest("Unsupported value for 'wa' specified in request.");
272+
} elseif (isset($_GET['assocId'])) {
273+
// logout response from ADFS SP
274+
$assocId = $_GET['assocId']; // Association ID of the SP that sent the logout response
275+
$relayState = $_GET['relayState']; // Data that was sent in the logout request to the SP. Can be null
276+
$logoutError = null; // null on success, or an instance of a \SimpleSAML\Error\Exception on failure.
277+
278+
return new StreamedResponse(
279+
/** @return void */
280+
function () use ($idp, $assocId, $relayState, $logoutError) {
281+
$idp->handleLogoutResponse($assocId, $relayState, $logoutError);
282+
}
283+
);
284+
}
285+
throw new SspError\BadRequest("Missing parameter 'wa' or 'assocId' in request.");
286+
}
287+
}

lib/IdP/ADFS.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ private static function generateResponse($issuer, $target, $nameid, $attributes,
138138
* @param string $key
139139
* @param string $cert
140140
* @param string $algo
141+
* @param string|null $passphrase
141142
* @return string
142143
*/
143144
private static function signResponse($response, $key, $cert, $algo, $passphrase)

0 commit comments

Comments
 (0)