This is an automated email from the ASF dual-hosted git repository.
chaitalicod pushed a commit to branch atlas-2.6
in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/atlas-2.6 by this push:
new 3dc819970 ATLAS-5308: Add support for header based authentication
(#664)
3dc819970 is described below
commit 3dc8199707d338971226a4b171103358725960d9
Author: chaitalicod <[email protected]>
AuthorDate: Tue Jun 9 19:14:56 2026 +0530
ATLAS-5308: Add support for header based authentication (#664)
Co-authored-by: chaitali.borole <[email protected]>
(cherry picked from commit 0f9409d6261fc124d1be85fa740305960ac6d84a)
---
distro/src/conf/atlas-application.properties | 8 +-
.../web/filters/AtlasAuthenticationToken.java | 55 +++++++
.../web/filters/AtlasHeaderPreAuthFilter.java | 171 +++++++++++++++++++++
.../org/apache/atlas/web/filters/AuditFilter.java | 11 +-
.../atlas/web/security/AtlasSecurityConfig.java | 11 +-
webapp/src/main/resources/spring-security.xml | 4 +
.../web/filters/AtlasHeaderPreAuthFilterTest.java | 146 ++++++++++++++++++
.../web/security/AtlasSecurityConfigTest.java | 14 +-
8 files changed, 414 insertions(+), 6 deletions(-)
diff --git a/distro/src/conf/atlas-application.properties
b/distro/src/conf/atlas-application.properties
index b5734d7a8..126143a20 100755
--- a/distro/src/conf/atlas-application.properties
+++ b/distro/src/conf/atlas-application.properties
@@ -281,4 +281,10 @@ atlas.search.gremlin.enable=false
######### Skip check for the same attribute name in Parent type and Child type
#########
-#atlas.skip.check.for.parent.child.attribute.name=true
\ No newline at end of file
+#atlas.skip.check.for.parent.child.attribute.name=true
+
+######### Header Based Authentication #########
+#atlas.authn.header.enabled=false
+#atlas.authn.header.username=x-awc-username
+#atlas.authn.header.roles=x-awc-roles
+#atlas.authn.header.requestid=x-awc-requestid
\ No newline at end of file
diff --git
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationToken.java
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationToken.java
new file mode 100644
index 000000000..15cd70b9a
--- /dev/null
+++
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationToken.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.atlas.web.filters;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+public class AtlasAuthenticationToken extends AbstractAuthenticationToken {
+ public static final int AUTH_TYPE_TRUSTED_PROXY = 3;
+
+ private final UserDetails principal;
+ private final int authType;
+
+ public AtlasAuthenticationToken(UserDetails principal, Collection<?
extends GrantedAuthority> authorities, int authType) {
+ super(authorities);
+
+ this.principal = principal;
+ this.authType = authType;
+
+ super.setAuthenticated(true);
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return principal;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return null;
+ }
+
+ public int getAuthType() {
+ return authType;
+ }
+}
diff --git
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasHeaderPreAuthFilter.java
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasHeaderPreAuthFilter.java
new file mode 100644
index 000000000..423995bc6
--- /dev/null
+++
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasHeaderPreAuthFilter.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.atlas.web.filters;
+
+import org.apache.atlas.ApplicationProperties;
+import org.apache.atlas.web.model.User;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import
org.springframework.security.web.authentication.WebAuthenticationDetails;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@Component
+public class AtlasHeaderPreAuthFilter implements Filter {
+ private static final Logger LOG =
LoggerFactory.getLogger(AtlasHeaderPreAuthFilter.class);
+
+ public static final String PROP_HEADER_AUTH_ENABLED =
"atlas.authn.header.enabled";
+ public static final String PROP_USERNAME_HEADER =
"atlas.authn.header.username";
+ public static final String PROP_ROLES_HEADER =
"atlas.authn.header.roles";
+ public static final String PROP_REQUEST_ID_HEADER =
"atlas.authn.header.requestid";
+ public static final String REQUEST_ID_ATTRIBUTE = "atlas.request.id";
+
+ private Configuration configuration;
+ private boolean headerAuthEnabled;
+ private String userNameHeaderName;
+ private String rolesHeaderName;
+
+ @Inject
+ public AtlasHeaderPreAuthFilter() {
+ loadConfiguration();
+ }
+
+ private void loadConfiguration() {
+ try {
+ configuration = ApplicationProperties.get();
+ } catch (Exception e) {
+ LOG.error("Error loading application properties for header
pre-auth", e);
+ configuration = null;
+ }
+ if (configuration == null) {
+ headerAuthEnabled = false;
+ userNameHeaderName = null;
+ rolesHeaderName = null;
+ return;
+ }
+ headerAuthEnabled =
configuration.getBoolean(PROP_HEADER_AUTH_ENABLED, false);
+ userNameHeaderName =
StringUtils.trimToNull(configuration.getString(PROP_USERNAME_HEADER, ""));
+ rolesHeaderName =
StringUtils.trimToNull(configuration.getString(PROP_ROLES_HEADER, ""));
+ }
+
+ private List<GrantedAuthority> getAuthoritiesFromRolesHeader(String
rolesHeader) {
+ List<GrantedAuthority> ret = new ArrayList<>();
+ if (StringUtils.isBlank(rolesHeader)) {
+ return ret;
+ }
+
+ for (String role : rolesHeader.split(",")) {
+ String trimmed = StringUtils.trimToNull(role);
+ if (trimmed != null) {
+ ret.add(new
org.springframework.security.core.authority.SimpleGrantedAuthority(trimmed));
+ }
+ }
+
+ return ret;
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) {
+ loadConfiguration();
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse
servletResponse, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
+ HttpServletResponse httpResponse = (HttpServletResponse)
servletResponse;
+
+ AtlasResponseRequestWrapper responseWrapper = new
AtlasResponseRequestWrapper(httpResponse);
+ HeadersUtil.setSecurityHeaders(responseWrapper);
+
+ try {
+ if (headerAuthEnabled) {
+ Authentication pre =
SecurityContextHolder.getContext().getAuthentication();
+
+ if (pre == null || !pre.isAuthenticated()) {
+ String username =
StringUtils.trimToNull(httpRequest.getHeader(userNameHeaderName));
+
+ if (username != null) {
+ List<GrantedAuthority> grantedAuths =
+
getAuthoritiesFromRolesHeader(httpRequest.getHeader(rolesHeaderName));
+
+ UserDetails principal = new User(username, "",
grantedAuths);
+
+ AtlasAuthenticationToken token =
+ new AtlasAuthenticationToken(principal,
grantedAuths,
+
AtlasAuthenticationToken.AUTH_TYPE_TRUSTED_PROXY);
+
+ token.setDetails(new
WebAuthenticationDetails(httpRequest));
+
+
SecurityContextHolder.getContext().setAuthentication(token);
+ }
+ }
+ }
+
+ Authentication auth =
SecurityContextHolder.getContext().getAuthentication();
+ String requestId = getRequestId(auth, httpRequest);
+ httpRequest.setAttribute(REQUEST_ID_ATTRIBUTE, requestId);
+
+ chain.doFilter(servletRequest, responseWrapper);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (ServletException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String getRequestId(Authentication auth, HttpServletRequest
request) {
+ String requestIdHeaderName = configuration != null ?
configuration.getString(PROP_REQUEST_ID_HEADER) : null;
+
+ if (requestIdHeaderName != null &&
+ auth instanceof AtlasAuthenticationToken &&
+ ((AtlasAuthenticationToken) auth).getAuthType() ==
AtlasAuthenticationToken.AUTH_TYPE_TRUSTED_PROXY) {
+ String requestId =
StringUtils.trimToNull(request.getHeader(requestIdHeaderName));
+ if (requestId != null) {
+ return requestId;
+ }
+ }
+
+ return UUID.randomUUID().toString();
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
diff --git a/webapp/src/main/java/org/apache/atlas/web/filters/AuditFilter.java
b/webapp/src/main/java/org/apache/atlas/web/filters/AuditFilter.java
index 207879c7a..0a64e6b16 100755
--- a/webapp/src/main/java/org/apache/atlas/web/filters/AuditFilter.java
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/AuditFilter.java
@@ -83,7 +83,7 @@ public class AuditFilter implements Filter {
final Date requestTime = new Date();
final HttpServletRequest httpRequest = (HttpServletRequest)
request;
final HttpServletResponse httpResponse = (HttpServletResponse)
response;
- final String requestId =
UUID.randomUUID().toString();
+ final String requestId =
getRequestId(httpRequest);
final Thread currentThread = Thread.currentThread();
final String oldName = currentThread.getName();
final String user =
AtlasAuthorizationUtils.getCurrentUserName();
@@ -140,6 +140,15 @@ public class AuditFilter implements Filter {
return oldName + " - " + requestId;
}
+ private String getRequestId(HttpServletRequest httpRequest) {
+ String requestId = (String)
httpRequest.getAttribute(AtlasHeaderPreAuthFilter.REQUEST_ID_ATTRIBUTE);
+ if (StringUtils.isNotEmpty(requestId)) {
+ return requestId;
+ }
+
+ return UUID.randomUUID().toString();
+ }
+
private void recordAudit(HttpServletRequest httpRequest, Date when, String
who, int httpStatus, long timeTaken) {
final String fromAddress = httpRequest.getRemoteAddr();
final String whatRequest = httpRequest.getMethod();
diff --git
a/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
b/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
index 0f7ad76b4..fbcdf3d7e 100644
---
a/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
+++
b/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
@@ -22,6 +22,7 @@ import
org.apache.atlas.web.filters.AtlasAuthenticationEntryPoint;
import org.apache.atlas.web.filters.AtlasAuthenticationFilter;
import org.apache.atlas.web.filters.AtlasCSRFPreventionFilter;
import org.apache.atlas.web.filters.AtlasDelegatingAuthenticationEntryPoint;
+import org.apache.atlas.web.filters.AtlasHeaderPreAuthFilter;
import org.apache.atlas.web.filters.AtlasKnoxSSOAuthenticationFilter;
import org.apache.atlas.web.filters.HeadersUtil;
import org.apache.atlas.web.filters.StaleTransactionCleanupFilter;
@@ -93,6 +94,7 @@ public class AtlasSecurityConfig extends
WebSecurityConfigurerAdapter {
private final AtlasAuthenticationProvider authenticationProvider;
private final AtlasAuthenticationSuccessHandler successHandler;
private final AtlasAuthenticationFailureHandler failureHandler;
+ private final AtlasHeaderPreAuthFilter headerPreAuthFilter;
private final AtlasKnoxSSOAuthenticationFilter ssoAuthenticationFilter;
private final AtlasAuthenticationFilter atlasAuthenticationFilter;
private final AtlasCSRFPreventionFilter csrfPreventionFilter;
@@ -111,7 +113,8 @@ public class AtlasSecurityConfig extends
WebSecurityConfigurerAdapter {
private KeycloakConfigResolver keycloakConfigResolver;
@Inject
- public AtlasSecurityConfig(AtlasKnoxSSOAuthenticationFilter
ssoAuthenticationFilter,
+ public AtlasSecurityConfig(AtlasHeaderPreAuthFilter headerPreAuthFilter,
+ AtlasKnoxSSOAuthenticationFilter ssoAuthenticationFilter,
AtlasCSRFPreventionFilter atlasCSRFPreventionFilter,
AtlasAuthenticationFilter atlasAuthenticationFilter,
AtlasAuthenticationProvider authenticationProvider,
@@ -121,6 +124,7 @@ public class AtlasSecurityConfig extends
WebSecurityConfigurerAdapter {
Configuration configuration,
StaleTransactionCleanupFilter staleTransactionCleanupFilter,
ActiveServerFilter activeServerFilter) {
+ this.headerPreAuthFilter = headerPreAuthFilter;
this.ssoAuthenticationFilter = ssoAuthenticationFilter;
this.csrfPreventionFilter = atlasCSRFPreventionFilter;
this.atlasAuthenticationFilter = atlasAuthenticationFilter;
@@ -238,8 +242,9 @@ public class AtlasSecurityConfig extends
WebSecurityConfigurerAdapter {
httpSecurity.addFilterAfter(activeServerFilter,
BasicAuthenticationFilter.class);
}
- httpSecurity.addFilterAfter(staleTransactionCleanupFilter,
BasicAuthenticationFilter.class)
- .addFilterBefore(ssoAuthenticationFilter,
BasicAuthenticationFilter.class)
+ httpSecurity.addFilterBefore(headerPreAuthFilter,
BasicAuthenticationFilter.class)
+ .addFilterAfter(ssoAuthenticationFilter,
AtlasHeaderPreAuthFilter.class)
+ .addFilterAfter(staleTransactionCleanupFilter,
BasicAuthenticationFilter.class)
.addFilterAfter(atlasAuthenticationFilter,
SecurityContextHolderAwareRequestFilter.class)
.addFilterAfter(csrfPreventionFilter,
AtlasAuthenticationFilter.class);
diff --git a/webapp/src/main/resources/spring-security.xml
b/webapp/src/main/resources/spring-security.xml
index 3020690dc..ea41d46ab 100644
--- a/webapp/src/main/resources/spring-security.xml
+++ b/webapp/src/main/resources/spring-security.xml
@@ -34,6 +34,7 @@
<security:session-management
session-fixation-protection="newSession" />
<intercept-url pattern="/**" access="isAuthenticated()" />
+ <security:custom-filter position="PRE_AUTH_FILTER"
ref="headerPreAuthFilter" />
<custom-filter ref="ssoAuthenticationFilter" after="BASIC_AUTH_FILTER"
/>
<security:custom-filter ref="krbAuthenticationFilter"
after="SERVLET_API_SUPPORT_FILTER" />
@@ -54,6 +55,9 @@
<csrf disabled="true"/>
</security:http>
+ <beans:bean id="headerPreAuthFilter"
class="org.apache.atlas.web.filters.AtlasHeaderPreAuthFilter">
+ </beans:bean>
+
<beans:bean id="krbAuthenticationFilter"
class="org.apache.atlas.web.filters.AtlasAuthenticationFilter">
</beans:bean>
diff --git
a/webapp/src/test/java/org/apache/atlas/web/filters/AtlasHeaderPreAuthFilterTest.java
b/webapp/src/test/java/org/apache/atlas/web/filters/AtlasHeaderPreAuthFilterTest.java
new file mode 100644
index 000000000..cd959aaa6
--- /dev/null
+++
b/webapp/src/test/java/org/apache/atlas/web/filters/AtlasHeaderPreAuthFilterTest.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.atlas.web.filters;
+
+import org.apache.atlas.ApplicationProperties;
+import org.apache.commons.configuration2.Configuration;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.MockitoAnnotations;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+public class AtlasHeaderPreAuthFilterTest {
+ @Mock
+ private HttpServletRequest request;
+
+ @Mock
+ private HttpServletResponse response;
+
+ @Mock
+ private FilterChain filterChain;
+
+ @Mock
+ private Configuration configuration;
+
+ @BeforeMethod
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ SecurityContextHolder.clearContext();
+ }
+
+ @AfterMethod
+ public void tearDown() {
+ SecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void testDoFilterEnabledWithUsernameAndRoles() throws Exception {
+
when(configuration.getBoolean(AtlasHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
false)).thenReturn(true);
+
when(configuration.getString(AtlasHeaderPreAuthFilter.PROP_USERNAME_HEADER, ""))
+ .thenReturn("x-user");
+
when(configuration.getString(AtlasHeaderPreAuthFilter.PROP_ROLES_HEADER, ""))
+ .thenReturn("x-roles");
+ when(request.getHeader("x-user")).thenReturn("alice");
+ when(request.getHeader("x-roles")).thenReturn("ROLE_ADMIN, ROLE_USER");
+
+ try (MockedStatic<ApplicationProperties> appProps =
org.mockito.Mockito.mockStatic(ApplicationProperties.class)) {
+
appProps.when(ApplicationProperties::get).thenReturn(configuration);
+
+ AtlasHeaderPreAuthFilter filter = new AtlasHeaderPreAuthFilter();
+ filter.doFilter(request, response, filterChain);
+ }
+
+ Authentication auth =
SecurityContextHolder.getContext().getAuthentication();
+ assertNotNull(auth);
+ assertTrue(auth instanceof AtlasAuthenticationToken);
+
+ AtlasAuthenticationToken token = (AtlasAuthenticationToken) auth;
+ UserDetails principal = (UserDetails) token.getPrincipal();
+
+ assertEquals(principal.getUsername(), "alice");
+ assertEquals(token.getAuthorities().size(), 2);
+ assertEquals(token.getAuthType(),
AtlasAuthenticationToken.AUTH_TYPE_TRUSTED_PROXY);
+ verify(filterChain).doFilter(eq(request),
any(HttpServletResponse.class));
+ }
+
+ @Test
+ public void testDoFilterEnabledWithoutUsernameDoesNotAuthenticate() throws
IOException, ServletException {
+
when(configuration.getBoolean(AtlasHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
false)).thenReturn(true);
+
when(configuration.getString(AtlasHeaderPreAuthFilter.PROP_USERNAME_HEADER, ""))
+ .thenReturn("x-user");
+
when(configuration.getString(AtlasHeaderPreAuthFilter.PROP_ROLES_HEADER, ""))
+ .thenReturn("x-roles");
+ when(request.getHeader("x-user")).thenReturn(" ");
+
+ try (MockedStatic<ApplicationProperties> appProps =
org.mockito.Mockito.mockStatic(ApplicationProperties.class)) {
+
appProps.when(ApplicationProperties::get).thenReturn(configuration);
+
+ AtlasHeaderPreAuthFilter filter = new AtlasHeaderPreAuthFilter();
+ filter.doFilter(request, response, filterChain);
+ }
+
+ assertEquals(SecurityContextHolder.getContext().getAuthentication(),
null);
+ verify(filterChain).doFilter(eq(request),
any(HttpServletResponse.class));
+ }
+
+ @Test
+ public void testDoFilterEnabledKeepsExistingAuthentication() throws
IOException, ServletException {
+ Authentication existing =
org.mockito.Mockito.mock(Authentication.class);
+ when(existing.isAuthenticated()).thenReturn(true);
+ SecurityContextHolder.getContext().setAuthentication(existing);
+
+
when(configuration.getBoolean(AtlasHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
false)).thenReturn(true);
+
when(configuration.getString(AtlasHeaderPreAuthFilter.PROP_USERNAME_HEADER, ""))
+ .thenReturn("x-user");
+
when(configuration.getString(AtlasHeaderPreAuthFilter.PROP_ROLES_HEADER, ""))
+ .thenReturn("x-roles");
+ when(request.getHeader("x-user")).thenReturn("alice");
+
+ try (MockedStatic<ApplicationProperties> appProps =
org.mockito.Mockito.mockStatic(ApplicationProperties.class)) {
+
appProps.when(ApplicationProperties::get).thenReturn(configuration);
+
+ AtlasHeaderPreAuthFilter filter = new AtlasHeaderPreAuthFilter();
+ filter.doFilter(request, response, filterChain);
+ }
+
+ assertSame(SecurityContextHolder.getContext().getAuthentication(),
existing);
+ verify(filterChain).doFilter(eq(request),
any(HttpServletResponse.class));
+ }
+}
diff --git
a/webapp/src/test/java/org/apache/atlas/web/security/AtlasSecurityConfigTest.java
b/webapp/src/test/java/org/apache/atlas/web/security/AtlasSecurityConfigTest.java
index a0d14f293..4828b4b92 100644
---
a/webapp/src/test/java/org/apache/atlas/web/security/AtlasSecurityConfigTest.java
+++
b/webapp/src/test/java/org/apache/atlas/web/security/AtlasSecurityConfigTest.java
@@ -24,6 +24,7 @@ import
org.apache.atlas.web.filters.AtlasAuthenticationEntryPoint;
import org.apache.atlas.web.filters.AtlasAuthenticationFilter;
import org.apache.atlas.web.filters.AtlasCSRFPreventionFilter;
import org.apache.atlas.web.filters.AtlasDelegatingAuthenticationEntryPoint;
+import org.apache.atlas.web.filters.AtlasHeaderPreAuthFilter;
import org.apache.atlas.web.filters.AtlasKnoxSSOAuthenticationFilter;
import org.apache.atlas.web.filters.StaleTransactionCleanupFilter;
import org.apache.commons.configuration2.Configuration;
@@ -98,6 +99,9 @@ import static org.testng.Assert.assertTrue;
@SuppressWarnings("deprecation")
public class AtlasSecurityConfigTest {
+ @Mock
+ private AtlasHeaderPreAuthFilter mockHeaderPreAuthFilter;
+
@Mock
private AtlasKnoxSSOAuthenticationFilter mockSsoAuthenticationFilter;
@@ -160,6 +164,7 @@ public class AtlasSecurityConfigTest {
// Execute
atlasSecurityConfig = new AtlasSecurityConfig(
+ mockHeaderPreAuthFilter,
mockSsoAuthenticationFilter,
mockCsrfPreventionFilter,
mockAtlasAuthenticationFilter,
@@ -186,6 +191,7 @@ public class AtlasSecurityConfigTest {
// Execute
atlasSecurityConfig = new AtlasSecurityConfig(
+ mockHeaderPreAuthFilter,
mockSsoAuthenticationFilter,
mockCsrfPreventionFilter,
mockAtlasAuthenticationFilter,
@@ -346,6 +352,7 @@ public class AtlasSecurityConfigTest {
// Create AtlasSecurityConfig instance
AtlasSecurityConfig configInstance = new AtlasSecurityConfig(
+ mockHeaderPreAuthFilter,
mockSsoAuthenticationFilter,
mockCsrfPreventionFilter,
mockAtlasAuthenticationFilter,
@@ -430,6 +437,7 @@ public class AtlasSecurityConfigTest {
// Create fresh AtlasSecurityConfig instance
AtlasSecurityConfig configInstance = new AtlasSecurityConfig(
+ mockHeaderPreAuthFilter,
mockSsoAuthenticationFilter,
mockCsrfPreventionFilter,
mockAtlasAuthenticationFilter,
@@ -480,8 +488,9 @@ public class AtlasSecurityConfigTest {
}
// Verify standard filters are always added
+ verify(freshHttpSecurity,
atLeastOnce()).addFilterBefore(eq(mockHeaderPreAuthFilter), any());
+ verify(freshHttpSecurity,
atLeastOnce()).addFilterAfter(eq(mockSsoAuthenticationFilter),
eq(AtlasHeaderPreAuthFilter.class));
verify(freshHttpSecurity,
atLeastOnce()).addFilterAfter(eq(mockStaleTransactionCleanupFilter), any());
- verify(freshHttpSecurity,
atLeastOnce()).addFilterBefore(eq(mockSsoAuthenticationFilter), any());
verify(freshHttpSecurity,
atLeastOnce()).addFilterAfter(eq(mockAtlasAuthenticationFilter), any());
verify(freshHttpSecurity,
atLeastOnce()).addFilterAfter(eq(mockCsrfPreventionFilter), any());
@@ -581,6 +590,7 @@ public class AtlasSecurityConfigTest {
setupKeycloakConfiguration("/path/to/keycloak.json");
atlasSecurityConfig = new AtlasSecurityConfig(
+ mockHeaderPreAuthFilter,
mockSsoAuthenticationFilter,
mockCsrfPreventionFilter,
mockAtlasAuthenticationFilter,
@@ -811,6 +821,7 @@ public class AtlasSecurityConfigTest {
public void testInjectAnnotation() throws Exception {
// Verify @Inject annotation on constructor
Inject injectAnnotation = AtlasSecurityConfig.class.getConstructor(
+ AtlasHeaderPreAuthFilter.class,
AtlasKnoxSSOAuthenticationFilter.class,
AtlasCSRFPreventionFilter.class,
AtlasAuthenticationFilter.class,
@@ -836,6 +847,7 @@ public class AtlasSecurityConfigTest {
}
atlasSecurityConfig = new AtlasSecurityConfig(
+ mockHeaderPreAuthFilter,
mockSsoAuthenticationFilter,
mockCsrfPreventionFilter,
mockAtlasAuthenticationFilter,