Compare commits

...

50 Commits

Author SHA1 Message Date
rra
d7d39e85ac remove d15 references for now
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-29 11:03:58 +00:00
3wc
1e924472bb Update to newer Keycloak base template
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
productNameFull → productName
2023-03-06 09:43:02 -05:00
3f10bd7a95 fix: new themes path
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-13 09:47:19 +01:00
10581b44b1 Unrecommended style changes
All checks were successful
continuous-integration/drone/push Build is passing
2022-03-04 11:03:05 +01:00
add791e087 absolutely butchering this css to fix the T&Cs login
All checks were successful
continuous-integration/drone/push Build is passing
2022-03-04 10:59:31 +01:00
7f22479d29 change text color on button
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing
2022-03-03 16:06:36 +01:00
ec69c49371 fix: submit button on forgot password
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-25 16:10:52 +01:00
f526c20e78 add hover styling to login button
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-21 16:09:22 +05:00
85d715ad00 Merge branch 'main' of ssh://git.autonomic.zone:2222/ruangrupa/login.lumbung.space
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-20 18:17:58 +05:00
ac2a6c1753 make login form responsive 2022-01-20 18:17:54 +05:00
eb9fafdc96 padding for terms form (again)
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-17 21:32:14 +01:00
82df4ba11d terms padding
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-17 21:27:41 +01:00
7cd9da93aa fix typo
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-13 13:53:23 +05:00
2aaef7bab0 more top margin
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-13 08:31:01 +01:00
9fe94e6ce7 Added logo and fonts.
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-13 08:23:50 +01:00
f943915553 Fixing more nitty gritty stuff.
All that's left is the font switch and the logo.
2022-01-13 08:23:50 +01:00
9feb042414 Styling for login page
1. Color override
2. Borders override

Still to complete: button and font. Sign in to alignment. Lumbung.Space
logo.
2022-01-13 08:23:50 +01:00
65d61005c4 drop that from here
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 17:30:20 +01:00
d33ba9590f omfg typos
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 16:51:42 +01:00
1a21f4c1ab fix html
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 16:46:06 +01:00
1c01bfd00f unbork that entire unbork attempt
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 16:43:17 +01:00
f89f7be21c unbork my unborking of html input for email link
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 16:39:15 +01:00
b084b18e5a unbork the borked html
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 16:31:57 +01:00
5ad9090417 hijack this message to link to members
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 16:24:35 +01:00
51fb2029f0 fix: no html allowed here either, idk
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 16:15:42 +01:00
fccad406d3 fix: html hacking to get a clickable link 2022-01-11 16:06:14 +01:00
1f4fec6aa3 fix: formatting, wording 2022-01-11 15:55:54 +01:00
854ec97956 fix: no html here, idk 2022-01-11 15:55:15 +01:00
e49ee45709 feat: verify email flow
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 15:51:35 +01:00
b736318908 feat: t&cs
All checks were successful
continuous-integration/drone/push Build is passing
2022-01-11 14:32:07 +01:00
b595726742 feat: more helpful verify mail message 2022-01-11 14:23:41 +01:00
rra
fed3f486aa style OTP config
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2021-09-20 17:51:30 +02:00
rra
15d0773bce remove kc-wrapper in OTP fields 2021-09-20 17:51:13 +02:00
rra
037aaf63eb fix update pass and update profile by removing more kc-wrapper layers
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2021-06-17 11:40:08 +02:00
rra
57eeabe134 rm the backupfile 2021-06-16 18:11:32 +02:00
rra
5f08b3ea3a remove kcwrapper elements, improve register form, handle narrow screens
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2021-06-16 16:57:47 +02:00
rra
581fbd415c refine login screen
All checks were successful
continuous-integration/drone/push Build is passing
2021-06-16 15:52:24 +02:00
rra
49d8906b92 work on other views as well
All checks were successful
continuous-integration/drone/push Build is passing
2021-06-05 00:40:12 +02:00
rra
5954f22939 make missing field info appear below input form 2021-06-05 00:39:53 +02:00
rra
795b1d0539 first draft login view
All checks were successful
continuous-integration/drone/push Build is passing
2021-06-04 16:15:47 +02:00
rra
1e69982156 add note to self & others 2021-06-04 16:15:03 +02:00
c9e5477b12 Drop that, already said
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-24 12:54:17 +02:00
0296bd97d6 Make the title more specific
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-24 12:53:30 +02:00
9e15ffecef Add more hacking docs
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-24 12:52:43 +02:00
df66e3116a Destroy the container automatically 2021-05-24 12:52:31 +02:00
09f914057c Add convenience script and makefile for hacking 2021-05-24 12:45:11 +02:00
4e2415e807 Documentation prod/local dev stuff
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-05 13:31:10 +02:00
1134b4572b Copy/pasta over login from the base theme
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-05 13:19:21 +02:00
c215e7997f Add CI badge
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-05 13:13:10 +02:00
49fe169288 Add drone configuration 2021-05-05 13:12:11 +02:00
66 changed files with 2808 additions and 20 deletions

19
.drone.yml Normal file
View File

@ -0,0 +1,19 @@
---
kind: pipeline
name: deploy to autonomic-ruangrupa
steps:
- name: deploy new theme
image: 3wordchant/docker-cp-deploy:latest
settings:
host: lumbung.space
service: login_lumbung_space_app
source: lumbung.space
dest: /opt/keycloak/themes
deploy_key:
from_secret: drone_ssh_lumbung.space
trigger:
branch:
- main
event:
exclude:
- pull_request

View File

@ -1,7 +1,40 @@
# login.lumbung.space
[![Build Status](https://drone.autonomic.zone/api/badges/ruangrupa/login.lumbung.space/status.svg?ref=refs/heads/main)](https://drone.autonomic.zone/ruangrupa/login.lumbung.space)
> [login.lumbung.space](https://login.lumbung.space)
[Custom theming](https://www.keycloak.org/docs/latest/server_development/index.html#_themes) for the Keycloak SSO service.
Please see [default-themes/README.md](./default-themes/README.md) and [lumbung.space/README.md](./lumbung.space/README.md) for more info.
## Deployment
Just send commits and the [Drone CI/CD configuration](./.drone.yml) will take care of the rest.
## Custom theming workflow
You'll need a local [Docker](https://docs.docker.com/engine/install/debian/) installation.
Then run a local Keycloak instance and mount the theme into the container with the following ([makefile source](./makefile)):
```
$ make
```
An example workflow for customising the login theme would be:
- Log into [localhost:8080](http://localhost:8080) with username: `admin` and password: `admin`
- Go to [Realm Settings > Themes](http://localhost:8080/auth/admin/master/console/#/realms/master/theme-settings)
- Choose a custom login theme via Login Theme > lumbung.space and click Save
- Sign out and you'll be redirected to the login page
- Now, test you can make an edit and it is reflected on reload, change the "Username or email" string in [mesages_en.properties](./lumbung.space/login/messages/messages_en.properties)
- Reload the page, your change should be live
See related documentation and tutorials for the hacking:
- [Create a custom theme for Keycloak](https://auscunningham.medium.com/create-a-custom-theme-for-keycloak-8781207be604)
- [Change Login Theme in Keycloak Docker image](https://austincunningham.ddns.net/2020/changekeycloakdockertheme)
- [Keycloak themes documentation](https://www.keycloak.org/docs/latest/server_development/index.html#_themes)
- [Keycloak Github repo for default themes](https://github.com/keycloak/keycloak/tree/master/themes/src/main/resources/theme)
- [Keycloak container documentation](https://github.com/keycloak/keycloak-containers/tree/master/server)

View File

@ -0,0 +1,5 @@
embed-server --std-out=echo --server-config=standalone-ha.xml
/subsystem=keycloak-server/theme=defaults/:write-attribute(name=cacheThemes,value=false)
/subsystem=keycloak-server/theme=defaults/:write-attribute(name=cacheTemplates,value=false)
/subsystem=keycloak-server/theme=defaults/:write-attribute(name=staticMaxAge,value=-1)
stop-embedded-server

View File

@ -19,11 +19,11 @@
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to ${productNameFull}</title>
<title>Welcome to ${productName}</title>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -49,9 +49,10 @@
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2">
<div class="welcome-header">
<img src="${resourcesPath}/logo.png" alt="${productName}" border="0" />
<h1>Welcome to <strong>${productNameFull}</strong></h1>
<h1>Welcome to <strong>${productName}</strong></h1>
</div>
<div class="row">
<#if adminConsoleEnabled>
<div class="col-xs-12 col-sm-4">
<div class="card-pf h-l">
<#if successMessage?has_content>
@ -60,15 +61,15 @@
<p class="alert error">${errorMessage}</p>
<h3><img src="welcome-content/user.png">Administration Console</h3>
<#elseif bootstrap>
<#if localUser>
<h3><img src="welcome-content/user.png">Administration Console</h3>
<p>Please create an initial admin user to get started.</p>
<#else>
<p class="welcome-message">
<img src="welcome-content/alert.png">You need local access to create the initial admin user. <br><br>Open <a href="http://localhost:8080/auth">http://localhost:8080/auth</a>
<br>or use the add-user-keycloak script.
</p>
</#if>
<#if localUser>
<h3><img src="welcome-content/user.png">Administration Console</h3>
<p>Please create an initial admin user to get started.</p>
<#else>
<p class="welcome-message">
<img src="welcome-content/alert.png">You need local access to create the initial admin user. <br><br>Open <a href="${localAdminUrl}">${localAdminUrl}</a>
<br>${adminUserCreationMessage}.
</p>
</#if>
</#if>
<#if bootstrap && localUser>
@ -93,14 +94,16 @@
<button id="create-button" type="submit" class="btn btn-primary">Create</button>
</form>
</#if>
<div class="welcome-primary-link">
<h3><a href="${adminUrl}"><img src="welcome-content/user.png">Administration Console <i class="fa fa-angle-right link" aria-hidden="true"></i></a></h3>
<div class="description">
Centrally manage all aspects of the ${productNameFull} server
Centrally manage all aspects of the ${productName} server
</div>
</div>
</div>
</div>
</#if> <#-- adminConsoleEnabled -->
<div class="col-xs-12 col-sm-4">
<div class="card-pf h-l">
<h3><a href="${properties.documentationUrl}"><img class="doc-img" src="welcome-content/admin-console.png">Documentation <i class="fa fa-angle-right link" aria-hidden="true"></i></a></h3>
@ -120,18 +123,14 @@
<h3><a href="https://groups.google.com/forum/#!forum/keycloak-user"><img src="welcome-content/mail.png">Mailing List <i class="fa fa-angle-right link" aria-hidden="true"></i></a></h3>
</div>
<div class="card-pf h-m">
<h3><a href="https://issues.jboss.org/browse/KEYCLOAK"><img src="welcome-content/bug.png">Report an issue <i class="fa fa-angle-right link" aria-hidden="true"></i></a></h3>
<h3><a href="https://github.com/keycloak/keycloak/issues"><img src="welcome-content/bug.png">Report an issue <i class="fa fa-angle-right link" aria-hidden="true"></i></a></h3>
</div>
</#if>
</div>
</div>
<div class='footer'>
<#if properties.displayCommunityLinks = "true">
<a href="http://www.jboss.org"><img src="welcome-content/jboss_community.png" alt="JBoss and JBoss Community"></a>
</#if>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,3 +1,9 @@
# lumbung.space
Custom theme for [login.lumung.space](https://login.lumbung.space).
- [login](./login) was copied from [default-themes/base/login](../default-themes/base/login)
## N.N themeing workflow:
If the browser complains about resource `was blocked due to MIME type (“”) mismatch (X-Content-Type-Options: nosniff).` is _actually_ the fact that it can not find that resource, it won't throw a 404 instead..

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("emailTestBodyHtml",realmName))?no_esc}
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("emailVerificationBodyCodeHtml",code))?no_esc}
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("emailVerificationBodyHtml",link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration)))?no_esc}
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("eventLoginErrorBodyHtml",event.date,event.ipAddress))?no_esc}
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("eventRemoveTotpBodyHtml",event.date, event.ipAddress))?no_esc}
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("eventUpdatePasswordBodyHtml",event.date, event.ipAddress))?no_esc}
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("eventUpdateTotpBodyHtml",event.date, event.ipAddress))?no_esc}
</body>
</html>

View File

@ -0,0 +1,9 @@
<#outputformat "plainText">
<#assign requiredActionsText><#if requiredActions??><#list requiredActions><#items as reqActionItem>${msg("requiredAction.${reqActionItem}")}<#sep>, </#sep></#items></#list></#if></#assign>
</#outputformat>
<html>
<body>
${kcSanitize(msg("executeActionsBodyHtml",link, linkExpiration, realmName, requiredActionsText, linkExpirationFormatter(linkExpiration)))?no_esc}
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("identityProviderLinkBodyHtml", identityProviderAlias, realmName, identityProviderContext.username, link, linkExpiration, linkExpirationFormatter(linkExpiration)))?no_esc}
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
${kcSanitize(msg("passwordResetBodyHtml",link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration)))?no_esc}
</body>
</html>

View File

@ -0,0 +1,50 @@
emailVerificationSubject=lumbung[dot]space: verify email
emailVerificationBody=Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {3}.\n\nIf you didn''t create this account, just ignore this message.
emailVerificationBodyHtml=<p>We''re excited to have you here! One more step to join! Please verify your account by pressing the link below.</p><p><a href="{0}">Link to e-mail address verification</a></p><p>Warmest regards, lumbung.space working group</p>
emailTestSubject=[KEYCLOAK] - SMTP test message
emailTestBody=This is a test message
emailTestBodyHtml=<p>This is a test message</p>
identityProviderLinkSubject=Link {0}
identityProviderLinkBody=Someone wants to link your "{1}" account with "{0}" account of user {2} . If this was you, click the link below to link accounts\n\n{3}\n\nThis link will expire within {5}.\n\nIf you don''t want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.
identityProviderLinkBodyHtml=<p>Someone wants to link your <b>{1}</b> account with <b>{0}</b> account of user {2} . If this was you, click the link below to link accounts</p><p><a href="{3}">Link to confirm account linking</a></p><p>This link will expire within {5}.</p><p>If you don''t want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.</p>
passwordResetSubject=Reset password
passwordResetBody=Someone just requested to change your {2} account''s credentials. If this was you, click on the link below to reset them.\n\n{0}\n\nThis link and code will expire within {3}.\n\nIf you don''t want to reset your credentials, just ignore this message and nothing will be changed.
passwordResetBodyHtml=<p>Someone just requested to change your {2} account''s credentials. If this was you, click on the link below to reset them.</p><p><a href="{0}">Link to reset credentials</a></p><p>This link will expire within {3}.</p><p>If you don''t want to reset your credentials, just ignore this message and nothing will be changed.</p>
executeActionsSubject=Update Your Account
executeActionsBody=Your administrator has just requested that you update your {2} account by performing the following action(s): {3}. Click on the link below to start this process.\n\n{0}\n\nThis link will expire within {4}.\n\nIf you are unaware that your administrator has requested this, just ignore this message and nothing will be changed.
executeActionsBodyHtml=<p>Your administrator has just requested that you update your {2} account by performing the following action(s): {3}. Click on the link below to start this process.</p><p><a href="{0}">Link to account update</a></p><p>This link will expire within {4}.</p><p>If you are unaware that your administrator has requested this, just ignore this message and nothing will be changed.</p>
eventLoginErrorSubject=Login error
eventLoginErrorBody=A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an administrator.
eventLoginErrorBodyHtml=<p>A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an administrator.</p>
eventRemoveTotpSubject=Remove OTP
eventRemoveTotpBody=OTP was removed from your account on {0} from {1}. If this was not you, please contact an administrator.
eventRemoveTotpBodyHtml=<p>OTP was removed from your account on {0} from {1}. If this was not you, please contact an administrator.</p>
eventUpdatePasswordSubject=Update password
eventUpdatePasswordBody=Your password was changed on {0} from {1}. If this was not you, please contact an administrator.
eventUpdatePasswordBodyHtml=<p>Your password was changed on {0} from {1}. If this was not you, please contact an administrator.</p>
eventUpdateTotpSubject=Update OTP
eventUpdateTotpBody=OTP was updated for your account on {0} from {1}. If this was not you, please contact an administrator.
eventUpdateTotpBodyHtml=<p>OTP was updated for your account on {0} from {1}. If this was not you, please contact an administrator.</p>
requiredAction.CONFIGURE_TOTP=Configure OTP
requiredAction.terms_and_conditions=Terms and Conditions
requiredAction.UPDATE_PASSWORD=Update Password
requiredAction.UPDATE_PROFILE=Update Profile
requiredAction.VERIFY_EMAIL=lumbung[dot]space: verify email
# units for link expiration timeout formatting
linkExpirationFormatter.timePeriodUnit.seconds=seconds
linkExpirationFormatter.timePeriodUnit.seconds.1=second
linkExpirationFormatter.timePeriodUnit.minutes=minutes
linkExpirationFormatter.timePeriodUnit.minutes.1=minute
#for language which have more unit plural forms depending on the value (eg. Czech and other Slavic langs) you can override unit text for some other values like this:
#linkExpirationFormatter.timePeriodUnit.minutes.2=minuty
#linkExpirationFormatter.timePeriodUnit.minutes.3=minuty
#linkExpirationFormatter.timePeriodUnit.minutes.4=minuty
linkExpirationFormatter.timePeriodUnit.hours=hours
linkExpirationFormatter.timePeriodUnit.hours.1=hour
linkExpirationFormatter.timePeriodUnit.days=days
linkExpirationFormatter.timePeriodUnit.days.1=day
emailVerificationBodyCode=Please verify your email address by entering in the following code.\n\n{0}\n\n.
emailVerificationBodyCodeHtml=<p>Please verify your email address by entering in the following code.</p><p><b>{0}</b></p>

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("emailTestBody", realmName)}

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("emailVerificationBodyCode",code)}

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("emailVerificationBody",link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration))}

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("eventLoginErrorBody",event.date,event.ipAddress)}

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("eventRemoveTotpBody",event.date, event.ipAddress)}

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("eventUpdatePasswordBody",event.date, event.ipAddress)}

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("eventUpdateTotpBody",event.date, event.ipAddress)}

View File

@ -0,0 +1,4 @@
<#ftl output_format="plainText">
<#assign requiredActionsText><#if requiredActions??><#list requiredActions><#items as reqActionItem>${msg("requiredAction.${reqActionItem}")}<#sep>, </#items></#list><#else></#if></#assign>
${msg("executeActionsBody",link, linkExpiration, realmName, requiredActionsText, linkExpirationFormatter(linkExpiration))}

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("identityProviderLinkBody", identityProviderAlias, realmName, identityProviderContext.username, link, linkExpiration, linkExpirationFormatter(linkExpiration))}

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("passwordResetBody",link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration))}

View File

