Skip to content

Commit

Permalink
add phrasea-admin to phrasea realm
Browse files Browse the repository at this point in the history
  • Loading branch information
4rthem committed Sep 26, 2023
1 parent 5c7457c commit 1209963
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 19 deletions.
3 changes: 3 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ KEYCLOAK_DB_NAME=keycloak
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=__CHANGE_ME_rTLDzTAFiFIQiHDm

DEFAULT_ADMIN_USERNAME=phrasea-admin
DEFAULT_ADMIN_PASSWORD=__CHANGE_ME_CAZ7B1ZP4os2kZPL

# Keycloak2
KEYCLOAK2_DB_NAME=keycloak2
KEYCLOAK2_ADMIN=admin2
Expand Down
7 changes: 3 additions & 4 deletions configurator/src/Command/Migration20230807Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,11 @@ public function execute(InputInterface $input, OutputInterface $output): int
foreach ($roles as $role) {
$realmRoles = array_merge($realmRoles, match ($role) {
'ROLE_SUPER_ADMIN', 'ROLE_ADMIN', 'ROLE_CHUCK-NORRIS' => [
KeycloakInterface::GROUP_ADMIN,
KeycloakInterface::GROUP_SUPER_ADMIN,
KeycloakInterface::ROLE_ADMIN,
],
'ROLE_TECH' => [KeycloakInterface::GROUP_TECH],
'ROLE_TECH' => [KeycloakInterface::ROLE_TECH],
'ROLE_ADMIN_OAUTH_CLIENTS',
'ROLE_ADMIN_USERS' => [KeycloakInterface::GROUP_USER_ADMIN, KeycloakInterface::GROUP_GROUP_ADMIN],
'ROLE_ADMIN_USERS' => [KeycloakInterface::ROLE_USER_ADMIN, KeycloakInterface::ROLE_GROUP_ADMIN],
default => [],
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public function __construct(
private KeycloakManager $keycloakManager,
private array $symfonyApplications,
private array $frontendApplications,
private string $keycloakRealm,
) {
}

Expand All @@ -22,10 +21,10 @@ public function configure(OutputInterface $output): void
$this->configureRealm();

foreach ([
KeycloakInterface::GROUP_SUPER_ADMIN => 'Can do anything',
KeycloakInterface::GROUP_TECH => 'Access to Dev/Ops Operations',
KeycloakInterface::GROUP_USER_ADMIN => 'Manage Users',
KeycloakInterface::GROUP_GROUP_ADMIN => 'Manage Groups',
KeycloakInterface::ROLE_ADMIN => 'Can do anything',
KeycloakInterface::ROLE_TECH => 'Access to Dev/Ops Operations',
KeycloakInterface::ROLE_USER_ADMIN => 'Manage Users',
KeycloakInterface::ROLE_GROUP_ADMIN => 'Manage Groups',
] as $role => $desc) {
$this->keycloakManager->createRole($role, $desc);
}
Expand Down Expand Up @@ -72,6 +71,23 @@ public function configure(OutputInterface $output): void
]
);
}

$defaultAdmin = $this->keycloakManager->createUser([
'username' => getenv('DEFAULT_ADMIN_USERNAME'),
'enabled' => true,
'credentials' => [[
'type' => 'password',
'value' => getenv('DEFAULT_ADMIN_PASSWORD'),
'temporary' => true,
]]
]);

$this->keycloakManager->addRolesToUser($defaultAdmin['id'], [
KeycloakInterface::ROLE_ADMIN,
]);
$this->keycloakManager->addClientRolesToUser($defaultAdmin['id'], [
'realm-admin',
]);
}

private function getAppScopes(): array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@

interface KeycloakInterface
{
final public const GROUP_ADMIN = 'admin';
final public const GROUP_SUPER_ADMIN = 'super-admin';
final public const GROUP_TECH = 'tech';
final public const GROUP_USER_ADMIN = 'user-admin';
final public const GROUP_GROUP_ADMIN = 'group-admin';
final public const ROLE_ADMIN = 'admin';
final public const ROLE_TECH = 'tech';
final public const ROLE_USER_ADMIN = 'user-admin';
final public const ROLE_GROUP_ADMIN = 'group-admin';
}
47 changes: 47 additions & 0 deletions configurator/src/Configurator/Vendor/Keycloak/KeycloakManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public function __construct(
private readonly string $keycloakRealm,
)
{
if ('master' === $this->keycloakRealm) {
throw new \LogicException('Your Keycloak Realm cannot be named "master".');
}
}

