Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/discopower.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ This causes SimpleSAMLphp to use DiscoPower in preference to the built-in discov
Arranging identity providers onto tabs
--------------------------------------

DiscoPower determines its list of identity providers by parsing the [IdP remote metadata](https://simplesamlphp.org/docs/stable/simplesamlphp-reference-idp-remote) in both the `saml20-idp-remote` and `shib13-idp-remote` sets.
DiscoPower determines its list of identity providers by parsing the [IdP remote metadata](https://simplesamlphp.org/docs/stable/simplesamlphp-reference-idp-remote).

In order to specify which tab(s) an identity provider should be displayed on, you can set the `tabs` attribute in the entity's metadata. If you're using locally hosted metadata, you can do this by simply editing your metadata as follows:

Expand Down Expand Up @@ -121,4 +121,4 @@ where the `$entities` parameter is a reference to an array containing the metada
Interacting with metarefresh
----------------------------

If you're making use of the [metarefresh](https://github.com/simplesamlphp/simplesamlphp-module-metarefresh) module for automated metadata management, then you need to add any metadata paramters into the appropriate `template` in `config/config-metarefresh.php` so that they get applied each time metadata is refreshed.
If you're making use of the [metarefresh](https://github.com/simplesamlphp/simplesamlphp-module-metarefresh) module for automated metadata management, then you need to add any metadata paramters into the appropriate `template` in `config/config-metarefresh.php` so that they get applied each time metadata is refreshed.
81 changes: 81 additions & 0 deletions lib/Controller/DiscoPower.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\Module\discopower\Controller;

use Exception;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\HTTP\RunnableResponse;
use SimpleSAML\Module\discopower\PowerIdPDisco;
use SimpleSAML\Session;
use SimpleSAML\XHTML\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;

class DiscoPower
{
/**
* @param \Symfony\Component\HttpFoundation\Request $request The current request.
* @return \SimpleSAML\HTTP\RunnableResponse
*/
public function main(Request $request): RunnableResponse
{
try {
$discoHandler = new PowerIdPDisco(
['saml20-idp-remote'],
'poweridpdisco'
);
} catch (Exception $exception) {
// An error here should be caused by invalid query parameters
throw new Error\Error('DISCOPARAMS', $exception);
}

try {
return new RunnableResponse([$discoHandler, 'handleRequest'], []);
} catch (Exception $exception) {
// An error here should be caused by metadata
throw new Error\Error('METADATA', $exception);
}
}

/**
* An AJAX handler to retrieve a list of disco tabs from the session.
* This allows us to dynamically update the tab list without inline javascript.
*
* @param \Symfony\Component\HttpFoundation\Request $request The current request.
*/
public function tablist(Request $request): Response
{
$session = Session::getSessionFromRequest();
$tabs = $session->getData('discopower:tabList', 'tabs');
$faventry = $session->getData('discopower:tabList', 'faventry');
$defaulttab = $session->getData('discopower:tabList', 'defaulttab');

if (!is_array($tabs)) {
throw new Error\Exception('Could not get tab list from session');
}

$response = new JsonResponse();

// handle JSONP requests
if ($request->query->has('callback')) {
$callback = $request->query->get('callback');
if (!preg_match('/^[a-z0-9_]+$/i', $callback)) {
throw new Error\Exception('Unsafe JSONP callback function name ' . var_export($callback, true));
}
$response->setCallback($callback);
}

$response->setData(
[
'faventry' => $faventry,
'default' => $defaulttab,
'tabs' => $tabs,
]
);
return $response;
}
}
6 changes: 6 additions & 0 deletions routing/routes/routes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
discopower-main:
path: /disco.php
defaults: { _controller: 'SimpleSAML\Module\discopower\Controller\DiscoPower::main' }
discopower-tablist:
path: /tablist
defaults: { _controller: 'SimpleSAML\Module\discopower\Controller\DiscoPower::tablist' }
121 changes: 121 additions & 0 deletions tests/lib/Controller/DiscoPowerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\Test\Module\discopower\Controller;

use PHPUnit\Framework\TestCase;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\Module\discopower\Controller;
use SimpleSAML\Session;
use SimpleSAML\TestUtils\ClearStateTestCase;
use SimpleSAML\XHTML\Template;
use Symfony\Component\HttpFoundation\Request;

/**
* Set of tests for the controllers in the "discopwer" module.
*
* @covers \SimpleSAML\Module\discopower\Controller\DiscoPower
*/
class DiscoPowerTest extends ClearStateTestCase
{
/**
* Set up for each test.
*/
protected function setUp(): void
{
parent::setUp();

$this->config = Configuration::loadFromArray(
[
'module.enable' => ['discopower' => true],
],
'[ARRAY]',
'simplesaml'
);

Configuration::setPreLoadedConfig($this->config, 'config.php');
}

public function testDiscoPowerNoDiscoParams(): void
{
$request = Request::create(
'/disco.php',
'GET'
);

$c = new Controller\DiscoPower();

$this->expectException(Error\Error::class);
$this->expectExceptionMessage("DISCOPARAMS");
$r = $c->main($request);
}

public function testTablistJson(): void
{
$session = Session::getSessionFromRequest();
$session->setData('discopower:tabList', 'faventry', 'http://example.org/idp');
$session->setData('discopower:tabList', 'tabs', ['Frankrijk', 'Nederland', 'Duitsland']);
$session->setData('discopower:tabList', 'defaulttab', 'Nederland');

$request = Request::create(
'/tablist',
'GET'
);

$c = new Controller\DiscoPower();

$r = $c->tablist($request);
$this->assertTrue($r->isSuccessful());
$this->assertEquals('application/json', $r->headers->get('Content-Type'));
$this->assertEquals('{"faventry":"http:\/\/example.org\/idp","default":"Nederland","tabs":["Frankrijk","Nederland","Duitsland"]}', $r->getContent());

$request = Request::create(
'/tablist',
'GET',
['callback' => 'aapnoot'],
);

$c = new Controller\DiscoPower();

$r = $c->tablist($request);
$this->assertTrue($r->isSuccessful());
$this->assertEquals('text/javascript', $r->headers->get('Content-Type'));
$this->assertEquals('/**/aapnoot({"faventry":"http:\/\/example.org\/idp","default":"Nederland","tabs":["Frankrijk","Nederland","Duitsland"]});', $r->getContent());
}

public function testTablistJsonNoSession(): void
{
$request = Request::create(
'/tablist',
'GET',
);

$c = new Controller\DiscoPower();

$this->expectException(Error\Exception::class);
$this->expectExceptionMessage("Could not get tab list from session");
$r = $c->tablist($request);
}

public function testTablistJsonUnsafeCallback(): void
{
$session = Session::getSessionFromRequest();
$session->setData('discopower:tabList', 'faventry', 'http://example.org/idp');
$session->setData('discopower:tabList', 'tabs', ['Frankrijk', 'Nederland', 'Duitsland']);
$session->setData('discopower:tabList', 'defaulttab', 'Nederland');

$request = Request::create(
'/tablist',
'GET',
['callback' => 'alert("hallo")'],
);

$c = new Controller\DiscoPower();

$this->expectException(Error\Exception::class);
$this->expectExceptionMessage("Unsafe JSONP callback");
$r = $c->tablist($request);
}
}
2 changes: 1 addition & 1 deletion www/assets/js/tablist.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
$(document).ready(function () {
$("#tabdiv").tabs();
$.getJSON("tablist.php", function (data) {
$.getJSON("tablist", function (data) {
$("#tabdiv").select(data["default"]);
for (var i = 0; i < data["tabs"].length; i++) {
var tab = data["tabs"][i];
Expand Down
18 changes: 0 additions & 18 deletions www/disco.php

This file was deleted.

42 changes: 0 additions & 42 deletions www/tablist.php

This file was deleted.