View source
<?php
namespace Drupal\keycloak\Service;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Url;
use Drupal\openid_connect\Plugin\OpenIDConnectClientManager;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\HttpFoundation\RedirectResponse;
class KeycloakService implements KeycloakServiceInterface {
protected const OPENID_CONNECT_CONFIG_NAME = 'openid_connect.settings.keycloak';
protected $config;
protected $oidcClientManager;
protected $languageManager;
protected $currentUser;
protected $privateTempstore;
protected $loggerFactory;
private static $sessionInfoKeys;
public function __construct(ConfigFactoryInterface $config_factory, OpenIDConnectClientManager $oidc_client_manager, LanguageManagerInterface $language_manager, AccountProxyInterface $current_user, PrivateTempStoreFactory $private_tempstore, LoggerChannelFactoryInterface $logger) {
$this->config = $config_factory
->get(static::OPENID_CONNECT_CONFIG_NAME);
$this->oidcClientManager = $oidc_client_manager;
$this->languageManager = $language_manager;
$this->currentUser = $current_user;
$this->privateTempstore = $private_tempstore;
$this->loggerFactory = $logger;
}
public function isEnabled() {
return $this->config
->get('enabled');
}
public function getBaseUrl() {
return $this->config
->get('settings.keycloak_base');
}
public function getRealm() {
return $this->config
->get('settings.keycloak_realm');
}
public function getEndpoints() {
$base = $this
->getBaseUrl() . '/realms/' . $this
->getRealm();
return [
'authorization' => $base . self::KEYCLOAK_AUTH_ENDPOINT_URI,
'token' => $base . self::KEYCLOAK_TOKEN_ENDPOINT_URI,
'userinfo' => $base . self::KEYCLOAK_USERINFO_ENDPOINT_URI,
'end_session' => $base . self::KEYCLOAK_END_SESSION_ENDPOINT_URI,
'session_iframe' => $base . self::KEYCLOAK_CHECK_SESSION_IFRAME_URI,
];
}
public function isKeycloakUser() {
if (!$this->currentUser
->isAuthenticated() || !$this
->isEnabled()) {
return FALSE;
}
$tempstore = $this->privateTempstore
->get('keycloak');
return !empty($tempstore);
}
public function getSessionInfoDefaultKeys() {
if (!isset(self::$sessionInfoKeys)) {
$default_keys = [
self::KEYCLOAK_SESSION_ACCESS_TOKEN,
self::KEYCLOAK_SESSION_REFRESH_TOKEN,
self::KEYCLOAK_SESSION_ID_TOKEN,
self::KEYCLOAK_SESSION_CLIENT_ID,
self::KEYCLOAK_SESSION_SESSION_ID,
];
self::$sessionInfoKeys = $default_keys;
}
return self::$sessionInfoKeys;
}
public function getSessionInfo($keys = NULL) {
$session_info = [];
if (!$this
->isKeycloakUser()) {
return $session_info;
}
$default_keys = $this
->getSessionInfoDefaultKeys();
$keys = empty($keys) ? $default_keys : array_intersect($default_keys, $keys);
$tempstore = $this->privateTempstore
->get('keycloak');
foreach ($keys as $key) {
$session_info[$key] = $tempstore
->get($key);
}
return $session_info;
}
public function setSessionInfo(array $info) {
if (!$this->currentUser
->isAuthenticated() || !$this
->isEnabled()) {
return FALSE;
}
$default_keys = $this
->getSessionInfoDefaultKeys();
$old_values = $this
->getSessionInfo();
$new_values = array_merge($old_values, $info);
$tempstore = $this->privateTempstore
->get('keycloak');
foreach ($default_keys as $key) {
$tempstore
->set($key, $new_values[$key]);
}
return TRUE;
}
public function isI18nEnabled() {
return $this
->isEnabled() && $this->languageManager
->isMultilingual() && $this->config
->get('settings.keycloak_i18n.enabled');
}
public function getI18nMapping($reverse = FALSE, $include_enabled = TRUE) {
$mappings = [];
$languages = $this->languageManager
->getLanguages();
if (empty($languages)) {
return $mappings;
}
$configured = $this->config
->get('settings.keycloak_i18n_mapping');
$kc_mappings = [];
if (!empty($configured)) {
foreach ($configured as $mapping) {
$kc_mappings[$mapping['langcode']] = $mapping['target'];
}
}
foreach ($languages as $langcode => $language) {
if (empty($kc_mappings[$langcode]) && !$include_enabled) {
continue;
}
$mapping = [
'language_id' => $langcode,
'locale' => !empty($kc_mappings[$langcode]) ? $kc_mappings[$langcode] : $langcode,
'label' => $language
->getName(),
];
$mappings[$reverse ? $mapping['locale'] : $langcode] = $mapping;
}
return $mappings;
}
public function isSsoEnabled() {
return $this
->isEnabled() && $this->config
->get('settings.keycloak_sso');
}
public function isKeycloakSignOutEnabled() {
return $this->config
->get('enabled') && $this->config
->get('settings.keycloak_sign_out');
}
public function getKeycloakSignOutEndpoint() {
return $this
->getEndpoints()['end_session'];
}
public function getKeycloakSignoutResponse(array $session_information) {
$logout_redirect = Url::fromRoute('<front>', [], [
'absolute' => TRUE,
])
->toString();
if ($this
->isKeycloakSignOutEnabled() && !empty($session_information[self::KEYCLOAK_SESSION_ID_TOKEN])) {
return new RedirectResponse(Url::fromRoute('keycloak.logout', [], [
'query' => [
'id_token_hint' => $session_information[self::KEYCLOAK_SESSION_ID_TOKEN],
'post_logout_redirect_uri' => $logout_redirect,
],
])
->toString());
}
return new RedirectResponse($logout_redirect);
}
public function isCheckSessionEnabled() {
return $this->config
->get('enabled') && $this->config
->get('settings.check_session.enabled');
}
public function getCheckSessionInterval() {
return $this->config
->get('settings.check_session.interval');
}
public function getCheckSessionIframeUrl() {
return $this
->getEndpoints()['session_iframe'];
}
public function getClientInstance() {
$config = $this->config
->get('settings');
if (empty($config)) {
$config = [];
}
return $this->oidcClientManager
->createInstance('keycloak', $config);
}
public function getLogger() {
return $this->loggerFactory
->get('openid_connect_keycloak');
}
public function isDebugMode() {
return $this->config
->get('settings.debug');
}
}