private function getAuthenticatedClient(): HttpClientInterface
Expand Down Expand Up @@ -367,6 +370,19 @@ public function getRealmRoles(): array
return $response->toArray();
}

public function getRealmClientRoles(): array
{
$realmClient = $this->getClientByClientId('realm-management');

$response = $this->getAuthenticatedClient()
->request('GET', UriTemplate::resolve('{realm}/clients/{realmClientId}/roles', [
'realm' => $this->keycloakRealm,
'realmClientId' => $realmClient['id'],
]));

return $response->toArray();
}

public function getUserRoles(string $userId): array
{
return $this->getAuthenticatedClient()
Expand Down Expand Up @@ -405,6 +421,37 @@ public function addRolesToUser(string $userId, array $roleNames): void
]), 409);
}

public function addClientRolesToUser(string $userId, array $roleNames): void
{
$realmClient = $this->getClientByClientId('realm-management');
$allRoles = $this->getRealmClientRoles();
$userRoles = array_map(fn (array $r): string => $r['id'], $this->getUserRoles($userId));

$roles = array_map(function (string $roleName) use ($userRoles, $allRoles): ?array {
foreach ($allRoles as $r) {
if ($roleName === $r['name']) {
if (!in_array($r['id'], $userRoles, true)) {
return $r;
} else {
return null;
}
}
}

throw new \InvalidArgumentException(sprintf('Role "%s" not found', $roleName));
}, $roleNames);
$roles = array_filter($roles, fn (array|null $r): bool => null !== $r);

HttpClientUtil::catchHttpCode(fn() => $this->getAuthenticatedClient()
->request('POST', UriTemplate::resolve('{realm}/users/{userId}/role-mappings/clients/{realmClientId}', [
'realm' => $this->keycloakRealm,
'userId' => $userId,
'realmClientId' => $realmClient['id'],
]), [
'json' => $roles,
]), 409);
}

public function addUserToGroup(string $userId, string $groupId): void
{
HttpClientUtil::catchHttpCode(fn() => $this->getAuthenticatedClient()
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ services:
- NOTIFY_DB_NAME
- UPLOADER_DB_NAME
- KEYCLOAK_REALM_NAME
- DEFAULT_ADMIN_USERNAME
- DEFAULT_ADMIN_PASSWORD
working_dir: /var/workspace
volumes:
- ./:/var/workspace
Expand Down
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,7 @@ services:
profiles:
- configurator
environment:
- APP_ENV
- KEYCLOAK_URL
- KEYCLOAK_ADMIN
- KEYCLOAK_ADMIN_PASSWORD
Expand Down Expand Up @@ -1009,6 +1010,8 @@ services:
- MAIL_FROM
- MAILER_DSN
- KEYCLOAK_REALM_NAME
- DEFAULT_ADMIN_USERNAME
- DEFAULT_ADMIN_PASSWORD
extra_hosts:
- keycloak.${PHRASEA_DOMAIN}:${PS_GATEWAY_IP}

Expand Down
2 changes: 1 addition & 1 deletion lib/php/auth-bundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->addDefaultsIfNotSet()
->children()
->scalarNode('url')->defaultValue('%env(KEYCLOAK_URL)%')->end()
->scalarNode('realm')->defaultValue('%env(KEYCLOAK_REALM)%')->end()
->scalarNode('realm')->defaultValue('%env(KEYCLOAK_REALM_NAME)%')->end()
->end()
->end()
->scalarNode('client_id')->defaultValue('%env(ADMIN_CLIENT_ID)%')->end()
Expand Down
2 changes: 1 addition & 1 deletion lib/php/auth-bundle/Resources/config/services.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
parameters:
env(VERIFY_SSL): true
env(KEYCLOAK_REALM): master
env(KEYCLOAK_REALM_NAME): phrasea

services:
_defaults:
Expand Down
5 changes: 2 additions & 3 deletions lib/php/auth-bundle/Security/RoleMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

namespace Alchemy\AuthBundle\Security;

final class RoleMapper
final readonly class RoleMapper
{
public function __construct(
private readonly array $mapping = [
private array $mapping = [
'admin' => 'ROLE_ADMIN',
]
)
{

}

public function getRoles(array $idpRoles): array
Expand Down

0 comments on commit 1209963

Please sign in to comment.