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 daac4a1f2 ATLAS-5284: Support JWT authentication for Atlas (#655)
daac4a1f2 is described below

commit daac4a1f26792dd2765fd94cff8a08368977794d
Author: chaitalicod <[email protected]>
AuthorDate: Thu Jun 11 00:03:06 2026 +0530

    ATLAS-5284: Support JWT authentication for Atlas (#655)
    
    Co-authored-by: chaitali.borole <[email protected]>
    (cherry picked from commit 9bcd37e27f13eaa177eff6d508bded8c1505b94d)
---
 authn/pom.xml                                      |  70 +++++
 .../org/apache/atlas/authn/handler/AtlasAuth.java  |  65 +++++
 .../atlas/authn/handler/AtlasAuthHandler.java      |  29 +++
 .../handler/jwt/AtlasDefaultJwtAuthHandler.java    |  86 ++++++
 .../authn/handler/jwt/AtlasJwtAuthHandler.java     | 290 +++++++++++++++++++++
 .../java/org/apache/atlas/AtlasBaseClient.java     |  48 +++-
 .../token/retriever/JwTokenRetrieverDefault.java   | 153 +++++++++++
 .../atlas/token/retriever/TokenRetriever.java      |  24 ++
 pom.xml                                            |   8 +
 webapp/pom.xml                                     |   7 +-
 .../web/filters/AtlasAuthenticationFilter.java     |   2 +-
 .../atlas/web/filters/AtlasJwtAuthFilter.java      | 119 +++++++++
 .../atlas/web/filters/AtlasJwtAuthWrapper.java     | 129 +++++++++
 .../filters/AtlasKnoxSSOAuthenticationFilter.java  |   1 +
 .../atlas/web/security/AtlasSecurityConfig.java    |  10 +-
 .../atlas/web/filters/AtlasJwtAuthFilterTest.java  |  97 +++++++
 .../atlas/web/filters/AtlasJwtAuthWrapperTest.java | 108 ++++++++
 .../web/security/AtlasSecurityConfigTest.java      |  26 +-
 18 files changed, 1258 insertions(+), 14 deletions(-)

diff --git a/authn/pom.xml b/authn/pom.xml
new file mode 100644
index 000000000..622ab32da
--- /dev/null
+++ b/authn/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.atlas</groupId>
+        <artifactId>apache-atlas</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>atlas-authn</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Apache Atlas Authentication</name>
+    <description>JWT and authentication handler support for Apache 
Atlas</description>
+
+    <properties>
+        <checkstyle.failOnViolation>true</checkstyle.failOnViolation>
+        <checkstyle.skip>false</checkstyle.skip>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.nimbusds</groupId>
+            <artifactId>nimbus-jose-jwt</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>${javax.servlet.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-configuration2</artifactId>
+            <version>${commons-conf2.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${commons-lang3.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>
diff --git a/authn/src/main/java/org/apache/atlas/authn/handler/AtlasAuth.java 
b/authn/src/main/java/org/apache/atlas/authn/handler/AtlasAuth.java
new file mode 100644
index 000000000..db2dbb90e
--- /dev/null
+++ b/authn/src/main/java/org/apache/atlas/authn/handler/AtlasAuth.java
@@ -0,0 +1,65 @@
+/*
+ * 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.authn.handler;
+
+public class AtlasAuth {
+    public enum AuthType {
+        JWT_JWKS("JWT-JWKS");
+
+        private final String authType;
+
+        AuthType(String authType) {
+            this.authType = authType;
+        }
+    }
+
+    private String    userName;
+    private AuthType type;
+    private boolean   isAuthenticated;
+
+    public AtlasAuth(final String username, AuthType type) {
+        this.userName        = username;
+        this.isAuthenticated = true;
+        this.type            = type;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public AuthType getType() {
+        return type;
+    }
+
+    public void setType(AuthType type) {
+        this.type = type;
+    }
+
+    public boolean isAuthenticated() {
+        return isAuthenticated;
+    }
+
+    public void setAuthenticated(boolean authenticated) {
+        isAuthenticated = authenticated;
+    }
+}
diff --git 
a/authn/src/main/java/org/apache/atlas/authn/handler/AtlasAuthHandler.java 
b/authn/src/main/java/org/apache/atlas/authn/handler/AtlasAuthHandler.java
new file mode 100644
index 000000000..35fea06de
--- /dev/null
+++ b/authn/src/main/java/org/apache/atlas/authn/handler/AtlasAuthHandler.java
@@ -0,0 +1,29 @@
+/*
+ * 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.authn.handler;
+
+import org.apache.commons.configuration2.Configuration;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface AtlasAuthHandler {
+    void initialize(Configuration config) throws Exception;
+
+    AtlasAuth authenticate(HttpServletRequest request);
+}
diff --git 
a/authn/src/main/java/org/apache/atlas/authn/handler/jwt/AtlasDefaultJwtAuthHandler.java
 
b/authn/src/main/java/org/apache/atlas/authn/handler/jwt/AtlasDefaultJwtAuthHandler.java
new file mode 100644
index 000000000..981b44f5e
--- /dev/null
+++ 
b/authn/src/main/java/org/apache/atlas/authn/handler/jwt/AtlasDefaultJwtAuthHandler.java
@@ -0,0 +1,86 @@
+/*
+ * 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.authn.handler.jwt;
+
+import com.nimbusds.jose.proc.JWSKeySelector;
+import com.nimbusds.jose.proc.SecurityContext;
+import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
+import com.nimbusds.jwt.proc.DefaultJWTClaimsVerifier;
+import com.nimbusds.jwt.proc.DefaultJWTProcessor;
+import com.nimbusds.jwt.proc.JWTClaimsSetVerifier;
+import org.apache.atlas.authn.handler.AtlasAuth;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+public class AtlasDefaultJwtAuthHandler extends AtlasJwtAuthHandler {
+    protected static final String AUTHORIZATION_HEADER = "Authorization";
+
+    @Override
+    public ConfigurableJWTProcessor<SecurityContext> 
getJwtProcessor(JWSKeySelector<SecurityContext> keySelector) {
+        ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new 
DefaultJWTProcessor<>();
+        JWTClaimsSetVerifier<SecurityContext> claimsVerifier   = new 
DefaultJWTClaimsVerifier<>();
+
+        jwtProcessor.setJWSKeySelector(keySelector);
+        jwtProcessor.setJWTClaimsSetVerifier(claimsVerifier);
+
+        return jwtProcessor;
+    }
+
+    @Override
+    public AtlasAuth authenticate(HttpServletRequest request) {
+        AtlasAuth atlasAuth = null;
+        String jwtAuthHeaderStr = getJwtAuthHeader(request);
+        String jwtCookieStr     = StringUtils.isBlank(jwtAuthHeaderStr) ? 
getJwtCookie(request) : null;
+
+        String username = authenticate(jwtAuthHeaderStr, jwtCookieStr);
+        if (username != null) {
+            atlasAuth = new AtlasAuth(username, AtlasAuth.AuthType.JWT_JWKS);
+        }
+        return atlasAuth;
+    }
+
+    public static boolean canAuthenticateRequest(final ServletRequest request) 
{
+        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+        String jwtAuthHeaderStr               = 
getJwtAuthHeader(httpServletRequest);
+        String jwtCookieStr                   = 
StringUtils.isBlank(jwtAuthHeaderStr) ? getJwtCookie(httpServletRequest) : null;
+        return shouldProceedAuth(jwtAuthHeaderStr, jwtCookieStr);
+    }
+
+    public static String getJwtAuthHeader(final HttpServletRequest 
httpServletRequest) {
+        return httpServletRequest.getHeader(AUTHORIZATION_HEADER);
+    }
+
+    public static String getJwtCookie(final HttpServletRequest 
httpServletRequest) {
+        String jwtCookieStr = null;
+        Cookie[] cookies    = httpServletRequest.getCookies();
+
+        if (cookies != null) {
+            for (Cookie cookie : cookies) {
+                if (cookieName.equals(cookie.getName())) {
+                    jwtCookieStr = cookie.getName() + "=" + cookie.getValue();
+                    break;
+                }
+            }
+        }
+        return jwtCookieStr;
+    }
+}
diff --git 
a/authn/src/main/java/org/apache/atlas/authn/handler/jwt/AtlasJwtAuthHandler.java
 
b/authn/src/main/java/org/apache/atlas/authn/handler/jwt/AtlasJwtAuthHandler.java
new file mode 100644
index 000000000..0411d6e95
--- /dev/null
+++ 
b/authn/src/main/java/org/apache/atlas/authn/handler/jwt/AtlasJwtAuthHandler.java
@@ -0,0 +1,290 @@
+/*
+ * 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.authn.handler.jwt;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSObject;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.crypto.RSASSAVerifier;
+import com.nimbusds.jose.jwk.source.JWKSource;
+import com.nimbusds.jose.jwk.source.RemoteJWKSet;
+import com.nimbusds.jose.proc.BadJOSEException;
+import com.nimbusds.jose.proc.JWSKeySelector;
+import com.nimbusds.jose.proc.JWSVerificationKeySelector;
+import com.nimbusds.jose.proc.SecurityContext;
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
+import org.apache.atlas.authn.handler.AtlasAuthHandler;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.X509EncodedKeySpec;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Date;
+import java.util.List;
+
+public abstract class AtlasJwtAuthHandler implements AtlasAuthHandler {
+    private static final Logger LOG = 
LoggerFactory.getLogger(AtlasJwtAuthHandler.class);
+
+    private JWSVerifier        verifier;
+    private String             jwksProviderUrl;
+    public static final String KEY_PROVIDER_URL    = "atlas.jwt.provider.url";
+    public static final String KEY_JWT_PUBLIC_KEY  = "atlas.jwt.public-key";
+    public static final String KEY_JWT_COOKIE_NAME = "atlas.jwt.cookie-name";
+    public static final String KEY_JWT_AUDIENCES   = "atlas.jwt.audiences";
+    public static final String JWT_AUTHZ_PREFIX    = "Bearer ";
+
+    protected List<String> audiences;
+    protected JWKSource<SecurityContext> keySource;
+
+    protected static String cookieName = "hadoop-jwt";
+
+    @Override
+    public void initialize(final Configuration configuration) throws Exception 
{
+        LOG.debug("===>>> AtlasJwtAuthHandler.initialize()");
+
+        jwksProviderUrl = configuration.getString(KEY_PROVIDER_URL);
+        if (!StringUtils.isBlank(jwksProviderUrl)) {
+            keySource = new RemoteJWKSet<>(new URL(jwksProviderUrl));
+        }
+
+        String pemPublicKey = configuration.getString(KEY_JWT_PUBLIC_KEY);
+
+        if (StringUtils.isNotBlank(pemPublicKey)) {
+            verifier = new RSASSAVerifier(parseJwtPublicKey(pemPublicKey));
+        } else if (StringUtils.isBlank(jwksProviderUrl)) {
+            throw new Exception("AtlasJwtAuthHandler: Mandatory configs 
('atlas.jwt.provider.url' & 'atlas.jwt.public-key') are missing, must provide 
at least one.");
+        }
+
+        String customCookieName = configuration.getString(KEY_JWT_COOKIE_NAME);
+        if (customCookieName != null) {
+            cookieName = customCookieName;
+        }
+
+        String audiencesStr = configuration.getString(KEY_JWT_AUDIENCES);
+        if (StringUtils.isNotBlank(audiencesStr)) {
+            audiences = Arrays.asList(audiencesStr.split(","));
+        }
+
+        LOG.debug("<<<=== AtlasJwtAuthHandler.initialize()");
+    }
+
+    protected String authenticate(final String jwtAuthHeader, final String 
jwtCookie) {
+        LOG.debug("===>>> AtlasJwtAuthHandler.authenticate()");
+
+        if (shouldProceedAuth(jwtAuthHeader, jwtCookie)) {
+            String serializedJWT = getJWT(jwtAuthHeader, jwtCookie);
+
+            if (StringUtils.isNotBlank(serializedJWT)) {
+                try {
+                    final SignedJWT jwtToken = SignedJWT.parse(serializedJWT);
+                    boolean         valid    = validateToken(jwtToken);
+                    if (valid) {
+                        final String userName = 
jwtToken.getJWTClaimsSet().getSubject();
+                        LOG.info("JWT claims validated; issuing principal 
user={}", userName);
+                        return userName;
+                    } else {
+                        String sub = null;
+                        try {
+                            sub = jwtToken.getJWTClaimsSet().getSubject();
+                        } catch (ParseException ignored) {
+                            // ignore
+                        }
+                        LOG.warn("JWT validation failed (signature, audience, 
or expiry). subject={}", sub);
+                    }
+                } catch (ParseException pe) {
+                    LOG.warn("Unable to parse the JWT token", pe);
+                }
+            } else {
+                LOG.warn("JWT token not found.");
+            }
+        }
+
+        LOG.debug("<<<=== AtlasJwtAuthHandler.authenticate()");
+
+        return null;
+    }
+
+    protected String getJWT(final String jwtAuthHeader, final String 
jwtCookie) {
+        String serializedJWT = null;
+
+        if (StringUtils.isNotBlank(jwtAuthHeader) && 
jwtAuthHeader.startsWith(JWT_AUTHZ_PREFIX)) {
+            serializedJWT = jwtAuthHeader.substring(JWT_AUTHZ_PREFIX.length());
+        }
+
+        if (StringUtils.isBlank(serializedJWT) && 
StringUtils.isNotBlank(jwtCookie)) {
+            String[] cookie = jwtCookie.split("=");
+            if (cookieName.equals(cookie[0])) {
+                serializedJWT = cookie[1];
+            }
+        }
+
+        return serializedJWT;
+    }
+
+    protected boolean validateToken(final SignedJWT jwtToken) {
+        boolean expValid = validateExpiration(jwtToken);
+        boolean sigValid = false;
+        boolean audValid = false;
+
+        if (expValid) {
+            sigValid = validateSignature(jwtToken);
+
+            if (sigValid) {
+                audValid = validateAudiences(jwtToken);
+            }
+        }
+
+        LOG.debug("expValid={}, sigValid={}, audValid={}", expValid, sigValid, 
audValid);
+
+        return sigValid && audValid && expValid;
+    }
+
+    protected boolean validateSignature(final SignedJWT jwtToken) {
+        boolean valid = false;
+
+        if (JWSObject.State.SIGNED == jwtToken.getState()) {
+            LOG.debug("JWT token is in a SIGNED state");
+
+            if (jwtToken.getSignature() != null) {
+                try {
+                    if (StringUtils.isNotBlank(jwksProviderUrl)) {
+                        JWSKeySelector<SecurityContext> keySelector            
= new JWSVerificationKeySelector<>(jwtToken.getHeader().getAlgorithm(), 
keySource);
+                        ConfigurableJWTProcessor<SecurityContext> jwtProcessor 
= getJwtProcessor(keySelector);
+
+                        jwtProcessor.process(jwtToken, null);
+                        valid = true;
+                        LOG.debug("JWT token has been successfully verified.");
+                    } else if (verifier != null) {
+                        if (jwtToken.verify(verifier)) {
+                            valid = true;
+                            LOG.debug("JWT token has been successfully 
verified.");
+                        } else {
+                            LOG.warn("JWT signature verification failed.");
+                        }
+                    } else {
+                        LOG.warn("Cannot authenticate JWT token as neither 
JWKS provider URL nor public key provided.");
+                    }
+                } catch (JOSEException | BadJOSEException e) {
+                    LOG.error("Error while validating signature.", e);
+                }
+            }
+        }
+
+        if (!valid) {
+            LOG.warn("Signature could not be verified.");
+        }
+
+        return valid;
+    }
+
+    private static RSAPublicKey parseJwtPublicKey(String pem) throws Exception 
{
+        String trimmed = StringUtils.trimToEmpty(pem);
+
+        if (trimmed.contains("BEGIN CERTIFICATE")) {
+            CertificateFactory factory = 
CertificateFactory.getInstance("X.509");
+            try (ByteArrayInputStream input = new 
ByteArrayInputStream(trimmed.getBytes(StandardCharsets.UTF_8))) {
+                X509Certificate cert = (X509Certificate) 
factory.generateCertificate(input);
+                PublicKey key        = cert.getPublicKey();
+
+                if (key instanceof RSAPublicKey) {
+                    return (RSAPublicKey) key;
+                }
+            }
+
+            throw new IllegalArgumentException("Certificate does not contain 
an RSA public key");
+        }
+
+        String base64 = trimmed
+                .replace("-----BEGIN PUBLIC KEY-----", "")
+                .replace("-----END PUBLIC KEY-----", "")
+                .replaceAll("\\s", "");
+
+        byte[]              decoded = Base64.getDecoder().decode(base64);
+        X509EncodedKeySpec spec     = new X509EncodedKeySpec(decoded);
+        KeyFactory          kf      = KeyFactory.getInstance("RSA");
+        PublicKey           key     = kf.generatePublic(spec);
+
+        if (key instanceof RSAPublicKey) {
+            return (RSAPublicKey) key;
+        }
+
+        throw new IllegalArgumentException("Provided key is not an RSA public 
key");
+    }
+
+    public abstract ConfigurableJWTProcessor<SecurityContext> 
getJwtProcessor(JWSKeySelector<SecurityContext> keySelector);
+
+    protected boolean validateAudiences(final SignedJWT jwtToken) {
+        boolean valid = false;
+        try {
+            List<String> tokenAudienceList = 
jwtToken.getJWTClaimsSet().getAudience();
+            if (audiences == null) {
+                valid = true;
+            } else {
+                for (String aud : tokenAudienceList) {
+                    if (audiences.contains(aud)) {
+                        LOG.debug("JWT token audience has been successfully 
validated.");
+                        valid = true;
+                        break;
+                    }
+                }
+                if (!valid) {
+                    LOG.warn("JWT audience validation failed.");
+                }
+            }
+        } catch (ParseException pe) {
+            LOG.warn("Unable to parse the JWT token.", pe);
+        }
+        return valid;
+    }
+
+    protected boolean validateExpiration(final SignedJWT jwtToken) {
+        boolean valid = false;
+        try {
+            Date expires = jwtToken.getJWTClaimsSet().getExpirationTime();
+            if (expires == null || new Date().before(expires)) {
+                valid = true;
+                LOG.debug("JWT token expiration date has been successfully 
validated.");
+            } else {
+                LOG.warn("JWT token provided is expired.");
+            }
+        } catch (ParseException pe) {
+            LOG.warn("Failed to validate JWT expiry.", pe);
+        }
+
+        return valid;
+    }
+
+    public static boolean shouldProceedAuth(final String authHeader, final 
String jwtCookie) {
+        return (StringUtils.isNotBlank(authHeader) && 
authHeader.startsWith(JWT_AUTHZ_PREFIX))
+                || (StringUtils.isNotBlank(jwtCookie) && 
jwtCookie.startsWith(cookieName));
+    }
+}
diff --git a/client/common/src/main/java/org/apache/atlas/AtlasBaseClient.java 
b/client/common/src/main/java/org/apache/atlas/AtlasBaseClient.java
index 2faa7c5e1..b6371d32f 100644
--- a/client/common/src/main/java/org/apache/atlas/AtlasBaseClient.java
+++ b/client/common/src/main/java/org/apache/atlas/AtlasBaseClient.java
@@ -43,6 +43,8 @@ import org.apache.atlas.model.impexp.AtlasImportResult;
 import org.apache.atlas.model.impexp.AtlasServer;
 import org.apache.atlas.model.metrics.AtlasMetrics;
 import org.apache.atlas.security.SecureClientUtils;
+import org.apache.atlas.token.retriever.JwTokenRetrieverDefault;
+import org.apache.atlas.token.retriever.TokenRetriever;
 import org.apache.atlas.type.AtlasType;
 import org.apache.atlas.utils.AtlasJson;
 import org.apache.atlas.utils.AuthenticationUtil;
@@ -69,8 +71,10 @@ import java.net.ConnectException;
 import java.net.URI;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import static org.apache.atlas.security.SecurityProperties.TLS_ENABLED;
+import static 
org.apache.atlas.token.retriever.JwTokenRetrieverDefault.JWT_SOURCE;
 
 public abstract class AtlasBaseClient {
     private static final Logger LOG = 
LoggerFactory.getLogger(AtlasBaseClient.class);
@@ -109,6 +113,8 @@ public abstract class AtlasBaseClient {
     private static final API    EXPORT                  = new API(BASE_URI + 
ADMIN_EXPORT, HttpMethod.POST, Response.Status.OK, MediaType.APPLICATION_JSON, 
MediaType.APPLICATION_OCTET_STREAM);
     private static final String IMPORT_REQUEST_PARAMTER = "request";
     private static final String IMPORT_DATA_PARAMETER   = "data";
+    private static final String AUTHORIZATION_HEADER    = "Authorization";
+    private static final String JWT_AUTHZ_PREFIX        = "Bearer ";
 
     protected WebResource        service;
     protected Configuration      configuration;
@@ -117,6 +123,8 @@ public abstract class AtlasBaseClient {
     private   AtlasClientContext atlasClientContext;
     private   boolean            retryEnabled;
     private   Cookie             cookie;
+    private   boolean            useJwtAuth;
+    private   TokenRetriever<String> tokenRetriever;
 
     private SecureClientUtils clientUtils;
 
@@ -361,7 +369,7 @@ public abstract class AtlasBaseClient {
 
         final URLConnectionClientHandler handler;
 
-        if (isKerberosEnabled) {
+        if (isKerberosEnabled && !useJwtAuth) {
             handler = clientUtils.getClientConnectionHandler(config, 
configuration, doAsUser, ugi);
         } else {
             if (configuration.getBoolean(TLS_ENABLED, false)) {
@@ -457,6 +465,8 @@ public abstract class AtlasBaseClient {
                 requestBuilder.cookie(cookie);
             }
 
+            handleJwt(requestBuilder);
+
             clientResponse = requestBuilder.method(api.getMethod(), 
ClientResponse.class, requestObject);
 
             LOG.debug("HTTP Status  : {}", clientResponse.getStatus());
@@ -537,11 +547,13 @@ public abstract class AtlasBaseClient {
     }
 
     void initializeState(Configuration configuration, String[] baseUrls, 
UserGroupInformation ugi, String doAsUser) {
-        this.configuration = configuration;
+        this.configuration  = configuration;
+        useJwtAuth          = isJwtSourceConfigured(configuration);
+        tokenRetriever      = useJwtAuth ? getJwtTokenRetriever(configuration) 
: null;
 
         Client client = getClient(configuration, ugi, doAsUser);
 
-        if ((!AuthenticationUtil.isKerberosAuthenticationEnabled()) && 
basicAuthUser != null && basicAuthPassword != null) {
+        if (!useJwtAuth && 
(!AuthenticationUtil.isKerberosAuthenticationEnabled()) && basicAuthUser != 
null && basicAuthPassword != null) {
             final HTTPBasicAuthFilter authFilter = new 
HTTPBasicAuthFilter(basicAuthUser, basicAuthPassword);
 
             client.addFilter(authFilter);
@@ -553,6 +565,36 @@ public abstract class AtlasBaseClient {
         service            = 
client.resource(UriBuilder.fromUri(activeServiceUrl).build());
     }
 
+    private TokenRetriever<String> getJwtTokenRetriever(Configuration 
configuration) {
+        return new JwTokenRetrieverDefault(configuration);
+    }
+
+    private boolean isJwtSourceConfigured(Configuration configuration) {
+        if (configuration == null) {
+            return false;
+        }
+
+        String jwtSource = configuration.getString(JWT_SOURCE, "");
+        return StringUtils.isNotBlank(jwtSource);
+    }
+
+    private void handleJwt(com.sun.jersey.api.client.WebResource.Builder 
requestBuilder) {
+        if (!useJwtAuth) {
+            return;
+        }
+        if (tokenRetriever == null) {
+            LOG.warn("AtlasBaseClient.handleJwt(): tokenRetriever is null. 
Skipping JWT header injection.");
+            return;
+        }
+
+        Optional<String> jwtOptional = tokenRetriever.retrieve();
+        if (jwtOptional.isPresent()) {
+            requestBuilder.header(AUTHORIZATION_HEADER, JWT_AUTHZ_PREFIX + 
jwtOptional.get());
+        } else {
+            LOG.warn("AtlasBaseClient.handleJwt(): JWT token not available 
from configured retriever. Authorization header not set.");
+        }
+    }
+
     void sleepBetweenRetries() {
         try {
             Thread.sleep(getSleepBetweenRetriesMs());
diff --git 
a/client/common/src/main/java/org/apache/atlas/token/retriever/JwTokenRetrieverDefault.java
 
b/client/common/src/main/java/org/apache/atlas/token/retriever/JwTokenRetrieverDefault.java
new file mode 100644
index 000000000..c9c858f7d
--- /dev/null
+++ 
b/client/common/src/main/java/org/apache/atlas/token/retriever/JwTokenRetrieverDefault.java
@@ -0,0 +1,153 @@
+/**
+ * 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.token.retriever;
+
+import org.apache.atlas.security.SecurityUtil;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Optional;
+
+public class JwTokenRetrieverDefault implements TokenRetriever<String> {
+    private static final Logger LOG = 
LoggerFactory.getLogger(JwTokenRetrieverDefault.class);
+
+    public static final String JWT_SOURCE     = "atlas.jwt.source";
+    public static final String JWT_ENV        = "atlas.jwt.env";
+    public static final String JWT_FILE       = "atlas.jwt.file";
+    public static final String JWT_CRED_FILE  = "atlas.jwt.cred.file";
+    public static final String JWT_CRED_ALIAS = "atlas.jwt.cred.alias";
+
+    private static final String SOURCE_ENV  = "env";
+    private static final String SOURCE_FILE = "file";
+    private static final String SOURCE_CRED = "cred";
+    private static final long CRED_CHECK_INTERVAL_MS = 60 * 1000;
+
+    private final String jwtSource;
+    private final String jwtEnvVar;
+    private final String jwtFilePath;
+    private final String jwtCredPathPropertyName;
+    private final String jwtCredFilePath;
+    private final String jwtCredAlias;
+    private final Configuration configuration;
+    private long jwtFileLastModified;
+    private long jwtCredFileLastCheckedAt;
+
+    private volatile Optional<String> cachedJwt = Optional.empty();
+
+    public JwTokenRetrieverDefault(Configuration config) {
+        configuration           = config;
+        jwtSource               = 
StringUtils.trimToEmpty(config.getString(JWT_SOURCE, ""));
+        jwtEnvVar               = 
StringUtils.trimToEmpty(config.getString(JWT_ENV, ""));
+        jwtFilePath             = 
StringUtils.trimToEmpty(config.getString(JWT_FILE, ""));
+        jwtCredPathPropertyName = JWT_CRED_FILE;
+        jwtCredFilePath         = 
StringUtils.trimToEmpty(config.getString(jwtCredPathPropertyName, ""));
+        jwtCredAlias            = 
StringUtils.trimToEmpty(config.getString(JWT_CRED_ALIAS, ""));
+    }
+
+    @Override
+    public synchronized Optional<String> retrieve() {
+        String source = StringUtils.lowerCase(jwtSource);
+        switch (source) {
+            case SOURCE_ENV:
+                return getJwtFromEnv();
+            case SOURCE_FILE:
+                return getJwtFromFile();
+            case SOURCE_CRED:
+                return getJwtFromCredProvider();
+            default:
+                if (StringUtils.isNotBlank(source)) {
+                    LOG.warn("JwTokenRetrieverDefault.retrieve(): unsupported 
source='{}'", source);
+                }
+                return Optional.empty();
+        }
+    }
+
+    private Optional<String> getJwtFromEnv() {
+        if (StringUtils.isBlank(jwtEnvVar)) {
+            LOG.warn("JwTokenRetrieverDefault.getJwtFromEnv(): '{}' is not 
configured.", JWT_ENV);
+            return Optional.empty();
+        }
+
+        String token = StringUtils.trimToEmpty(System.getenv(jwtEnvVar));
+        return StringUtils.isBlank(token) ? Optional.empty() : 
Optional.of(token);
+    }
+
+    private Optional<String> getJwtFromFile() {
+        if (StringUtils.isBlank(jwtFilePath)) {
+            LOG.warn("JwTokenRetrieverDefault.getJwtFromFile(): '{}' is not 
configured.", JWT_FILE);
+            return Optional.empty();
+        }
+
+        File jwtFile = new File(jwtFilePath);
+        if (!jwtFile.canRead()) {
+            return cachedJwt;
+        }
+
+        if (jwtFile.lastModified() == jwtFileLastModified && 
cachedJwt.isPresent()) {
+            return cachedJwt;
+        }
+
+        try (BufferedReader reader = new BufferedReader(new 
FileReader(jwtFile))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                if (StringUtils.isNotBlank(line) && !line.startsWith("#")) {
+                    cachedJwt           = Optional.of(line.trim());
+                    jwtFileLastModified = jwtFile.lastModified();
+                    break;
+                }
+            }
+        } catch (IOException e) {
+            LOG.error("JwTokenRetrieverDefault.getJwtFromFile(): failed to 
read JWT from file={}", jwtFilePath, e);
+        }
+
+        return cachedJwt;
+    }
+
+    private Optional<String> getJwtFromCredProvider() {
+        if (StringUtils.isBlank(jwtCredFilePath) || 
StringUtils.isBlank(jwtCredAlias)) {
+            LOG.warn("JwTokenRetrieverDefault.getJwtFromCredProvider(): '{}' 
or '{}' is not configured.",
+                    JWT_CRED_FILE, JWT_CRED_ALIAS);
+            return Optional.empty();
+        }
+
+        long now = System.currentTimeMillis();
+        if ((now - jwtCredFileLastCheckedAt) <= CRED_CHECK_INTERVAL_MS && 
cachedJwt.isPresent()) {
+            return cachedJwt;
+        }
+
+        try {
+            String token = StringUtils.trimToEmpty(
+                    SecurityUtil.getPassword(configuration, jwtCredAlias, 
jwtCredPathPropertyName));
+            if (StringUtils.isNotBlank(token)) {
+                cachedJwt = Optional.of(token);
+            }
+        } catch (Exception e) {
+            LOG.error("JwTokenRetrieverDefault.getJwtFromCredProvider(): 
failed to read JWT from credential provider.", e);
+        } finally {
+            jwtCredFileLastCheckedAt = now;
+        }
+
+        return cachedJwt;
+    }
+}
diff --git 
a/client/common/src/main/java/org/apache/atlas/token/retriever/TokenRetriever.java
 
b/client/common/src/main/java/org/apache/atlas/token/retriever/TokenRetriever.java
new file mode 100644
index 000000000..cdcd84a42
--- /dev/null
+++ 
b/client/common/src/main/java/org/apache/atlas/token/retriever/TokenRetriever.java
@@ -0,0 +1,24 @@
+/**
+ * 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.token.retriever;
+
+import java.util.Optional;
+
+public interface TokenRetriever<T> {
+    Optional<T> retrieve();
+}
diff --git a/pom.xml b/pom.xml
index c5fa6b1f3..15bab027d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,7 @@
         <module>addons/storm-bridge-shim</module>
         <module>addons/trino-extractor</module>
         <module>atlas-examples</module>
+        <module>authn</module>
         <module>authorization</module>
         <module>build-tools</module>
         <module>client</module>
@@ -158,6 +159,7 @@
         <maven-plugin-sortpom.version>3.0.1</maven-plugin-sortpom.version>
         <maven-site-plugin.version>3.7</maven-site-plugin.version>
         <netty.version>4.1.125.Final</netty.version>
+        <nimbus-jose-jwt.version>9.37.3</nimbus-jose-jwt.version>
         <node-for-v1.version>v22.14.0</node-for-v1.version>
         <node-for-v2.version>v12.16.0</node-for-v2.version>
         <npm-for-v1.version>10.9.2</npm-for-v1.version>
@@ -262,6 +264,12 @@
                 </exclusions>
             </dependency>
 
+            <dependency>
+                <groupId>com.nimbusds</groupId>
+                <artifactId>nimbus-jose-jwt</artifactId>
+                <version>${nimbus-jose-jwt.version}</version>
+            </dependency>
+
             <dependency>
                 <groupId>com.squareup.okio</groupId>
                 <artifactId>okio</artifactId>
diff --git a/webapp/pom.xml b/webapp/pom.xml
index d0ce93d4d..a7b5f7837 100755
--- a/webapp/pom.xml
+++ b/webapp/pom.xml
@@ -66,7 +66,6 @@
         <dependency>
             <groupId>com.nimbusds</groupId>
             <artifactId>nimbus-jose-jwt</artifactId>
-            <version>9.37.3</version>
             <scope>compile</scope>
             <exclusions>
                 <exclusion>
@@ -136,6 +135,12 @@
             <version>5.2.0</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.atlas</groupId>
+            <artifactId>atlas-authn</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.atlas</groupId>
             <artifactId>atlas-authorization</artifactId>
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
 
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
index bc477f762..d72122aa6 100644
--- 
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
+++ 
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
@@ -427,7 +427,7 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
             if (existingAuth == null) {
                 String authHeader = httpRequest.getHeader("Authorization");
 
-                if (authHeader != null && authHeader.startsWith("Basic")) {
+                if (authHeader != null && (authHeader.startsWith("Basic") || 
authHeader.startsWith("Bearer"))) {
                     filterChain.doFilter(request, response);
                 } else if (isKerberos) {
                     doKerberosAuth(request, response, filterChain);
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasJwtAuthFilter.java 
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasJwtAuthFilter.java
new file mode 100644
index 000000000..c931b37a0
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasJwtAuthFilter.java
@@ -0,0 +1,119 @@
+/*
+ * 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.authn.handler.AtlasAuth;
+import org.apache.atlas.authn.handler.jwt.AtlasDefaultJwtAuthHandler;
+import org.apache.atlas.authn.handler.jwt.AtlasJwtAuthHandler;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import 
org.springframework.security.web.authentication.WebAuthenticationDetails;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+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 java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+@Lazy
+@Component
+public class AtlasJwtAuthFilter extends AtlasDefaultJwtAuthHandler implements 
Filter {
+    private static final Logger LOG                = 
LoggerFactory.getLogger(AtlasJwtAuthFilter.class);
+    private static final String DEFAULT_ATLAS_ROLE = "ROLE_USER";
+
+    @PostConstruct
+    public void initialize() {
+        LOG.debug("===>>> AtlasJwtAuthFilter.initialize()");
+
+        try {
+            Configuration config = ApplicationProperties.get();
+            if 
(StringUtils.isEmpty(config.getString(AtlasJwtAuthHandler.KEY_PROVIDER_URL))) {
+                config.setProperty(AtlasJwtAuthHandler.KEY_PROVIDER_URL,
+                        
config.getString(AtlasKnoxSSOAuthenticationFilter.JWT_AUTH_PROVIDER_URL));
+            }
+            config.setProperty(AtlasJwtAuthHandler.KEY_JWT_PUBLIC_KEY,
+                    
config.getString(AtlasKnoxSSOAuthenticationFilter.JWT_PUBLIC_KEY, ""));
+            config.setProperty(AtlasJwtAuthHandler.KEY_JWT_COOKIE_NAME,
+                    
config.getString(AtlasKnoxSSOAuthenticationFilter.JWT_COOKIE_NAME,
+                            
AtlasKnoxSSOAuthenticationFilter.JWT_COOKIE_NAME_DEFAULT));
+            config.setProperty(AtlasJwtAuthHandler.KEY_JWT_AUDIENCES,
+                    
config.getString(AtlasKnoxSSOAuthenticationFilter.JWT_AUDIENCES, ""));
+
+            super.initialize(config);
+        } catch (Exception e) {
+            LOG.error("Failed to initialize Atlas JWT Auth Filter.", e);
+        }
+
+        LOG.debug("<<<=== AtlasJwtAuthFilter.initialize()");
+    }
+
+    @Override
+    public void init(FilterConfig filterConfig) {
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain)
+            throws IOException, ServletException {
+        LOG.debug("===>>> AtlasJwtAuthFilter.doFilter()");
+
+        HttpServletRequest httpServletRequest = (HttpServletRequest) 
servletRequest;
+        AtlasAuth atlasAuth                   = 
authenticate(httpServletRequest);
+
+        if (atlasAuth != null) {
+            final List<GrantedAuthority> grantedAuths = Arrays.asList(new 
SimpleGrantedAuthority(DEFAULT_ATLAS_ROLE));
+            final UserDetails principal               = new 
User(atlasAuth.getUserName(), "", grantedAuths);
+            final Authentication finalAuthentication  = new 
UsernamePasswordAuthenticationToken(principal, "", grantedAuths);
+            final WebAuthenticationDetails webDetails = new 
WebAuthenticationDetails(httpServletRequest);
+            ((AbstractAuthenticationToken) 
finalAuthentication).setDetails(webDetails);
+            
SecurityContextHolder.getContext().setAuthentication(finalAuthentication);
+        }
+
+        Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();
+        if (auth != null) {
+            LOG.debug("<<<=== AtlasJwtAuthFilter.doFilter() - user=[{}], 
isUserAuthenticated=[{}]",
+                    auth.getPrincipal(), auth.isAuthenticated());
+        } else {
+            LOG.warn("<<<=== AtlasJwtAuthFilter.doFilter() - Failed to 
authenticate request using Atlas JWT authentication framework.");
+        }
+    }
+
+    @Override
+    public void destroy() {
+    }
+}
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasJwtAuthWrapper.java 
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasJwtAuthWrapper.java
new file mode 100644
index 000000000..74680530b
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasJwtAuthWrapper.java
@@ -0,0 +1,129 @@
+/*
+ * 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.AtlasException;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.servlet.FilterChain;
+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;
+
+@Lazy
+@Component
+public class AtlasJwtAuthWrapper extends GenericFilterBean {
+    private static final Logger LOG = 
LoggerFactory.getLogger(AtlasJwtAuthWrapper.class);
+
+    private String[] browserUserAgents = new String[] {""};
+
+    private final Configuration configuration;
+
+    @Lazy
+    @Autowired
+    AtlasJwtAuthFilter atlasJwtAuthFilter;
+
+    @Inject
+    public AtlasJwtAuthWrapper(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    @PostConstruct
+    public void initialize() {
+        String defaultUserAgent = 
configuration.getString(AtlasKnoxSSOAuthenticationFilter.DEFAULT_BROWSER_USERAGENT);
+        String userAgent        = 
configuration.getString(AtlasKnoxSSOAuthenticationFilter.BROWSER_USERAGENT);
+
+        if (StringUtils.isBlank(userAgent) && 
StringUtils.isNotBlank(defaultUserAgent)) {
+            userAgent = defaultUserAgent;
+        }
+
+        if (StringUtils.isNotBlank(userAgent)) {
+            browserUserAgents = userAgent.split(",");
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain)
+            throws IOException, ServletException {
+        LOG.debug("===>>> AtlasJwtAuthWrapper.doFilter({}, {}, {})", 
servletRequest, servletResponse, filterChain);
+
+        Configuration configuration = null;
+        try {
+            configuration = ApplicationProperties.get();
+        } catch (AtlasException e) {
+            throw new RuntimeException(e);
+        }
+        boolean isProxyEnabled      = 
configuration.getBoolean("atlas.authentication.method.trustedproxy", false);
+        boolean useJwtAuthMechanism = servletRequest != null && 
!isRequestAuthenticated() && 
AtlasJwtAuthFilter.canAuthenticateRequest(servletRequest);
+        boolean ssoEnabled          = 
configuration.getBoolean("atlas.sso.knox.enabled", false);
+
+        if (!ssoEnabled && useJwtAuthMechanism && !isProxyEnabled) {
+            atlasJwtAuthFilter.doFilter(servletRequest, servletResponse, 
filterChain);
+
+            if (!isRequestAuthenticated()) {
+                String userAgent = ((HttpServletRequest) 
servletRequest).getHeader("User-Agent");
+                if (isBrowserAgent(userAgent)) {
+                    LOG.debug("Redirecting to login page as request does not 
have valid JWT auth details.");
+                    ((HttpServletResponse) 
servletResponse).sendRedirect("/login.jsp");
+                }
+            }
+        } else {
+            LOG.debug("<<<=== AtlasJwtAuthWrapper.doFilter() - Skipping JWT 
auth.");
+        }
+        filterChain.doFilter(servletRequest, servletResponse);
+
+        LOG.debug("<<<=== AtlasJwtAuthWrapper.doFilter()");
+    }
+
+    protected boolean isBrowserAgent(String userAgent) {
+        boolean isBrowser = false;
+
+        if (browserUserAgents.length > 0 && StringUtils.isNotBlank(userAgent)) 
{
+            for (String ua : browserUserAgents) {
+                if (userAgent.toLowerCase().startsWith(ua.toLowerCase())) {
+                    isBrowser = true;
+                    break;
+                }
+            }
+        }
+
+        return isBrowser;
+    }
+
+    private boolean isRequestAuthenticated() {
+        Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();
+        return auth != null && auth.isAuthenticated();
+    }
+}
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasKnoxSSOAuthenticationFilter.java
 
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasKnoxSSOAuthenticationFilter.java
index c41f9d468..f2d43390b 100644
--- 
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasKnoxSSOAuthenticationFilter.java
+++ 
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasKnoxSSOAuthenticationFilter.java
@@ -82,6 +82,7 @@ public class AtlasKnoxSSOAuthenticationFilter implements 
Filter {
     public static final String JWT_COOKIE_NAME                      = 
"atlas.sso.knox.cookiename";
     public static final String JWT_ORIGINAL_URL_QUERY_PARAM         = 
"atlas.sso.knox.query.param.originalurl";
     public static final String JWT_COOKIE_NAME_DEFAULT              = 
"hadoop-jwt";
+    public static final String JWT_AUDIENCES                        = 
"atlas.sso.knox.audiences";
     public static final String JWT_ORIGINAL_URL_QUERY_PARAM_DEFAULT = 
"originalUrl";
     public static final String DEFAULT_BROWSER_USERAGENT            = 
"Mozilla,Opera,Chrome";
     public static final String PROXY_ATLAS_URL_PATH                 = "/atlas";
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 fbcdf3d7e..532f3319c 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
@@ -23,6 +23,7 @@ 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.AtlasJwtAuthWrapper;
 import org.apache.atlas.web.filters.AtlasKnoxSSOAuthenticationFilter;
 import org.apache.atlas.web.filters.HeadersUtil;
 import org.apache.atlas.web.filters.StaleTransactionCleanupFilter;
@@ -99,6 +100,7 @@ public class AtlasSecurityConfig extends 
WebSecurityConfigurerAdapter {
     private final AtlasAuthenticationFilter         atlasAuthenticationFilter;
     private final AtlasCSRFPreventionFilter         csrfPreventionFilter;
     private final AtlasAuthenticationEntryPoint     
atlasAuthenticationEntryPoint;
+    private final AtlasJwtAuthWrapper               atlasJwtAuthWrapper;
 
     // Our own Atlas filters need to be registered as well
     private final Configuration                 configuration;
@@ -123,7 +125,8 @@ public class AtlasSecurityConfig extends 
WebSecurityConfigurerAdapter {
             AtlasAuthenticationEntryPoint atlasAuthenticationEntryPoint,
             Configuration configuration,
             StaleTransactionCleanupFilter staleTransactionCleanupFilter,
-            ActiveServerFilter activeServerFilter) {
+            ActiveServerFilter activeServerFilter,
+            AtlasJwtAuthWrapper atlasJwtAuthWrapper) {
         this.headerPreAuthFilter           = headerPreAuthFilter;
         this.ssoAuthenticationFilter       = ssoAuthenticationFilter;
         this.csrfPreventionFilter          = atlasCSRFPreventionFilter;
@@ -135,6 +138,7 @@ public class AtlasSecurityConfig extends 
WebSecurityConfigurerAdapter {
         this.configuration                 = configuration;
         this.staleTransactionCleanupFilter = staleTransactionCleanupFilter;
         this.activeServerFilter            = activeServerFilter;
+        this.atlasJwtAuthWrapper           = atlasJwtAuthWrapper;
 
         this.keycloakEnabled = 
configuration.getBoolean(AtlasAuthenticationProvider.KEYCLOAK_AUTH_METHOD, 
false);
     }
@@ -242,8 +246,10 @@ public class AtlasSecurityConfig extends 
WebSecurityConfigurerAdapter {
             httpSecurity.addFilterAfter(activeServerFilter, 
BasicAuthenticationFilter.class);
         }
 
-        httpSecurity.addFilterBefore(headerPreAuthFilter, 
BasicAuthenticationFilter.class)
+        httpSecurity
+                .addFilterBefore(headerPreAuthFilter, 
BasicAuthenticationFilter.class)
                 .addFilterAfter(ssoAuthenticationFilter, 
AtlasHeaderPreAuthFilter.class)
+                .addFilterAfter(atlasJwtAuthWrapper, 
AtlasKnoxSSOAuthenticationFilter.class)
                 .addFilterAfter(staleTransactionCleanupFilter, 
BasicAuthenticationFilter.class)
                 .addFilterAfter(atlasAuthenticationFilter, 
SecurityContextHolderAwareRequestFilter.class)
                 .addFilterAfter(csrfPreventionFilter, 
AtlasAuthenticationFilter.class);
diff --git 
a/webapp/src/test/java/org/apache/atlas/web/filters/AtlasJwtAuthFilterTest.java 
b/webapp/src/test/java/org/apache/atlas/web/filters/AtlasJwtAuthFilterTest.java
new file mode 100644
index 000000000..503c7eafd
--- /dev/null
+++ 
b/webapp/src/test/java/org/apache/atlas/web/filters/AtlasJwtAuthFilterTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.authn.handler.AtlasAuth;
+import org.mockito.Mockito;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+public class AtlasJwtAuthFilterTest {
+    @AfterMethod
+    public void cleanup() {
+        SecurityContextHolder.clearContext();
+    }
+
+    @Test
+    public void testInit_noopDoesNotThrow() throws Exception {
+        AtlasJwtAuthFilter filter = new AtlasJwtAuthFilter();
+        filter.init(mock(javax.servlet.FilterConfig.class));
+    }
+
+    @Test
+    public void testDestroy_noopDoesNotThrow() {
+        AtlasJwtAuthFilter filter = new AtlasJwtAuthFilter();
+        filter.destroy();
+    }
+
+    @Test
+    public void testDoFilter_setsAuthenticationWhenAuthenticateSucceeds() 
throws Exception {
+        AtlasJwtAuthFilter filter = Mockito.spy(new AtlasJwtAuthFilter());
+
+        HttpServletRequest req  = mock(HttpServletRequest.class);
+        ServletResponse res     = mock(ServletResponse.class);
+        FilterChain chain       = mock(FilterChain.class);
+
+        AtlasAuth atlasAuth = new AtlasAuth("alice", 
AtlasAuth.AuthType.JWT_JWKS);
+
+        
doReturn(atlasAuth).when(filter).authenticate(any(HttpServletRequest.class));
+
+        filter.doFilter(req, res, chain);
+
+        Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();
+        assertNotNull(auth);
+        assertTrue(auth.getPrincipal() instanceof User);
+        User user = (User) auth.getPrincipal();
+        assertEquals(user.getUsername(), "alice");
+        assertNotNull(auth.getAuthorities());
+        assertFalse(auth.getAuthorities().isEmpty());
+    }
+
+    @Test
+    public void 
testDoFilter_leavesAuthenticationNullWhenAuthenticateReturnsNull() throws 
Exception {
+        AtlasJwtAuthFilter filter = Mockito.spy(new AtlasJwtAuthFilter());
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        ServletResponse res    = mock(ServletResponse.class);
+        FilterChain chain      = mock(FilterChain.class);
+
+        
doReturn(null).when(filter).authenticate(any(HttpServletRequest.class));
+
+        filter.doFilter(req, res, chain);
+
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
+    }
+}
diff --git 
a/webapp/src/test/java/org/apache/atlas/web/filters/AtlasJwtAuthWrapperTest.java
 
b/webapp/src/test/java/org/apache/atlas/web/filters/AtlasJwtAuthWrapperTest.java
new file mode 100644
index 000000000..d9d1d5a0d
--- /dev/null
+++ 
b/webapp/src/test/java/org/apache/atlas/web/filters/AtlasJwtAuthWrapperTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.commons.configuration2.Configuration;
+import org.mockito.Mockito;
+import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.util.Collections;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class AtlasJwtAuthWrapperTest {
+    @AfterMethod
+    public void tearDown() {
+        SecurityContextHolder.clearContext();
+    }
+
+    @Test
+    public void testDoFilter_redirectsToLoginForBrowserWhenNotAuthenticated() 
throws Exception {
+        SecurityContextHolder.clearContext();
+
+        Configuration configuration = mock(Configuration.class);
+        
when(configuration.getString(AtlasKnoxSSOAuthenticationFilter.DEFAULT_BROWSER_USERAGENT)).thenReturn("Mozilla,Opera,Chrome");
+        
when(configuration.getString(AtlasKnoxSSOAuthenticationFilter.BROWSER_USERAGENT)).thenReturn(null);
+
+        AtlasJwtAuthWrapper wrapper = Mockito.spy(new 
AtlasJwtAuthWrapper(configuration));
+        wrapper.initialize();
+
+        AtlasJwtAuthFilter jwtFilter = mock(AtlasJwtAuthFilter.class);
+        wrapper.atlasJwtAuthFilter = jwtFilter;
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        HttpServletResponse res = mock(HttpServletResponse.class);
+        FilterChain chain = mock(FilterChain.class);
+
+        when(req.getHeader("User-Agent")).thenReturn("Mozilla/5.0");
+        when(req.getHeader("Authorization")).thenReturn("Bearer sometoken");
+        doNothing().when(res).sendRedirect(anyString());
+
+        wrapper.doFilter(req, res, chain);
+
+        verify(jwtFilter, times(1)).doFilter(any(ServletRequest.class), 
any(ServletResponse.class), any(FilterChain.class));
+        verify(res, atLeastOnce()).sendRedirect(anyString());
+        verify(chain, times(1)).doFilter(req, res);
+    }
+
+    @Test
+    public void testDoFilter_skipsJwtWhenAlreadyAuthenticated() throws 
Exception {
+        User principal = new User("user", "", Collections.emptyList());
+        UsernamePasswordAuthenticationToken authentication =
+                new UsernamePasswordAuthenticationToken(principal, "", 
principal.getAuthorities());
+        SecurityContextHolder.getContext().setAuthentication(authentication);
+
+        Configuration configuration = mock(Configuration.class);
+        
when(configuration.getString(AtlasKnoxSSOAuthenticationFilter.DEFAULT_BROWSER_USERAGENT)).thenReturn("Mozilla,Opera,Chrome");
+        
when(configuration.getString(AtlasKnoxSSOAuthenticationFilter.BROWSER_USERAGENT)).thenReturn(null);
+
+        AtlasJwtAuthWrapper wrapper = Mockito.spy(new 
AtlasJwtAuthWrapper(configuration));
+        wrapper.initialize();
+
+        AtlasJwtAuthFilter jwtFilter = mock(AtlasJwtAuthFilter.class);
+        wrapper.atlasJwtAuthFilter = jwtFilter;
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        HttpServletResponse res = mock(HttpServletResponse.class);
+        FilterChain chain = mock(FilterChain.class);
+
+        wrapper.doFilter(req, res, chain);
+
+        verify(jwtFilter, never()).doFilter(any(ServletRequest.class), 
any(ServletResponse.class), any(FilterChain.class));
+        verify(chain, times(1)).doFilter(req, res);
+    }
+}
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 4828b4b92..cbf47cbf9 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
@@ -25,6 +25,7 @@ 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.AtlasJwtAuthWrapper;
 import org.apache.atlas.web.filters.AtlasKnoxSSOAuthenticationFilter;
 import org.apache.atlas.web.filters.StaleTransactionCleanupFilter;
 import org.apache.commons.configuration2.Configuration;
@@ -132,6 +133,9 @@ public class AtlasSecurityConfigTest {
     @Mock
     private ActiveServerFilter mockActiveServerFilter;
 
+    @Mock
+    private AtlasJwtAuthWrapper mockAtlasJwtAuthWrapper;
+
     @Mock
     private KeycloakConfigResolver mockKeycloakConfigResolver;
 
@@ -174,7 +178,8 @@ public class AtlasSecurityConfigTest {
                 mockAtlasAuthenticationEntryPoint,
                 mockConfiguration,
                 mockStaleTransactionCleanupFilter,
-                mockActiveServerFilter);
+                mockActiveServerFilter,
+                mockAtlasJwtAuthWrapper);
 
         // Verify using reflection
         assertFalse((Boolean) getPrivateField(atlasSecurityConfig, 
"keycloakEnabled"));
@@ -201,7 +206,8 @@ public class AtlasSecurityConfigTest {
                 mockAtlasAuthenticationEntryPoint,
                 mockConfiguration,
                 mockStaleTransactionCleanupFilter,
-                mockActiveServerFilter);
+                mockActiveServerFilter,
+                mockAtlasJwtAuthWrapper);
 
         // Verify using reflection
         assertTrue((Boolean) getPrivateField(atlasSecurityConfig, 
"keycloakEnabled"));
@@ -362,7 +368,8 @@ public class AtlasSecurityConfigTest {
                 mockAtlasAuthenticationEntryPoint,
                 mockConfiguration,
                 mockStaleTransactionCleanupFilter,
-                mockActiveServerFilter);
+                mockActiveServerFilter,
+                mockAtlasJwtAuthWrapper);
 
         // Set up comprehensive HttpSecurity mocking first
         setupHttpSecurityMocks();
@@ -447,7 +454,8 @@ public class AtlasSecurityConfigTest {
                 mockAtlasAuthenticationEntryPoint,
                 mockConfiguration,
                 mockStaleTransactionCleanupFilter,
-                mockActiveServerFilter);
+                mockActiveServerFilter,
+                mockAtlasJwtAuthWrapper);
 
         // Create fresh HttpSecurity mock for each test to avoid state 
pollution
         HttpSecurity freshHttpSecurity = mock(HttpSecurity.class);
@@ -490,6 +498,7 @@ 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(mockAtlasJwtAuthWrapper), 
eq(AtlasKnoxSSOAuthenticationFilter.class));
         verify(freshHttpSecurity, 
atLeastOnce()).addFilterAfter(eq(mockStaleTransactionCleanupFilter), any());
         verify(freshHttpSecurity, 
atLeastOnce()).addFilterAfter(eq(mockAtlasAuthenticationFilter), any());
         verify(freshHttpSecurity, 
atLeastOnce()).addFilterAfter(eq(mockCsrfPreventionFilter), any());
@@ -600,7 +609,8 @@ public class AtlasSecurityConfigTest {
                 mockAtlasAuthenticationEntryPoint,
                 mockConfiguration,
                 mockStaleTransactionCleanupFilter,
-                mockActiveServerFilter);
+                mockActiveServerFilter,
+                mockAtlasJwtAuthWrapper);
 
         setPrivateField(atlasSecurityConfig, "keycloakConfigFileResource", 
mockKeycloakConfigFileResource);
 
@@ -831,7 +841,8 @@ public class AtlasSecurityConfigTest {
                 AtlasAuthenticationEntryPoint.class,
                 Configuration.class,
                 StaleTransactionCleanupFilter.class,
-                ActiveServerFilter.class
+                ActiveServerFilter.class,
+                AtlasJwtAuthWrapper.class
         ).getAnnotation(Inject.class);
         assertNotNull(injectAnnotation);
     }
@@ -857,7 +868,8 @@ public class AtlasSecurityConfigTest {
                 mockAtlasAuthenticationEntryPoint,
                 mockConfiguration,
                 mockStaleTransactionCleanupFilter,
-                mockActiveServerFilter);
+                mockActiveServerFilter,
+                mockAtlasJwtAuthWrapper);
 
         // Set the keycloakConfigFileResource using reflection
         setPrivateField(atlasSecurityConfig, "keycloakConfigFileResource", 
mockKeycloakConfigFileResource);

Reply via email to