@ -0,0 +1,7 @@
_ __ _ _
| |/ /___ _ _ ___| | ___ __ _| | __
| ' // _ \ | | |/ __| |/ _ \ / _` | |/ /
| . \ __/ |_| | (__| | (_) | (_| | <
|_|\_\___|\__, |\___|_|\___/ \__,_|_|\_\
|___/

19
lumbung.space/login/code.ftl Executable file
View File

@ -0,0 +1,19 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "header">
<#if code.success>
${msg("codeSuccessTitle")}
<#else>
${msg("codeErrorTitle", code.error)}
</#if>
<#elseif section = "form">
<div id="kc-code">
<#if code.success>
<p>${msg("copyCodeInstruction")}</p>
<input id="code" class="${properties.kcTextareaClass!}" value="${code.code}"/>
<#else>
<p id="error">${code.error}</p>
</#if>
</div>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,33 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "header">
${msg("deleteAccountConfirm")}
<#elseif section = "form">
<form action="${url.loginAction}" class="form-vertical" method="post">
<div class="alert alert-warning" style="margin-top:0 !important;margin-bottom:30px !important">
<span class="pficon pficon-warning-triangle-o"></span>
${msg("irreversibleAction")}
</div>
<p>${msg("deletingImplies")}</p>
<ul style="color: #72767b;list-style: disc;list-style-position: inside;">
<li>${msg("loggingOutImmediately")}</li>
<li>${msg("errasingData")}</li>
</ul>
<p class="delete-account-text">${msg("finalDeletionConfirmation")}</p>
<div id="kc-form-buttons">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doConfirmDelete")}" />
<#if triggered_from_aia>
<button class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" style="margin-left: calc(100% - 220px)" type="submit" name="cancel-aia" value="true" />${msg("doCancel")}</button>
</#if>
</div>
</form>
</#if>
</@layout.registrationLayout>

13
lumbung.space/login/error.ftl Executable file
View File

@ -0,0 +1,13 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=false; section>
<#if section = "header">
${msg("errorTitle")}
<#elseif section = "form">
<div id="kc-error-message">
<p class="instruction">${message.summary?no_esc}</p>
<#if client?? && client.baseUrl?has_content>
<p><a id="backToApplication" href="${client.baseUrl}">${kcSanitize(msg("backToApplication"))?no_esc}</a></p>
</#if>
</div>
</#if>
</@layout.registrationLayout>

24
lumbung.space/login/info.ftl Executable file
View File

@ -0,0 +1,24 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=false; section>
<#if section = "header">
<#if messageHeader??>
${messageHeader}
<#else>
${message.summary}
</#if>
<#elseif section = "form">
<div id="kc-info-message">
<p class="instruction">${message.summary}<#if requiredActions??><#list requiredActions>: <b><#items as reqActionItem>${msg("requiredAction.${reqActionItem}")}<#sep>, </#items></b></#list><#else></#if></p>
<#if skipLink??>
<#else>
<#if pageRedirectUri?has_content>
<p><a href="${pageRedirectUri}">${kcSanitize(msg("backToApplication"))?no_esc}</a></p>
<#elseif actionUri?has_content>
<p><a href="${actionUri}">${kcSanitize(msg("proceedWithAction"))?no_esc}</a></p>
<#elseif (client.baseUrl)?has_content>
<p><a href="${client.baseUrl}">${kcSanitize(msg("backToApplication"))?no_esc}</a></p>
</#if>
</#if>
</div>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,31 @@
<#ftl output_format="plainText">
${msg("loginTotpIntro")}
${msg("loginTotpStep1")}
<#list totp.policy.supportedApplications as app>
* ${app}
</#list>
${msg("loginTotpManualStep2")}
${totp.totpSecretEncoded}
${msg("loginTotpManualStep3")}
- ${msg("loginTotpType")}: ${msg("loginTotp." + totp.policy.type)}
- ${msg("loginTotpAlgorithm")}: ${totp.policy.getAlgorithmKey()}
- ${msg("loginTotpDigits")}: ${totp.policy.digits}
<#if totp.policy.type = "totp">
- ${msg("loginTotpInterval")}: ${totp.policy.period}
<#elseif totp.policy.type = "hotp">
- ${msg("loginTotpCounter")}: ${totp.policy.initialCounter}
</#if>
Enter in your one time password so we can verify you have installed it correctly.

View File

@ -0,0 +1,108 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayRequiredFields=false displayMessage=!messagesPerField.existsError('totp','userLabel'); section>
<#if section = "header">
${msg("loginTotpTitle")}
<#elseif section = "form">
<ol id="kc-totp-settings">
<li>
<p>${msg("loginTotpStep1")}</p>
<ul id="kc-totp-supported-apps">
<#list totp.policy.supportedApplications as app>
<li>${app}</li>
</#list>
</ul>
</li>
<#if mode?? && mode = "manual">
<li>
<p>${msg("loginTotpManualStep2")}</p>
<p><span id="kc-totp-secret-key">${totp.totpSecretEncoded}</span></p>
<p><a href="${totp.qrUrl}" id="mode-barcode">${msg("loginTotpScanBarcode")}</a></p>
</li>
<li>
<p>${msg("loginTotpManualStep3")}</p>
<p>
<ul>
<li id="kc-totp-type">${msg("loginTotpType")}: ${msg("loginTotp." + totp.policy.type)}</li>
<li id="kc-totp-algorithm">${msg("loginTotpAlgorithm")}: ${totp.policy.getAlgorithmKey()}</li>
<li id="kc-totp-digits">${msg("loginTotpDigits")}: ${totp.policy.digits}</li>
<#if totp.policy.type = "totp">
<li id="kc-totp-period">${msg("loginTotpInterval")}: ${totp.policy.period}</li>
<#elseif totp.policy.type = "hotp">
<li id="kc-totp-counter">${msg("loginTotpCounter")}: ${totp.policy.initialCounter}</li>
</#if>
</ul>
</p>
</li>
<#else>
<li>
<p>${msg("loginTotpStep2")}</p>
<img id="kc-totp-secret-qr-code" src="data:image/png;base64, ${totp.totpSecretQrCode}" alt="Figure: Barcode"><br/>
<p><a href="${totp.manualUrl}" id="mode-manual">${msg("loginTotpUnableToScan")}</a></p>
</li>
</#if>
<li>
<p>${msg("loginTotpStep3")}</p>
<p>${msg("loginTotpStep3DeviceName")}</p>
</li>
</ol>
<form action="${url.loginAction}" class="${properties.kcFormClass!}" id="kc-totp-settings-form" method="post">
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcInputWrapperClass!}">
<label for="totp" class="control-label">${msg("authenticatorCode")}</label> <span class="required">*</span>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input type="text" id="totp" name="totp" autocomplete="off" class="${properties.kcInputClass!}"
aria-invalid="<#if messagesPerField.existsError('totp')>true</#if>"
/>
<#if messagesPerField.existsError('totp')>
<span id="input-error-otp-code" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('totp'))?no_esc}
</span>
</#if>
</div>
<input type="hidden" id="totpSecret" name="totpSecret" value="${totp.totpSecret}" />
<#if mode??><input type="hidden" id="mode" name="mode" value="${mode}"/></#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcInputWrapperClass!}">
<label for="userLabel" class="control-label">${msg("loginTotpDeviceName")}</label> <#if totp.otpCredentials?size gte 1><span class="required">*</span></#if>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input type="text" class="${properties.kcInputClass!}" id="userLabel" name="userLabel" autocomplete="off"
aria-invalid="<#if messagesPerField.existsError('userLabel')>true</#if>"
/>
<#if messagesPerField.existsError('userLabel')>
<span id="input-error-otp-label" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('userLabel'))?no_esc}
</span>
</#if>
</div>
</div>
<#if isAppInitiatedAction??>
<input type="submit"
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}"
id="saveTOTPBtn" value="${msg("doSubmit")}"
/>
<button type="submit"
class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!} ${properties.kcButtonLargeClass!}"
id="cancelTOTPBtn" name="cancel-aia" value="true" />${msg("doCancel")}
</button>
<#else>
<input type="submit"
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
id="saveTOTPBtn" value="${msg("doSubmit")}"
/>
</#if>
</form>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,13 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "header">
${msg("confirmLinkIdpTitle")}
<#elseif section = "form">
<form id="kc-register-form" action="${url.loginAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" name="submitAction" id="updateProfile" value="updateProfile">${msg("confirmLinkIdpReviewProfile")}</button>
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" name="submitAction" id="linkAccount" value="linkAccount">${msg("confirmLinkIdpContinue", idpDisplayName)}</button>
</div>
</form>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,16 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "header">
${msg("emailLinkIdpTitle", idpDisplayName)}
<#elseif section = "form">
<p id="instruction1" class="instruction">
${msg("emailLinkIdp1", idpDisplayName, brokerContext.username, realm.displayName)}
</p>
<p id="instruction2" class="instruction">
${msg("emailLinkIdp2")} <a href="${url.loginAction}">${msg("doClickHere")}</a> ${msg("emailLinkIdp3")}
</p>
<p id="instruction3" class="instruction">
${msg("emailLinkIdp4")} <a href="${url.loginAction}">${msg("doClickHere")}</a> ${msg("emailLinkIdp5")}
</p>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,41 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout bodyClass="oauth"; section>
<#if section = "header">
<#if client.name?has_content>
${msg("oauthGrantTitle",advancedMsg(client.name))}
<#else>
${msg("oauthGrantTitle",client.clientId)}
</#if>
<#elseif section = "form">
<div id="kc-oauth" class="content-area">
<h3>${msg("oauthGrantRequest")}</h3>
<ul>
<#if oauth.clientScopesRequested??>
<#list oauth.clientScopesRequested as clientScope>
<li>
<span>${advancedMsg(clientScope.consentScreenText)}</span>
</li>
</#list>
</#if>
</ul>
<form class="form-actions" action="${url.oauthAction}" method="POST">
<input type="hidden" name="code" value="${oauth.code}">
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options">
<div class="${properties.kcFormOptionsWrapperClass!}">
</div>
</div>
<div id="kc-form-buttons">
<div class="${properties.kcFormButtonsWrapperClass!}">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="accept" id="kc-login" type="submit" value="${msg("doYes")}"/>
<input class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="cancel" id="kc-cancel" type="submit" value="${msg("doNo")}"/>
</div>
</div>
</div>
</form>
<div class="clearfix"></div>
</div>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,31 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "header">
${msg("oauth2DeviceVerificationTitle")}
<#elseif section = "form">
<form id="kc-user-verify-device-user-code-form" class="${properties.kcFormClass!}" action="${url.oauth2DeviceVerificationAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="device-user-code" class="${properties.kcLabelClass!}">${msg("verifyOAuth2DeviceUserCode")}</label>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input id="device-user-code" name="device_user_code" autocomplete="off" type="text" class="${properties.kcInputClass!}" autofocus />
</div>
</div>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
<div class="${properties.kcFormButtonsWrapperClass!}">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}"/>
</div>
</div>
</div>
</form>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,50 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('totp'); section>
<#if section="header">
${msg("doLogIn")}
<#elseif section="form">
<form id="kc-otp-login-form" class="${properties.kcFormClass!}" action="${url.loginAction}"
method="post">
<#if otpLogin.userOtpCredentials?size gt 1>
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcInputWrapperClass!}">
<#list otpLogin.userOtpCredentials as otpCredential>
<input id="kc-otp-credential-${otpCredential?index}" class="${properties.kcLoginOTPListInputClass!}" type="radio" name="selectedCredentialId" value="${otpCredential.id}" <#if otpCredential.id == otpLogin.selectedCredentialId>checked="checked"</#if>>
<label for="kc-otp-credential-${otpCredential?index}" class="${properties.kcLoginOTPListClass!}" tabindex="${otpCredential?index}">
<span class="${properties.kcLoginOTPListItemHeaderClass!}">
<span class="${properties.kcLoginOTPListItemIconBodyClass!}">
<i class="${properties.kcLoginOTPListItemIconClass!}" aria-hidden="true"></i>
</span>
<span class="${properties.kcLoginOTPListItemTitleClass!}">${otpCredential.userLabel}</span>
</span>
</label>
</#list>
</div>
</div>
</#if>
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="otp" class="${properties.kcLabelClass!}">${msg("loginOtpOneTime")}</label>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input id="otp" name="otp" autocomplete="off" type="text" class="${properties.kcInputClass!}"
autofocus aria-invalid="<#if messagesPerField.existsError('totp')>true</#if>"/>
<#if messagesPerField.existsError('totp')>
<span id="input-error-otp-code" class="${properties.kcInputErrorMessageClass!}"
aria-live="polite">
${kcSanitize(messagesPerField.get('totp'))?no_esc}
</span>
</#if>
</div>
</div>
<div class="${properties.kcFormGroupClass!}">
<input
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
name="login" id="kc-login" type="submit" value="${msg("doLogIn")}" />
</form>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,11 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "header">
${msg("pageExpiredTitle")}
<#elseif section = "form">
<p id="instruction1" class="instruction">
${msg("pageExpiredMsg1")} <a id="loginRestartLink" href="${url.loginRestartFlowUrl}">${msg("doClickHere")}</a> .<br/>
${msg("pageExpiredMsg2")} <a id="loginContinueLink" href="${url.loginAction}">${msg("doClickHere")}</a> .
</p>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,43 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('password'); section>
<#if section = "header">
${msg("doLogIn")}
<#elseif section = "form">
<div id="kc-form">
<div id="kc-form-wrapper">
<form id="kc-form-login" onsubmit="login.disabled = true; return true;" action="${url.loginAction}"
method="post">
<div class="${properties.kcFormGroupClass!} no-bottom-margin">
<hr/>
<label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
<input tabindex="2" id="password" class="${properties.kcInputClass!}" name="password"
type="password" autocomplete="on"
aria-invalid="<#if messagesPerField.existsError('password')>true</#if>"
/>
<#if messagesPerField.existsError('password')>
<span id="input-error-password" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('password'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!} ${properties.kcFormSettingClass!}">
<div id="kc-form-options">
</div>
<div class="${properties.kcFormOptionsWrapperClass!}">
<#if realm.resetPasswordAllowed>
<span><a tabindex="5"
href="${url.loginResetCredentialsUrl}">${msg("doForgotPassword")}</a></span>
</#if>
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormGroupClass!}">
<input tabindex="4" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
</div>
</form>
</div>
</div>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,36 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayInfo=true displayMessage=!messagesPerField.existsError('username'); section>
<#if section = "header">
${msg("emailForgotTitle")}
<#elseif section = "form">
<form id="kc-reset-password-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<label for="username" class="${properties.kcLabelClass!}"><#if !realm.loginWithEmailAllowed>${msg("username")}<#elseif !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>
<#if auth?has_content && auth.showUsername()>
<input type="text" id="username" name="username" class="${properties.kcInputClass!}" autofocus value="${auth.attemptedUsername}" aria-invalid="<#if messagesPerField.existsError('username')>true</#if>"/>
<#else>
<input type="text" id="username" name="username" class="${properties.kcInputClass!}" autofocus aria-invalid="<#if messagesPerField.existsError('username')>true</#if>"/>
</#if>
<#if messagesPerField.existsError('username')>
<span id="input-error-username" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('username'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!} ${properties.kcFormSettingClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">
<span><a href="${url.loginUrl}">${kcSanitize(msg("backToLogin"))?no_esc}</a></span>
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}"/>
</div>
</div>
</form>
<#elseif section = "info" >
${msg("emailInstruction")}
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,61 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('password','password-confirm'); section>
<#if section = "header">
${msg("updatePasswordTitle")}
<#elseif section = "form">
<form id="kc-passwd-update-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<input type="text" id="username" name="username" value="${username}" autocomplete="username"
readonly="readonly" style="display:none;"/>
<input type="password" id="password" name="password" autocomplete="current-password" style="display:none;"/>
<div class="${properties.kcFormGroupClass!}">
<label for="password-new" class="${properties.kcLabelClass!}">${msg("passwordNew")}</label>
<input type="password" id="password-new" name="password-new" class="${properties.kcInputClass!}"
autofocus autocomplete="new-password"
aria-invalid="<#if messagesPerField.existsError('password','password-confirm')>true</#if>"
<#if messagesPerField.existsError('password')>
<span id="input-error-password" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('password'))?no_esc}
</span>
</#if>
</div>
</div>
<div class="${properties.kcFormGroupClass!}">
<label for="password-confirm" class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label>
<input type="password" id="password-confirm" name="password-confirm"
class="${properties.kcInputClass!}"
autocomplete="new-password"
aria-invalid="<#if messagesPerField.existsError('password-confirm')>true</#if>"
/>
<#if messagesPerField.existsError('password-confirm')>
<span id="input-error-password-confirm" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('password-confirm'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">
<#if isAppInitiatedAction??>
<div class="checkbox">
<label><input type="checkbox" id="logout-sessions" name="logout-sessions" value="on" checked> ${msg("logoutOtherSessions")}</label>
</div>
</#if>
</div>
</div>
<#if isAppInitiatedAction??>
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
<button class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" type="submit" name="cancel-aia" value="true" />${msg("doCancel")}</button>
<#else>
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
</#if>
</div>
</form>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,79 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username','email','firstName','lastName'); section>
<#if section = "header">
${msg("loginProfileTitle")}
<#elseif section = "form">
<form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<#if user.editUsernameAllowed>
<div class="${properties.kcFormGroupClass!}">
<label for="username" class="${properties.kcLabelClass!}">${msg("username")}</label>
<input type="text" id="username" name="username" value="${(user.username!'')}"
class="${properties.kcInputClass!}"
aria-invalid="<#if messagesPerField.existsError('username')>true</#if>"
/>
<#if messagesPerField.existsError('username')>
<span id="input-error-username" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('username'))?no_esc}
</span>
</#if>
</div>
</#if>
<div class="${properties.kcFormGroupClass!}">
<label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
<input type="text" id="email" name="email" value="${(user.email!'')}"
class="${properties.kcInputClass!}"
aria-invalid="<#if messagesPerField.existsError('email')>true</#if>"
/>
<#if messagesPerField.existsError('email')>
<span id="input-error-email" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('email'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<label for="firstName" class="${properties.kcLabelClass!}">${msg("firstName")}</label>
<input type="text" id="firstName" name="firstName" value="${(user.firstName!'')}"
class="${properties.kcInputClass!}"
aria-invalid="<#if messagesPerField.existsError('firstName')>true</#if>"
/>
<#if messagesPerField.existsError('firstName')>
<span id="input-error-firstname" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('firstName'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<label for="lastName" class="${properties.kcLabelClass!}">${msg("lastName")}</label>
<input type="text" id="lastName" name="lastName" value="${(user.lastName!'')}"
class="${properties.kcInputClass!}"
aria-invalid="<#if messagesPerField.existsError('lastName')>true</#if>"
/>
<#if messagesPerField.existsError('lastName')>
<span id="input-error-lastname" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('lastName'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">
</div>
</div>
<#if isAppInitiatedAction??>
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
<button class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" type="submit" name="cancel-aia" value="true" />${msg("doCancel")}</button>
<#else>
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
</#if>
</div>
</form>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,92 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username') 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">
<div class="${properties.kcFormGroupClass!}">
<label for="username"
class="${properties.kcLabelClass!}"><#if !realm.loginWithEmailAllowed>${msg("username")}<#elseif !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>
<#if usernameEditDisabled??>
<input tabindex="1" id="username"
aria-invalid="<#if message?has_content && message.type = 'error'>true</#if>"
class="${properties.kcInputClass!}" name="username"
value="${(login.username!'')}"
type="text" disabled/>
<#else>
<input tabindex="1" id="username"
aria-invalid="<#if messagesPerField.existsError('username')>true</#if>"
class="${properties.kcInputClass!}" name="username"
value="${(login.username!'')}"
type="text" autofocus autocomplete="off"/>
</#if>
<#if messagesPerField.existsError('username')>
<span id="input-error-username" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('username'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!} ${properties.kcFormSettingClass!}">
<div id="kc-form-options">
<#if realm.rememberMe && !usernameEditDisabled??>
<div class="checkbox">
<label>
<#if login.rememberMe??>
<input tabindex="3" id="rememberMe" name="rememberMe" type="checkbox"
checked> ${msg("rememberMe")}
<#else>
<input tabindex="3" id="rememberMe" name="rememberMe"
type="checkbox"> ${msg("rememberMe")}
</#if>
</label>
</div>
</#if>
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormGroupClass!}">
<input tabindex="4"
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
</div>
</form>
</#if>
</div>
<#if realm.password && social.providers??>
<div id="kc-social-providers" class="${properties.kcFormSocialAccountSectionClass!}">
<hr/>
<h4>${msg("identity-provider-login-label")}</h4>
<ul class="${properties.kcFormSocialAccountListClass!} <#if social.providers?size gt 3>${properties.kcFormSocialAccountListGridClass!}</#if>">
<#list social.providers as p>
<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>
</#list>
</ul>
</div>
</#if>
<#elseif section = "info" >
<#if realm.password && realm.registrationAllowed && !registrationDisabled??>
<div id="kc-registration">
<span>${msg("noAccount")} <a tabindex="6" href="${url.registrationUrl}">${msg("doRegister")}</a></span>
</div>
</#if>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,2 @@
<#ftl output_format="plainText">
${msg("console-verify-email",email, code)}

View File

@ -0,0 +1,14 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayInfo=true; section>
<#if section = "header">
${msg("emailVerifyTitle")}
<#elseif section = "form">
<p class="instruction">${msg("emailVerifyInstruction1")}</p>
<#elseif section = "info">
<p class="instruction">
${msg("emailVerifyInstruction2")}
<br/>
<a href="${url.loginAction}">${msg("doClickHere")}</a> ${msg("emailVerifyInstruction3")}
</p>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,55 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "header">
${msg("doLogIn")}
<#elseif section = "form">
<form id="kc-x509-login-info" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="certificate_subjectDN" class="${properties.kcLabelClass!}">${msg("clientCertificate")}</label>
</div>
<#if x509.formData.subjectDN??>
<div class="${properties.kcLabelWrapperClass!}">
<label id="certificate_subjectDN" class="${properties.kcLabelClass!}">${(x509.formData.subjectDN!"")}</label>
</div>
<#else>
<div class="${properties.kcLabelWrapperClass!}">
<label id="certificate_subjectDN" class="${properties.kcLabelClass!}">${msg("noCertificate")}</label>
</div>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<#if x509.formData.isUserEnabled??>
<div class="${properties.kcLabelWrapperClass!}">
<label for="username" class="${properties.kcLabelClass!}">${msg("doX509Login")}</label>
</div>
<div class="${properties.kcLabelWrapperClass!}">
<label id="username" class="${properties.kcLabelClass!}">${(x509.formData.username!'')}</label>
</div>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
<div class="${properties.kcFormButtonsWrapperClass!}">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="login" id="kc-login" type="submit" value="${msg("doContinue")}"/>
<#if x509.formData.isUserEnabled??>
<input class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="cancel" id="kc-cancel" type="submit" value="${msg("doIgnore")}"/>
</#if>
</div>
</div>
</div>
</form>
</#if>
</@layout.registrationLayout>

119
lumbung.space/login/login.ftl Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,415 @@
doLogIn=sign in
doRegister=Register
doCancel=Cancel
doSubmit=Submit
doBack=Back
doYes=Yes
doNo=No
doContinue=Continue
doIgnore=Ignore
doAccept=Accept
doDecline=Decline
doForgotPassword=Forgot Password?
doClickHere=Click here
doImpersonate=Impersonate
doTryAgain=Try again
doTryAnotherWay=Try Another Way
doConfirmDelete=Confirm deletion
errorDeletingAccount=Error happened while deleting account
deletingAccountForbidden=You do not have enough permissions to delete your own account, contact admin.
kerberosNotConfigured=Kerberos Not Configured
kerberosNotConfiguredTitle=Kerberos Not Configured
bypassKerberosDetail=Either you are not logged in by Kerberos or your browser is not set up for Kerberos login. Please click continue to login in through other means
kerberosNotSetUp=Kerberos is not set up. You cannot login.
registerTitle=Register
loginAccountTitle= sign in to
loginTitle=Sign in to {0}
loginTitleHtml={0}
impersonateTitle={0} Impersonate User
impersonateTitleHtml=<strong>{0}</strong> Impersonate User
realmChoice=Realm
unknownUser=Unknown user
loginTotpTitle=Mobile Authenticator Setup
loginProfileTitle=Update Account Information
loginTimeout=Your login attempt timed out. Login will start from the beginning.
oauthGrantTitle=Grant Access to {0}
oauthGrantTitleHtml={0}
errorTitle=We are sorry...
errorTitleHtml=We are <strong>sorry</strong> ...
emailVerifyTitle=Email verification
emailForgotTitle=Forgot Your Password?
updatePasswordTitle=Update password
codeSuccessTitle=Success code
codeErrorTitle=Error code\: {0}
displayUnsupported=Requested display type unsupported
browserRequired=Browser required to login
browserContinue=Browser required to complete login
browserContinuePrompt=Open browser and continue login? [y/n]:
browserContinueAnswer=y
termsTitle=Terms and Conditions
termsText=<p>Terms and conditions to be defined</p>
termsPlainText=Terms and conditions to be defined.
recaptchaFailed=Invalid Recaptcha
recaptchaNotConfigured=Recaptcha is required, but not configured
consentDenied=Consent denied.
noAccount=New user?
username=Username
usernameOrEmail=username or email
firstName=First name
givenName=Given name
fullName=Full name
lastName=Last name
familyName=Family name
email=Email
password=password
passwordConfirm=Confirm password
passwordNew=New Password
passwordNewConfirm=New Password confirmation
rememberMe=Remember me
authenticatorCode=One-time code
address=Address
street=Street
locality=City or Locality
region=State, Province, or Region
postal_code=Zip or Postal code
country=Country
emailVerified=Email verified
website=Web page
phoneNumber=Phone number
phoneNumberVerified=Phone number verified
gender=Gender
birthday=Birthdate
zoneinfo=Time zone
gssDelegationCredential=GSS Delegation Credential
logoutOtherSessions=Sign out from other devices
profileScopeConsentText=User profile
emailScopeConsentText=Email address
addressScopeConsentText=Address
phoneScopeConsentText=Phone number
offlineAccessScopeConsentText=Offline Access
samlRoleListScopeConsentText=My Roles
rolesScopeConsentText=User roles
restartLoginTooltip=Restart login
loginTotpIntro=You need to set up a One Time Password generator to access this account
loginTotpStep1=Install one of the following applications on your mobile:
loginTotpStep2=Open the application and scan the barcode:
loginTotpStep3=Enter the one-time code provided by the application and click Submit to finish the setup.
loginTotpStep3DeviceName=Provide a Device Name to help you manage your OTP devices.
loginTotpManualStep2=Open the application and enter the key:
loginTotpManualStep3=Use the following configuration values if the application allows setting them:
loginTotpUnableToScan=Unable to scan?
loginTotpScanBarcode=Scan barcode?
loginCredential=Credential
loginOtpOneTime=One-time code
loginTotpType=Type
loginTotpAlgorithm=Algorithm
loginTotpDigits=Digits
loginTotpInterval=Interval
loginTotpCounter=Counter
loginTotpDeviceName=Device Name
loginTotp.totp=Time-based
loginTotp.hotp=Counter-based
loginChooseAuthenticator=Select login method
oauthGrantRequest=Do you grant these access privileges?
inResource=in
oauth2DeviceVerificationTitle=Device Login
verifyOAuth2DeviceUserCode=Enter the code provided by your device and click Submit
oauth2DeviceInvalidUserCodeMessage=Invalid code, please try again.
oauth2DeviceExpiredUserCodeMessage=The code has expired. Please go back to your device and try connecting again.
oauth2DeviceVerificationCompleteHeader=Device Login Successful
oauth2DeviceVerificationCompleteMessage=You may close this browser window and go back to your device.
oauth2DeviceVerificationFailedHeader=Device Login Failed
oauth2DeviceVerificationFailedMessage=You may close this browser window and go back to your device and try connecting again.
oauth2DeviceConsentDeniedMessage=Consent denied for connecting the device.
oauth2DeviceAuthorizationGrantDisabledMessage=Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client.
emailVerifyInstruction1=An email with instructions to verify your email address has been sent to you.
emailVerifyInstruction2=Haven''t received a verification code in your email?
emailVerifyInstruction3=to re-send the email. Don''t forget to check your spam folder! Feel free to mail contact@lumbung.space if you are still having problems, we''re happy to help out.
emailLinkIdpTitle=Link {0}
emailLinkIdp1=An email with instructions to link {0} account {1} with your {2} account has been sent to you.
emailLinkIdp2=Haven''t received a verification code in your email?
emailLinkIdp3=to re-send the email.
emailLinkIdp4=If you already verified the email in different browser
emailLinkIdp5=to continue.
backToLogin=&laquo; Back to Login
emailInstruction=Enter your username or email address and we will send you instructions on how to create a new password.
copyCodeInstruction=Please copy this code and paste it into your application:
pageExpiredTitle=Page has expired
pageExpiredMsg1=To restart the login process
pageExpiredMsg2=To continue the login process
personalInfo=Personal Info:
role_admin=Admin
role_realm-admin=Realm Admin
role_create-realm=Create realm
role_create-client=Create client
role_view-realm=View realm
role_view-users=View users
role_view-applications=View applications
role_view-clients=View clients
role_view-events=View events
role_view-identity-providers=View identity providers
role_manage-realm=Manage realm
role_manage-users=Manage users
role_manage-applications=Manage applications
role_manage-identity-providers=Manage identity providers
role_manage-clients=Manage clients
role_manage-events=Manage events
role_view-profile=View profile
role_manage-account=Manage account
role_manage-account-links=Manage account links
role_read-token=Read token
role_offline-access=Offline access
client_account=Account
client_account-console=Account Console
client_security-admin-console=Security Admin Console
client_admin-cli=Admin CLI
client_realm-management=Realm Management
client_broker=Broker
requiredFields=Required fields
invalidUserMessage=Invalid username or password.
invalidUsernameMessage=Invalid username.
invalidUsernameOrEmailMessage=Invalid username or email.
invalidPasswordMessage=Invalid password.
invalidEmailMessage=Invalid email address.
accountDisabledMessage=Account is disabled, contact your administrator.
accountTemporarilyDisabledMessage=Account is temporarily disabled; contact your administrator or retry later.
expiredCodeMessage=Login timeout. Please sign in again.
expiredActionMessage=Action expired. Please continue with login now.
expiredActionTokenNoSessionMessage=Action expired.
expiredActionTokenSessionExistsMessage=Action expired. Please start again.
missingFirstNameMessage=Please specify first name.
missingLastNameMessage=Please specify last name.
missingEmailMessage=Please specify email.
missingUsernameMessage=Please specify username.
missingPasswordMessage=Please specify password.
missingTotpMessage=Please specify authenticator code.
missingTotpDeviceNameMessage=Please specify device name.
notMatchPasswordMessage=Passwords don''t match.
invalidPasswordExistingMessage=Invalid existing password.
invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted.
invalidPasswordConfirmMessage=Password confirmation doesn''t match.
invalidTotpMessage=Invalid authenticator code.
usernameExistsMessage=Username already exists.
emailExistsMessage=Email already exists.
federatedIdentityExistsMessage=User with {0} {1} already exists. Please login to account management to link the account.
federatedIdentityUnavailableMessage=User {0} authenticated with identity provider {1} does not exists. Please contact your administrator.
confirmLinkIdpTitle=Account already exists
federatedIdentityConfirmLinkMessage=User with {0} {1} already exists. How do you want to continue?
federatedIdentityConfirmReauthenticateMessage=Authenticate to link your account with {0}
nestedFirstBrokerFlowMessage=The {0} user {1} is not linked to any known user.
confirmLinkIdpReviewProfile=Review profile
confirmLinkIdpContinue=Add to existing account
configureTotpMessage=You need to set up Mobile Authenticator to activate your account.
updateProfileMessage=You need to update your user profile to activate your account.
updatePasswordMessage=You need to change your password to activate your account.
resetPasswordMessage=You need to change your password.
verifyEmailMessage=You need to verify your email address to activate your account.
linkIdpMessage=You need to verify your email address to link your account with {0}.
emailSentMessage=You should receive an email shortly with further instructions.
emailSendErrorMessage=Failed to send email, please try again later.
accountUpdatedMessage=Your account has been updated.
accountPasswordUpdatedMessage=Your password has been updated.
delegationCompleteHeader=Login Successful
delegationCompleteMessage=You may close this browser window and go back to your console application.
delegationFailedHeader=Login Failed
delegationFailedMessage=You may close this browser window and go back to your console application and try logging in again.
noAccessMessage=No access
invalidPasswordMinLengthMessage=Invalid password: minimum length {0}.
invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits.
invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters.
invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters.
invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters.
invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username.
invalidPasswordNotEmailMessage=Invalid password: must not be equal to the email.
invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s).
invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords.
invalidPasswordGenericMessage=Invalid password: new password doesn''t match password policies.
failedToProcessResponseMessage=Failed to process response
httpsRequiredMessage=HTTPS required
realmNotEnabledMessage=Realm not enabled
invalidRequestMessage=Invalid Request
failedLogout=Logout failed
unknownLoginRequesterMessage=Unknown login requester
loginRequesterNotEnabledMessage=Login requester not enabled
bearerOnlyMessage=Bearer-only applications are not allowed to initiate browser login
standardFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client.
implicitFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.
invalidRedirectUriMessage=Invalid redirect uri
unsupportedNameIdFormatMessage=Unsupported NameIDFormat
invalidRequesterMessage=Invalid requester
registrationNotAllowedMessage=Registration not allowed
resetCredentialNotAllowedMessage=Reset Credential not allowed
permissionNotApprovedMessage=Permission not approved.
noRelayStateInResponseMessage=No relay state in response from identity provider.
insufficientPermissionMessage=Insufficient permissions to link identities.
couldNotProceedWithAuthenticationRequestMessage=Could not proceed with authentication request to identity provider.
couldNotObtainTokenMessage=Could not obtain token from identity provider.
unexpectedErrorRetrievingTokenMessage=Unexpected error when retrieving token from identity provider.
unexpectedErrorHandlingResponseMessage=Unexpected error when handling response from identity provider.
identityProviderAuthenticationFailedMessage=Authentication failed. Could not authenticate with identity provider.
couldNotSendAuthenticationRequestMessage=Could not send authentication request to identity provider.
unexpectedErrorHandlingRequestMessage=Unexpected error when handling authentication request to identity provider.
invalidAccessCodeMessage=Invalid access code.
sessionNotActiveMessage=Session not active.
invalidCodeMessage=An error occurred, please login again through your application.
identityProviderUnexpectedErrorMessage=Unexpected error when authenticating with identity provider
identityProviderMissingStateMessage=Missing state parameter in response from identity provider.
identityProviderNotFoundMessage=Could not find an identity provider with the identifier.
identityProviderLinkSuccess=You successfully verified your email. Please go back to your original browser and continue there with the login.
staleCodeMessage=This page is no longer valid, please go back to your application and sign in again
realmSupportsNoCredentialsMessage=Realm does not support any credential type.
credentialSetupRequired=Cannot login, credential setup required.
identityProviderNotUniqueMessage=Realm supports multiple identity providers. Could not determine which identity provider should be used to authenticate with.
emailVerifiedMessage=Your email address has been verified.
staleEmailVerificationLink=The link you clicked is an old stale link and is no longer valid. Maybe you have already verified your email.
identityProviderAlreadyLinkedMessage=Federated identity returned by {0} is already linked to another user.
confirmAccountLinking=Confirm linking the account {0} of identity provider {1} with your account.
confirmEmailAddressVerification=Confirm validity of e-mail address {0}.
confirmExecutionOfActions=Perform the following action(s)
locale_ca=Catal\u00E0
locale_cs=\u010Ce\u0161tina
locale_da=Dansk
locale_de=Deutsch
locale_en=English
locale_es=Espa\u00F1ol
locale_fr=Fran\u00E7ais
locale_hu=Magyar
locale_it=Italiano
locale_ja=\u65E5\u672C\u8A9E
locale_lt=Lietuvi\u0173
locale_nl=Nederlands
locale_no=Norsk
locale_pl=Polski
locale_pt_BR=Portugu\u00EAs (Brasil)
locale_pt-BR=Portugu\u00EAs (Brasil)
locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
locale_sk=Sloven\u010Dina
locale_sv=Svenska
locale_tr=T\u00FCrk\u00E7e
locale_zh-CN=\u4E2D\u6587\u7B80\u4F53
backToApplication=&laquo; Back to Application
missingParameterMessage=Missing parameters\: {0}
clientNotFoundMessage=Client not found.
clientDisabledMessage=Client disabled.
invalidParameterMessage=Invalid parameter\: {0}
alreadyLoggedIn=You are already logged in.
differentUserAuthenticated=You are already authenticated as different user ''{0}'' in this session. Please sign out first.
brokerLinkingSessionExpired=Requested broker account linking, but current session is no longer valid.
proceedWithAction=&raquo; Click here to proceed
requiredAction.CONFIGURE_TOTP=Configure OTP
requiredAction.terms_and_conditions=Terms and Conditions
requiredAction.UPDATE_PASSWORD=Update Password
requiredAction.UPDATE_PROFILE=Update Profile
requiredAction.VERIFY_EMAIL=Verify Email
doX509Login=You will be logged in as\:
clientCertificate=X509 client certificate\:
noCertificate=[No Certificate]
pageNotFound=Page not found
internalServerError=An internal server error has occurred
console-username=Username:
console-password=Password:
console-otp=One Time Password:
console-new-password=New Password:
console-confirm-password=Confirm Password:
console-update-password=Update of your password is required.
console-verify-email=You need to verify your email address. We sent an email to {0} that contains a verification code. Please enter this code into the input below.
console-email-code=Email Code:
console-accept-terms=Accept Terms? [y/n]:
console-accept=y
# Openshift messages
openshift.scope.user_info=User information
openshift.scope.user_check-access=User access information
openshift.scope.user_full=Full Access
openshift.scope.list-projects=List projects
# SAML authentication
saml.post-form.title=Authentication Redirect
saml.post-form.message=Redirecting, please wait.
saml.post-form.js-disabled=JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue.
saml.artifactResolutionServiceInvalidResponse=Unable to resolve artifact.
#authenticators
otp-display-name=Authenticator Application
otp-help-text=Enter a verification code from authenticator application.
password-display-name=Password
password-help-text=Sign in by entering your password.
auth-username-form-display-name=Username
auth-username-form-help-text=Start sign in by entering your username
auth-username-password-form-display-name=Username and password
auth-username-password-form-help-text=Sign in by entering your username and password.
# WebAuthn
webauthn-display-name=Security Key
webauthn-help-text=Use your security key to sign in.
webauthn-passwordless-display-name=Security Key
webauthn-passwordless-help-text=Use your security key for passwordless sign in.
webauthn-login-title=Security Key login
webauthn-registration-title=Security Key Registration
webauthn-available-authenticators=Available authenticators
webauthn-unsupported-browser-text=WebAuthn is not supported by this browser. Try another one or contact your administrator.
# WebAuthn Error
webauthn-error-title=Security Key Error
webauthn-error-registration=Failed to register your Security key.<br/> {0}
webauthn-error-api-get=Failed to authenticate by the Security key.<br/> {0}
webauthn-error-different-user=First authenticated user is not the one authenticated by the Security key.
webauthn-error-auth-verification=Security key authentication result is invalid.<br/> {0}
webauthn-error-register-verification=Security key registration result is invalid.<br/> {0}
webauthn-error-user-not-found=Unknown user authenticated by the Security key.
# Identity provider
identity-provider-redirector=Connect with another Identity Provider
identity-provider-login-label=Or sign in with
finalDeletionConfirmation=If you delete your account, it cannot be restored. To keep your account, click Cancel.
irreversibleAction=This action is irreversible
deleteAccountConfirm=Delete account confirmation
deletingImplies=Deleting your account implies:
errasingData=Erasing all your data
loggingOutImmediately=Logging you out immediately
accountUnusable=Any subsequent use of the application will not be possible with this account
userDeletedSuccessfully=User deleted successfully
access-denied=Access denied

113
lumbung.space/login/register.ftl Executable file
View File

@ -0,0 +1,113 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('firstName','lastName','email','username','password','password-confirm'); section>
<#if section = "header">
${msg("registerTitle")}
<#elseif section = "form">
<form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.registrationAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<label for="firstName" class="${properties.kcLabelClass!}">${msg("firstName")}</label>
<input type="text" id="firstName" class="${properties.kcInputClass!}" name="firstName"
value="${(register.formData.firstName!'')}"
aria-invalid="<#if messagesPerField.existsError('firstName')>true</#if>"
/>
<#if messagesPerField.existsError('firstName')>
<span id="input-error-firstname" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('firstName'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<label for="lastName" class="${properties.kcLabelClass!}">${msg("lastName")}</label>
<input type="text" id="lastName" class="${properties.kcInputClass!}" name="lastName"
value="${(register.formData.lastName!'')}"
aria-invalid="<#if messagesPerField.existsError('lastName')>true</#if>"
/>
<#if messagesPerField.existsError('lastName')>
<span id="input-error-lastname" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('lastName'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
<input type="text" id="email" class="${properties.kcInputClass!}" name="email"
value="${(register.formData.email!'')}" autocomplete="email"
aria-invalid="<#if messagesPerField.existsError('email')>true</#if>"
/>
<#if messagesPerField.existsError('email')>
<span id="input-error-email" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('email'))?no_esc}
</span>
</#if>
</div>
<#if !realm.registrationEmailAsUsername>
<div class="${properties.kcFormGroupClass!}">
<label for="username" class="${properties.kcLabelClass!}">${msg("username")}</label>
<input type="text" id="username" class="${properties.kcInputClass!}" name="username"
value="${(register.formData.username!'')}" autocomplete="username"
aria-invalid="<#if messagesPerField.existsError('username')>true</#if>"
/>
<#if messagesPerField.existsError('username')>
<span id="input-error-username" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('username'))?no_esc}
</span>
</#if>
</div>
</#if>
<#if passwordRequired??>
<div class="${properties.kcFormGroupClass!}">
<label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
<input type="password" id="password" class="${properties.kcInputClass!}" name="password"
autocomplete="new-password"
aria-invalid="<#if messagesPerField.existsError('password','password-confirm')>true</#if>"
/>
<#if messagesPerField.existsError('password')>
<span id="input-error-password" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('password'))?no_esc}
</span>
</#if>
</div>
<div class="${properties.kcFormGroupClass!}">
<label for="password-confirm"
class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label>
<input type="password" id="password-confirm" class="${properties.kcInputClass!}"
name="password-confirm"
aria-invalid="<#if messagesPerField.existsError('password-confirm')>true</#if>"
/>
<#if messagesPerField.existsError('password-confirm')>
<span id="input-error-password-confirm" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('password-confirm'))?no_esc}
</span>
</#if>
</div>
</#if>
<#if recaptchaRequired??>
<div class="form-group">
<div class="g-recaptcha" data-size="compact" data-sitekey="${recaptchaSiteKey}"></div>
</div>
</#if>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">
<span><a href="${url.loginUrl}">${kcSanitize(msg("backToLogin"))?no_esc}</a></span>
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doRegister")}"/>
</div>
</div>
</form>
</#if>
</@layout.registrationLayout>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -0,0 +1,295 @@
@font-face {
font-family: Gudea;
font-style: normal;
font-weight: 400;
src: url(../fonts/gudea.woff2) format("woff2");
}
@font-face {
font-family: Gudea;
font-style: italic;
font-weight: 400;
src: url(../fonts/gudea-italic.woff2) format("woff2");
}
@font-face {
font-family: Gudea;
font-style: bold;
font-weight: 700;
src: url(../fonts/gudea-bold.woff2) format("woff2");
}
body {
font-size:1.3em;
font-family: Gudea, sans-serif;
}
a {
color: #1B4C8A;
}
.card-pf {
border:2px solid black;
max-width:500px;
margin:auto;
margin-top: 4em;
}
.col-xs-12.col-sm-12.col-md-12.col-lg-12 {
display: flex;
}
/*Login form */
.login-pf-header {
background-color: #BCE1D1;
height: 3.6em;
}
.header-container {
display: flex;
flex-direction: column;
margin-top: -3em;
}
.logo {
background-color: white;
border: 1px solid black;
margin-left: 5.5em;
transform: rotate(5deg);
}
#kc-page-title {
margin-left: 0.75em;
font-size: 1em;
display: inline-block;
height: 100%;
font-weight: normal;
}
#kc-form-wrapper {
margin-top: 1em;
}
#kc-terms-text {
padding: 1em;
}
#terms-form {
padding-left: 1em;
padding-bottom: 1em;
}
#kc-form-login {
display: flex;
align-items: baseline;
flex-direction: column;
max-width: 500px;
margin: 0 auto;
}
.form-group {
font-size: 14px;
margin: 10px auto;
width: 440px;
display: flex;
flex-direction: column;
}
.form-group.login-pf-settings {
display: flex;
flex-direction: row;
justify-content: space-between;
vertical-align: baseline;
align-items: baseline;
border: none;
}
#kc-username.form-group{
border: none;
padding-left: 1em;
font-size: 14px;
}
.form-group label {
padding-bottom: 0.5em;
}
#kc-form-buttons {
all: unset;
display: inline-block;
width: 100%;
height: 2em;
align-self: center;
background-color: #AFAFAF;
border-top: 2px solid black;
cursor: pointer;
}
#kc-form-buttons:hover {
background-color: #bce1d1;
}
#kc-form-buttons:hover .login-button {
color: black;
}
.login-button {
all: unset;
display: block;
border: none;
color: #FFFFFF;
font-size: 1em;
font-weight: bold;
margin: auto;
padding: 0.3em;
}
.btn-lg {
all: unset;
display: block;
border: none;
color: #FFFFFF;
font-size: 1em;
font-weight: bold;
margin: auto;
padding: 0.2em;
}
#terms-form .btn-lg {
all: unset;
display: block;
border: none;
color: black;
font-size: 1em;
font-weight: bold;
margin: auto;
padding: 0.2em;
}
#terms-form .btn-lg:hover {
color: gray;
}
.pf-c-form-control {
border: none;
padding: 5px 5px 5px 5px;
border: 2px solid black;
flex-grow: 1;
}
/*OTP Login*/
#kc-username.form-group {
padding-left: 1em;
border: none;
}
#kc-attempted-username {
padding: 0;
font-style: unset;
}
div#kc-username:before{
content: "Logging in as: ";
}
.kc-login-tooltip {
text-align: right;
padding-right: 1em;
}
/*Login form + options*/
#kc-info {
padding: 0.5em;
font-size: 14px;
}
.pf-c-form__helper-text {
display: block;
border-top: 2px solid black;
text-align: right;
padding-right: 1em;
padding: 0.2em;
}
.required{
background-color: salmon;
}
/*Register form*/
#kc-register-form {
margin-left: 1em;
margin-right: 1em;
margin-top: 1em;
margin-bottom: 1.5em;
}
/*Page has expired message*/
#instruction1 {
margin: 2em;
font-size: 1rem;
}
#input-error {
border-top: 2px solid black;
width: 100%;
padding: 0;
padding-top: 0px;
padding-bottom: 0px;
display: inline-block;
padding-top: 0.2em;
padding-bottom: 0.2em;
text-align: center;
}
/* Reset */
.pf-c-alert__title .kc-feedback-text{
font-size: 14px;
}
/* Register */
.pf-c-form__helper-text .pf-m-error .required .kc-feedback-text{
border-top: 2px solid black;
}
/* media queries */
@media screen and (max-width: 530px) {
#kc-page-title {
border: unset;
}
#kc-register-form {
margin: unset;
margin-bottom: 1.5em;
}
.logo {
max-width: 320px;
transform: none;
}
.logo svg {
width: 100%;
}
.form-group {
width: 88vw;
}
.form-group.login-pf-settings {
margin-bottom: 2em;
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,114 @@
// for embedded scripts, quoted and modified from https://github.com/swansontec/rfc4648.js by William Swanson
'use strict';
var base64url = base64url || {};
(function(base64url) {
function parse (string, encoding, opts = {}) {
// Build the character lookup table:
if (!encoding.codes) {
encoding.codes = {};
for (let i = 0; i < encoding.chars.length; ++i) {
encoding.codes[encoding.chars[i]] = i;
}
}
// The string must have a whole number of bytes:
if (!opts.loose && (string.length * encoding.bits) & 7) {
throw new SyntaxError('Invalid padding');
}
// Count the padding bytes:
let end = string.length;
while (string[end - 1] === '=') {
--end;
// If we get a whole number of bytes, there is too much padding:
if (!opts.loose && !(((string.length - end) * encoding.bits) & 7)) {
throw new SyntaxError('Invalid padding');
}
}
// Allocate the output:
const out = new (opts.out || Uint8Array)(((end * encoding.bits) / 8) | 0);
// Parse the data:
let bits = 0; // Number of bits currently in the buffer
let buffer = 0; // Bits waiting to be written out, MSB first
let written = 0; // Next byte to write
for (let i = 0; i < end; ++i) {
// Read one character from the string:
const value = encoding.codes[string[i]];
if (value === void 0) {
throw new SyntaxError('Invalid character ' + string[i]);
}
// Append the bits to the buffer:
buffer = (buffer << encoding.bits) | value;
bits += encoding.bits;
// Write out some bits if the buffer has a byte's worth:
if (bits >= 8) {
bits -= 8;
out[written++] = 0xff & (buffer >> bits);
}
}
// Verify that we have received just enough bits:
if (bits >= encoding.bits || 0xff & (buffer << (8 - bits))) {
throw new SyntaxError('Unexpected end of data');
}
return out
}
function stringify (data, encoding, opts = {}) {
const { pad = true } = opts;
const mask = (1 << encoding.bits) - 1;
let out = '';
let bits = 0; // Number of bits currently in the buffer
let buffer = 0; // Bits waiting to be written out, MSB first
for (let i = 0; i < data.length; ++i) {
// Slurp data into the buffer:
buffer = (buffer << 8) | (0xff & data[i]);
bits += 8;
// Write out as much as we can:
while (bits > encoding.bits) {
bits -= encoding.bits;
out += encoding.chars[mask & (buffer >> bits)];
}
}
// Partial character:
if (bits) {
out += encoding.chars[mask & (buffer << (encoding.bits - bits))];
}
// Add padding characters until we hit a byte boundary:
if (pad) {
while ((out.length * encoding.bits) & 7) {
out += '=';
}
}
return out
}
const encoding = {
chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
bits: 6
}
base64url.decode = function (string, opts) {
return parse(string, encoding, opts);
}
base64url.encode = function (data, opts) {
return stringify(data, encoding, opts)
}
return base64url;
}(base64url));

View File

@ -0,0 +1,25 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "header">
${msg("saml.post-form.title")}
<#elseif section = "form">
<script>window.onload = function() {document.forms[0].submit()};</script>
<p>${msg("saml.post-form.message")}</p>
<form name="saml-post-binding" method="post" action="${samlPost.url}">
<#if samlPost.SAMLRequest??>
<input type="hidden" name="SAMLRequest" value="${samlPost.SAMLRequest}"/>
</#if>
<#if samlPost.SAMLResponse??>
<input type="hidden" name="SAMLResponse" value="${samlPost.SAMLResponse}"/>
</#if>
<#if samlPost.relayState??>
<input type="hidden" name="RelayState" value="${samlPost.relayState}"/>
</#if>
<noscript>
<p>${msg("saml.post-form.js-disabled")}</p>
<input type="submit" value="${msg("doContinue")}"/>
</noscript>
</form>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,43 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayInfo=false; section>
<#if section = "header" || section = "show-username">
<script type="text/javascript">
function fillAndSubmit(authExecId) {
document.getElementById('authexec-hidden-input').value = authExecId;
document.getElementById('kc-select-credential-form').submit();
}
</script>
<#if section = "header">
${msg("loginChooseAuthenticator")}
</#if>
<#elseif section = "form">
<form id="kc-select-credential-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<div class="${properties.kcSelectAuthListClass!}">
<#list auth.authenticationSelections as authenticationSelection>
<div class="${properties.kcSelectAuthListItemClass!}" onclick="fillAndSubmit('${authenticationSelection.authExecId}')">
<div class="${properties.kcSelectAuthListItemIconClass!}">
<i class="${properties['${authenticationSelection.iconCssClass}']!authenticationSelection.iconCssClass} fa-2x"></i>
</div>
<div class="${properties.kcSelectAuthListItemBodyClass!}">
<div class="${properties.kcSelectAuthListItemHeadingClass!}">
${msg('${authenticationSelection.displayName}')}
</div>
<div class="${properties.kcSelectAuthListItemDescriptionClass!}">
${msg('${authenticationSelection.helpText}')}
</div>
</div>
<div class="${properties.kcSelectAuthListItemFillClass!}"></div>
<div class="${properties.kcSelectAuthListItemArrowClass!}">
<i class="${properties.kcSelectAuthListItemArrowIconClass!}"></i>
</div>
</div>
</#list>
<input type="hidden" id="authexec-hidden-input" name="authenticationExecution" />
</div>
</form>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,152 @@
<#macro registrationLayout bodyClass="" displayInfo=false displayMessage=true displayRequiredFields=false showAnotherWayIfPresent=true>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" class="${properties.kcHtmlClass!}">
<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>
<#if properties.scripts?has_content>
<#list properties.scripts?split(' ') as script>
<script src="${url.resourcesPath}/${script}" type="text/javascript"></script>
</#list>
</#if>
<#if scripts??>
<#list scripts as script>
<script src="${script}" type="text/javascript"></script>
</#list>
</#if>
</head>
<body class="${properties.kcBodyClass!}">
<div class="${properties.kcLoginClass!}">
<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="${properties.kcLocaleDropDownClass!}">
<a href="#" id="kc-current-locale-link">${locale.current}</a>
<ul class="${properties.kcLocaleListClass!}">
<#list locale.supported as l>
<li class="${properties.kcLocaleListItemClass!}">
<a class="${properties.kcLocaleItemClass!}" href="${l.url}">${l.label}</a>
</li>
</#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}">
<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}">
<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() && showAnotherWayIfPresent>
<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>
<#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>
</body>
</html>
</#macro>

37
lumbung.space/login/terms.ftl Executable file
View File

@ -0,0 +1,37 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=false; section>
<#if section = "header">
${msg("termsTitle")}
<#elseif section = "form">
<div id="kc-terms-text">
<h2>Welcome to lumbung.space</h2>
<p>lumbung.space is an experimental social and publishing platform by and for the lumbung-interlokal and lumbung artists. It is built on open platforms, co-operative governance and as a community infrastructure meant for our practices to develop and thrive.</p
<p>Along side the Community Guidelines and the Privacy Statement, these terms of service lumbung.space is:</p>
<ul>
<li>non-profit, non-extractive, owned and operated by is community of users, that means you!</li>
<li>currently made up of parts, cloud, tv, social, books, pen, and the members page</li>
<li>experimental and a place of learning, we are trying to find out what a social platform for a lumbung practice looks like</li>
</ul>
<h3>A shared resource</h3>
<p>lumbung.space is a shared resource and an environment that strives to be welcoming, generous, funny and critical. Be considerate to others, respectful to the resources, be ready to ask for help if you need it, or to give help if others do! Feel free to try, play, modify and use as you see fit! A shared resource that does not sell, trade, or otherwise transfer to outside parties your personally identifiable information.</p>
<h3>Account/Site</h3>
<p>If you create/have an account on the lumbung.space, you are responsible for maintaining the security of your account, and you are fully responsible for all activities that occur under the account and any other actions taken in connection with the lumbung.space's ecosystem (various apps). You must not describe or assign keywords to lumbung.space in a misleading or unlawful manner, including in a manner intended to trade on the name or reputation of others, and lumbung.space's moderator may change or remove any description or keyword that it considers inappropriate or unlawful, or otherwise likely to cause lumbung.space.</p>
<h3>Liability</h3>
<p>lumbung.space is built to prioritize the safety of your data. There are back-up routines in place and encryption is used everywhere. Despite all that, storing data on-line comes with risks. By using lumbung.space you agree that lumbung.space is not liable for unexpected downtime, data loss or breaches. You take care of your own backups and don't use lumbung.space as the only place to store materials.</p>
<h3>Data & content policy</h3>
<p>You own all the data you upload or create on lumbung.space. That means lumbung.space will not lay claim to it but also that you do not infringe on other's copyright. Whenever you publish something on lumbung.space so that third parties can see it, for example by publishing it on the front page, you do so with the explicit understanding that you have the right to publish it.You can always delete your accounts and your data at any time or contact us to help you do so.</p>
</div>
<form id="terms-form" class="form-actions" action="${url.loginAction}" method="POST">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="accept" id="kc-accept" type="submit" value="${msg("doAccept")}"/>
<input class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="cancel" id="kc-decline" type="submit" value="${msg("doDecline")}"/>
</form>
<div class="clearfix"></div>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,130 @@
parent=base
import=common/keycloak
styles=css/login.css
scripts=css/test.js
meta=viewport==width=device-width,initial-scale=1
kcHtmlClass=login-pf
kcLoginClass=login-pf-page
kcLogoLink=http://www.keycloak.org
kcLogoClass=login-pf-brand
kcContainerClass=container-fluid
kcContentClass=col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3
kcHeaderClass=login-pf-page-header
kcFeedbackAreaClass=col-md-12
kcLocaleClass=col-xs-12 col-sm-1
## Locale
kcLocaleMainClass=pf-c-dropdown
kcLocaleListClass=pf-c-dropdown__menu pf-m-align-right
kcLocaleItemClass=pf-c-dropdown__menu-item
## Alert
kcAlertClass=pf-c-alert pf-m-inline
kcAlertTitleClass=pf-c-alert__title kc-feedback-text
kcFormAreaClass=col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2
kcFormCardClass=card-pf
### Social providers
kcFormSocialAccountListClass=pf-c-login__main-footer-links kc-social-links
kcFormSocialAccountListGridClass=pf-l-grid kc-social-grid
kcFormSocialAccountListButtonClass=pf-c-button pf-m-control pf-m-block kc-social-item kc-social-gray
kcFormSocialAccountGridItem=pf-l-grid__item
kcFormSocialAccountNameClass=kc-social-provider-name
kcFormSocialAccountLinkClass=pf-c-login__main-footer-links-item-link
kcFormSocialAccountSectionClass=kc-social-section kc-social-gray
kcFormHeaderClass=login-pf-header
kcFeedbackErrorIcon=fa fa-fw fa-exclamation-circle
kcFeedbackWarningIcon=fa fa-fw fa-exclamation-triangle
kcFeedbackSuccessIcon=fa fa-fw fa-check-circle
kcFeedbackInfoIcon=fa fa-fw fa-info-circle
kcResetFlowIcon=pficon pficon-arrow fa
kcWebAuthnKeyIcon=pficon pficon-key
kcFormClass=form-horizontal
kcFormGroupClass=form-group
kcFormGroupErrorClass=has-error
kcLabelClass=pf-c-form__label pf-c-form__label-text
kcLabelWrapperClass=col-xs-12 col-sm-12 col-md-12 col-lg-12
kcInputClass=pf-c-form-control
kcInputErrorMessageClass=pf-c-form__helper-text pf-m-error required kc-feedback-text
kcInputWrapperClass=col-xs-12 col-sm-12 col-md-12 col-lg-12
kcFormOptionsClass=col-xs-12 col-sm-12 col-md-12 col-lg-12
kcFormButtonsClass=col-xs-12 col-sm-12 col-md-12 col-lg-12
kcFormSettingClass=login-pf-settings
kcTextareaClass=form-control
kcSignUpClass=login-pf-signup
kcInfoAreaClass=col-xs-12 col-sm-4 col-md-4 col-lg-5 details
##### css classes for form buttons
# main class used for all buttons
kcButtonClass=pf-c-button
# classes defining priority of the button - primary or default (there is typically only one priority button for the form)
kcButtonPrimaryClass=pf-m-primary
kcButtonDefaultClass=btn-default
# classes defining size of the button
kcButtonLargeClass=btn-lg
kcButtonBlockClass=pf-m-block
##### css classes for input
kcInputLargeClass=input-lg
##### css classes for form accessability
kcSrOnlyClass=sr-only
##### css classes for select-authenticator form
kcSelectAuthListClass=pf-l-stack select-auth-container
kcSelectAuthListItemClass=pf-l-stack__item select-auth-box-parent pf-l-split
kcSelectAuthListItemIconClass=pf-l-split__item select-auth-box-icon
kcSelectAuthListItemBodyClass=pf-l-split__item pf-l-stack
kcSelectAuthListItemHeadingClass=pf-l-stack__item select-auth-box-headline pf-c-title
kcSelectAuthListItemDescriptionClass=pf-l-stack__item select-auth-box-desc
kcSelectAuthListItemFillClass=pf-l-split__item pf-m-fill
kcSelectAuthListItemArrowClass=pf-l-split__item select-auth-box-arrow
kcSelectAuthListItemArrowIconClass=fa fa-angle-right fa-lg
##### css classes for the authenticators
kcAuthenticatorDefaultClass=fa list-view-pf-icon-lg
kcAuthenticatorPasswordClass=fa fa-unlock list-view-pf-icon-lg
kcAuthenticatorOTPClass=fa fa-mobile list-view-pf-icon-lg
kcAuthenticatorWebAuthnClass=fa fa-key list-view-pf-icon-lg
kcAuthenticatorWebAuthnPasswordlessClass=fa fa-key list-view-pf-icon-lg
##### css classes for the OTP Login Form
kcLoginOTPListClass=pf-c-tile
kcLoginOTPListInputClass=pf-c-tile__input
kcLoginOTPListItemHeaderClass=pf-c-tile__header
kcLoginOTPListItemIconBodyClass=pf-c-tile__icon
kcLoginOTPListItemIconClass=fa fa-mobile
kcLoginOTPListItemTitleClass=pf-c-tile__title
##### css classes for identity providers logos
kcCommonLogoIdP=kc-social-provider-logo kc-social-gray
## Social
kcLogoIdP-facebook=fa fa-facebook
kcLogoIdP-google=fa fa-google
kcLogoIdP-github=fa fa-github
kcLogoIdP-linkedin=fa fa-linkedin
kcLogoIdP-instagram=fa fa-instagram
## windows instead of microsoft - not included in PF4
kcLogoIdP-microsoft=fa fa-windows
kcLogoIdP-bitbucket=fa fa-bitbucket
kcLogoIdP-gitlab=fa fa-gitlab
kcLogoIdP-paypal=fa fa-paypal
kcLogoIdP-stackoverflow=fa fa-stack-overflow
kcLogoIdP-twitter=fa fa-twitter
kcLogoIdP-openshift-v4=pf-icon pf-icon-openshift
kcLogoIdP-openshift-v3=pf-icon pf-icon-openshift

View File

@ -0,0 +1,115 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout showAnotherWayIfPresent=false; section>
<#if section = "title">
title
<#elseif section = "header">
${kcSanitize(msg("webauthn-login-title"))?no_esc}
<#elseif section = "form">
<form id="webauth" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<input type="hidden" id="clientDataJSON" name="clientDataJSON"/>
<input type="hidden" id="authenticatorData" name="authenticatorData"/>
<input type="hidden" id="signature" name="signature"/>
<input type="hidden" id="credentialId" name="credentialId"/>
<input type="hidden" id="userHandle" name="userHandle"/>
<input type="hidden" id="error" name="error"/>
</div>
</form>
<#if authenticators??>
<form id="authn_select" class="${properties.kcFormClass!}">
<#list authenticators.authenticators as authenticator>
<input type="hidden" name="authn_use_chk" value="${authenticator.credentialId}"/>
</#list>
</form>
</#if>
<script type="text/javascript" src="${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="${url.resourcesPath}/js/base64url.js"></script>
<script type="text/javascript">
window.onload = () => {
let isUserIdentified = ${isUserIdentified};
if (!isUserIdentified) {
doAuthenticate([]);
return;
}
checkAllowCredentials();
};
function checkAllowCredentials() {
let allowCredentials = [];
let authn_use = document.forms['authn_select'].authn_use_chk;
if (authn_use !== undefined) {
if (authn_use.length === undefined) {
allowCredentials.push({
id: base64url.decode(authn_use.value, {loose: true}),
type: 'public-key',
});
} else {
for (let i = 0; i < authn_use.length; i++) {
allowCredentials.push({
id: base64url.decode(authn_use[i].value, {loose: true}),
type: 'public-key',
});
}
}
}
doAuthenticate(allowCredentials);
}
function doAuthenticate(allowCredentials) {
// Check if WebAuthn is supported by this browser
if (!window.PublicKeyCredential) {
$("#error").val("${msg("webauthn-unsupported-browser-text")?no_esc}");
$("#webauth").submit();
return;
}
let challenge = "${challenge}";
let userVerification = "${userVerification}";
let rpId = "${rpId}";
let publicKey = {
rpId : rpId,
challenge: base64url.decode(challenge, { loose: true })
};
if (allowCredentials.length) {
publicKey.allowCredentials = allowCredentials;
}
if (userVerification !== 'not specified') publicKey.userVerification = userVerification;
navigator.credentials.get({publicKey})
.then((result) => {
window.result = result;
let clientDataJSON = result.response.clientDataJSON;
let authenticatorData = result.response.authenticatorData;
let signature = result.response.signature;
$("#clientDataJSON").val(base64url.encode(new Uint8Array(clientDataJSON), { pad: false }));
$("#authenticatorData").val(base64url.encode(new Uint8Array(authenticatorData), { pad: false }));
$("#signature").val(base64url.encode(new Uint8Array(signature), { pad: false }));
$("#credentialId").val(result.id);
if(result.response.userHandle) {
$("#userHandle").val(base64url.encode(new Uint8Array(result.response.userHandle), { pad: false }));
}
$("#webauth").submit();
})
.catch((err) => {
$("#error").val(err);
$("#webauth").submit();
})
;
}
</script>
<#elseif section = "info">
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,55 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=true; section>
<#if section = "header">
${kcSanitize(msg("webauthn-error-title"))?no_esc}
<#elseif section = "form">
<script type="text/javascript">
refreshPage = () => {
document.getElementById('isSetRetry').value = 'retry';
document.getElementById('executionValue').value = '${execution}';
document.getElementById('kc-error-credential-form').submit();
}
</script>
<form id="kc-error-credential-form" class="${properties.kcFormClass!}" action="${url.loginAction}"
method="post">
<input type="hidden" id="executionValue" name="authenticationExecution"/>
<input type="hidden" id="isSetRetry" name="isSetRetry"/>
</form>
<#if authenticators??>
<table class="table">
<thead>
<tr>
<th>${kcSanitize(msg("webauthn-available-authenticators"))?no_esc}</th>
</tr>
</thead>
<tbody>
<#list authenticators.authenticators as authenticator>
<tr>
<th>
<span id="kc-webauthn-authenticator">${kcSanitize(authenticator.label)?no_esc}</span>
</th>
</tr>
</#list>
</tbody>
</table>
</#if>
<input tabindex="4" onclick="refreshPage()" type="button"
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
name="try-again" id="kc-try-again" value="${kcSanitize(msg("doTryAgain"))?no_esc}"
/>
<#if isAppInitiatedAction??>
<form action="${url.loginAction}" class="${properties.kcFormClass!}" id="kc-webauthn-settings-form" method="post">
<button type="submit"
class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
id="cancelWebAuthnAIA" name="cancel-aia" value="true"/>${msg("doCancel")}
</button>
</form>
</#if>
</#if>
</@layout.registrationLayout>

