Skip to content
Snippets Groups Projects
Commit 9df060d0 authored by Marko Ivancic's avatar Marko Ivancic
Browse files

WIP

parent 55e47c94
No related branches found
No related tags found
1 merge request!11Show service logo if available
Pipeline #83538 passed
Showing
with 179 additions and 21 deletions
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:none;}</style></defs><title>no-image</title><path d="M30,3.4141,28.5859,2,2,28.5859,3.4141,30l2-2H26a2.0027,2.0027,0,0,0,2-2V5.4141ZM26,26H7.4141l7.7929-7.793,2.3788,2.3787a2,2,0,0,0,2.8284,0L22,19l4,3.9973Zm0-5.8318-2.5858-2.5859a2,2,0,0,0-2.8284,0L19,19.1682l-2.377-2.3771L26,7.4141Z"/><path d="M6,22V19l5-4.9966,1.3733,1.3733,1.4159-1.416-1.375-1.375a2,2,0,0,0-2.8284,0L6,16.1716V6H22V4H6A2.002,2.002,0,0,0,4,6V22Z"/><rect id="_Transparent_Rectangle_" data-name="&lt;Transparent Rectangle&gt;" class="cls-1" width="32" height="32"/></svg>
\ No newline at end of file
...@@ -6,15 +6,18 @@ namespace SimpleSAML\Module\accounting\Entities\Bases; ...@@ -6,15 +6,18 @@ namespace SimpleSAML\Module\accounting\Entities\Bases;
use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
use SimpleSAML\Module\accounting\Entities\Interfaces\ProviderInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\ProviderInterface;
use SimpleSAML\Module\accounting\Services\HelpersManager;
abstract class AbstractProvider implements ProviderInterface abstract class AbstractProvider implements ProviderInterface
{ {
protected array $metadata; protected array $metadata;
protected HelpersManager $helpersManager;
protected string $entityId; protected string $entityId;
public function __construct(array $metadata) public function __construct(array $metadata, HelpersManager $helpersManager = null)
{ {
$this->metadata = $metadata; $this->metadata = $metadata;
$this->helpersManager = $helpersManager ?? new HelpersManager();
$this->entityId = $this->resolveEntityId(); $this->entityId = $this->resolveEntityId();
} }
...@@ -57,6 +60,7 @@ abstract class AbstractProvider implements ProviderInterface ...@@ -57,6 +60,7 @@ abstract class AbstractProvider implements ProviderInterface
abstract public function getName(string $locale = self::DEFAULT_LOCALE): ?string; abstract public function getName(string $locale = self::DEFAULT_LOCALE): ?string;
abstract public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string; abstract public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string;
abstract public function getLogoUrl(): ?string;
abstract protected function resolveEntityId(): string; abstract protected function resolveEntityId(): string;
abstract public function getProtocol(): AuthenticationProtocolInterface; abstract public function getProtocol(): AuthenticationProtocolInterface;
abstract protected function getProviderDescription(): string; abstract protected function getProviderDescription(): string;
......
...@@ -15,5 +15,6 @@ interface ProviderInterface ...@@ -15,5 +15,6 @@ interface ProviderInterface
public function getName(string $locale = self::DEFAULT_LOCALE): ?string; public function getName(string $locale = self::DEFAULT_LOCALE): ?string;
public function getEntityId(): string; public function getEntityId(): string;
public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string; public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string;
public function getLogoUrl(): ?string;
public function getProtocol(): AuthenticationProtocolInterface; public function getProtocol(): AuthenticationProtocolInterface;
} }
<?php
namespace SimpleSAML\Module\accounting\Entities\Providers\Bases;
use SimpleSAML\Module\accounting\Entities\Authentication;
use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
abstract class AbstractOidcProvider extends AbstractProvider
{
public const METADATA_KEY_LOGO_URI = 'logo_uri';
abstract public function getName(string $locale = self::DEFAULT_LOCALE): ?string;
abstract public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string;
abstract protected function resolveEntityId(): string;
abstract protected function getProviderDescription(): string;
public function getLogoUrl(): ?string
{
if (
!empty($this->metadata[self::METADATA_KEY_LOGO_URI]) &&
is_string($this->metadata[self::METADATA_KEY_LOGO_URI])
) {
return $this->metadata[self::METADATA_KEY_LOGO_URI];
}
return null;
}
public function getProtocol(): AuthenticationProtocolInterface
{
return new Authentication\Protocol\Oidc();
}
}
...@@ -15,6 +15,8 @@ abstract class AbstractSaml2Provider extends AbstractProvider ...@@ -15,6 +15,8 @@ abstract class AbstractSaml2Provider extends AbstractProvider
public const METADATA_KEY_UI_INFO = 'UIInfo'; public const METADATA_KEY_UI_INFO = 'UIInfo';
public const METADATA_KEY_UI_INFO_DESCRIPTION = 'Description'; public const METADATA_KEY_UI_INFO_DESCRIPTION = 'Description';
public const METADATA_KEY_UI_INFO_DISPLAY_NAME = 'DisplayName'; public const METADATA_KEY_UI_INFO_DISPLAY_NAME = 'DisplayName';
public const METADATA_KEY_UI_INFO_LOGO = 'Logo';
public const METADATA_KEY_UI_INFO_LOGO_URL = 'url';
protected function getEntityInfoString(string $key, string $locale = self::DEFAULT_LOCALE): ?string protected function getEntityInfoString(string $key, string $locale = self::DEFAULT_LOCALE): ?string
{ {
...@@ -49,6 +51,30 @@ abstract class AbstractSaml2Provider extends AbstractProvider ...@@ -49,6 +51,30 @@ abstract class AbstractSaml2Provider extends AbstractProvider
$this->getEntityUiInfoString(self::METADATA_KEY_UI_INFO_DESCRIPTION, $locale); $this->getEntityUiInfoString(self::METADATA_KEY_UI_INFO_DESCRIPTION, $locale);
} }
public function getLogoUrl(): ?string
{
$logoElement = $this->helpersManager->getArr()->getNestedElementByKey(
$this->metadata,
self::METADATA_KEY_UI_INFO,
self::METADATA_KEY_UI_INFO_LOGO,
0,
self::METADATA_KEY_UI_INFO_LOGO_URL
);
if (!is_array($logoElement)) {
return null;
}
/** @var mixed $logoUrl */
$logoUrl = current($logoElement);
if (is_string($logoUrl) && filter_var($logoUrl, FILTER_VALIDATE_URL)) {
return $logoUrl;
}
return null;
}
/** /**
* @throws MetadataException * @throws MetadataException
*/ */
......
...@@ -4,13 +4,11 @@ declare(strict_types=1); ...@@ -4,13 +4,11 @@ declare(strict_types=1);
namespace SimpleSAML\Module\accounting\Entities\Providers\Identity; namespace SimpleSAML\Module\accounting\Entities\Providers\Identity;
use SimpleSAML\Module\accounting\Entities\Authentication;
use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface;
use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider;
use SimpleSAML\Module\accounting\Exceptions\MetadataException; use SimpleSAML\Module\accounting\Exceptions\MetadataException;
class Oidc extends AbstractProvider implements IdentityProviderInterface class Oidc extends AbstractOidcProvider implements IdentityProviderInterface
{ {
public const METADATA_KEY_ENTITY_ID = 'issuer'; public const METADATA_KEY_ENTITY_ID = 'issuer';
...@@ -39,11 +37,6 @@ class Oidc extends AbstractProvider implements IdentityProviderInterface ...@@ -39,11 +37,6 @@ class Oidc extends AbstractProvider implements IdentityProviderInterface
throw new MetadataException('OpenID VersionedDataProvider metadata does not contain entity ID.'); throw new MetadataException('OpenID VersionedDataProvider metadata does not contain entity ID.');
} }
public function getProtocol(): AuthenticationProtocolInterface
{
return new Authentication\Protocol\Oidc();
}
protected function getProviderDescription(): string protected function getProviderDescription(): string
{ {
return $this->getProtocol()->getDesignation() . ' OpenID Provider'; return $this->getProtocol()->getDesignation() . ' OpenID Provider';
......
...@@ -4,13 +4,11 @@ declare(strict_types=1); ...@@ -4,13 +4,11 @@ declare(strict_types=1);
namespace SimpleSAML\Module\accounting\Entities\Providers\Service; namespace SimpleSAML\Module\accounting\Entities\Providers\Service;
use SimpleSAML\Module\accounting\Entities\Authentication;
use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider;
use SimpleSAML\Module\accounting\Exceptions\MetadataException; use SimpleSAML\Module\accounting\Exceptions\MetadataException;
class Oidc extends AbstractProvider implements ServiceProviderInterface class Oidc extends AbstractOidcProvider implements ServiceProviderInterface
{ {
public const METADATA_KEY_ENTITY_ID = 'id'; public const METADATA_KEY_ENTITY_ID = 'id';
public const METADATA_KEY_NAME = 'name'; public const METADATA_KEY_NAME = 'name';
...@@ -41,11 +39,6 @@ class Oidc extends AbstractProvider implements ServiceProviderInterface ...@@ -41,11 +39,6 @@ class Oidc extends AbstractProvider implements ServiceProviderInterface
throw new MetadataException('Relying VersionedDataProvider metadata does not contain entity ID.'); throw new MetadataException('Relying VersionedDataProvider metadata does not contain entity ID.');
} }
public function getProtocol(): AuthenticationProtocolInterface
{
return new Authentication\Protocol\Oidc();
}
protected function getProviderDescription(): string protected function getProviderDescription(): string
{ {
return $this->getProtocol()->getDesignation() . ' Relying Party'; return $this->getProtocol()->getDesignation() . ' Relying Party';
......
...@@ -37,4 +37,33 @@ class Arr ...@@ -37,4 +37,33 @@ class Arr
$keys = array_keys($array); $keys = array_keys($array);
return $keys !== array_keys($keys); return $keys !== array_keys($keys);
} }
/**
* @param array $array
* @param string|int ...$keys
* @return array|null
*/
public function getNestedElementByKey(array $array, ...$keys): ?array
{
$element = $array;
foreach ($keys as $key) {
if (!is_array($element)) {
return null;
}
if (!isset($element[$key])) {
return null;
}
/** @var mixed $element */
$element = $element[$key];
}
if (is_array($element)) {
return $element;
}
return [$element];
}
} }
...@@ -20,7 +20,14 @@ ...@@ -20,7 +20,14 @@
{% for connectedServiceProvider in connectedServiceProviderBag.getAll %} {% for connectedServiceProvider in connectedServiceProviderBag.getAll %}
<tr id="connected-service-provider-{{ loop.index }}"> <tr id="connected-service-provider-{{ loop.index }}">
<td>{{ connectedServiceProvider.getServiceProvider.getName|e }}</td> <td>
<img src="{{ connectedServiceProvider.serviceProvider.logoUrl ?? asset('css/src/icons/no-image.svg', 'accounting') }}"
width="30"
height="30"
loading="lazy"
alt="Service Logo"/>
{{ connectedServiceProvider.getServiceProvider.getName|e }}
</td>
<td>{{ connectedServiceProvider.getNumberOfAuthentications|e }}</td> <td>{{ connectedServiceProvider.getNumberOfAuthentications|e }}</td>
<td>{{ connectedServiceProvider.getLastAuthenticationAt|date() }}</td> <td>{{ connectedServiceProvider.getLastAuthenticationAt|date() }}</td>
</tr> </tr>
......
...@@ -44,7 +44,22 @@ final class StateArrays ...@@ -44,7 +44,22 @@ final class StateArrays
'metadata-index' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp', 'metadata-index' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
'metadata-set' => 'saml20-sp-remote', 'metadata-set' => 'saml20-sp-remote',
'name' => 'Test service', 'name' => 'Test service',
'description' => 'Test service description' 'description' => 'Test service description',
'UIInfo' => [
'DisplayName' => [
'en' => 'Test service UiInfo',
],
'Description' => [
'en' => 'Test service description UiInfo',
],
'Logo' => [
[
'url' => 'https://placehold.co/100x80/orange/white?text=test',
'height' => 80,
'width' => 100,
],
],
],
], ],
'saml:RelayState' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/admin/test/default-sp', 'saml:RelayState' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/admin/test/default-sp',
'saml:RequestId' => null, 'saml:RequestId' => null,
...@@ -117,6 +132,21 @@ final class StateArrays ...@@ -117,6 +132,21 @@ final class StateArrays
'entityid' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp', 'entityid' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
'metadata-index' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp', 'metadata-index' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
'metadata-set' => 'saml20-sp-remote', 'metadata-set' => 'saml20-sp-remote',
'UIInfo' => [
'DisplayName' => [
'en' => 'Test service UiInfo',
],
'Description' => [
'en' => 'Test service description UiInfo',
],
'Logo' => [
[
'url' => 'https://placehold.co/100x80/orange/white?text=test',
'height' => 80,
'width' => 100,
],
],
],
], ],
'Source' => [ 'Source' => [
'host' => 'localhost.someone.from.hr', 'host' => 'localhost.someone.from.hr',
......
...@@ -117,6 +117,11 @@ class AbstractProviderTest extends TestCase ...@@ -117,6 +117,11 @@ class AbstractProviderTest extends TestCase
{ {
return 'provider description'; return 'provider description';
} }
public function getLogoUrl(): ?string
{
return 'https://example.org/logo';
}
}; };
} }
} }
...@@ -11,6 +11,7 @@ use SimpleSAML\Module\accounting\Exceptions\MetadataException; ...@@ -11,6 +11,7 @@ use SimpleSAML\Module\accounting\Exceptions\MetadataException;
/** /**
* @covers \SimpleSAML\Module\accounting\Entities\Providers\Identity\Oidc * @covers \SimpleSAML\Module\accounting\Entities\Providers\Identity\Oidc
* @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
* @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider
*/ */
class OidcTest extends TestCase class OidcTest extends TestCase
{ {
......
...@@ -11,6 +11,7 @@ use SimpleSAML\Module\accounting\Exceptions\MetadataException; ...@@ -11,6 +11,7 @@ use SimpleSAML\Module\accounting\Exceptions\MetadataException;
/** /**
* @covers \SimpleSAML\Module\accounting\Entities\Providers\Service\Oidc * @covers \SimpleSAML\Module\accounting\Entities\Providers\Service\Oidc
* @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
* @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider
*/ */
class OidcTest extends TestCase class OidcTest extends TestCase
{ {
......
...@@ -70,4 +70,36 @@ class ArrayTest extends TestCase ...@@ -70,4 +70,36 @@ class ArrayTest extends TestCase
$this->assertTrue((new Arr())->isAssociative($associative)); $this->assertTrue((new Arr())->isAssociative($associative));
$this->assertTrue((new Arr())->isAssociative($mixed)); $this->assertTrue((new Arr())->isAssociative($mixed));
} }
public function testGetNestedElementByKey(): void
{
$simpleIndexed = [1, 2, 3];
$nestedIndexed = [[1, [2, [4, [5]]]], [3, 4]];
$nestedAssociative = ['a' => ['b' => 'c'], 'd' => 'e'];
$arrHelper = new Arr();
$this->assertSame($arrHelper->getNestedElementByKey($simpleIndexed, 0), [1]);
$this->assertNull($arrHelper->getNestedElementByKey($simpleIndexed, 3));
$this->assertNull($arrHelper->getNestedElementByKey($simpleIndexed, 'a'));
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0), [1, [2, [4, [5]]]]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0), [1, [2, [4, [5]]]]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 0), [1]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1), [2, [4, [5]]]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1, 0), [2]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1, 1), [4, [5]]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1, 1, 0), [4]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1, 1, 1), [5]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 1), [3, 4]);
$this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 1, 0), [3]);
$this->assertNull($arrHelper->getNestedElementByKey($nestedIndexed, 3));
$this->assertNull($arrHelper->getNestedElementByKey($nestedIndexed, 'a'));
$this->assertSame($arrHelper->getNestedElementByKey($nestedAssociative, 'a'), ['b' => 'c']);
$this->assertSame($arrHelper->getNestedElementByKey($nestedAssociative, 'a', 'b'), ['c']);
$this->assertSame($arrHelper->getNestedElementByKey($nestedAssociative, 'd'), ['e']);
$this->assertNull($arrHelper->getNestedElementByKey($nestedAssociative, 3));
$this->assertNull($arrHelper->getNestedElementByKey($nestedAssociative, 'f'));
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment