+
+@layout.mainLayout>
diff --git a/themes/src/main/resources/theme/unixdog/account/log.ftl b/themes/src/main/resources/theme/unixdog/account/log.ftl
new file mode 100644
index 0000000000..29046cf0d2
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/account/log.ftl
@@ -0,0 +1,35 @@
+<#import "template.ftl" as layout>
+<@layout.mainLayout active='log' bodyClass='log'; section>
+
+
+
+
${msg("accountLogHtmlTitle")}
+
+
+
+
+
+
+
${msg("date")}
+
${msg("event")}
+
${msg("ip")}
+
${msg("client")}
+
${msg("details")}
+
+
+
+
+ <#list log.events as event>
+
+
${event.date?datetime}
+
${event.event}
+
${event.ipAddress}
+
${event.client!}
+
<#list event.details as detail>${detail.key} = ${detail.value} <#if detail_has_next>, #if>#list>
+
+ #list>
+
+
+
+
+@layout.mainLayout>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/unixdog/account/messages/messages_en.properties b/themes/src/main/resources/theme/unixdog/account/messages/messages_en.properties
new file mode 100755
index 0000000000..d96e6bdc66
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/account/messages/messages_en.properties
@@ -0,0 +1,441 @@
+doSave=Save
+doCancel=Cancel
+doLogOutAllSessions=Log out all sessions
+doRemove=Remove
+doAdd=Add
+doSignOut=Sign out
+doLogIn=Log In
+doLink=Link
+noAccessMessage=Access not allowed
+
+personalInfoSidebarTitle=Personal info
+accountSecuritySidebarTitle=Account security
+signingInSidebarTitle=Signing in
+deviceActivitySidebarTitle=Device activity
+linkedAccountsSidebarTitle=Linked accounts
+
+editAccountHtmlTitle=Edit Account
+personalInfoHtmlTitle=Personal Info
+federatedIdentitiesHtmlTitle=Federated Identities
+accountLogHtmlTitle=Account Log
+changePasswordHtmlTitle=Change Password
+deviceActivityHtmlTitle=Device Activity
+sessionsHtmlTitle=Sessions
+accountManagementTitle=Keycloak Account Management
+authenticatorTitle=Authenticator
+applicationsHtmlTitle=Applications
+linkedAccountsHtmlTitle=Linked accounts
+
+accountManagementWelcomeMessage=Welcome to Keycloak Account Management
+personalInfoIntroMessage=Manage your basic information
+accountSecurityTitle=Account Security
+accountSecurityIntroMessage=Control your password and account access
+applicationsIntroMessage=Track and manage your app permission to access your account
+resourceIntroMessage=Share your resources among team members
+passwordLastUpdateMessage=Your password was updated at
+updatePasswordTitle=Update Password
+updatePasswordMessageTitle=Make sure you choose a strong password
+updatePasswordMessage=A strong password contains a mix of numbers, letters, and symbols. It is hard to guess, does not resemble a real word, and is only used for this account.
+personalSubTitle=Your Personal Info
+personalSubMessage=Manage your basic information.
+
+authenticatorCode=One-time code
+email=Email
+firstName=First name
+givenName=Given name
+fullName=Full name
+lastName=Last name
+familyName=Family name
+password=Password
+currentPassword=Current Password
+passwordConfirm=Confirmation
+passwordNew=New Password
+username=Username
+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
+
+profileScopeConsentText=User profile
+emailScopeConsentText=Email address
+addressScopeConsentText=Address
+phoneScopeConsentText=Phone number
+offlineAccessScopeConsentText=Offline Access
+samlRoleListScopeConsentText=My Roles
+rolesScopeConsentText=User roles
+
+role_admin=Admin
+role_realm-admin=Realm Admin
+role_create-realm=Create realm
+role_view-realm=View realm
+role_view-users=View users
+role_view-applications=View applications
+role_view-groups=View groups
+role_view-clients=View clients
+role_view-events=View events
+role_view-identity-providers=View identity providers
+role_view-consent=View consents
+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_manage-consent=Manage consents
+role_read-token=Read token
+role_offline-access=Offline access
+role_uma_authorization=Obtain permissions
+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
+allFieldsRequired=All fields required
+
+backToApplication=« Back to application
+backTo=Back to {0}
+
+date=Date
+event=Event
+ip=IP
+client=Client
+clients=Clients
+details=Details
+started=Started
+lastAccess=Last Access
+expires=Expires
+applications=Applications
+
+account=Account
+federatedIdentity=Federated Identity
+authenticator=Authenticator
+device-activity=Device activity
+sessions=Sessions
+log=Log
+
+application=Application
+availableRoles=Available Roles
+grantedPermissions=Granted Permissions
+grantedPersonalInfo=Granted Personal Info
+additionalGrants=Additional Grants
+action=Action
+inResource=in
+fullAccess=Full Access
+offlineToken=Offline Token
+revoke=Revoke Grant
+
+configureAuthenticators=Configured Authenticators
+mobile=Mobile
+totpStep1=Install one of the following applications on your mobile:
+totpStep2=Open the application and scan the barcode:
+totpStep3=Enter the one-time code provided by the application and click Save to finish the setup.
+totpStep3DeviceName=Provide a Device Name to help you manage your OTP devices.
+
+totpManualStep2=Open the application and enter the key:
+totpManualStep3=Use the following configuration values if the application allows setting them:
+totpUnableToScan=Unable to scan?
+totpScanBarcode=Scan barcode?
+
+totp.totp=Time-based
+totp.hotp=Counter-based
+
+totpType=Type
+totpAlgorithm=Algorithm
+totpDigits=Digits
+totpInterval=Interval
+totpCounter=Counter
+totpDeviceName=Device Name
+
+totpAppFreeOTPName=FreeOTP
+totpAppGoogleName=Google Authenticator
+totpAppMicrosoftAuthenticatorName=Microsoft Authenticator
+
+irreversibleAction=This action is irreversible
+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
+
+missingUsernameMessage=Please specify username.
+missingFirstNameMessage=Please specify first name.
+invalidEmailMessage=Invalid email address.
+missingLastNameMessage=Please specify last name.
+missingEmailMessage=Please specify email.
+missingPasswordMessage=Please specify password.
+notMatchPasswordMessage=Passwords don''t match.
+invalidUserMessage=Invalid user
+updateReadOnlyAttributesRejectedMessage=Update of read-only attribute rejected
+
+missingTotpMessage=Please specify authenticator code.
+missingTotpDeviceNameMessage=Please specify device name.
+invalidPasswordExistingMessage=Invalid existing password.
+invalidPasswordConfirmMessage=Password confirmation doesn''t match.
+invalidTotpMessage=Invalid authenticator code.
+
+usernameExistsMessage=Username already exists.
+emailExistsMessage=Email already exists.
+
+readOnlyUserMessage=You can''t update your account as it is read-only.
+readOnlyUsernameMessage=You can''t update your username as it is read-only.
+readOnlyPasswordMessage=You can''t update your password as your account is read-only.
+
+successTotpMessage=Mobile authenticator configured.
+successTotpRemovedMessage=Mobile authenticator removed.
+
+successGrantRevokedMessage=Grant revoked successfully.
+
+accountUpdatedMessage=Your account has been updated.
+accountPasswordUpdatedMessage=Your password has been updated.
+
+missingIdentityProviderMessage=Identity provider not specified.
+invalidFederatedIdentityActionMessage=Invalid or missing action.
+identityProviderNotFoundMessage=Specified identity provider not found.
+federatedIdentityLinkNotActiveMessage=This identity is not active anymore.
+federatedIdentityRemovingLastProviderMessage=You can''t remove last federated identity as you don''t have a password.
+identityProviderRedirectErrorMessage=Failed to redirect to identity provider.
+identityProviderRemovedMessage=Identity provider removed successfully.
+identityProviderAlreadyLinkedMessage=Federated identity returned by {0} is already linked to another user.
+staleCodeAccountMessage=The page expired. Please try one more time.
+consentDenied=Consent denied.
+access-denied-when-idp-auth=Access denied when authenticating with {0}
+
+accountDisabledMessage=Account is disabled, contact your administrator.
+
+accountTemporarilyDisabledMessage=Account is temporarily disabled, contact your administrator or try again later.
+invalidPasswordMinLengthMessage=Invalid password: minimum length {0}.
+invalidPasswordMaxLengthMessage=Invalid password: maximum length {0}.
+invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters.
+invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits.
+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.
+invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted.
+invalidPasswordGenericMessage=Invalid password: new password doesn''t match password policies.
+
+# Authorization
+myResources=My Resources
+myResourcesSub=My resources
+doDeny=Deny
+doRevoke=Revoke
+doApprove=Approve
+doRemoveSharing=Remove Sharing
+doRemoveRequest=Remove Request
+peopleAccessResource=People with access to this resource
+resourceManagedPolicies=Permissions granting access to this resource
+resourceNoPermissionsGrantingAccess=No permissions granting access to this resource
+anyAction=Any action
+description=Description
+name=Name
+scopes=Scopes
+resource=Resource
+user=User
+peopleSharingThisResource=People sharing this resource
+shareWithOthers=Share with others
+needMyApproval=Need my approval
+requestsWaitingApproval=Your requests waiting approval
+icon=Icon
+requestor=Requestor
+owner=Owner
+resourcesSharedWithMe=Resources shared with me
+permissionRequestion=Permission Requestion
+permission=Permission
+shares=share(s)
+notBeingShared=This resource is not being shared.
+notHaveAnyResource=You don't have any resources
+noResourcesSharedWithYou=There are no resources shared with you
+havePermissionRequestsWaitingForApproval=You have {0} permission request(s) waiting for approval.
+clickHereForDetails=Click here for details.
+resourceIsNotBeingShared=The resource is not being shared
+
+locale_ar=\u0639\u0631\u0628\u064A
+locale_ca=Catal\u00e0
+locale_cs=\u010Ce\u0161tina
+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_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
+locale_fi=Suomi
+
+# Applications
+applicationName=Name
+applicationType=Application Type
+applicationInUse=In-use app only
+clearAllFilter=Clear all filters
+activeFilters=Active filters
+filterByName=Filter By Name ...
+allApps=All applications
+internalApps=Internal applications
+thirdpartyApps=Third-Party applications
+appResults=Results
+clientNotFoundMessage=Client not found.
+
+# Authentication
+authentication=Authentication
+authenticationTitle=Authentication
+
+# Linked account
+authorizedProvider=Authorized Provider
+authorizedProviderMessage=Authorized Providers linked with your account
+identityProvider=Identity Provider
+identityProviderMessage=To link your account with identity providers you have configured
+socialLogin=Social Login
+userDefined=User Defined
+removeAccess=Remove Access
+removeAccessMessage=You will need to grant access again, if you want to use this app account.
+
+#Authenticator
+authenticatorStatusMessage=Two-factor authentication is currently
+authenticatorFinishSetUpTitle=Your Two-Factor Authentication
+authenticatorFinishSetUpMessage=Each time you sign in to your Keycloak account, you will be asked to provide a two-factor authentication code.
+authenticatorSubTitle=Set Up Two-Factor Authentication
+authenticatorSubMessage=To enhance the security of your account, enable at least one of the available two-factor authentication methods.
+authenticatorMobileTitle=Mobile Authenticator
+authenticatorMobileMessage=Use mobile Authenticator to get Verification codes as the two-factor authentication.
+authenticatorMobileFinishSetUpMessage=The authenticator has been bound to your phone.
+authenticatorActionSetup=Set up
+authenticatorSMSTitle=SMS Code
+authenticatorSMSMessage=Keycloak will send the Verification code to your phone as the two-factor authentication.
+authenticatorSMSFinishSetUpMessage=Text messages are sent to
+authenticatorDefaultStatus=Default
+authenticatorChangePhone=Change Phone Number
+
+#Authenticator - Mobile Authenticator setup
+authenticatorMobileSetupTitle=Mobile Authenticator Setup
+smscodeIntroMessage=Enter your phone number and a verification code will be sent to your phone.
+mobileSetupStep1=Install an authenticator application on your phone. The applications listed here are supported.
+mobileSetupStep2=Open the application and scan the barcode:
+mobileSetupStep3=Enter the one-time code provided by the application and click Save to finish the setup.
+scanBarCode=Want to scan the barcode?
+enterBarCode=Enter the one-time code
+doCopy=Copy
+doFinish=Finish
+
+#Authenticator - SMS Code setup
+authenticatorSMSCodeSetupTitle=SMS Code Setup
+chooseYourCountry=Choose your country
+enterYourPhoneNumber=Enter your phone number
+sendVerficationCode=Send Verification Code
+enterYourVerficationCode=Enter your verification code
+
+#Authenticator - backup Code setup
+authenticatorBackupCodesSetupTitle=Recovery Authentication Codes Setup
+realmName=Realm
+doDownload=Download
+doPrint=Print
+generateNewBackupCodes=Generate New Recovery Authentication Codes
+backtoAuthenticatorPage=Back to Authenticator Page
+
+
+#Resources
+resources=Resources
+sharedwithMe=Shared with Me
+share=Share
+sharedwith=Shared with
+accessPermissions=Access Permissions
+permissionRequests=Permission Requests
+approve=Approve
+approveAll=Approve all
+people=people
+perPage=per page
+currentPage=Current Page
+sharetheResource=Share the resource
+group=Group
+selectPermission=Select Permission
+addPeople=Add people to share your resource with
+addTeam=Add team to share your resource with
+myPermissions=My Permissions
+waitingforApproval=Waiting for approval
+anyPermission=Any Permission
+
+# 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
+
+error-invalid-value=Invalid value.
+error-invalid-blank=Please specify value.
+error-empty=Please specify value.
+error-invalid-length=Attribute {0} must have a length between {1} and {2}.
+error-invalid-length-too-short=Attribute {0} must have minimal length of {1}.
+error-invalid-length-too-long=Attribute {0} must have maximal length of {2}.
+error-invalid-email=Invalid email address.
+error-invalid-number=Invalid number.
+error-number-out-of-range=Attribute {0} must be a number between {1} and {2}.
+error-number-out-of-range-too-small=Attribute {0} must have minimal value of {1}.
+error-number-out-of-range-too-big=Attribute {0} must have maximal value of {2}.
+error-pattern-no-match=Invalid value.
+error-invalid-uri=Invalid URL.
+error-invalid-uri-scheme=Invalid URL scheme.
+error-invalid-uri-fragment=Invalid URL fragment.
+error-user-attribute-required=Please specify attribute {0}.
+error-invalid-date=Invalid date.
+error-user-attribute-read-only=The field {0} is read only.
+error-username-invalid-character=Username contains invalid character.
+error-person-name-invalid-character=Name contains invalid character.
+
+# Signing in page
+signingIn=Signing in
+signingInSubMessage=Configure ways to sign in.
+credentialCreatedAt=Created
+successRemovedMessage={0} was removed.
+stopUsingCred=Stop using {0}?
+changePassword=Change password
+removeCred=Remove {0}
+setUpNew=Set up {0}
+removeCredAriaLabel=Remove credential
+updateCredAriaLabel=Update credential
+notSetUp={0} is not set up.
+two-factor=Two-factor authentication
+passwordless=Passwordless
+unknown=Unknown
+password-display-name=Password
+password-help-text=Sign in by entering your password.
+otp-display-name=OTP Codes (2FA)
+otp-help-text=Enter a verification code from authenticator application.
+default-help-text=
+recovery-authn-code=My recovery authentication codes
+recovery-authn-codes-display-name=Recovery authentication codes
+recovery-authn-codes-help-text=These codes can be used to regain your access in case your other 2FA means are not available.
+recovery-codes-number-used={0} recovery codes used
+recovery-codes-number-remaining={0} recovery codes remaining
+recovery-codes-generate-new-codes=Generate new codes to ensure access to your account
+webauthn-display-name=WebAuthn (2FA)
+webauthn-help-text=Use your security key to sign in.
+webauthn-passwordless-display-name=Passwordless WebAuthn
+webauthn-passwordless-help-text=Use your security key for passwordless sign in.
+basic-authentication=Basic authentication
+invalidRequestMessage=Invalid request
diff --git a/themes/src/main/resources/theme/unixdog/account/password.ftl b/themes/src/main/resources/theme/unixdog/account/password.ftl
new file mode 100755
index 0000000000..4a043f28b9
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/account/password.ftl
@@ -0,0 +1,59 @@
+<#import "template.ftl" as layout>
+<@layout.mainLayout active='password' bodyClass='password'; section>
+
+
+ #if>
+@layout.registrationLayout>
diff --git a/themes/src/main/resources/theme/unixdog/login/messages/messages_en.properties b/themes/src/main/resources/theme/unixdog/login/messages/messages_en.properties
new file mode 100755
index 0000000000..9aed132290
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/login/messages/messages_en.properties
@@ -0,0 +1,511 @@
+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 your account
+loginTitle=Sign in to {0}
+loginTitleHtml={0}
+impersonateTitle={0} Impersonate User
+impersonateTitleHtml={0} Impersonate User
+realmChoice=Realm
+unknownUser=Unknown user
+loginTotpTitle=Mobile Authenticator Setup
+loginProfileTitle=Update Account Information
+loginIdpReviewProfileTitle=Update Account Information
+loginTimeout=Your login attempt timed out. Login will start from the beginning.
+reauthenticate=Please re-authenticate to continue
+oauthGrantTitle=Grant Access to {0}
+oauthGrantTitleHtml={0}
+oauthGrantInformation=Make sure you trust {0} by learning how {0} will handle your data.
+oauthGrantReview=You could review the
+oauthGrantTos=terms of service.
+oauthGrantPolicy=privacy policy.
+errorTitle=We are sorry...
+errorTitleHtml=We are sorry ...
+emailVerifyTitle=Email verification
+emailForgotTitle=Forgot Your Password?
+updateEmailTitle=Update email
+emailUpdateConfirmationSentTitle=Confirmation email sent
+emailUpdateConfirmationSent=A confirmation email has been sent to {0}. You must follow the instructions of the former to complete the email update.
+emailUpdatedTitle=Email updated
+emailUpdated=The account email has been successfully updated to {0}.
+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
+
+# Transports
+usb=USB
+nfc=NFC
+bluetooth=Bluetooth
+internal=Internal
+unknown=Unknown
+
+termsTitle=Terms and Conditions
+termsText=
Terms and conditions to be defined
+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
+
+totpAppFreeOTPName=FreeOTP
+totpAppGoogleName=Google Authenticator
+totpAppMicrosoftAuthenticatorName=Microsoft Authenticator
+
+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 your address {0}.
+emailVerifyInstruction2=Haven''t received a verification code in your email?
+emailVerifyInstruction3=to re-send the email.
+
+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=« Back to Login
+
+emailInstruction=Enter your username or email address and we will send you instructions on how to create a new password.
+emailInstructionUsername=Enter your username 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.
+sessionLimitExceeded=There are too many sessions
+
+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.
+
+error-invalid-value=Invalid value.
+error-invalid-blank=Please specify value.
+error-empty=Please specify value.
+error-invalid-length=Length must be between {1} and {2}.
+error-invalid-length-too-short=Minimal length is {1}.
+error-invalid-length-too-long=Maximal length is {2}.
+error-invalid-email=Invalid email address.
+error-invalid-number=Invalid number.
+error-number-out-of-range=Number must be between {1} and {2}.
+error-number-out-of-range-too-small=Number must have minimal value of {1}.
+error-number-out-of-range-too-big=Number must have maximal value of {2}.
+error-pattern-no-match=Invalid value.
+error-invalid-uri=Invalid URL.
+error-invalid-uri-scheme=Invalid URL scheme.
+error-invalid-uri-fragment=Invalid URL fragment.
+error-user-attribute-required=Please specify this field.
+error-invalid-date=Invalid date.
+error-user-attribute-read-only=This field is read only.
+error-username-invalid-character=Value contains invalid character.
+error-person-name-invalid-character=Value contains invalid character.
+
+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 exist. 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.
+configureBackupCodesMessage=You need to set up Backup Codes 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.
+updateEmailMessage=You need to update your email address 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}.
+invalidPasswordMaxLengthMessage=Invalid password: maximum 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
+successLogout=You are logged out
+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.
+cookieNotFoundMessage=Cookie not found. Please make sure cookies are enabled in your browser.
+insufficientLevelOfAuthentication=The requested level of authentication has not been satisfied.
+identityProviderUnexpectedErrorMessage=Unexpected error when authenticating with identity provider
+identityProviderMissingStateMessage=Missing state parameter in response from identity provider.
+identityProviderInvalidResponseMessage=Invalid response from identity provider.
+identityProviderInvalidSignatureMessage=Invalid signature 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_ar=\u0639\u0631\u0628\u064A
+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
+locale_fi=Suomi
+
+backToApplication=« 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=» Click here to proceed
+acrNotFulfilled=Authentication requirements not fulfilled
+
+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
+requiredAction.CONFIGURE_RECOVERY_AUTHN_CODES=Generate Recovery Codes
+requiredAction.webauthn-register-passwordless=Webauthn Register Passwordless
+
+invalidTokenRequiredActions=Required actions included in the link are not valid
+
+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.
+
+# Recovery Codes
+auth-recovery-authn-code-form-display-name=Recovery Authentication Code
+auth-recovery-authn-code-form-help-text=Enter a recovery authentication code from a previously generated list.
+auth-recovery-code-info-message=Enter the specified recovery code.
+auth-recovery-code-prompt=Recovery code #{0}
+auth-recovery-code-header=Login with a recovery authentication code
+recovery-codes-error-invalid=Invalid recovery authentication code
+recovery-code-config-header=Recovery Authentication Codes
+recovery-code-config-warning-title=These recovery codes won't appear again after leaving this page
+recovery-code-config-warning-message=Make sure to print, download, or copy them to a password manager and keep them save. Canceling this setup will remove these recovery codes from your account.
+recovery-codes-print=Print
+recovery-codes-download=Download
+recovery-codes-copy=Copy
+recovery-codes-copied=Copied
+recovery-codes-confirmation-message=I have saved these codes somewhere safe
+recovery-codes-action-complete=Complete setup
+recovery-codes-action-cancel=Cancel setup
+recovery-codes-download-file-header=Keep these recovery codes somewhere safe.
+recovery-codes-download-file-description=Recovery codes are single-use passcodes that allow you to sign in to your account if you do not have access to your authenticator.
+recovery-codes-download-file-date= These codes were generated on
+recovery-codes-label-default=Recovery codes
+
+# 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 Security Keys
+webauthn-unsupported-browser-text=WebAuthn is not supported by this browser. Try another one or contact your administrator.
+webauthn-doAuthenticate=Sign in with Security Key
+webauthn-createdAt-label=Created
+
+# WebAuthn Error
+webauthn-error-title=Security Key Error
+webauthn-error-registration=Failed to register your Security key. {0}
+webauthn-error-api-get=Failed to authenticate by the Security key. {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. {0}
+webauthn-error-register-verification=Security key registration result is invalid. {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
+idp-email-verification-display-name=Email Verification
+idp-email-verification-help-text=Link your account by validating your email.
+idp-username-password-form-display-name=Username and password
+idp-username-password-form-help-text=Link your account by logging in.
+
+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
+access-denied-when-idp-auth=Access denied when authenticating with {0}
+
+frontchannel-logout.title=Logging out
+frontchannel-logout.message=You are logging out from following apps
+logoutConfirmTitle=Logging out
+logoutConfirmHeader=Do you want to logout?
+doLogout=Logout
+
+readOnlyUsernameMessage=You can''t update your username as it is read-only.
diff --git a/themes/src/main/resources/theme/unixdog/login/register-user-profile.ftl b/themes/src/main/resources/theme/unixdog/login/register-user-profile.ftl
new file mode 100755
index 0000000000..e0d533b89f
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/login/register-user-profile.ftl
@@ -0,0 +1,74 @@
+<#import "template.ftl" as layout>
+<#import "user-profile-commons.ftl" as userProfileCommons>
+<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section>
+ <#if section = "header">
+ ${msg("registerTitle")}
+ <#elseif section = "form">
+
+ #if>
+@layout.registrationLayout>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/unixdog/login/register.ftl b/themes/src/main/resources/theme/unixdog/login/register.ftl
new file mode 100755
index 0000000000..db50984798
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/login/register.ftl
@@ -0,0 +1,141 @@
+<#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">
+
+ #if>
+@layout.registrationLayout>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/unixdog/login/resources/css/main.css b/themes/src/main/resources/theme/unixdog/login/resources/css/main.css
new file mode 100644
index 0000000000..ff2d6d6778
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/login/resources/css/main.css
@@ -0,0 +1,209 @@
+body {
+ font-family: monospace;
+ margin: 0;
+ background: #080e08;
+ color: #f6f6f6;
+
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+}
+
+h1, h2 {
+ color: #4af626;
+}
+
+footer {
+ padding: 10px;
+ max-width: 800px;
+ width: 100%;
+ background: #3a7920;
+ color: #f6f6f6;
+
+ margin: auto auto 0;
+ box-sizing: border-box;
+}
+
+a:link {
+ color: #2cacb0;
+}
+
+a:visited {
+ color: #b4778f;
+}
+@media (prefers-color-scheme: light) {
+ body {
+ background: #fcfffc;
+ color: #211c1b;
+ }
+
+ h1, h2 {
+ color: #4c982a;
+ }
+
+ a:link {
+ color: #1f7b7e;
+ }
+
+ a:visited {
+ color: #7c5263;
+ }
+
+ textarea {
+ background: #ffffff;
+ color: #211c1b;
+ }
+}
+
+header {
+ background: linear-gradient(
+ 90deg,
+ rgba(255, 0, 0, 1) 0%,
+ rgba(255, 154, 0, 1) 10%,
+ rgba(208, 222, 33, 1) 20%,
+ rgba(79, 220, 74, 1) 30%,
+ rgba(63, 218, 216, 1) 40%,
+ rgba(47, 201, 226, 1) 50%,
+ rgba(28, 127, 238, 1) 60%,
+ rgba(95, 21, 242, 1) 70%,
+ rgba(186, 12, 248, 1) 80%,
+ rgba(251, 7, 217, 1) 90%,
+ rgba(255, 0, 0, 1) 100%
+ );
+ min-height: 50px;
+ display: flex;
+ color: black;
+ box-sizing: border-box;
+}
+
+#header-content {
+ max-width: 800px;
+ margin: auto;
+ width: 100%;
+ align-content: center;
+ flex-direction: row;
+ display: flex;
+ padding: 10px;
+}
+#header-content h1 {
+ color: black;
+ margin: auto auto auto 1rem;
+}
+
+#header-content img {
+ display: inline;
+}
+
+main {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 10px;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+
+span.copyleft {
+ display: inline-block;
+ transform: rotate(180deg);
+}
+
+footer a:link, footer a:visited {
+ text-decoration: none;
+ font-weight: bold;
+ color: white;
+}
+
+footer a:hover {
+ text-decoration: underline;
+}
+
+
+input {
+ background: #332c29;
+ color: #f6f6f6;
+}
+
+textarea {
+ background: #332c29;
+ color: #f6f6f6;
+}
+
+textarea.big {
+ width: 100%;
+ height: 5em;
+}
+
+.error, .required {
+ color: #f00;
+}
+
+#nav {
+ margin: auto 0 auto auto;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+}
+
+#nav a {
+ display: block;
+ padding: 10px;
+}
+
+pre {
+ white-space: pre-wrap;
+}
+
+#header-content a:link {
+ text-decoration: none;
+ color: black;
+}
+#header-content a:visited {
+ text-decoration: none;
+ color: black;
+}
+
+#header-content a:hover {
+ text-decoration: underline;
+}
+
+label.field-with-error {
+ color: red;
+}
+
+img.stats {
+ width: 100%;
+ display: block;
+}
+
+/* Tables */
+table {
+ border-collapse: collapse;
+ width: 100%;
+}
+th, td {
+ padding: 5px;
+}
+th {
+ border-bottom: solid 2px currentColor;
+}
+
+td:first-child {
+ border-right: solid 2px currentColor;
+ border-left: none;
+}
+td {
+ border-right: solid 2px currentColor;
+ border-left: solid 2px currentColor;
+}
+td:last-child {
+ border-right: none;
+ border-left: solid 2px currentColor;
+}
+
+/* Responsive */
+.responsive-wrapper {
+ overflow-x: auto;
+ width: 100%;
+}
+
diff --git a/themes/src/main/resources/theme/unixdog/login/resources/img/favicon.ico b/themes/src/main/resources/theme/unixdog/login/resources/img/favicon.ico
new file mode 100644
index 0000000000..46eafce9bc
Binary files /dev/null and b/themes/src/main/resources/theme/unixdog/login/resources/img/favicon.ico differ
diff --git a/themes/src/main/resources/theme/unixdog/login/resources/js/base64url.js b/themes/src/main/resources/theme/unixdog/login/resources/js/base64url.js
new file mode 100644
index 0000000000..64555bfbd5
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/login/resources/js/base64url.js
@@ -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));
+
+
diff --git a/themes/src/main/resources/theme/unixdog/login/saml-post-form.ftl b/themes/src/main/resources/theme/unixdog/login/saml-post-form.ftl
new file mode 100644
index 0000000000..94b0c30fca
--- /dev/null
+++ b/themes/src/main/resources/theme/unixdog/login/saml-post-form.ftl
@@ -0,0 +1,25 @@
+<#import "template.ftl" as layout>
+<@layout.registrationLayout; section>
+ <#if section = "header">
+ ${msg("saml.post-form.title")}
+ <#elseif section = "form">
+
+
+
+ <#-- 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??)>
+