Refactor header authority controller authentication (#2954)

1. (breaking changes) hawkbit.server.ddi.security.rp.cnHeader and sslIssuerHashHeader are renamed to controllerIdHeader and authorityHeader correspondingly.
2. (breaking changes) their default values are changed: X-Ssl-Client-Cn -> X-Controller-Id and X-Ssl-Issuer-Hash-%d -> X-Authority
3. Now the authority header configuration is not a string forma but just a string. The implemenation checks for this header as comma or ; separated list or seeks for header iteration <authority_header>-%d (iteration starts from 0 or 1
4. Doc fixed
5. As there are breaking changes configuration changes may be needed: a) with changing the hawkbit.server.ddi.security.rp you could turn back the previous default headers (note X-Ssl-Issuer-Hash-%d shall now be X-Ssl-Issuer-Hash), or b) you may change the headers sent by the reverse proxy

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2026-03-12 10:36:37 +02:00
committed by GitHub
parent a1608cce19
commit 011d7f567e
8 changed files with 127 additions and 126 deletions

View File

@@ -118,8 +118,8 @@ server.forward-headers-strategy=NATIVE
```
2. In Hawkbit's UI section, under system configuration, make sure to select *Allow targets to authenticate via a
certificate authenticated by a reverse proxy* and input the fixed issuer hash as "Hawkbit". This can be whetever you
have configured in the nginx configuration in `proxy_set_header X-Ssl-Issuer-Hash-1` below.
certificate authenticated by a reverse proxy* and input the fixed issuer hash as "Hawkbit". This can be whenever you
have configured in the nginx configuration in `proxy_set_header X-Authority-1` below.
3. After placing your certificates and keys, you need to deploy your proxy server and apply the provided configurations.
You can apply mutual TLS specifically to the URL given below to implement the process only for devices using the
@@ -184,8 +184,8 @@ server {
# Client certificate Common Name and Issuer Hash is required
# for auth in hawkbit.
proxy_set_header X-Ssl-Client-Cn $ssl_client_s_dn_cn;
proxy_set_header X-Ssl-Issuer-Hash-1 Hawkbit;
proxy_set_header X-Controller-Id $ssl_client_s_dn_cn;
proxy_set_header X-Authority-1 Hawkbit;
# These are required for clients to upload and download software.
proxy_request_buffering off;

View File

@@ -29,14 +29,6 @@ public class DdiSecurityProperties {
private final Rp rp = new Rp();
private final Authentication authentication = new Authentication();
public Authentication getAuthentication() {
return authentication;
}
public Rp getRp() {
return rp;
}
/**
* Reverse proxy configuration. Defines the security properties for
* authenticating controllers behind a reverse proxy which terminates the
@@ -47,16 +39,19 @@ public class DdiSecurityProperties {
public static class Rp {
/**
* HTTP header field for common name of a DDI target client certificate.
* HTTP header field for controller ID (e.g. CN of the controller certificate) of a DDI target client certificate.
*/
private String cnHeader = "X-Ssl-Client-Cn";
private String controllerIdHeader = "X-Controller-Id";
/**
* HTTP header field for issuer hash of a DDI target client certificate.
* HTTP header field for authority(ies) (e.g. SHA-256 fingerprints of issuer certificates) of a DDI target client certificate.
*/
private String sslIssuerHashHeader = "X-Ssl-Issuer-Hash-%d";
private String authorityHeader = "X-Authority";
/**
* List of trusted (reverse proxy) IP addresses for performing DDI
* client certificate auth.
* Regular expression for authorities list separator
*/
private String authoritiesSeparatorRegex = "[;,]";
/**
* List of trusted (reverse proxy) IP addresses for performing DDI client certificate auth.
*/
private List<String> trustedIPs;
}
@@ -67,14 +62,14 @@ public class DdiSecurityProperties {
@Data
public static class Authentication {
private final Targettoken targettoken = new Targettoken();
private final Gatewaytoken gatewaytoken = new Gatewaytoken();
private final TargetToken targettoken = new TargetToken();
private final GatewayToken gatewaytoken = new GatewayToken();
/**
* Target token auth. Tokens are defined per target.
*/
@Data
public static class Targettoken {
public static class TargetToken {
/**
* Set to true to enable target token auth.
@@ -86,7 +81,7 @@ public class DdiSecurityProperties {
* Gateway token auth. Tokens are defined per tenant. Use with care!
*/
@Data
public static class Gatewaytoken {
public static class GatewayToken {
/**
* Gateway token based authentication enabled.

View File

@@ -9,17 +9,17 @@
*/
package org.eclipse.hawkbit.security.controller;
import static org.eclipse.hawkbit.audit.SecurityLogger.LOGGER;
import static org.eclipse.hawkbit.context.AccessContext.asTenant;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_HEADER_AUTHORITY_NAME;
import static org.eclipse.hawkbit.repository.helper.TenantConfigHelper.getAsSystem;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_HEADER_AUTHORITY;
import java.util.Arrays;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.helper.TenantConfigHelper;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
/**
@@ -29,62 +29,46 @@ import org.springframework.security.core.Authentication;
@Slf4j
public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthenticator {
private static final Logger LOG_SECURITY_AUTH = LoggerFactory.getLogger("server-security.auth");
// e.g: X-Controller-Id: controller-1 or X-Subject-CN: controller-1
private final String controllerIdHeader;
// e.g.: X-Authority: X,Y or X-CA-Fingerprint-0: <e.g. SHA-256 fingerprint>
// could be used with one or multiple authorities that has confirmed the controller id:
// 1. <authority>=X,Y,Z -> comma separated list of authorities (could be single authority)
// 2. <authority>-0=X, <authority>-1=Y, .. ... until we get a null header
private final String authorityHeader;
private final String authoritiesSeparatorRegex;
// Example Headers with Cert Information
// Clientip: 217.24.201.180
// X-Forwarded-Proto: https
// X-Ssl-Client-Cn: my.name
// X-Ssl-Client-Dn: CN=my.name,CN=O,CN=R,CN=DE,CN=BOSCH,CN=pki,DC=bosch,DC=com
// X-Ssl-Client-Hash: 7f:87:cb:b5:9c:e0:c5:0a:1a:a6:57:69:0f:ca:0a:95
// X-Ssl-Client-Notafter: Dec 18 08:02:45 2017 GMT
// X-Ssl-Client-Notbefore: Dec 18 07:32:45 2014 GMT
// X-Ssl-Client-Verify: ok
// X-Ssl-Issuer: CN=Bosch-CA1-DE,CN=PKI,DC=Bosch,DC=com
// X-Ssl-Issuer-Dn-1: CN=Bosch-CA-DE,CN=PKI,DC=Bosch,DC=com
// X-Ssl-Issuer-Hash-1: ae:11:f5:6a:0a:e8:74:50:81:0e:0c:37:ec:c5:22:fc
private final String caCommonNameHeader;
// the X-Ssl-Issuer-Hash basic header: Contains the x509 fingerprint hash, this
// header exists multiple times in the request for all trusted chains.
private final String sslIssuerHashBasicHeader;
public SecurityHeaderAuthenticator(final String caCommonNameHeader, final String caAuthorityNameHeader) {
this.caCommonNameHeader = caCommonNameHeader;
this.sslIssuerHashBasicHeader = caAuthorityNameHeader;
public SecurityHeaderAuthenticator(final DdiSecurityProperties.Rp rp) {
this.controllerIdHeader = rp.getControllerIdHeader();
this.authorityHeader = rp.getAuthorityHeader();
this.authoritiesSeparatorRegex = rp.getAuthoritiesSeparatorRegex();
}
@Override
public Authentication authenticate(final ControllerSecurityToken controllerSecurityToken) {
// retrieve the common name header and the authority name header from the http request and combine them together
final String commonNameValue = controllerSecurityToken.getHeader(caCommonNameHeader);
if (commonNameValue == null) {
log.debug("The request doesn't contain the 'common name' header");
final String verifiedControllerId = controllerSecurityToken.getHeader(controllerIdHeader);
if (verifiedControllerId == null) {
log.debug("The request doesn't contain the '{}' header", controllerIdHeader);
return null;
}
if (!commonNameValue.equals(controllerSecurityToken.getControllerId())) {
log.debug("The request contains the 'common name' header but it doesn't match the controller id");
if (!verifiedControllerId.equals(controllerSecurityToken.getControllerId())) {
log.debug("The request contains the '{}' header but it doesn't match the controller id", controllerIdHeader);
return null;
}
if (!isEnabled(controllerSecurityToken)) {
if (!isEnabled(controllerSecurityToken)) { // in order to do not do calls to db - check after previous header checks
log.debug("The gateway header authentication is disabled");
return null;
}
final String sslIssuerHashValue = getIssuerHashHeader(
controllerSecurityToken,
asTenant(
controllerSecurityToken.getTenant(),
() -> TenantConfigHelper.getAsSystem(AUTHENTICATION_HEADER_AUTHORITY_NAME, String.class)));
if (sslIssuerHashValue == null) {
log.debug("The request contains the 'common name' header but trusted hash is not found");
final String tenant = controllerSecurityToken.getTenant();
if (verify(controllerSecurityToken, asTenant(tenant, () -> getAsSystem(AUTHENTICATION_HEADER_AUTHORITY, String.class)))) {
log.trace("Found trusted authority ****, using as credentials (tenant: {})", tenant);
return authenticatedController(tenant, verifiedControllerId);
} else {
return null;
}
if (log.isTraceEnabled()) {
log.debug("Found sslIssuerHash ****, using as credentials for tenant {}", controllerSecurityToken.getTenant());
}
return authenticatedController(controllerSecurityToken.getTenant(), commonNameValue);
}
@Override
@@ -98,28 +82,52 @@ public class SecurityHeaderAuthenticator extends Authenticator.AbstractAuthentic
}
/**
* Iterates over the {@link #sslIssuerHashBasicHeader} basic header {@code X-Ssl-Issuer-Hash-%d} and try to find the same hash as known.
* It's ok if we find the hash in any the trusted CA chain to accept this request for this tenant.
* Check {@link #authorityHeader} basic header or iterates over {@link #authorityHeader}-%d and try to find the same authority as trusted.
* It's ok if we find any authority (in headers, authenticated the controller) to accept this request for this tenant.
*/
@SuppressWarnings("java:S2629") // check if debug is enabled is maybe heavier then evaluation
private String getIssuerHashHeader(final ControllerSecurityToken controllerSecurityToken, final String knownIssuerHashes) {
// there may be several knownIssuerHashes configured for the tenant
final List<String> knownHashes = Arrays.stream(knownIssuerHashes.split("[;,]")).map(String::toLowerCase).toList();
@SuppressWarnings({ "java:S2629", "java:S135", "java:S3776" }) // check if debug is enabled is maybe heavier than evaluation, rest - fine
private boolean verify(final ControllerSecurityToken controllerSecurityToken, final String headerAuthority) {
// there may be several trusted authorities (headerAuthority config value) configured for the tenant
final List<String> trustedAuthorities = Arrays.stream(headerAuthority.split(authoritiesSeparatorRegex))
.map(String::toLowerCase).map(String::trim).toList();
// iterate over the headers until we get a null header.
String foundHash;
for (int iHeader = 1; (foundHash = controllerSecurityToken.getHeader(
String.format(sslIssuerHashBasicHeader, iHeader))) != null; iHeader++) {
if (knownHashes.contains(foundHash.toLowerCase())) {
if (log.isTraceEnabled()) {
log.trace("Found matching ssl issuer hash at position {}", iHeader);
boolean hasAuthorityHeader = false;
String matchingAuthority = null;
final String authorityHeaderValue = controllerSecurityToken.getHeader(authorityHeader);
if (authorityHeaderValue == null) {
// go for authority header prefixed iteration. iterate over the headers until we get a null header. Start from index 0 or 1
for (int i = 0; ; i++) {
final String authority = controllerSecurityToken.getHeader(authorityHeader + "-" + i);
if (authority == null) {
if (i != 0) {
break; // end of index iteration
} // if 0, try if start from 1
} else {
hasAuthorityHeader = true;
final String authorityLower = authority.toLowerCase();
if (trustedAuthorities.contains(authorityLower)) {
matchingAuthority = authorityLower;
break;
}
}
return foundHash.toLowerCase();
}
} else {
hasAuthorityHeader = true;
matchingAuthority = Arrays.stream(authorityHeaderValue.split(authoritiesSeparatorRegex))
.map(String::toLowerCase).map(String::trim)
.filter(trustedAuthorities::contains)
.findFirst().orElse(null);
}
LOG_SECURITY_AUTH.debug(
"Certificate request but no matching hash found in headers {} for common name {} in request",
sslIssuerHashBasicHeader, controllerSecurityToken.getHeader(caCommonNameHeader));
return null;
if (matchingAuthority == null) {
if (hasAuthorityHeader) {
LOGGER.debug("[SEC_HEADER_AUTH] Request has an authority header(s) but it doesn't match any trusted authority");
}
} else if (log.isTraceEnabled()) {
log.trace("Found matching authority {}", matchingAuthority);
}
return matchingAuthority != null;
}
}

View File

@@ -10,7 +10,7 @@
package org.eclipse.hawkbit.security.controller;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_HEADER_AUTHORITY_NAME;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_HEADER_AUTHORITY;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_HEADER_ENABLED;
import static org.mockito.Mockito.when;
@@ -33,23 +33,23 @@ class SecurityHeaderAuthenticatorTest {
private static final String CA_COMMON_NAME = "ca-cn";
private static final String CA_COMMON_NAME_VALUE = "box1";
private static final String X_SSL_ISSUER_HASH_1 = "X-Ssl-Issuer-Hash-1";
private static final String X_AUTHORITY_1 = "X-Authority-1";
private static final String SINGLE_HASH = "hash1";
private static final String SECOND_HASH = "hash2";
private static final String THIRD_HASH = "hash3";
private static final String UNKNOWN_HASH = "unknown";
private static final String SINGLE_AUTHORITY = "hash1";
private static final String SECOND_AUTHORITY = "hash2";
private static final String THIRD_AUTHORITY = "hash3";
private static final String UNKNOWN_AUTHORITY = "unknown";
private static final String MULTI_HASH = "HASH1;hash2,HASH3,HASH1";
private static final String MULTI_AUTHORITY = "HASH1;hash2,HASH3,HASH1";
private static final TenantConfigurationValue<String> CONFIG_VALUE_SINGLE_HASH = TenantConfigurationValue
.<String> builder().value(SINGLE_HASH).build();
private static final TenantConfigurationValue<String> CONFIG_VALUE_MULTI_HASH = TenantConfigurationValue
.<String> builder().value(MULTI_HASH).build();
private static final TenantConfigurationValue<Boolean> CONFIG_VALUE_ENABLED = TenantConfigurationValue
.<Boolean> builder().value(true).build();
private static final TenantConfigurationValue<Boolean> CONFIG_VALUE_DISABLED = TenantConfigurationValue
.<Boolean> builder().value(false).build();
private static final TenantConfigurationValue<String> CONFIG_VALUE_SINGLE_AUTHORITY = TenantConfigurationValue.<String> builder()
.value(SINGLE_AUTHORITY).build();
private static final TenantConfigurationValue<String> CONFIG_VALUE_MULTI_AUTHORITY = TenantConfigurationValue.<String> builder()
.value(MULTI_AUTHORITY).build();
private static final TenantConfigurationValue<Boolean> CONFIG_VALUE_ENABLED = TenantConfigurationValue.<Boolean> builder()
.value(true).build();
private static final TenantConfigurationValue<Boolean> CONFIG_VALUE_DISABLED = TenantConfigurationValue.<Boolean> builder()
.value(false).build();
private Authenticator authenticator;
@@ -59,17 +59,19 @@ class SecurityHeaderAuthenticatorTest {
@BeforeEach
void before() {
TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagementMock);
authenticator = new SecurityHeaderAuthenticator(CA_COMMON_NAME, "X-Ssl-Issuer-Hash-%d");
final DdiSecurityProperties.Rp rp = new DdiSecurityProperties.Rp();
rp.setControllerIdHeader(CA_COMMON_NAME);
authenticator = new SecurityHeaderAuthenticator(rp);
}
/**
* Tests successful authentication with multiple a single hashes
*/
@Test
void testWithSingleKnownHash() {
final ControllerSecurityToken securityToken = prepareSecurityToken(SINGLE_HASH);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_SINGLE_HASH);
void testWithSingleTrustedAuthority() {
final ControllerSecurityToken securityToken = prepareSecurityToken(SINGLE_AUTHORITY);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_AUTHORITY, String.class))
.thenReturn(CONFIG_VALUE_SINGLE_AUTHORITY);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_ENABLED, Boolean.class))
.thenReturn(CONFIG_VALUE_ENABLED);
@@ -82,19 +84,19 @@ class SecurityHeaderAuthenticatorTest {
* Tests successful authentication with multiple hashes
*/
@Test
void testWithMultipleKnownHashes() {
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_MULTI_HASH);
void testWithMultipleTrustedAuthority() {
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_AUTHORITY, String.class))
.thenReturn(CONFIG_VALUE_MULTI_AUTHORITY);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_ENABLED, Boolean.class))
.thenReturn(CONFIG_VALUE_ENABLED);
assertThat(authenticator.authenticate(prepareSecurityToken(SINGLE_HASH)))
assertThat(authenticator.authenticate(prepareSecurityToken(SINGLE_AUTHORITY)))
.isNotNull()
.hasFieldOrPropertyWithValue("principal", CA_COMMON_NAME_VALUE);
assertThat(authenticator.authenticate(prepareSecurityToken(SECOND_HASH)))
assertThat(authenticator.authenticate(prepareSecurityToken(SECOND_AUTHORITY)))
.isNotNull()
.hasFieldOrPropertyWithValue("principal", CA_COMMON_NAME_VALUE);
assertThat(authenticator.authenticate(prepareSecurityToken(THIRD_HASH)))
assertThat(authenticator.authenticate(prepareSecurityToken(THIRD_AUTHORITY)))
.isNotNull()
.hasFieldOrPropertyWithValue("principal", CA_COMMON_NAME_VALUE);
}
@@ -103,10 +105,10 @@ class SecurityHeaderAuthenticatorTest {
* Tests that if the hash is unknown, the authentication fails
*/
@Test
void testWithUnknownHash() {
final ControllerSecurityToken securityToken = prepareSecurityToken(UNKNOWN_HASH);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_AUTHORITY_NAME, String.class))
.thenReturn(CONFIG_VALUE_MULTI_HASH);
void testWithUnTrustedAuthority() {
final ControllerSecurityToken securityToken = prepareSecurityToken(UNKNOWN_AUTHORITY);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_AUTHORITY, String.class))
.thenReturn(CONFIG_VALUE_MULTI_AUTHORITY);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_ENABLED, Boolean.class))
.thenReturn(CONFIG_VALUE_ENABLED);
@@ -120,7 +122,7 @@ class SecurityHeaderAuthenticatorTest {
void testWithNonMatchingCN() {
final ControllerSecurityToken securityToken = new ControllerSecurityToken("DEFAULT", "otherControllerID");
securityToken.putHeader(CA_COMMON_NAME, CA_COMMON_NAME_VALUE);
securityToken.putHeader(X_SSL_ISSUER_HASH_1, SINGLE_HASH);
securityToken.putHeader(X_AUTHORITY_1, SINGLE_AUTHORITY);
assertThat(authenticator.authenticate(securityToken)).isNull();
}
@@ -137,10 +139,9 @@ class SecurityHeaderAuthenticatorTest {
* Tests that if disabled, the authentication fails
*/
@Test
void testWithSingleKnownHashButDisabled() {
final ControllerSecurityToken securityToken = prepareSecurityToken(SINGLE_HASH);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_ENABLED, Boolean.class))
.thenReturn(CONFIG_VALUE_DISABLED);
void testWithSingleTrustedAuthorityButDisabled() {
final ControllerSecurityToken securityToken = prepareSecurityToken(SINGLE_AUTHORITY);
when(tenantConfigurationManagementMock.getConfigurationValue(AUTHENTICATION_HEADER_ENABLED, Boolean.class)).thenReturn(CONFIG_VALUE_DISABLED);
assertThat(authenticator.authenticate(securityToken)).isNull();
}
@@ -148,7 +149,7 @@ class SecurityHeaderAuthenticatorTest {
private static ControllerSecurityToken prepareSecurityToken(final String issuerHashHeaderValue) {
final ControllerSecurityToken securityToken = new ControllerSecurityToken("DEFAULT", CA_COMMON_NAME_VALUE);
securityToken.putHeader(CA_COMMON_NAME, CA_COMMON_NAME_VALUE);
securityToken.putHeader(X_SSL_ISSUER_HASH_1, issuerHashHeaderValue);
securityToken.putHeader(X_AUTHORITY_1, issuerHashHeaderValue);
return securityToken;
}
}

View File

@@ -83,8 +83,7 @@ class ControllerDownloadSecurityConfiguration {
.anonymous(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.addFilterBefore(new AuthenticationFilters.SecurityHeaderAuthenticationFilter(
new SecurityHeaderAuthenticator(
ddiSecurityConfiguration.getRp().getCnHeader(), ddiSecurityConfiguration.getRp().getSslIssuerHashHeader()),
new SecurityHeaderAuthenticator(ddiSecurityConfiguration.getRp()),
ddiSecurityConfiguration), AuthorizationFilter.class)
.addFilterBefore(new AuthenticationFilters.SecurityTokenAuthenticationFilter(
new SecurityTokenAuthenticator(controllerManagement),

View File

@@ -91,9 +91,7 @@ class ControllerSecurityConfiguration {
.csrf(AbstractHttpConfigurer::disable)
.addFilterBefore(
new AuthenticationFilters.SecurityHeaderAuthenticationFilter(
new SecurityHeaderAuthenticator(
ddiSecurityConfiguration.getRp().getCnHeader(),
ddiSecurityConfiguration.getRp().getSslIssuerHashHeader()), ddiSecurityConfiguration),
new SecurityHeaderAuthenticator(ddiSecurityConfiguration.getRp()), ddiSecurityConfiguration),
AuthorizationFilter.class)
.addFilterBefore(
new AuthenticationFilters.SecurityTokenAuthenticationFilter(

View File

@@ -69,9 +69,9 @@ public class TenantConfigurationProperties {
*/
public static final String AUTHENTICATION_HEADER_ENABLED = "authentication.header.enabled";
/**
* Header based authentication authority name.
* Header based authentication authority(-ies, could be list).
*/
public static final String AUTHENTICATION_HEADER_AUTHORITY_NAME = "authentication.header.authority";
public static final String AUTHENTICATION_HEADER_AUTHORITY = "authentication.header.authority";
/**
* Target token based authentication enabled.
*/

View File

@@ -90,7 +90,7 @@ public class HawkbitFlywayDbInit {
log.info("Start ({}): {}@{}, table: {}, locations: {}, sql-migration-suffixes: {}",
MODE, USER, URL, TABLE, LOCATIONS, SQL_MIGRATION_SUFFIXES);
// configured via system properties callbacks are with prority. If not confiured - try to load via service loader
// configured via system properties callbacks are with priority. If not configured - try to load via service loader
final Callback[] callbackViaServiceLoader = CALLBACKS.length == 0 ? ServiceLoader.load(Callback.class).stream()
.map(ServiceLoader.Provider::get)
.toArray(Callback[]::new) : new Callback[0];