198 lines
11 KiB
HTML
198 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Keycloak</title>
|
|
</head>
|
|
<body>
|
|
<div id="TemplateConfigPage" data-role="page" class="page type-interior pluginConfigurationPage" data-require="emby-input,emby-button,emby-select,emby-checkbox">
|
|
<div data-role="content">
|
|
<div class="content-primary">
|
|
<h1>Keycloak Authentication</h1>
|
|
<form id="TemplateConfigForm">
|
|
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
<label class="emby-checkbox-label">
|
|
<input id="Enabled" name="TrueFalseCheckBox" type="checkbox" is="emby-checkbox"/>
|
|
<span>Enable Keycloak authentication</span>
|
|
</label>
|
|
</div>
|
|
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
<label class="emby-checkbox-label">
|
|
<input id="CreateUser" name="TrueFalseCheckBox" type="checkbox" is="emby-checkbox"/>
|
|
<span>Create Keycloak user if it does not exist</span>
|
|
</label>
|
|
</div>
|
|
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
<label class="emby-checkbox-label">
|
|
<input id="Enable2Fa" name="TrueFalseCheckBox" type="checkbox" is="emby-checkbox"/>
|
|
<span>Enable Two-factor authentication</span>
|
|
</label>
|
|
<div class="fieldDescription">You need to add the TOTP (6 digits) to the password when logging in</div>
|
|
</div>
|
|
<div class="inputContainer">
|
|
<label class="inputLabel inputLabelUnfocused" for="AuthServerUrl">Keycloak server URL</label>
|
|
<input id="AuthServerUrl" name="AuthServerUrl" type="text" is="emby-input"/>
|
|
</div>
|
|
<div class="inputContainer">
|
|
<label class="inputeLabel inputLabelUnfocused" for="Realm">Keycloak Realm</label>
|
|
<input id="Realm" name="AString" type="text" is="emby-input"/>
|
|
</div>
|
|
<div class="inputContainer">
|
|
<label class="inputeLabel inputLabelUnfocused" for="ClientId">Client ID</label>
|
|
<input id="ClientId" name="AString" type="text" is="emby-input"/>
|
|
</div>
|
|
<div class="inputContainer">
|
|
<label class="inputeLabel inputLabelUnfocused" for="ClientSecret">Client Secret</label>
|
|
<input id="ClientSecret" name="AString" type="text" is="emby-input"/>
|
|
</div>
|
|
<div class="inputContainer">
|
|
<label class="inputeLabel inputLabelUnfocused" for="OAuthScope"> OAuth Scope</label>
|
|
<input id="OAuthScope" name="AString" type="text" is="emby-input"/>
|
|
</div>
|
|
<div class="inputContainer">
|
|
<label class="inputeLabel inputLabelUnfocused" for="RolesTokenAttribute"> Roles token attribute</label>
|
|
<input id="RolesTokenAttribute" name="AString" type="text" is="emby-input"/>
|
|
<div class="fieldDescription">Access token attribute with the list of roles. Seperate keys with a '.' if the role list is part of a nested object.</div>
|
|
</div>
|
|
<div class="inputContainer">
|
|
<label class="inputeLabel inputLabelUnfocused" for="UsernameTokenAttribute"> Username token attribute</label>
|
|
<input id="UsernameTokenAttribute" name="AString" type="text" is="emby-input"/>
|
|
<div class="fieldDescription">Access token attribute with the username</div>
|
|
</div>
|
|
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
<label class="emby-checkbox-label">
|
|
<input id="AllowUsersWithoutRole" name="TrueFalseCheckBox" type="checkbox" is="emby-checkbox"/>
|
|
<span>Allow users without a role to log in</span>
|
|
</label>
|
|
</div>
|
|
|
|
<label class="checkboxContainer">
|
|
<input type="checkbox" is="emby-checkbox" id="EnableAllFolders" />
|
|
<span>Enable access to all libraries</span>
|
|
</label>
|
|
<div class="folderAccessListContainer">
|
|
<div id="FolderAccessList"></div>
|
|
<div class="fieldDescription">Enable access to certain libraries by default</div>
|
|
<div class="fieldDescription">Add library access to certain users by giving them the 'lib-<ID>' role</div>
|
|
<p class="fieldDescription" id="LibraryIdTable"></p>
|
|
</div>
|
|
|
|
<div>
|
|
<button is="emby-button" type="submit" class="raised button-submit block emby-button">
|
|
<span>Save</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<script type="text/javascript">
|
|
var KeycloakPluginConfig = {
|
|
pluginUniqueId: '40886866-b3dd-4d6a-bf9b-25c83e6c3d10',
|
|
chkEnabled: document.querySelector('#Enabled'),
|
|
chkCreateUser: document.querySelector('#CreateUser'),
|
|
txtAuthServerUrl: document.querySelector('#AuthServerUrl'),
|
|
txtRealm: document.querySelector('#Realm'),
|
|
txtClientId: document.querySelector('#ClientId'),
|
|
txtClientSecret: document.querySelector('#ClientSecret'),
|
|
txtOAuthScope: document.querySelector('#OAuthScope'),
|
|
txtRolesTokenAttribute: document.querySelector('#RolesTokenAttribute'),
|
|
txtUsernameTokenAttribute: document.querySelector('#UsernameTokenAttribute'),
|
|
chkEnable2Fa: document.querySelector('#Enable2Fa'),
|
|
chkAllowUsersWithoutRole: document.querySelector('#AllowUsersWithoutRole'),
|
|
chkEnableAllFolders: document.querySelector('#EnableAllFolders'),
|
|
libraryIdTable: document.querySelector("#LibraryIdTable"),
|
|
folderAccessList: document.querySelector("#FolderAccessList"),
|
|
};
|
|
|
|
document.querySelector('#TemplateConfigPage')
|
|
.addEventListener('pageshow', function () {
|
|
Dashboard.showLoadingMsg();
|
|
ApiClient.getPluginConfiguration(KeycloakPluginConfig.pluginUniqueId).then(function (config) {
|
|
KeycloakPluginConfig.chkEnabled.checked = config.Enabled;
|
|
KeycloakPluginConfig.chkCreateUser.checked = config.CreateUser;
|
|
KeycloakPluginConfig.txtAuthServerUrl.value = config.AuthServerUrl;
|
|
KeycloakPluginConfig.txtRealm.value = config.Realm;
|
|
KeycloakPluginConfig.txtClientId.value = config.ClientId;
|
|
KeycloakPluginConfig.txtClientSecret.value = config.ClientSecret;
|
|
KeycloakPluginConfig.txtOAuthScope.value = config.OAuthScope;
|
|
KeycloakPluginConfig.txtRolesTokenAttribute.value = config.RolesTokenAttribute;
|
|
KeycloakPluginConfig.txtUsernameTokenAttribute.value = config.UsernameTokenAttribute;
|
|
KeycloakPluginConfig.chkEnable2Fa.checked = config.Enable2Fa;
|
|
KeycloakPluginConfig.chkEnableAllFolders.checked = config.EnableAllFolders;
|
|
KeycloakPluginConfig.chkAllowUsersWithoutRole.checked = config.AllowUsersWithoutRole;
|
|
loadMediaFolders(config).then(() => {
|
|
Dashboard.hideLoadingMsg();
|
|
});
|
|
});
|
|
});
|
|
|
|
document.querySelector('#TemplateConfigForm')
|
|
.addEventListener('submit', function (e) {
|
|
e.preventDefault();
|
|
Dashboard.showLoadingMsg();
|
|
ApiClient.getPluginConfiguration(KeycloakPluginConfig.pluginUniqueId).then(function (config) {
|
|
config.Enabled = KeycloakPluginConfig.chkEnabled.checked;
|
|
config.CreateUser = KeycloakPluginConfig.chkCreateUser.checked;
|
|
config.AuthServerUrl = KeycloakPluginConfig.txtAuthServerUrl.value;
|
|
config.Realm = KeycloakPluginConfig.txtRealm.value;
|
|
config.ClientId = KeycloakPluginConfig.txtClientId.value;
|
|
config.ClientSecret = KeycloakPluginConfig.txtClientSecret.value;
|
|
config.OAuthScope = KeycloakPluginConfig.txtOAuthScope.value;
|
|
config.RolesTokenAttribute = KeycloakPluginConfig.txtRolesTokenAttribute.value;
|
|
config.UsernameTokenAttribute = KeycloakPluginConfig.txtUsernameTokenAttribute.value;
|
|
config.Enable2Fa = KeycloakPluginConfig.chkEnable2Fa.checked;
|
|
config.EnableAllFolders = KeycloakPluginConfig.chkEnableAllFolders.checked;
|
|
config.AllowUsersWithoutRole = KeycloakPluginConfig.chkAllowUsersWithoutRole.checked;
|
|
|
|
let folders = document.querySelectorAll('#folderList input');
|
|
folders = Array.prototype.filter.call(folders, folder => folder.checked)
|
|
.map(folder => folder.getAttribute("data-id"));
|
|
config.EnabledFolders = folders;
|
|
|
|
ApiClient.updatePluginConfiguration(KeycloakPluginConfig.pluginUniqueId, config).then(function (result) {
|
|
Dashboard.processPluginConfigurationUpdateResult(result);
|
|
});
|
|
});
|
|
return false;
|
|
});
|
|
|
|
function escapeHTML(str){
|
|
return new Option(str).innerHTML;
|
|
}
|
|
|
|
function loadMediaFolders(config) {
|
|
return ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders", { IsHidden: false })).then((mediaFolders) => {
|
|
let html = "";
|
|
html += '<h3 class="checkboxListLabel">${HeaderLibraries}</h3>';
|
|
html +=
|
|
'<div id="folderList" class="checkboxList paperList checkboxList-paperList">';
|
|
let tableHtml = "<table><tbody>\n";
|
|
|
|
if (Array.isArray(mediaFolders.Items)) {
|
|
mediaFolders.Items.forEach((folder) => {
|
|
const isChecked =
|
|
config.EnableAllFolders ||
|
|
config.EnabledFolders.indexOf(folder.Id) != -1;
|
|
const checkedAttribute = isChecked ? " checked" : "";
|
|
html +=
|
|
'<label class="emby-checkbox-label"><input type="checkbox" is="emby-checkbox" class="chkFolder emby-checkbox" data-id="' +
|
|
folder.Id +
|
|
'" ' +
|
|
checkedAttribute +
|
|
"><span>" +
|
|
escapeHTML(folder.Name) +
|
|
"</span></label>";
|
|
tableHtml += "<tr><td><b>" + escapeHTML(folder.Name) + "</b></td><td><code>lib-" + folder.Id + "</code></td></tr>\n";
|
|
});
|
|
}
|
|
|
|
html += "</div>";
|
|
tableHtml += "</tbody></table>";
|
|
KeycloakPluginConfig.folderAccessList.innerHTML = html;
|
|
KeycloakPluginConfig.libraryIdTable.innerHTML = tableHtml;
|
|
});
|
|
}
|
|
</script>
|
|
</div>
|
|
</body>
|
|
</html>
|