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

Merge branch 'oidc' into 'main'

Enable revoking OIDC tokens

See merge request !5
parents 70141eda faf9e61c
Branches
No related tags found
1 merge request!5Enable revoking OIDC tokens
Pipeline #79947 passed
Showing
with 2891 additions and 517 deletions
......@@ -35,7 +35,7 @@ jobs:
test-latest:
runs-on: ubuntu-latest
container:
image: cicnavi/dap:08
image: cicnavi/dap:81
steps:
- uses: actions/checkout@v3
- name: Validate composer.json and composer.lock
......
......@@ -20,10 +20,10 @@ test-74:
- composer install --prefer-dist --no-progress --no-suggest
- composer run-script pre-commit
# PHP latest
test-08:
# PHP v8.1
test-81:
stage: test
image: cicnavi/dap:08
image: cicnavi/dap:81
script:
- composer install --prefer-dist --no-progress --no-suggest
- composer run-script pre-commit
......@@ -28,6 +28,7 @@
"php": "^7.4 || ^8.0",
"ext-pdo": "*",
"ext-pdo_sqlite": "*",
"composer-runtime-api": "^2.0",
"doctrine/dbal": "^3",
"psr/log": "^1|^2|^3",
"simplesamlphp/composer-module-installer": "^1",
......@@ -37,8 +38,9 @@
"vimeo/psalm": "^5",
"phpunit/phpunit": "^9",
"squizlabs/php_codesniffer": "^3",
"simplesamlphp/simplesamlphp": "^2@beta",
"simplesamlphp/simplesamlphp-test-framework": "^1"
"simplesamlphp/simplesamlphp": "^2",
"simplesamlphp/simplesamlphp-test-framework": "^1",
"simplesamlphp/simplesamlphp-module-oidc": "^3"
},
"suggest": {
"ext-pcntl": "Enables job runner to gracefully respond to SIGTERM signal.",
......
This diff is collapsed.
......@@ -3,7 +3,7 @@
declare(strict_types=1);
use SimpleSAML\Locale\Translate;
use SimpleSAML\Module\accounting\Helpers\ModuleRoutes;
use SimpleSAML\Module\accounting\Helpers\Routes;
use SimpleSAML\Module\accounting\ModuleConfiguration;
use SimpleSAML\XHTML\Template;
......@@ -12,11 +12,11 @@ function accounting_hook_adminmenu(Template &$template): void
{
$menuKey = 'menu';
$moduleRoutesHelper = new ModuleRoutes();
$moduleRoutesHelper = new Routes();
$profilePageEntry = [
ModuleConfiguration::MODULE_NAME => [
'url' => $moduleRoutesHelper->getUrl(ModuleRoutes::PATH_USER_PERSONAL_DATA),
'url' => $moduleRoutesHelper->getUrl(Routes::PATH_USER_PERSONAL_DATA),
'name' => Translate::noop('Profile Page'),
],
];
......
......@@ -3,14 +3,14 @@
declare(strict_types=1);
use SimpleSAML\Locale\Translate;
use SimpleSAML\Module\accounting\Helpers\ModuleRoutes;
use SimpleSAML\Module\accounting\Helpers\Routes;
use SimpleSAML\Module\accounting\ModuleConfiguration;
use SimpleSAML\XHTML\Template;
/** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection Reference is used by SimpleSAMLphp */
function accounting_hook_configpage(Template &$template): void
{
$moduleRoutesHelper = new ModuleRoutes();
$moduleRoutesHelper = new Routes();
$dataLinksKey = 'links';
......@@ -19,7 +19,7 @@ function accounting_hook_configpage(Template &$template): void
}
$template->data[$dataLinksKey][] = [
'href' => $moduleRoutesHelper->getUrl(ModuleRoutes::PATH_ADMIN_CONFIGURATION_STATUS),
'href' => $moduleRoutesHelper->getUrl(Routes::PATH_ADMIN_CONFIGURATION_STATUS),
'text' => Translate::noop('Accounting configuration status'),
];
......
......@@ -39,4 +39,4 @@
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
\ No newline at end of file
}
......@@ -458,4 +458,30 @@
display: none;
}
}
\ No newline at end of file
}
/** Alerts */
/* The alert message box */
.alerts .alert {
padding: 20px;
margin-bottom: 15px;
}
/* The close button */
.close-btn {
margin-left: 15px;
color: white;
font-weight: bold;
float: right;
font-size: 22px;
line-height: 20px;
cursor: pointer;
transition: 0.3s;
}
/* When moving the mouse over the close button */
.close-btn:hover {
color: black;
}
accounting-admin-configuration-status:
path: /admin/configuration/status
defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\Admin\Configuration::status' }
controller: SimpleSAML\Module\accounting\Http\Controllers\Admin\Configuration::status
accounting-user-personal-data:
path: /user/personal-data
defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::personalData' }
controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::personalData
accounting-user-connected-organizations:
path: /user/connected-organizations
defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::connectedOrganizations' }
controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::connectedOrganizations
accounting-user-activity:
path: /user/activity
defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::activity' }
controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::activity
accounting-user-oidc-tokens:
path: /user/oidc-tokens
controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::oidcTokens
accounting-user-oidc-token-revoke:
path: /user/oidc-tokens/revoke
controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::oidcTokenRevoke
methods: POST
accounting-user-oidc-token-revoke-xhr:
path: /user/oidc-tokens/revoke-xhr
controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::oidcTokenRevokeXhr
methods: POST
accounting-user-logout:
path: /user/logout
controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::logout
methods:
- GET
- POST
defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::logout' }
......@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SimpleSAML\Module\accounting\Entities\Bases;
use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
use SimpleSAML\Module\accounting\Entities\Interfaces\ProviderInterface;
abstract class AbstractProvider implements ProviderInterface
......@@ -52,4 +53,5 @@ abstract class AbstractProvider implements ProviderInterface
abstract public function getName(string $locale = 'en'): ?string;
abstract public function getDescription(string $locale = 'en'): ?string;
abstract protected function resolveEntityId(): string;
abstract public function getProtocol(): AuthenticationProtocolInterface;
}
......@@ -9,10 +9,13 @@ use SimpleSAML\Module\accounting\Entities\Interfaces\StateInterface;
use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
use SimpleSAML\Module\accounting\Services\HelpersManager;
use DateTimeImmutable;
use SimpleSAML\Module\accounting\Traits\HasUserAttributesTrait;
use Throwable;
abstract class AbstractState implements StateInterface
{
use HasUserAttributesTrait;
public const KEY_ATTRIBUTES = 'Attributes';
public const KEY_ACCOUNTING = 'accounting';
public const ACCOUNTING_KEY_CLIENT_IP_ADDRESS = 'client_ip_address';
......@@ -20,7 +23,6 @@ abstract class AbstractState implements StateInterface
protected string $identityProviderEntityId;
protected string $serviceProviderEntityId;
protected array $attributes;
protected DateTimeImmutable $createdAt;
protected ?DateTimeImmutable $authenticationInstant;
protected array $identityProviderMetadata;
......@@ -99,29 +101,6 @@ abstract class AbstractState implements StateInterface
return $this->serviceProviderEntityId;
}
public function getAttributes(): array
{
return $this->attributes;
}
public function getFirstAttributeValue(string $attributeName): ?string
{
if (($value = $this->getAttributeValue($attributeName)) !== null) {
return (string)reset($value);
}
return null;
}
public function getAttributeValue(string $attributeName): ?array
{
if (!empty($this->attributes[$attributeName]) && is_array($this->attributes[$attributeName])) {
return $this->attributes[$attributeName];
}
return null;
}
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
......
......@@ -13,4 +13,5 @@ interface ProviderInterface
public function getName(string $locale = 'en'): ?string;
public function getEntityId(): string;
public function getDescription(string $locale = 'en'): ?string;
public function getProtocol(): AuthenticationProtocolInterface;
}
......@@ -4,7 +4,9 @@ declare(strict_types=1);
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\Exceptions\MetadataException;
......@@ -36,4 +38,9 @@ class Oidc extends AbstractProvider implements IdentityProviderInterface
throw new MetadataException('OpenID Provider metadata does not contain entity ID.');
}
public function getProtocol(): AuthenticationProtocolInterface
{
return new Authentication\Protocol\Oidc();
}
}
......@@ -4,7 +4,9 @@ declare(strict_types=1);
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\Exceptions\MetadataException;
......@@ -38,4 +40,9 @@ class Saml2 extends AbstractProvider implements IdentityProviderInterface
throw new MetadataException('Identity provider metadata does not contain entity ID.');
}
public function getProtocol(): AuthenticationProtocolInterface
{
return new Authentication\Protocol\Saml2();
}
}
......@@ -4,7 +4,9 @@ declare(strict_types=1);
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\Exceptions\MetadataException;
......@@ -38,4 +40,9 @@ class Oidc extends AbstractProvider implements ServiceProviderInterface
throw new MetadataException('Relying Provider metadata does not contain entity ID.');
}
public function getProtocol(): AuthenticationProtocolInterface
{
return new Authentication\Protocol\Oidc();
}
}
......@@ -4,7 +4,9 @@ declare(strict_types=1);
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\Exceptions\MetadataException;
......@@ -38,4 +40,9 @@ class Saml2 extends AbstractProvider implements ServiceProviderInterface
throw new MetadataException('Service provider metadata does not contain entity ID.');
}
public function getProtocol(): AuthenticationProtocolInterface
{
return new Authentication\Protocol\Saml2();
}
}
......@@ -4,20 +4,14 @@ declare(strict_types=1);
namespace SimpleSAML\Module\accounting\Entities;
use SimpleSAML\Module\accounting\Traits\HasUserAttributesTrait;
class User
{
protected array $attributes;
use HasUserAttributesTrait;
public function __construct(array $attributes)
{
$this->attributes = $attributes;
}
/**
* @return array
*/
public function getAttributes(): array
{
return $this->attributes;
}
}
......@@ -17,4 +17,24 @@ class Arr
ksort($array);
}
/**
* @param array $array
* @param int|string $key
* @return array
*/
public function groupByValue(array $array, $key): array
{
return array_reduce($array, function (array $carry, array $item) use ($key) {
/** @psalm-suppress MixedArrayOffset, MixedArrayAssignment */
$carry[$item[$key]][] = $item;
return $carry;
}, []);
}
public function isAssociative(array $array): bool
{
$keys = array_keys($array);
return $keys !== array_keys($keys);
}
}
......@@ -9,6 +9,7 @@ use DateTimeImmutable;
class DateTime
{
public const FORMAT_MYSQL = 'Y-m-d H:i:s';
/**
* Convert date interval to seconds, interval being minimum 1 second.
* @param DateInterval $dateInterval Minimum is 1 second.
......@@ -27,4 +28,13 @@ class DateTime
return $duration;
}
public function toFormattedString(
\DateTimeInterface $dateTime = null,
string $format = self::FORMAT_MYSQL
): string {
$dateTime = $dateTime ?? new DateTimeImmutable();
return $dateTime->format($format);
}
}
......@@ -8,7 +8,7 @@ use Throwable;
class Random
{
public function getRandomInt(int $minimum = PHP_INT_MIN, int $maximum = PHP_INT_MAX): int
public function getInt(int $minimum = PHP_INT_MIN, int $maximum = PHP_INT_MAX): int
{
try {
return random_int($minimum, $maximum);
......@@ -18,4 +18,15 @@ class Random
// @codeCoverageIgnoreEnd
}
}
public function getString(int $length = 16): string
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[$this->getInt(0, $charactersLength - 1)];
}
return $randomString;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment