commit ff7d8d141416eb8633fd184c157f30296540299f Author: decentral1se Date: Wed Dec 7 10:14:55 2022 +0100 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..832fb90 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# id.autonomic.zone + +Custom theme for Keycloak. + +## Customisations + +* `./hacktheplanet/login/resources/img/bg.png` is the new background image (`.login-pf` in `login.css`) +* the logo / text above the login box is now `display: none` + +## Hacking + +``` +make +``` + +Then visit [localhost](http://localhost:8080). + +* admin username: `admin` +* admin password: `password` + +Go to `Realm Settings > Themes`. Choose a custom login theme via `Login Theme > +hacktheplanet` 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. diff --git a/hacktheplanet/login/resources/css/login.css b/hacktheplanet/login/resources/css/login.css new file mode 100644 index 0000000..161b34b --- /dev/null +++ b/hacktheplanet/login/resources/css/login.css @@ -0,0 +1,589 @@ +/* Patternfly CSS places a "bg-login.jpg" as the background on this ".login-pf" class. + This clashes with the "keycloak-bg.png' background defined on the body below. + Therefore the Patternfly background must be set to none. */ +.login-pf { + background: none; +} + +.login-pf body { + background: url("../img/bg.jpg") no-repeat center center fixed; + background-size: cover; + height: 100%; +} + +textarea.pf-c-form-control { + height: auto; +} + +.pf-c-alert__title { + font-size: var(--pf-global--FontSize--xs); +} + +p.instruction { + margin: 5px 0; +} + +.pf-c-button.pf-m-control { + border: solid var(--pf-global--BorderWidth--sm); + border-color: rgba(230, 230, 230, 0.5); +} + +h1#kc-page-title { + margin-top: 10px; +} + +#kc-locale ul { + background-color: var(--pf-global--BackgroundColor--100); + display: none; + top: 20px; + min-width: 100px; + padding: 0; +} + +#kc-locale-dropdown{ + display: inline-block; +} + +#kc-locale-dropdown:hover ul { + display:block; +} + +#kc-locale-dropdown a { + color: var(--pf-global--Color--200); + text-align: right; + font-size: var(--pf-global--FontSize--sm); +} + +a#kc-current-locale-link::after { + content: "\2c5"; + margin-left: var(--pf-global--spacer--xs) +} + +.login-pf .container { + padding-top: 40px; +} + +.login-pf a:hover { + color: #0099d3; +} + +#kc-logo { + width: 100%; +} + +div.kc-logo-text { + display: none; +} + +div.kc-logo-text span { + display: none; +} + +#kc-header { + color: #ededed; + overflow: visible; + white-space: nowrap; +} + +#kc-header-wrapper { + font-size: 29px; + text-transform: uppercase; + letter-spacing: 3px; + line-height: 1.2em; + padding: 62px 10px 20px; + white-space: normal; +} + +#kc-content { + width: 100%; +} + +#kc-attempted-username { + font-size: 20px; + font-family: inherit; + font-weight: normal; + padding-right: 10px; +} + +#kc-username { + text-align: center; + margin-bottom:-10px; +} + +#kc-webauthn-settings-form { + padding-top: 8px; +} + +#kc-form-webauthn .select-auth-box-parent { + pointer-events: none; +} + +#kc-form-webauthn .select-auth-box-desc { + color: var(--pf-global--palette--black-600); +} + +#kc-form-webauthn .select-auth-box-headline { + color: var(--pf-global--Color--300); +} + +#kc-form-webauthn .select-auth-box-icon { + flex: 0 0 3em; +} + +#kc-form-webauthn .select-auth-box-icon-properties { + margin-top: 10px; + font-size: 1.8em; +} + +#kc-form-webauthn .select-auth-box-icon-properties.unknown-transport-class { + margin-top: 3px; +} + +#kc-form-webauthn .pf-l-stack__item { + margin: -1px 0; +} + +#kc-content-wrapper { + margin-top: 20px; +} + +#kc-form-wrapper { + margin-top: 10px; +} + +#kc-info { + margin: 20px -40px -30px; +} + +#kc-info-wrapper { + font-size: 13px; + padding: 15px 35px; + background-color: #F0F0F0; +} + +#kc-form-options span { + display: block; +} + +#kc-form-options .checkbox { + margin-top: 0; + color: #72767b; +} + +#kc-terms-text { + margin-bottom: 20px; +} + +#kc-registration { + margin-bottom: 0; +} + +/* TOTP */ + +.subtitle { + text-align: right; + margin-top: 30px; + color: #909090; +} + +.required { + color: var(--pf-global--danger-color--200); +} + +ol#kc-totp-settings { + margin: 0; + padding-left: 20px; +} + +ul#kc-totp-supported-apps { + margin-bottom: 10px; +} + +#kc-totp-secret-qr-code { + max-width:150px; + max-height:150px; +} + +#kc-totp-secret-key { + background-color: #fff; + color: #333333; + font-size: 16px; + padding: 10px 0; +} + +/* OAuth */ + +#kc-oauth h3 { + margin-top: 0; +} + +#kc-oauth ul { + list-style: none; + padding: 0; + margin: 0; +} + +#kc-oauth ul li { + border-top: 1px solid rgba(255, 255, 255, 0.1); + font-size: 12px; + padding: 10px 0; +} + +#kc-oauth ul li:first-of-type { + border-top: 0; +} + +#kc-oauth .kc-role { + display: inline-block; + width: 50%; +} + +/* Code */ +#kc-code textarea { + width: 100%; + height: 8em; +} + +/* Social */ +.kc-social-links { + margin-top: 20px; +} + +.kc-social-provider-logo { + font-size: 23px; + width: 30px; + height: 25px; + float: left; +} + +.kc-social-gray { + color: var(--pf-global--Color--200); +} + +.kc-social-item { + margin-bottom: var(--pf-global--spacer--sm); + font-size: 15px; + text-align: center; +} + +.kc-social-provider-name { + position: relative; + top: 3px; +} + +.kc-social-icon-text { + left: -15px; +} + +.kc-social-grid { + display:grid; + grid-column-gap: 10px; + grid-row-gap: 5px; + grid-column-end: span 6; + --pf-l-grid__item--GridColumnEnd: span 6; +} + +.kc-social-grid .kc-social-icon-text { + left: -10px; +} + +.kc-login-tooltip { + position: relative; + display: inline-block; +} + +.kc-social-section { + text-align: center; +} + +.kc-social-section hr{ + margin-bottom: 10px +} + +.kc-login-tooltip .kc-tooltip-text{ + top:-3px; + left:160%; + background-color: black; + visibility: hidden; + color: #fff; + + min-width:130px; + text-align: center; + border-radius: 2px; + box-shadow:0 1px 8px rgba(0,0,0,0.6); + padding: 5px; + + position: absolute; + opacity:0; + transition:opacity 0.5s; +} + +/* Show tooltip */ +.kc-login-tooltip:hover .kc-tooltip-text { + visibility: visible; + opacity:0.7; +} + +/* Arrow for tooltip */ +.kc-login-tooltip .kc-tooltip-text::after { + content: " "; + position: absolute; + top: 15px; + right: 100%; + margin-top: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent black transparent transparent; +} + +@media (min-width: 768px) { + #kc-container-wrapper { + position: absolute; + width: 100%; + } + + .login-pf .container { + padding-right: 80px; + } + + #kc-locale { + position: relative; + text-align: right; + z-index: 9999; + } +} + +@media (max-width: 767px) { + + .login-pf body { + background: white; + } + + #kc-header { + padding-left: 15px; + padding-right: 15px; + float: none; + text-align: left; + } + + #kc-header-wrapper { + font-size: 16px; + font-weight: bold; + padding: 20px 60px 0 0; + color: #72767b; + letter-spacing: 0; + } + + div.kc-logo-text { + display: none; + } + + #kc-form { + float: none; + } + + #kc-info-wrapper { + border-top: 1px solid rgba(255, 255, 255, 0.1); + background-color: transparent; + } + + .login-pf .container { + padding-top: 15px; + padding-bottom: 15px; + } + + #kc-locale { + position: absolute; + width: 200px; + top: 20px; + right: 20px; + text-align: right; + z-index: 9999; + } +} + +@media (min-height: 646px) { + #kc-container-wrapper { + bottom: 12%; + } +} + +@media (max-height: 645px) { + #kc-container-wrapper { + padding-top: 50px; + top: 20%; + } +} + +.card-pf form.form-actions .btn { + float: right; + margin-left: 10px; +} + +#kc-form-buttons { + margin-top: 20px; +} + +.login-pf-page .login-pf-brand { + margin-top: 20px; + max-width: 360px; + width: 40%; +} + +.select-auth-box-arrow{ + display: flex; + align-items: center; + margin-right: 2rem; +} + +.select-auth-box-icon{ + display: flex; + flex: 0 0 2em; + justify-content: center; + margin-right: 1rem; + margin-left: 3rem; +} + +.select-auth-box-parent{ + border-top: 1px solid var(--pf-global--palette--black-200); + padding-top: 1rem; + padding-bottom: 1rem; + cursor: pointer; +} + +.select-auth-box-parent:hover{ + background-color: #f7f8f8; +} + +.select-auth-container { + padding-bottom: 0px !important; +} + +.select-auth-box-headline { + font-size: var(--pf-global--FontSize--md); + color: var(--pf-global--primary-color--100); + font-weight: bold; +} + +.select-auth-box-desc { + font-size: var(--pf-global--FontSize--sm); +} + +.select-auth-box-paragraph { + text-align: center; + font-size: var(--pf-global--FontSize--md); + margin-bottom: 5px; +} + +.card-pf { + margin: 0 auto; + box-shadow: var(--pf-global--BoxShadow--lg); + padding: 0 20px; + max-width: 500px; + border-top: 4px solid; + border-color: var(--pf-global--primary-color--100); +} + +/*phone*/ +@media (max-width: 767px) { + .login-pf-page .card-pf { + max-width: none; + margin-left: 0; + margin-right: 0; + padding-top: 0; + border-top: 0; + box-shadow: 0 0; + } + + .kc-social-grid { + grid-column-end: 12; + --pf-l-grid__item--GridColumnEnd: span 12; + } + + .kc-social-grid .kc-social-icon-text { + left: -15px; + } +} + +.login-pf-page .login-pf-signup { + font-size: 15px; + color: #72767b; +} +#kc-content-wrapper .row { + margin-left: 0; + margin-right: 0; +} + +.login-pf-page.login-pf-page-accounts { + margin-left: auto; + margin-right: auto; +} + +.login-pf-page .btn-primary { + margin-top: 0; +} + +.login-pf-page .list-view-pf .list-group-item { + border-bottom: 1px solid #ededed; +} + +.login-pf-page .list-view-pf-description { + width: 100%; +} + +#kc-form-login div.form-group:last-of-type, +#kc-register-form div.form-group:last-of-type, +#kc-update-profile-form div.form-group:last-of-type, +#kc-update-email-form div.form-group:last-of-type{ + margin-bottom: 0px; +} + +.no-bottom-margin { + margin-bottom: 0; +} + +#kc-back { + margin-top: 5px; +} + +/* Recovery codes */ +.kc-recovery-codes-warning { + margin-bottom: 32px; +} +.kc-recovery-codes-warning .pf-c-alert__description p { + font-size: 0.875rem; +} +.kc-recovery-codes-list { + list-style: none; + columns: 2; + margin: 16px 0; + padding: 16px 16px 8px 16px; + border: 1px solid #D2D2D2; +} +.kc-recovery-codes-list li { + margin-bottom: 8px; + font-size: 11px; +} +.kc-recovery-codes-list li span { + color: #6A6E73; + width: 16px; + text-align: right; + display: inline-block; + margin-right: 1px; +} + +.kc-recovery-codes-actions { + margin-bottom: 24px; +} +.kc-recovery-codes-actions button { + padding-left: 0; +} +.kc-recovery-codes-actions button i { + margin-right: 8px; +} + +.kc-recovery-codes-confirmation { + align-items: baseline; + margin-bottom: 16px; +} +/* End Recovery codes */ diff --git a/hacktheplanet/login/resources/img/bg.jpg b/hacktheplanet/login/resources/img/bg.jpg new file mode 100644 index 0000000..6a5c870 Binary files /dev/null and b/hacktheplanet/login/resources/img/bg.jpg differ diff --git a/hacktheplanet/login/resources/img/bg.png b/hacktheplanet/login/resources/img/bg.png new file mode 100644 index 0000000..5f3c9b4 Binary files /dev/null and b/hacktheplanet/login/resources/img/bg.png differ diff --git a/hacktheplanet/login/resources/img/feedback-error-arrow-down.png b/hacktheplanet/login/resources/img/feedback-error-arrow-down.png new file mode 100644 index 0000000..6f2d9d2 Binary files /dev/null and b/hacktheplanet/login/resources/img/feedback-error-arrow-down.png differ diff --git a/hacktheplanet/login/resources/img/feedback-error-sign.png b/hacktheplanet/login/resources/img/feedback-error-sign.png new file mode 100644 index 0000000..0dd5004 Binary files /dev/null and b/hacktheplanet/login/resources/img/feedback-error-sign.png differ diff --git a/hacktheplanet/login/resources/img/feedback-success-arrow-down.png b/hacktheplanet/login/resources/img/feedback-success-arrow-down.png new file mode 100644 index 0000000..03cc0c4 Binary files /dev/null and b/hacktheplanet/login/resources/img/feedback-success-arrow-down.png differ diff --git a/hacktheplanet/login/resources/img/feedback-success-sign.png b/hacktheplanet/login/resources/img/feedback-success-sign.png new file mode 100644 index 0000000..640bd71 Binary files /dev/null and b/hacktheplanet/login/resources/img/feedback-success-sign.png differ diff --git a/hacktheplanet/login/resources/img/feedback-warning-arrow-down.png b/hacktheplanet/login/resources/img/feedback-warning-arrow-down.png new file mode 100644 index 0000000..6f2d9d2 Binary files /dev/null and b/hacktheplanet/login/resources/img/feedback-warning-arrow-down.png differ diff --git a/hacktheplanet/login/resources/img/feedback-warning-sign.png b/hacktheplanet/login/resources/img/feedback-warning-sign.png new file mode 100644 index 0000000..f9392a3 Binary files /dev/null and b/hacktheplanet/login/resources/img/feedback-warning-sign.png differ diff --git a/hacktheplanet/login/resources/img/keycloak-bg.png b/hacktheplanet/login/resources/img/keycloak-bg.png new file mode 100644 index 0000000..4004db4 Binary files /dev/null and b/hacktheplanet/login/resources/img/keycloak-bg.png differ diff --git a/hacktheplanet/login/resources/img/keycloak-logo-text.png b/hacktheplanet/login/resources/img/keycloak-logo-text.png new file mode 100644 index 0000000..63f3b9f Binary files /dev/null and b/hacktheplanet/login/resources/img/keycloak-logo-text.png differ diff --git a/hacktheplanet/login/resources/img/keycloak-logo.png b/hacktheplanet/login/resources/img/keycloak-logo.png new file mode 100644 index 0000000..ffa5b0b Binary files /dev/null and b/hacktheplanet/login/resources/img/keycloak-logo.png differ diff --git a/hacktheplanet/login/resources/img/logo-round.png b/hacktheplanet/login/resources/img/logo-round.png new file mode 100644 index 0000000..bc6c9c7 Binary files /dev/null and b/hacktheplanet/login/resources/img/logo-round.png differ diff --git a/hacktheplanet/login/theme.properties b/hacktheplanet/login/theme.properties new file mode 100644 index 0000000..ddd1618 --- /dev/null +++ b/hacktheplanet/login/theme.properties @@ -0,0 +1,161 @@ +parent=base +import=common/keycloak + +styles=css/login.css +stylesCommon=web_modules/@patternfly/react-core/dist/styles/base.css web_modules/@patternfly/react-core/dist/styles/app.css node_modules/patternfly/dist/css/patternfly.min.css node_modules/patternfly/dist/css/patternfly-additions.min.css lib/pficon/pficon.css + +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 + +# WebAuthn icons +kcWebAuthnKeyIcon=pficon pficon-key +kcWebAuthnDefaultIcon=pficon pficon-key +kcWebAuthnUnknownIcon=pficon pficon-key unknown-transport-class +kcWebAuthnUSB=fa fa-usb +kcWebAuthnNFC=fa fa-wifi +kcWebAuthnBLE=fa fa-bluetooth-b +kcWebAuthnInternal=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 +kcInputHelperTextBeforeClass=pf-c-form__helper-text pf-c-form__helper-text-before +kcInputHelperTextAfterClass=pf-c-form__helper-text pf-c-form__helper-text-after +kcInputClassRadio=pf-c-radio +kcInputClassRadioInput=pf-c-radio__input +kcInputClassRadioLabel=pf-c-radio__label +kcInputClassCheckbox=pf-c-check +kcInputClassCheckboxInput=pf-c-check__input +kcInputClassCheckboxLabel=pf-c-check__label +kcInputClassRadioCheckboxLabelDisabled=pf-m-disabled +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 + +### user-profile grouping +kcFormGroupHeader=pf-c-form__group + +##### 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 +kcSelectAuthListItemIconPropertyClass=fa-2x select-auth-box-icon-properties +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 +kcSelectAuthListItemTitle=select-auth-box-paragraph + +##### css classes for the authenticators +kcAuthenticatorDefaultClass=fa fa-list 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 + +## Recovery codes +kcRecoveryCodesWarning=kc-recovery-codes-warning +kcRecoveryCodesList=kc-recovery-codes-list +kcRecoveryCodesActions=kc-recovery-codes-actions +kcRecoveryCodesConfirmation=kc-recovery-codes-confirmation +kcCheckClass=pf-c-check +kcCheckInputClass=pf-c-check__input +kcCheckLabelClass=pf-c-check__label diff --git a/makefile b/makefile new file mode 100644 index 0000000..a16779a --- /dev/null +++ b/makefile @@ -0,0 +1,20 @@ +default: run + +run: + @docker run \ + -p 8080:8080 \ + -v $$(pwd)/hacktheplanet:/opt/keycloak/themes/hacktheplanet \ + -e KEYCLOAK_ADMIN=admin \ + -e KEYCLOAK_ADMIN_PASSWORD=admin \ + --name keycloakdev \ + keycloak/keycloak:20.0.1 \ + start-dev \ + --spi-theme-static-max-age=-1 \ + --spi-theme-cache-themes=false \ + --spi-theme-cache-templates=false \ + +shell: + @docker exec -it keycloakdev /bin/bash + +stop: + @docker stop keycloakdev && docker rm keycloakdev