SSO Auto login and template cleanup

This commit is contained in:
Anthony Stirling
2025-01-09 11:37:02 +00:00
parent f879f5d533
commit e1a320ac37
5 changed files with 92 additions and 45 deletions

View File

@@ -27,4 +27,9 @@ public class EEAppConfig {
public boolean runningEnterpriseEdition() {
return licenseKeyChecker.getEnterpriseEnabledResult();
}
@Bean(name = "SSOAutoLogin")
public boolean ssoAutoLogin() {
return applicationProperties.getEnterpriseEdition().isSsoAutoLogin();
}
}

View File

@@ -94,7 +94,7 @@ public class KeygenLicenseVerifier {
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
log.info(" validateLicenseResponse body: " + response.body());
log.debug(" validateLicenseResponse body: " + response.body());
JsonNode jsonResponse = objectMapper.readTree(response.body());
if (response.statusCode() == 200) {

View File

@@ -366,6 +366,7 @@ public class ApplicationProperties {
private boolean enabled;
@ToString.Exclude private String key;
private int maxUsers;
private boolean ssoAutoLogin;
private CustomMetadata customMetadata = new CustomMetadata();
@Data

View File

@@ -63,6 +63,7 @@ security:
enterpriseEdition:
enabled: false # set to 'true' to enable enterprise edition
key: 00000000-0000-0000-0000-000000000000
SSOAutoLogin: false # Enable to auto login to first provided SSO
CustomMetadata:
autoUpdateMetadata: false # set to 'true' to automatically update metadata with below values
author: username # supports text such as 'John Doe' or types such as username to autopopulate with user's username
@@ -86,8 +87,8 @@ system:
tessdataDir: /usr/share/tessdata # path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored.
enableAnalytics: 'true' # set to 'true' to enable analytics, set to 'false' to disable analytics; for enterprise users, this is set to true
datasource:
enableCustomDatabase: false # set this property to 'true' if you would like to use your own custom database configuration
customDatabaseUrl: jdbc:postgresql://localhost:5432/postgres # set the url for your own custom database connection. If provided, the type, hostName, port and name are not necessary and will not be used
enableCustomDatabase: false # Enterprise users ONLY, set this property to 'true' if you would like to use your own custom database configuration
customDatabaseUrl: '' # eg jdbc:postgresql://localhost:5432/postgres, set the url for your own custom database connection. If provided, the type, hostName, port and name are not necessary and will not be used
username: postgres # set the database username
password: postgres # set the database password
type: postgresql # the type of the database to set (e.g. 'h2', 'postgresql')

View File

@@ -11,48 +11,88 @@
<div class="your-container-class"></div>
<div class="container-flex">
<main class="form-signin">
<script>
document.addEventListener('modeChanged', function(e) {
var mode = e.detail;
document.body.classList.remove("light-mode", "dark-mode", "rainbow-mode"); // remove all mode classes first
switch (mode) {
case "on":
document.body.classList.add("dark-mode");
break;
case "off":
document.body.classList.add("light-mode");
break;
case "rainbow":
document.body.classList.add("rainbow-mode");
break;
}
});
document.addEventListener('DOMContentLoaded', function() {
const defaultLocale = getStoredOrDefaultLocale();
checkUserLanguage(defaultLocale);
const dropdownItems = document.querySelectorAll('.lang_dropdown-item');
let activeItem;
for (let i = 0; i < dropdownItems.length; i++) {
const item = dropdownItems[i];
item.classList.remove('active');
if (item.dataset.bsLanguageCode === defaultLocale) {
item.classList.add('active');
activeItem = item;
}
item.addEventListener('click', handleDropdownItemClick);
}
const dropdown = document.getElementById('languageDropdown');
if (activeItem) {
dropdown.innerHTML = activeItem.innerHTML; // This will set the dropdown button's content to the active language's flag and name
}
});
<script th:inline="javascript">
const redirectAttempts = parseInt(localStorage.getItem('ssoRedirectAttempts') || '0');
const urlParams = new URLSearchParams(window.location.search);
const hasRedirectError = urlParams.has('error');
const hasLogout = urlParams.has('logout');
const hasMessage = urlParams.has('message');
const MAX_REDIRECT_ATTEMPTS = 3;
document.addEventListener('modeChanged', function(e) {
var mode = e.detail;
document.body.classList.remove("light-mode", "dark-mode", "rainbow-mode"); // remove all mode classes first
switch (mode) {
case "on":
document.body.classList.add("dark-mode");
break;
case "off":
document.body.classList.add("light-mode");
break;
case "rainbow":
document.body.classList.add("rainbow-mode");
break;
}
});
document.addEventListener('DOMContentLoaded', function() {
const runningEE = [[${@runningEE}]];
const SSOAutoLogin = [[${@SSOAutoLogin}]];
const loginMethod = [[${loginMethod}]];
const providerList = [[${providerlist}]];
const shouldAutoRedirect = !hasRedirectError &&
!hasLogout &&
!hasMessage &&
redirectAttempts < MAX_REDIRECT_ATTEMPTS &&
loginMethod !== 'normal' && runningEE && SSOAutoLogin;
console.log('Should redirect:', shouldAutoRedirect, {
'No error': !hasRedirectError,
'No logout': !hasLogout,
'No message': !hasMessage,
'Under max attempts': redirectAttempts < MAX_REDIRECT_ATTEMPTS,
'Is OAuth2': loginMethod === 'oauth2'
});
if (shouldAutoRedirect && providerList && Object.keys(providerList).length > 0) {
localStorage.setItem('ssoRedirectAttempts', redirectAttempts + 1);
const firstProvider = Object.keys(providerList)[0];
window.location.href = firstProvider;
}
// Reset redirect attempts if successful login or after 1 hour
const lastAttemptTime = parseInt(localStorage.getItem('lastRedirectAttempt') || '0');
if (Date.now() - lastAttemptTime > 3600000) { // 1 hour
localStorage.setItem('ssoRedirectAttempts', '0');
}
localStorage.setItem('lastRedirectAttempt', Date.now().toString());
const defaultLocale = getStoredOrDefaultLocale();
checkUserLanguage(defaultLocale);
const dropdownItems = document.querySelectorAll('.lang_dropdown-item');
let activeItem;
for (let i = 0; i < dropdownItems.length; i++) {
const item = dropdownItems[i];
item.classList.remove('active');
if (item.dataset.bsLanguageCode === defaultLocale) {
item.classList.add('active');
activeItem = item;
}
item.addEventListener('click', handleDropdownItemClick);
}
const dropdown = document.getElementById('languageDropdown');
if (activeItem) {
dropdown.innerHTML = activeItem.innerHTML; // This will set the dropdown button's content to the active language's flag and name
}
});
</script>
<div class="text-center">
<img class="my-4" th:src="@{'/favicon.svg'}" alt="favicon" width="144" height="144">