new shit
This commit is contained in:
commit
0d6eb2c535
10 changed files with 476 additions and 0 deletions
17
Dockerfile
Normal file
17
Dockerfile
Normal file
|
@ -0,0 +1,17 @@
|
|||
FROM quay.io/keycloak/keycloak:25.0.1 as comp
|
||||
|
||||
# Configure a database vendor
|
||||
ENV KC_DB=postgres
|
||||
|
||||
WORKDIR /opt/keycloak
|
||||
|
||||
# for demonstration purposes only, please make sure to use proper certificates in production instead
|
||||
RUN keytool -genkeypair -storepass password -storetype PKCS12 -keyalg RSA -keysize 2048 -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore conf/server.keystore
|
||||
|
||||
RUN /opt/keycloak/bin/kc.sh build
|
||||
|
||||
FROM quay.io/keycloak/keycloak:latest
|
||||
COPY --from=comp /opt/keycloak/ /opt/keycloak/
|
||||
COPY ./themes /opt/keycloak/themes
|
||||
|
||||
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
|
8
README.md
Normal file
8
README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Iwakura-Keycloak
|
||||
|
||||
Resources for Iwakura.rip's instance of Keycloak, which can be found [here](https://auth.iwakura.rip).
|
||||
|
||||
Included is:
|
||||
* Docker Image
|
||||
* Docker Compose File
|
||||
* Keycloak Custom Lain Theme
|
40
docker-compose.yml
Normal file
40
docker-compose.yml
Normal file
|
@ -0,0 +1,40 @@
|
|||
version: '3'
|
||||
|
||||
volumes:
|
||||
keycloak-db-data:
|
||||
driver: local
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:13.7
|
||||
container_name: postgres
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "sh -c 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}'"]
|
||||
volumes:
|
||||
- keycloak-db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: keycloak
|
||||
POSTGRES_USER: kc
|
||||
POSTGRES_PASSWORD: phai6ahphaimahguo6ia1OFaighe6G
|
||||
keycloak:
|
||||
#depends_on: postgres
|
||||
build: .
|
||||
container_name: keycloak
|
||||
environment:
|
||||
#Admin Credentials
|
||||
#KC_HOSTNAME_STRICT: 'false'
|
||||
#KC_HOSTNAME_STRICT_HTTPS: 'false'
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: MyKeycloak493
|
||||
KC_DB_URL: 'jdbc:postgresql://postgres/keycloak'
|
||||
KC_DB_USERNAME: kc
|
||||
KC_DB_PASSWORD: phai6ahphaimahguo6ia1OFaighe6G
|
||||
KC_HEALTH_ENABLED: 'true'
|
||||
KC_METRICS_ENABLED: 'true'
|
||||
KC_HOSTNAME: https://auth.iwakura.rip
|
||||
PROXY_ADDRESS_FORWARDING: "true"
|
||||
command: "start --optimized --proxy-headers forwarded --proxy edge"
|
||||
ports:
|
||||
- 8080:8080
|
||||
depends_on:
|
||||
- postgres
|
24
themes/README.md
Normal file
24
themes/README.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
Creating Themes
|
||||
===============
|
||||
|
||||
Themes are used to configure the look and feel of login pages and the account management console.
|
||||
|
||||
Custom themes packaged in a JAR file should be deployed to the `${kc.home.dir}/providers` directory. After that, run
|
||||
the `build` command to install them before starting the server.
|
||||
|
||||
You are also able to create your custom themes in this directory, directly. Themes within this directory do not require
|
||||
the `build` command to be installed.
|
||||
|
||||
When running the server in development mode using `start-dev`, themes are not cached so that you can easily work on them without a need to restart
|
||||
the server when making changes.
|
||||
|
||||
See the theme section in the [Server Developer Guide](https://www.keycloak.org/docs/latest/server_development/#_themes) for more details about how to create custom themes.
|
||||
|
||||
Overriding the built-in templates
|
||||
---------------------------------
|
||||
|
||||
While creating custom themes, especially when overriding templates, it may be useful to use the built-in templates as
|
||||
a reference. These can be found within the theme directory of `../lib/lib/main/org.keycloak.keycloak-themes-25.0.1.jar`, which can be opened using any
|
||||
standard ZIP archive tool.
|
||||
|
||||
**Built-in themes should not be modified directly, instead a custom theme should be created.**
|
119
themes/lain/login/login.ftl
Executable file
119
themes/lain/login/login.ftl
Executable file
|
@ -0,0 +1,119 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username','password') displayInfo=realm.password && realm.registrationAllowed && !registrationDisabled??; section>
|
||||
<#if section = "header">
|
||||
${msg("loginAccountTitle")}
|
||||
<#elseif section = "form">
|
||||
<div id="kc-form">
|
||||
<div id="kc-form-wrapper">
|
||||
<#if realm.password>
|
||||
<form id="kc-form-login" onsubmit="login.disabled = true; return true;" action="${url.loginAction}" method="post">
|
||||
<#if !usernameHidden??>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<label id="user-label" for="username" class="${properties.kcLabelClass!}"><#if !realm.loginWithEmailAllowed>${msg("username")}<#elseif !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>
|
||||
|
||||
[ <input tabindex="2" id="username" class="${properties.kcInputClass!}" name="username" value="${(login.username!'')}" type="text" autofocus autocomplete="username"
|
||||
aria-invalid="<#if messagesPerField.existsError('username','password')>true</#if>"
|
||||
/> ]
|
||||
|
||||
<#if messagesPerField.existsError('username','password')>
|
||||
<span id="input-error" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
|
||||
</div>
|
||||
</#if>
|
||||
<div class="break"></div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<label id="pw-label" for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
|
||||
|
||||
<!--<div class="${properties.kcInputGroup!}">-->
|
||||
[ <input tabindex="3" id="password" class="${properties.kcInputClass!}" name="password" type="password" autocomplete="current-password"
|
||||
aria-invalid="<#if messagesPerField.existsError('username','password')>true</#if>"
|
||||
/> ]
|
||||
<!--
|
||||
<button class="${properties.kcFormPasswordVisibilityButtonClass!}" type="button" aria-label="${msg("showPassword")}"
|
||||
aria-controls="password" data-password-toggle tabindex="4"
|
||||
data-icon-show="${properties.kcFormPasswordVisibilityIconShow!}" data-icon-hide="${properties.kcFormPasswordVisibilityIconHide!}"
|
||||
data-label-show="${msg('showPassword')}" data-label-hide="${msg('hidePassword')}">
|
||||
<i class="${properties.kcFormPasswordVisibilityIconShow!}" aria-hidden="true"></i>
|
||||
</button>
|
||||
-->
|
||||
<!--</div>-->
|
||||
|
||||
<#if usernameHidden?? && messagesPerField.existsError('username','password')>
|
||||
<span id="input-error" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
|
||||
</div>
|
||||
<div class="break"></div><br>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!} ${properties.kcFormSettingClass!}">
|
||||
<div id="kc-form-options">
|
||||
<#if realm.rememberMe && !usernameHidden??>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<#if login.rememberMe??>
|
||||
<input tabindex="5" id="rememberMe" name="rememberMe" type="checkbox" checked> ${msg("rememberMe")}
|
||||
<#else>
|
||||
<input tabindex="5" id="rememberMe" name="rememberMe" type="checkbox"> ${msg("rememberMe")}
|
||||
</#if>
|
||||
</label>
|
||||
</div>
|
||||
</#if>
|
||||
</div>
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
<#if realm.resetPasswordAllowed>
|
||||
<span><a tabindex="6" href="${url.loginResetCredentialsUrl}">${msg("doForgotPassword")}</a></span>
|
||||
</#if>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormGroupClass!}">
|
||||
<input type="hidden" id="id-hidden-input" name="credentialId" <#if auth.selectedCredential?has_content>value="${auth.selectedCredential}"</#if>/>
|
||||
<input tabindex="7" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="${url.resourcesPath}/js/passwordVisibility.js"></script>
|
||||
<#elseif section = "info" >
|
||||
<#if realm.password && realm.registrationAllowed && !registrationDisabled??>
|
||||
<div id="kc-registration-container">
|
||||
<div id="kc-registration">
|
||||
<span>${msg("noAccount")} <a tabindex="8"
|
||||
href="${url.registrationUrl}">${msg("doRegister")}</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
<#elseif section = "socialProviders" >
|
||||
<#if realm.password && social?? && social.providers?has_content>
|
||||
<div id="kc-social-providers" class="${properties.kcFormSocialAccountSectionClass!}">
|
||||
<hr/>
|
||||
<h2>${msg("identity-provider-login-label")}</h2>
|
||||
|
||||
<ul class="${properties.kcFormSocialAccountListClass!} <#if social.providers?size gt 3>${properties.kcFormSocialAccountListGridClass!}</#if>">
|
||||
<#list social.providers as p>
|
||||
<li>
|
||||
<a id="social-${p.alias}" class="${properties.kcFormSocialAccountListButtonClass!} <#if social.providers?size gt 3>${properties.kcFormSocialAccountGridItem!}</#if>"
|
||||
type="button" href="${p.loginUrl}">
|
||||
<#if p.iconClasses?has_content>
|
||||
<i class="${properties.kcCommonLogoIdP!} ${p.iconClasses!}" aria-hidden="true"></i>
|
||||
<span class="${properties.kcFormSocialAccountNameClass!} kc-social-icon-text">${p.displayName!}</span>
|
||||
<#else>
|
||||
<span class="${properties.kcFormSocialAccountNameClass!}">${p.displayName!}</span>
|
||||
</#if>
|
||||
</a>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
|
||||
</@layout.registrationLayout>
|
81
themes/lain/login/resources/css/styles.css
Normal file
81
themes/lain/login/resources/css/styles.css
Normal file
|
@ -0,0 +1,81 @@
|
|||
@keyframes fadeIn {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
:root {
|
||||
--term-color: #4AF626;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Hack Nerd Font";
|
||||
src: url(../fonts/HNF-Reg.ttf);
|
||||
}
|
||||
body {
|
||||
font-family: "Hack Nerd Font";
|
||||
background-color: black;
|
||||
color: var(--term-color);
|
||||
border: 1px solid var(--term-color);
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
padding-bottom: 30px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
input {
|
||||
border: none;
|
||||
}
|
||||
.kc-logo-text {
|
||||
display: none;
|
||||
}
|
||||
body {
|
||||
/*font-family: "Hack Nerd Font";
|
||||
color: var(--term-color);*/
|
||||
position:absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
#kc-form-login {
|
||||
width: 100%;
|
||||
}
|
||||
#kc-login {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
font-family: "Hack Nerd Font";
|
||||
transition: 0.3s;
|
||||
}
|
||||
input[type="submit"]:hover {
|
||||
background-color: var(--term-color);
|
||||
color: black;
|
||||
}
|
||||
input[type="submit"] {
|
||||
transition: 0.3s;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--term-color);
|
||||
}
|
||||
#pw-label, #user-label {
|
||||
margin-right: 30%;
|
||||
}
|
||||
label {display: inline;}
|
||||
input[type="text"]:focus, input[type="text"]:active, input[type="text"], input[type="password"]:focus, input[type="password"]:active, input[type="password"] {
|
||||
border:none;
|
||||
outline:none;
|
||||
font-family: "Hack Nerd Font";
|
||||
color: var(--term-color);
|
||||
background: transparent;
|
||||
}
|
||||
input[type="text"] {
|
||||
transition: 0.3s;
|
||||
}
|
||||
#input-error {
|
||||
display:none;
|
||||
}
|
||||
input[type="text"]::selection {
|
||||
background: var(--term-color);
|
||||
color: black;
|
||||
}
|
BIN
themes/lain/login/resources/fonts/HNF-Reg.ttf
Normal file
BIN
themes/lain/login/resources/fonts/HNF-Reg.ttf
Normal file
Binary file not shown.
12
themes/lain/login/resources/js/script.js
Normal file
12
themes/lain/login/resources/js/script.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
function setText(id, text) {
|
||||
document.getElementById(id).innerText= `${text}`
|
||||
}
|
||||
setText('kc-page-title', ' [ iwakura.rip login ] ')
|
||||
setText('user-label', 'username')
|
||||
setText('pw-label', 'password')
|
||||
document.getElementById("kc-login").value = " [ login ] "
|
||||
console.log(document.getElementById("kc-page-title"))
|
||||
for (let elem of document.getElementsByClassName("kc-logo-text")) {
|
||||
console.log(elem);
|
||||
elem.remove();
|
||||
}
|
171
themes/lain/login/template.ftl
Normal file
171
themes/lain/login/template.ftl
Normal file
|
@ -0,0 +1,171 @@
|
|||
<#macro registrationLayout bodyClass="" displayInfo=false displayMessage=true displayRequiredFields=false>
|
||||
<!DOCTYPE html>
|
||||
<html class="${properties.kcHtmlClass!}"<#if realm.internationalizationEnabled> lang="${locale.currentLanguageTag}"</#if>>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
|
||||
<#if properties.meta?has_content>
|
||||
<#list properties.meta?split(' ') as meta>
|
||||
<meta name="${meta?split('==')[0]}" content="${meta?split('==')[1]}"/>
|
||||
</#list>
|
||||
</#if>
|
||||
<title>${msg("loginTitle",(realm.displayName!''))}</title>
|
||||
<link rel="icon" href="${url.resourcesPath}/img/favicon.ico" />
|
||||
<#if properties.stylesCommon?has_content>
|
||||
<#list properties.stylesCommon?split(' ') as style>
|
||||
<link href="${url.resourcesCommonPath}/${style}" rel="stylesheet" />
|
||||
</#list>
|
||||
</#if>
|
||||
<#if properties.styles?has_content>
|
||||
<#list properties.styles?split(' ') as style>
|
||||
<link href="${url.resourcesPath}/${style}" rel="stylesheet" />
|
||||
</#list>
|
||||
</#if>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"rfc4648": "${url.resourcesCommonPath}/node_modules/rfc4648/lib/rfc4648.js"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="${url.resourcesPath}/js/menu-button-links.js" type="module"></script>
|
||||
<#if scripts??>
|
||||
<#list scripts as script>
|
||||
<script src="${script}" type="text/javascript"></script>
|
||||
</#list>
|
||||
</#if>
|
||||
<script type="module">
|
||||
import { checkCookiesAndSetTimer } from "${url.resourcesPath}/js/authChecker.js";
|
||||
|
||||
checkCookiesAndSetTimer(
|
||||
"${url.ssoLoginInOtherTabsUrl?no_esc}"
|
||||
);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="${properties.kcBodyClass!}">
|
||||
<div class="${properties.kcLoginClass!} h-page" >
|
||||
<div id="kc-header" class="${properties.kcHeaderClass!}">
|
||||
<div id="kc-header-wrapper"
|
||||
class="${properties.kcHeaderWrapperClass!}">${kcSanitize(msg("loginTitleHtml",(realm.displayNameHtml!'')))?no_esc}</div>
|
||||
</div>
|
||||
<div class="${properties.kcFormCardClass!}">
|
||||
<header class="${properties.kcFormHeaderClass!}">
|
||||
<#if realm.internationalizationEnabled && locale.supported?size gt 1>
|
||||
<div class="${properties.kcLocaleMainClass!}" id="kc-locale">
|
||||
<div id="kc-locale-wrapper" class="${properties.kcLocaleWrapperClass!}">
|
||||
<div id="kc-locale-dropdown" class="menu-button-links ${properties.kcLocaleDropDownClass!}">
|
||||
<button tabindex="1" id="kc-current-locale-link" aria-label="${msg("languages")}" aria-haspopup="true" aria-expanded="false" aria-controls="language-switch1">${locale.current}</button>
|
||||
<ul role="menu" tabindex="-1" aria-labelledby="kc-current-locale-link" aria-activedescendant="" id="language-switch1" class="${properties.kcLocaleListClass!}">
|
||||
<#assign i = 1>
|
||||
<#list locale.supported as l>
|
||||
<li class="${properties.kcLocaleListItemClass!}" role="none">
|
||||
<a role="menuitem" id="language-${i}" class="${properties.kcLocaleItemClass!}" href="${l.url}">${l.label}</a>
|
||||
</li>
|
||||
<#assign i++>
|
||||
</#list>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
<#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())>
|
||||
<#if displayRequiredFields>
|
||||
<div class="${properties.kcContentWrapperClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!} subtitle">
|
||||
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<h1 id="kc-page-title"><#nested "header"></h1>
|
||||
</div>
|
||||
</div>
|
||||
<#else>
|
||||
<h1 id="kc-page-title"><#nested "header"></h1>
|
||||
</#if>
|
||||
<#else>
|
||||
<#if displayRequiredFields>
|
||||
<div class="${properties.kcContentWrapperClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!} subtitle">
|
||||
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<#nested "show-username">
|
||||
<div id="kc-username" class="${properties.kcFormGroupClass!}">
|
||||
<label id="kc-attempted-username">${auth.attemptedUsername}</label>
|
||||
<a id="reset-login" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}">
|
||||
<div class="kc-login-tooltip">
|
||||
<i class="${properties.kcResetFlowIcon!}"></i>
|
||||
<span class="kc-tooltip-text">${msg("restartLoginTooltip")}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<#else>
|
||||
<#nested "show-username">
|
||||
<div id="kc-username" class="${properties.kcFormGroupClass!}">
|
||||
<label id="kc-attempted-username">${auth.attemptedUsername}</label>
|
||||
<a id="reset-login" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}">
|
||||
<div class="kc-login-tooltip">
|
||||
<i class="${properties.kcResetFlowIcon!}"></i>
|
||||
<span class="kc-tooltip-text">${msg("restartLoginTooltip")}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
</header>
|
||||
<div id="kc-content">
|
||||
<div id="kc-content-wrapper">
|
||||
|
||||
<#-- App-initiated actions should not see warning messages about the need to complete the action -->
|
||||
<#-- during login. -->
|
||||
<#if displayMessage && message?has_content && (message.type != 'warning' || !isAppInitiatedAction??)>
|
||||
<div class="alert-${message.type} ${properties.kcAlertClass!} pf-m-<#if message.type = 'error'>danger<#else>${message.type}</#if>">
|
||||
<div class="pf-c-alert__icon">
|
||||
<#if message.type = 'success'><span class="${properties.kcFeedbackSuccessIcon!}"></span></#if>
|
||||
<#if message.type = 'warning'><span class="${properties.kcFeedbackWarningIcon!}"></span></#if>
|
||||
<#if message.type = 'error'><span class="${properties.kcFeedbackErrorIcon!}"></span></#if>
|
||||
<#if message.type = 'info'><span class="${properties.kcFeedbackInfoIcon!}"></span></#if>
|
||||
</div>
|
||||
<span class="${properties.kcAlertTitleClass!}">${kcSanitize(message.summary)?no_esc}</span>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<#nested "form">
|
||||
|
||||
<#if auth?has_content && auth.showTryAnotherWayLink()>
|
||||
<form id="kc-select-try-another-way-form" action="${url.loginAction}" method="post">
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<input type="hidden" name="tryAnotherWay" value="on"/>
|
||||
<a href="#" id="try-another-way"
|
||||
onclick="document.forms['kc-select-try-another-way-form'].submit();return false;">${msg("doTryAnotherWay")}</a>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
|
||||
<#nested "socialProviders">
|
||||
|
||||
<#if displayInfo>
|
||||
<div id="kc-info" class="${properties.kcSignUpClass!}">
|
||||
<div id="kc-info-wrapper" class="${properties.kcInfoAreaWrapperClass!}">
|
||||
<#nested "info">
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<#if properties.scripts?has_content>
|
||||
<#list properties.scripts?split(' ') as script>
|
||||
<script src="${url.resourcesPath}/${script}" type="text/javascript"></script>
|
||||
</#list>
|
||||
</#if>
|
||||
</body>
|
||||
</html>
|
||||
</#macro>
|
4
themes/lain/login/theme.properties
Normal file
4
themes/lain/login/theme.properties
Normal file
|
@ -0,0 +1,4 @@
|
|||
parent=base
|
||||
import=common/keycloak
|
||||
styles=css/styles.css
|
||||
scripts=js/script.js
|
Reference in a new issue