Pull request #633: RED-4515: Intercept keycloak authentication and choose realm from tenant header
Merge in RED/persistence-service from RED-4515 to master * commit '618e27d0e9d8094764e1ade975619c99001ef4c1': RED-4515: Added suppression of a false-positive PMD violation RED-4515: Intercept keycloak authentication and choose realm from tenant header
This commit is contained in:
commit
e7e13d4508
@ -43,8 +43,10 @@ import lombok.RequiredArgsConstructor;
|
|||||||
@EnableConfigurationProperties(KeyCloakSettings.class)
|
@EnableConfigurationProperties(KeyCloakSettings.class)
|
||||||
@Import(KeycloakSpringBootConfigResolver.class)
|
@Import(KeycloakSpringBootConfigResolver.class)
|
||||||
public class SecuredKeyCloakConfiguration extends KeycloakWebSecurityConfigurerAdapter {
|
public class SecuredKeyCloakConfiguration extends KeycloakWebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
private final KeyCloakSettings keyCloakSettings;
|
private final KeyCloakSettings keyCloakSettings;
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public KeycloakBaseSpringBootConfiguration keycloakBaseSpringBootConfiguration() {
|
public KeycloakBaseSpringBootConfiguration keycloakBaseSpringBootConfiguration() {
|
||||||
|
|
||||||
@ -67,12 +69,13 @@ public class SecuredKeyCloakConfiguration extends KeycloakWebSecurityConfigurerA
|
|||||||
@Override
|
@Override
|
||||||
public void configure(WebSecurity web) {
|
public void configure(WebSecurity web) {
|
||||||
|
|
||||||
web.ignoring().antMatchers("/actuator/health/**",
|
web.ignoring()
|
||||||
"/redaction-gateway-v1/async/download/with-ott/**",
|
.antMatchers("/actuator/health/**",
|
||||||
"/redaction-gateway-v1/docs/**",
|
"/redaction-gateway-v1/async/download/with-ott/**",
|
||||||
"/redaction-gateway-v1/docs",
|
"/redaction-gateway-v1/docs/**",
|
||||||
"/redaction-gateway-v1",
|
"/redaction-gateway-v1/docs",
|
||||||
"/internal-api/**");
|
"/redaction-gateway-v1",
|
||||||
|
"/internal-api/**");
|
||||||
|
|
||||||
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
|
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
|
||||||
}
|
}
|
||||||
@ -84,6 +87,7 @@ public class SecuredKeyCloakConfiguration extends KeycloakWebSecurityConfigurerA
|
|||||||
protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
|
protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
|
||||||
|
|
||||||
KeycloakAuthenticationProcessingFilter filter = new KeycloakAuthenticationProcessingFilter(authenticationManagerBean());
|
KeycloakAuthenticationProcessingFilter filter = new KeycloakAuthenticationProcessingFilter(authenticationManagerBean());
|
||||||
|
|
||||||
filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
|
filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
|
||||||
filter.setRequestAuthenticatorFactory(new SpringSecurityRequestAuthenticatorFactory() {
|
filter.setRequestAuthenticatorFactory(new SpringSecurityRequestAuthenticatorFactory() {
|
||||||
|
|
||||||
@ -142,6 +146,4 @@ public class SecuredKeyCloakConfiguration extends KeycloakWebSecurityConfigurerA
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,26 @@
|
|||||||
package com.iqser.red.persistence.service.v1.external.api.impl;
|
package com.iqser.red.persistence.service.v1.external.api.impl;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||||
|
import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import com.iqser.red.persistence.service.v1.external.api.impl.multitenacy.HeaderBasedKeycloakRealmResolver;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan
|
@ComponentScan
|
||||||
public class PersistenceServiceExternalApiConfiguration {
|
public class PersistenceServiceExternalApiConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public KeycloakConfigResolver keycloakConfigResolver() {
|
||||||
|
return new HeaderBasedKeycloakRealmResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setKeycloakSpringBootProperties(final KeycloakSpringBootProperties keycloakProperties) {
|
||||||
|
HeaderBasedKeycloakRealmResolver.setAdapterConfig(keycloakProperties);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.iqser.red.persistence.service.v1.external.api.impl.multitenacy;
|
||||||
|
|
||||||
|
import static com.iqser.red.service.persistence.management.v1.processor.multitenancy.TenantInterceptor.TENANT_HEADER_NAME;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||||
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
|
import org.keycloak.adapters.OIDCHttpFacade;
|
||||||
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
|
|
||||||
|
import com.iqser.red.service.persistence.management.v1.processor.utils.MagicConverter;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class HeaderBasedKeycloakRealmResolver implements KeycloakConfigResolver {
|
||||||
|
|
||||||
|
private final Map<String, KeycloakDeployment> cache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private static AdapterConfig adapterConfig;
|
||||||
|
|
||||||
|
private KeycloakDeployment defaultDeployment;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
|
||||||
|
|
||||||
|
String tenant = getHeader(request, TENANT_HEADER_NAME);
|
||||||
|
|
||||||
|
if (tenant == null) {
|
||||||
|
if (defaultDeployment == null) {
|
||||||
|
defaultDeployment = KeycloakDeploymentBuilder.build(adapterConfig);
|
||||||
|
}
|
||||||
|
return defaultDeployment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache.computeIfAbsent(tenant, this::createKeyCloakDeployment);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private KeycloakDeployment createKeyCloakDeployment(String tenant) {
|
||||||
|
|
||||||
|
var config = MagicConverter.convert(adapterConfig, AdapterConfig.class);
|
||||||
|
config.setRealm(tenant);
|
||||||
|
|
||||||
|
return KeycloakDeploymentBuilder.build(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// PMD marks this as unused, although it is clearly used.
|
||||||
|
// This seems to be a bug in PMD.
|
||||||
|
@SuppressWarnings("PMD.UnusedPrivateMethod")
|
||||||
|
private String getHeader(HttpFacade.Request request, String headerName) {
|
||||||
|
|
||||||
|
List<String> values = request.getHeaders(headerName);
|
||||||
|
if (values == null || values.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return values.get(values.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user