Lines 93.93% 31 / 33
Methods 50.00% 2 / 4
Classes 0.00% 0 / 1
Covered by tests of size
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 create 96.42% 27 / 28 0.00% 0 / 1 8
 buildDiscoveryUrl 66.66% 2 / 3 0.00% 0 / 1 3.33
 toBool 100.00% 1 / 1 100.00% 1 / 1 4
27final readonly class KeycloakProviderConfigFactory
28{
29    public function __construct(
30        private Configuration $configuration,
31    ) {
32    }
33
34    public function create(): OidcProviderConfig
35    {
36        $baseUrl = rtrim(trim((string) $this->configuration->get('keycloak.baseUrl')), characters: '/');
37        $realm = trim((string) $this->configuration->get('keycloak.realm'));
38        $redirectUri = trim((string) $this->configuration->get('keycloak.redirectUri'));
39        $scopes = preg_split('/\s+/', trim((string) $this->configuration->get('keycloak.scopes')));
40        if ($scopes === false) {
41            $scopes = [];
42        }
43
44        $enabled = $this->toBool($this->configuration->get('keycloak.enable'));
45
46        if ($enabled && ($baseUrl === '' || $realm === '')) {
47            $missing = array_filter([
48                $baseUrl === '' ? 'baseUrl' : null,
49                $realm === '' ? 'realm' : null,
50            ]);
51            throw new InvalidArgumentException(sprintf('Keycloak enabled but missing: %s', implode(' and ', $missing)));
52        }
53
54        if ($redirectUri === '') {
55            $redirectUri = rtrim($this->configuration->getDefaultUrl(), characters: '/') . '/auth/keycloak/callback';
56        }
57
58        return new OidcProviderConfig(
59            provider: 'keycloak',
60            enabled: $enabled,
61            discoveryUrl: $this->buildDiscoveryUrl($baseUrl, $realm),
62            client: new OidcClientConfig(
63                clientId: trim((string) $this->configuration->get('keycloak.clientId')),
64                clientSecret: (string) $this->configuration->get('keycloak.clientSecret'),
65                redirectUri: $redirectUri,
66                scopes: array_values(array_filter($scopes, static fn(string $scope): bool => $scope !== '')),
67            ),
68            autoProvision: $this->toBool($this->configuration->get('keycloak.autoProvision')),
69            logoutRedirectUrl: trim((string) $this->configuration->get('keycloak.logoutRedirectUrl')),
70        );
71    }
72
73    private function buildDiscoveryUrl(string $baseUrl, string $realm): string
74    {
75        if ($baseUrl === '' || $realm === '') {
76            return '';
77        }
78
79        return $baseUrl . '/realms/' . rawurlencode($realm) . '/.well-known/openid-configuration';
80    }
81
82    private function toBool(mixed $value): bool
83    {
84        return $value === true || $value === 1 || $value === '1' || $value === 'true';
85    }
86}