View File

@ -0,0 +1,174 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "title">
title
<#elseif section = "header">
<span class="${properties.kcWebAuthnKeyIcon}"></span>
${kcSanitize(msg("webauthn-registration-title"))?no_esc}
<#elseif section = "form">
<form id="register" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<input type="hidden" id="clientDataJSON" name="clientDataJSON"/>
<input type="hidden" id="attestationObject" name="attestationObject"/>
<input type="hidden" id="publicKeyCredentialId" name="publicKeyCredentialId"/>
<input type="hidden" id="authenticatorLabel" name="authenticatorLabel"/>
<input type="hidden" id="error" name="error"/>
</div>
</form>
<script type="text/javascript" src="${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="${url.resourcesPath}/js/base64url.js"></script>
<script type="text/javascript">
function registerSecurityKey() {
// Check if WebAuthn is supported by this browser
if (!window.PublicKeyCredential) {
$("#error").val("${msg("webauthn-unsupported-browser-text")?no_esc}");
$("#register").submit();
return;
}
// mandatory parameters
let challenge = "${challenge}";
let userid = "${userid}";
let username = "${username}";
let signatureAlgorithms = "${signatureAlgorithms}";
let pubKeyCredParams = getPubKeyCredParams(signatureAlgorithms);
let rpEntityName = "${rpEntityName}";
let rp = {name: rpEntityName};
let publicKey = {
challenge: base64url.decode(challenge, {loose: true}),
rp: rp,
user: {
id: base64url.decode(userid, {loose: true}),
name: username,
displayName: username
},
pubKeyCredParams: pubKeyCredParams,
};
// optional parameters
let rpId = "${rpId}";
publicKey.rp.id = rpId;
let attestationConveyancePreference = "${attestationConveyancePreference}";
if (attestationConveyancePreference !== 'not specified') publicKey.attestation = attestationConveyancePreference;
let authenticatorSelection = {};
let isAuthenticatorSelectionSpecified = false;
let authenticatorAttachment = "${authenticatorAttachment}";
if (authenticatorAttachment !== 'not specified') {
authenticatorSelection.authenticatorAttachment = authenticatorAttachment;
isAuthenticatorSelectionSpecified = true;
}
let requireResidentKey = "${requireResidentKey}";
if (requireResidentKey !== 'not specified') {
if (requireResidentKey === 'Yes')
authenticatorSelection.requireResidentKey = true;
else
authenticatorSelection.requireResidentKey = false;
isAuthenticatorSelectionSpecified = true;
}
let userVerificationRequirement = "${userVerificationRequirement}";
if (userVerificationRequirement !== 'not specified') {
authenticatorSelection.userVerification = userVerificationRequirement;
isAuthenticatorSelectionSpecified = true;
}
if (isAuthenticatorSelectionSpecified) publicKey.authenticatorSelection = authenticatorSelection;
let createTimeout = ${createTimeout};
if (createTimeout != 0) publicKey.timeout = createTimeout * 1000;
let excludeCredentialIds = "${excludeCredentialIds}";
let excludeCredentials = getExcludeCredentials(excludeCredentialIds);
if (excludeCredentials.length > 0) publicKey.excludeCredentials = excludeCredentials;
navigator.credentials.create({publicKey})
.then(function (result) {
window.result = result;
let clientDataJSON = result.response.clientDataJSON;
let attestationObject = result.response.attestationObject;
let publicKeyCredentialId = result.rawId;
$("#clientDataJSON").val(base64url.encode(new Uint8Array(clientDataJSON), {pad: false}));
$("#attestationObject").val(base64url.encode(new Uint8Array(attestationObject), {pad: false}));
$("#publicKeyCredentialId").val(base64url.encode(new Uint8Array(publicKeyCredentialId), {pad: false}));
let initLabel = "WebAuthn Authenticator (Default Label)";
let labelResult = window.prompt("Please input your registered authenticator's label", initLabel);
if (labelResult === null) labelResult = initLabel;
$("#authenticatorLabel").val(labelResult);
$("#register").submit();
})
.catch(function (err) {
$("#error").val(err);
$("#register").submit();
});
}
function getPubKeyCredParams(signatureAlgorithms) {
let pubKeyCredParams = [];
if (signatureAlgorithms === "") {
pubKeyCredParams.push({type: "public-key", alg: -7});
return pubKeyCredParams;
}
let signatureAlgorithmsList = signatureAlgorithms.split(',');
for (let i = 0; i < signatureAlgorithmsList.length; i++) {
pubKeyCredParams.push({
type: "public-key",
alg: signatureAlgorithmsList[i]
});
}
return pubKeyCredParams;
}
function getExcludeCredentials(excludeCredentialIds) {
let excludeCredentials = [];
if (excludeCredentialIds === "") return excludeCredentials;
let excludeCredentialIdsList = excludeCredentialIds.split(',');
for (let i = 0; i < excludeCredentialIdsList.length; i++) {
excludeCredentials.push({
type: "public-key",
id: base64url.decode(excludeCredentialIdsList[i],
{loose: true})
});
}
return excludeCredentials;
}
</script>
<#if !isSetRetry?has_content && isAppInitiatedAction?has_content>
<input type="submit"
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
id="registerWebAuthnAIA" value="${msg("doRegister")}" onclick="registerSecurityKey()"
/>
<form action="${url.loginAction}" class="${properties.kcFormClass!}" id="kc-webauthn-settings-form"
method="post">
<button type="submit"
class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
id="cancelWebAuthnAIA" name="cancel-aia" value="true"/>${msg("doCancel")}
</button>
</form>
<#else>
<script>
registerSecurityKey();
</script>
</#if>
</#if>
</@layout.registrationLayout>

18
makefile Normal file
View File

@ -0,0 +1,18 @@
default: run
run: ## run a new container
@docker run \
-p 8080:8080 \
-v $$(pwd)/lumbung.space:/opt/jboss/keycloak/themes/lumbung.space \
-v $$(pwd)/bin/disable-theme-cache.cli:/opt/jboss/startup-scripts/disable-theme-cache.cli \
-e KEYCLOAK_USER=admin \
-e KEYCLOAK_PASSWORD=admin \
--name keycloakdev \
--rm \
jboss/keycloak:12.0.4
shell: ## get a shell in the container
@docker exec -it keycloakdev /bin/bash
stop: ## tear down the container
@docker stop keycloakdev && docker rm keycloakdev