You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2016/11/16 01:47:12 UTC

incubator-atlas git commit: ATLAS-1244: added support for KnoxSSO Authentication

Repository: incubator-atlas
Updated Branches:
  refs/heads/master ae92406d9 -> 854b79280


ATLAS-1244: added support for KnoxSSO Authentication

Signed-off-by: Madhan Neethiraj <ma...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/854b7928
Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/854b7928
Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/854b7928

Branch: refs/heads/master
Commit: 854b792802f9a56a47bb7bb461077921867bd967
Parents: ae92406
Author: nixonrodrigues <ni...@freestoneinfotech.com>
Authored: Wed Nov 2 16:47:59 2016 +0530
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Tue Nov 15 17:46:47 2016 -0800

----------------------------------------------------------------------
 distro/src/conf/atlas-application.properties    |   9 +
 release-log.txt                                 |   1 +
 webapp/pom.xml                                  |  12 +
 .../web/filters/AtlasAuthenticationFilter.java  |   2 +-
 .../AtlasKnoxSSOAuthenticationFilter.java       | 428 +++++++++++++++++++
 .../atlas/web/filters/SSOAuthentication.java    |  74 ++++
 .../filters/SSOAuthenticationProperties.java    |  78 ++++
 .../AtlasAbstractAuthenticationProvider.java    |  17 +-
 .../security/AtlasAuthenticationProvider.java   |  45 +-
 .../AtlasAuthenticationSuccessHandler.java      |   5 +
 webapp/src/main/resources/spring-security.xml   |   8 +-
 webapp/src/main/webapp/WEB-INF/web.xml          |   9 +
 webapp/src/test/webapp/WEB-INF/web.xml          |   9 +
 13 files changed, 680 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/distro/src/conf/atlas-application.properties
----------------------------------------------------------------------
diff --git a/distro/src/conf/atlas-application.properties b/distro/src/conf/atlas-application.properties
index 0349ccc..eea46a6 100755
--- a/distro/src/conf/atlas-application.properties
+++ b/distro/src/conf/atlas-application.properties
@@ -198,3 +198,12 @@ atlas.rest-csrf.custom-header=X-XSRF-HEADER
 
 #########  Enable Taxonomy  #########
 atlas.feature.taxonomy.enable=true
+
+############ KNOX Configs ################
+#atlas.sso.knox.browser.useragent=Mozilla,Chrome,Opera
+#atlas.sso.knox.enabled=true
+#atlas.sso.knox.providerurl=https://<knox gateway ip>:8443/gateway/knoxsso/api/v1/websso
+#atlas.sso.knox.publicKey=
+
+
+

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/release-log.txt
----------------------------------------------------------------------
diff --git a/release-log.txt b/release-log.txt
index 80391f4..0649f09 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -9,6 +9,7 @@ ATLAS-1060 Add composite indexes for exact match performance improvements for al
 ATLAS-1127 Modify creation and modification timestamps to Date instead of Long(sumasai)
 
 ALL CHANGES:
+ATLAS-1244 added support for KnoxSSO Authentication
 ATLAS-1295 Build failure due to patch for ATLAS-1081 (apoorvnaik via sumasai)
 ATLAS-1081 Atlas jetty server configuration (shwethags)
 ATLAS-1257 Map Entity REST APIs to ATLAS v1 backend (sumasai)

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/pom.xml
----------------------------------------------------------------------
diff --git a/webapp/pom.xml b/webapp/pom.xml
index b9e1111..594b602 100755
--- a/webapp/pom.xml
+++ b/webapp/pom.xml
@@ -355,6 +355,18 @@
             <scope>test</scope>
         </dependency>
 
+	 <dependency>
+            <groupId>com.nimbusds</groupId>
+            <artifactId>nimbus-jose-jwt</artifactId>
+            <version>3.9</version>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.bouncycastle</groupId>
+                    <artifactId>bcprov-jdk15on</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
----------------------------------------------------------------------
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 30200b5..3307015 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
@@ -435,7 +435,7 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
                         Collection<String> headerNames = httpResponse.getHeaderNames();
                         for (String headerName : headerNames) {
                             String value = httpResponse.getHeader(headerName);
-                            if (headerName.equalsIgnoreCase("Set-Cookie") && value.startsWith("JSESSIONID")) {
+                            if (headerName.equalsIgnoreCase("Set-Cookie") && value.startsWith("ATLASSESSIONID")) {
                                 chk = false;
                                 break;
                             }

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/java/org/apache/atlas/web/filters/AtlasKnoxSSOAuthenticationFilter.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..75a884d
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasKnoxSSOAuthenticationFilter.java
@@ -0,0 +1,428 @@
+
+/*
+ * 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 com.google.inject.Inject;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSObject;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.crypto.RSASSAVerifier;
+import com.nimbusds.jwt.SignedJWT;
+import org.apache.atlas.ApplicationProperties;
+import org.apache.atlas.web.security.AtlasAuthenticationProvider;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+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.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.web.authentication.WebAuthenticationDetails;
+import javax.servlet.*;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.List;
+
+
+public class AtlasKnoxSSOAuthenticationFilter implements Filter {
+    private static final Logger LOG = LoggerFactory.getLogger(AtlasKnoxSSOAuthenticationFilter.class);
+
+    public static final String BROWSER_USERAGENT = "atlas.sso.knox.browser.useragent";
+    public static final String JWT_AUTH_PROVIDER_URL = "atlas.sso.knox.providerurl";
+    public static final String JWT_PUBLIC_KEY = "atlas.sso.knox.publicKey";
+    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_ORIGINAL_URL_QUERY_PARAM_DEFAULT = "originalUrl";
+
+    private SSOAuthenticationProperties jwtProperties;
+
+    private String originalUrlQueryParam = "originalUrl";
+    private String authenticationProviderUrl = null;
+    private RSAPublicKey publicKey = null;
+    private String cookieName = "hadoop-jwt";
+    private Configuration configuration = null;
+    private boolean ssoEnabled = false;
+    private JWSVerifier verifier = null;
+
+    @Inject
+    public AtlasKnoxSSOAuthenticationFilter() {
+        try {
+            configuration = ApplicationProperties.get();
+        } catch (Exception e) {
+            LOG.error("Error while getting application properties", e);
+        }
+        ssoEnabled = configuration.getBoolean("atlas.sso.knox.enabled", false);
+        jwtProperties = loadJwtProperties();
+        setJwtProperties();
+    }
+
+    public AtlasKnoxSSOAuthenticationFilter(
+            SSOAuthenticationProperties jwtProperties) {
+        this.jwtProperties = jwtProperties;
+        setJwtProperties();
+    }
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    /*
+     * doFilter of AtlasKnoxSSOAuthenticationFilter is the first in the filter list so in this it check for the request
+     * if the request is from browser and sso is enabled then it process the request against knox sso
+     * else if it's ssoenable and the request is with local login string then it show's the appropriate msg
+     * else if ssoenable is false then it contiunes with further filters as it was before sso
+     */
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+
+        if (!ssoEnabled) {
+            filterChain.doFilter(servletRequest, servletResponse);
+            return;
+        }
+
+        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Knox doFilter {}", httpRequest.getRequestURI());
+        }
+
+        if (httpRequest.getSession() != null && httpRequest.getSession().getAttribute("locallogin") != null) {
+            servletRequest.setAttribute("ssoEnabled", false);
+            filterChain.doFilter(servletRequest, servletResponse);
+            return;
+        }
+
+        if (!isWebUserAgent(httpRequest.getHeader("User-Agent")) || jwtProperties == null || isAuthenticated()) {
+            filterChain.doFilter(servletRequest, servletResponse);
+            return;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Knox ssoEnabled  {} {}", ssoEnabled, httpRequest.getRequestURI());
+        }
+        //if jwt properties are loaded and is current not authenticated then it will go for sso authentication
+        //Note : Need to remove !isAuthenticated() after knoxsso solve the bug from cross-origin script
+        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
+        String serializedJWT = getJWTFromCookie(httpRequest);
+        // if we get the hadoop-jwt token from the cookies then will process it further
+        if (serializedJWT != null) {
+            SignedJWT jwtToken = null;
+            try {
+                jwtToken = SignedJWT.parse(serializedJWT);
+                boolean valid = validateToken(jwtToken);
+                //if the public key provide is correct and also token is not expired the process token
+                if (valid) {
+                    String userName = jwtToken.getJWTClaimsSet().getSubject();
+                    LOG.info("SSO login user : {} ", userName);
+                    //if we get the userName from the token then log into atlas using the same user
+                    if (userName != null && !userName.trim().isEmpty()) {
+                        List<GrantedAuthority> grantedAuths = AtlasAuthenticationProvider.getAuthoritiesFromUGI(userName);
+                        final UserDetails principal = new User(userName, "", grantedAuths);
+                        final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(principal, "", grantedAuths);
+                        WebAuthenticationDetails webDetails = new WebAuthenticationDetails(httpRequest);
+                        ((AbstractAuthenticationToken) finalAuthentication).setDetails(webDetails);
+                        AtlasAuthenticationProvider authenticationProvider = new AtlasAuthenticationProvider();
+                        authenticationProvider.setSsoEnabled(ssoEnabled);
+                        Authentication authentication = authenticationProvider.authenticate(finalAuthentication);
+                        SecurityContextHolder.getContext().setAuthentication(authentication);
+                    }
+
+                    filterChain.doFilter(servletRequest, httpServletResponse);
+                } else {  // if the token is not valid then redirect to knox sso
+                    String ssourl = constructLoginURL(httpRequest);
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("SSO URL ={} invalid", ssourl);
+                    }
+                    httpServletResponse.sendRedirect(ssourl);
+                }
+            } catch (ParseException e) {
+                LOG.warn("Unable to parse the JWT token", e);
+            }
+        } else {
+            String ssourl = constructLoginURL(httpRequest);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("SSO URL = {}  serializedJWT null", ssourl);
+            }
+            httpServletResponse.sendRedirect(ssourl);
+        }
+
+    }
+
+
+    private boolean isWebUserAgent(String userAgent) {
+        boolean isWeb = false;
+        if (jwtProperties != null) {
+            String userAgentList[] = jwtProperties.getUserAgentList();
+            if (userAgentList != null && userAgentList.length > 0) {
+                for (String ua : userAgentList) {
+                    if (StringUtils.startsWithIgnoreCase(userAgent, ua)) {
+                        isWeb = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return isWeb;
+    }
+
+
+    private void setJwtProperties() {
+        if (jwtProperties != null) {
+            authenticationProviderUrl = jwtProperties.getAuthenticationProviderUrl();
+            publicKey = jwtProperties.getPublicKey();
+            cookieName = jwtProperties.getCookieName();
+            originalUrlQueryParam = jwtProperties.getOriginalUrlQueryParam();
+            if (publicKey != null) {
+                verifier = new RSASSAVerifier(publicKey);
+            }
+        }
+    }
+
+    /**
+     * Do not try to validate JWT if user already authenticated via other
+     * provider
+     *
+     * @return true, if JWT validation required
+     */
+    private boolean isAuthenticated() {
+        Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
+        return !(!(existingAuth != null && existingAuth.isAuthenticated()) || existingAuth instanceof SSOAuthentication);
+    }
+
+    /**
+     * Encapsulate the acquisition of the JWT token from HTTP cookies within the
+     * request.
+     *
+     * @param req servlet request to get the JWT token from
+     * @return serialized JWT token
+     */
+    protected String getJWTFromCookie(HttpServletRequest req) {
+        String serializedJWT = null;
+        Cookie[] cookies = req.getCookies();
+        if (cookieName != null && cookies != null) {
+            for (Cookie cookie : cookies) {
+                if (cookieName.equals(cookie.getName())) {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug(cookieName + " cookie has been found and is being processed");
+                    }
+                    serializedJWT = cookie.getValue();
+                    break;
+                }
+            }
+        }
+        return serializedJWT;
+    }
+
+    /**
+     * Create the URL to be used for authentication of the user in the absence
+     * of a JWT token within the incoming request.
+     *
+     * @param request for getting the original request URL
+     * @return url to use as login url for redirect
+     */
+    protected String constructLoginURL(HttpServletRequest request) {
+        String delimiter = "?";
+        if (authenticationProviderUrl.contains("?")) {
+            delimiter = "&";
+        }
+        StringBuilder loginURL = new StringBuilder();
+        loginURL.append(authenticationProviderUrl).append(delimiter).append(originalUrlQueryParam).append("=").append(request.getRequestURL().append(getOriginalQueryString(request)));
+        return loginURL.toString();
+    }
+
+    private String getOriginalQueryString(HttpServletRequest request) {
+        String originalQueryString = request.getQueryString();
+        return (originalQueryString == null) ? "" : "?" + originalQueryString;
+    }
+
+    /**
+     * This method provides a single method for validating the JWT for use in
+     * request processing. It provides for the override of specific aspects of
+     * this implementation through submethods used within but also allows for
+     * the override of the entire token validation algorithm.
+     *
+     * @param jwtToken the token to validate
+     * @return true if valid
+     */
+    protected boolean validateToken(SignedJWT jwtToken) {
+        boolean isValid = validateSignature(jwtToken);
+
+        if (isValid) {
+            isValid = validateExpiration(jwtToken);
+            if (!isValid) {
+                LOG.warn("Expiration time validation of JWT token failed.");
+            }
+        } else {
+            LOG.warn("Signature of JWT token could not be verified. Please check the public key");
+        }
+        return isValid;
+    }
+
+    /**
+     * Verify the signature of the JWT token in this method. This method depends
+     * on the public key that was established during init based upon the
+     * provisioned public key. Override this method in subclasses in order to
+     * customize the signature verification behavior.
+     *
+     * @param jwtToken the token that contains the signature to be validated
+     * @return valid true if signature verifies successfully; false otherwise
+     */
+    protected boolean validateSignature(SignedJWT jwtToken) {
+        boolean valid = false;
+        if (JWSObject.State.SIGNED == jwtToken.getState()) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("SSO token is in a SIGNED state");
+            }
+            if (jwtToken.getSignature() != null) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("SSO token signature is not null");
+                }
+                try {
+                    if (verifier != null && jwtToken.verify(verifier)) {
+                        valid = true;
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("SSO token has been successfully verified");
+                        }
+                    } else {
+                        LOG.warn("SSO signature verification failed.Please check the public key");
+                    }
+                } catch (JOSEException je) {
+                    LOG.warn("Error while validating signature", je);
+                } catch (Exception e) {
+                    LOG.warn("Error while validating signature", e);
+                }
+            }
+        }
+        return valid;
+    }
+
+    /**
+     * Validate that the expiration time of the JWT token has not been violated.
+     * If it has then throw an AuthenticationException. Override this method in
+     * subclasses in order to customize the expiration validation behavior.
+     *
+     * @param jwtToken the token that contains the expiration date to validate
+     * @return valid true if the token has not expired; false otherwise
+     */
+    protected boolean validateExpiration(SignedJWT jwtToken) {
+        boolean valid = false;
+        try {
+            Date expires = jwtToken.getJWTClaimsSet().getExpirationTime();
+            if (expires == null || new Date().before(expires)) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("SSO token expiration date has been successfully validated");
+                }
+                valid = true;
+            } else {
+                LOG.warn("SSO expiration date validation failed.");
+            }
+        } catch (ParseException pe) {
+            LOG.warn("SSO expiration date validation failed.", pe);
+        }
+        return valid;
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    public SSOAuthenticationProperties loadJwtProperties() {
+        String providerUrl = configuration.getString(JWT_AUTH_PROVIDER_URL);
+        if (providerUrl != null && configuration.getBoolean("atlas.sso.knox.enabled", false)) {
+            SSOAuthenticationProperties jwtProperties = new SSOAuthenticationProperties();
+            String publicKeyPathStr = configuration.getString(JWT_PUBLIC_KEY);
+            if (publicKeyPathStr == null) {
+                LOG.error("Public key pem not specified for SSO auth provider {}. SSO auth will be disabled");
+                return null;
+            }
+            jwtProperties.setAuthenticationProviderUrl(providerUrl);
+            jwtProperties.setCookieName(configuration.getString(JWT_COOKIE_NAME, JWT_COOKIE_NAME_DEFAULT));
+            jwtProperties.setOriginalUrlQueryParam(configuration.getString(JWT_ORIGINAL_URL_QUERY_PARAM, JWT_ORIGINAL_URL_QUERY_PARAM_DEFAULT));
+            String userAgent = configuration.getString(BROWSER_USERAGENT);
+            if (userAgent != null && !userAgent.isEmpty()) {
+                jwtProperties.setUserAgentList(userAgent.split(","));
+            }
+            try {
+                RSAPublicKey publicKey = parseRSAPublicKey(publicKeyPathStr);
+                jwtProperties.setPublicKey(publicKey);
+            } catch (IOException e) {
+                LOG.error("Unable to read public certificate file. JWT auth will be disabled.", e);
+            } catch (CertificateException e) {
+                LOG.error("Unable to parse public certificate file. JWT auth will be disabled.", e);
+            } catch (ServletException e) {
+                LOG.error("ServletException while processing the properties", e);
+            }
+            return jwtProperties;
+        } else {
+            return null;
+        }
+    }
+
+	/*
+     * public static RSAPublicKey getPublicKeyFromFile(String filePath) throws
+	 * IOException, CertificateException {
+	 * FileUtils.readFileToString(new File(filePath));
+	 * getPublicKeyFromString(pemString); }
+	 */
+
+    public static RSAPublicKey parseRSAPublicKey(String pem)
+            throws CertificateException, UnsupportedEncodingException,
+            ServletException {
+        String PEM_HEADER = "-----BEGIN CERTIFICATE-----\n";
+        String PEM_FOOTER = "\n-----END CERTIFICATE-----";
+        String fullPem = PEM_HEADER + pem + PEM_FOOTER;
+        PublicKey key = null;
+        try {
+            CertificateFactory fact = CertificateFactory.getInstance("X.509");
+            ByteArrayInputStream is = new ByteArrayInputStream(fullPem.getBytes("UTF8"));
+            X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
+            key = cer.getPublicKey();
+        } catch (CertificateException ce) {
+            String message = null;
+            if (pem.startsWith(PEM_HEADER)) {
+                message = "CertificateException - be sure not to include PEM header " + "and footer in the PEM configuration element.";
+            } else {
+                message = "CertificateException - PEM may be corrupt";
+            }
+            throw new ServletException(message, ce);
+        } catch (UnsupportedEncodingException uee) {
+            throw new ServletException(uee);
+        }
+        return (RSAPublicKey) key;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/java/org/apache/atlas/web/filters/SSOAuthentication.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/filters/SSOAuthentication.java b/webapp/src/main/java/org/apache/atlas/web/filters/SSOAuthentication.java
new file mode 100644
index 0000000..a96d29f
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/SSOAuthentication.java
@@ -0,0 +1,74 @@
+/*
+ * 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 com.nimbusds.jwt.SignedJWT;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.Collection;
+
+/**
+ * Internal token which describes JWT authentication
+ */
+public class SSOAuthentication implements Authentication {
+
+    private final SignedJWT token;
+    private boolean authenticated = false;
+
+    public SSOAuthentication(SignedJWT token) {
+        this.token = token;
+    }
+
+    @Override
+    public SignedJWT getCredentials() {
+        return token;
+    }
+
+    @Override
+    public Object getDetails() {
+        return null;
+    }
+
+    @Override
+    public boolean isAuthenticated() {
+        return authenticated;
+    }
+
+    @Override
+    public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
+        this.authenticated = authenticated;
+    }
+
+    @Override
+    public String getName() {
+        return null;
+    }
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return null;
+    }
+
+    @Override
+    public Object getPrincipal() {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/java/org/apache/atlas/web/filters/SSOAuthenticationProperties.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/filters/SSOAuthenticationProperties.java b/webapp/src/main/java/org/apache/atlas/web/filters/SSOAuthenticationProperties.java
new file mode 100644
index 0000000..5d5ed17
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/SSOAuthenticationProperties.java
@@ -0,0 +1,78 @@
+/*
+ * 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 java.security.interfaces.RSAPublicKey;
+
+public class SSOAuthenticationProperties {
+
+    private String authenticationProviderUrl = null;
+    private RSAPublicKey publicKey = null;
+    private String cookieName = "hadoop-jwt";
+    private String originalUrlQueryParam = null;
+    private String[] userAgentList = null;
+
+    public String getAuthenticationProviderUrl() {
+        return authenticationProviderUrl;
+    }
+
+    public void setAuthenticationProviderUrl(String authenticationProviderUrl) {
+        this.authenticationProviderUrl = authenticationProviderUrl;
+    }
+
+    public RSAPublicKey getPublicKey() {
+        return publicKey;
+    }
+
+    public void setPublicKey(RSAPublicKey publicKey) {
+        this.publicKey = publicKey;
+    }
+
+    public String getCookieName() {
+        return cookieName;
+    }
+
+    public void setCookieName(String cookieName) {
+        this.cookieName = cookieName;
+    }
+
+    public String getOriginalUrlQueryParam() {
+        return originalUrlQueryParam;
+    }
+
+    public void setOriginalUrlQueryParam(String originalUrlQueryParam) {
+        this.originalUrlQueryParam = originalUrlQueryParam;
+    }
+
+    /**
+     * @return the userAgentList
+     */
+    public String[] getUserAgentList() {
+        return userAgentList;
+    }
+
+    /**
+     * @param userAgentList the userAgentList to set
+     */
+    public void setUserAgentList(String[] userAgentList) {
+        this.userAgentList = userAgentList;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/java/org/apache/atlas/web/security/AtlasAbstractAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAbstractAuthenticationProvider.java b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAbstractAuthenticationProvider.java
index 595387a..b99a30a 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAbstractAuthenticationProvider.java
+++ b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAbstractAuthenticationProvider.java
@@ -22,7 +22,11 @@ package org.apache.atlas.web.security;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
@@ -33,6 +37,7 @@ import org.springframework.security.core.userdetails.UserDetails;
 
 public abstract class AtlasAbstractAuthenticationProvider implements
         AuthenticationProvider {
+    private static final Logger LOG = LoggerFactory.getLogger(AtlasAbstractAuthenticationProvider.class);
 
     @Override
     public boolean supports(Class<?> authentication) {
@@ -92,16 +97,20 @@ public abstract class AtlasAbstractAuthenticationProvider implements
         return authentication;
     }
 
-    public List<GrantedAuthority> getAuthoritiesFromUGI(String userName) {
+    public static List<GrantedAuthority> getAuthoritiesFromUGI(String userName) {
         List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
-        UserGroupInformation ugi = UserGroupInformation.createRemoteUser(userName);
-        if (ugi != null) {
-            String[] userGroups = ugi.getGroupNames();
+        Configuration config = new Configuration();
+
+        try {
+            Groups gp = new Groups(config);
+            List<String> userGroups = gp.getGroups(userName);
             if (userGroups != null) {
                 for (String group : userGroups) {
                     grantedAuths.add(new SimpleGrantedAuthority(group));
                 }
             }
+        } catch (java.io.IOException e) {
+            LOG.error("Exception while fetching groups ", e);
         }
         return grantedAuths;
     }

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationProvider.java b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationProvider.java
index 23d3d70..68553df 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationProvider.java
+++ b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationProvider.java
@@ -39,6 +39,10 @@ public class AtlasAuthenticationProvider extends
     public static final String FILE_AUTH_METHOD = "atlas.authentication.method.file";
     public static final String LDAP_TYPE = "atlas.authentication.method.ldap.type";
 
+
+
+    private boolean ssoEnabled = false;
+
     @Autowired
     AtlasLdapAuthenticationProvider ldapAuthenticationProvider;
 
@@ -67,17 +71,27 @@ public class AtlasAuthenticationProvider extends
     public Authentication authenticate(Authentication authentication)
             throws AuthenticationException {
 
-        if (ldapType.equalsIgnoreCase("LDAP")) {
-            try {
-                authentication = ldapAuthenticationProvider.authenticate(authentication);
-            } catch (Exception ex) {
-                LOG.error("Error while LDAP authentication", ex);
+        if(ssoEnabled){
+            if (authentication != null){
+                authentication = getSSOAuthentication(authentication);
+                if(authentication!=null && authentication.isAuthenticated()){
+                    return authentication;
+                }
             }
-        } else if (ldapType.equalsIgnoreCase("AD")) {
-            try {
-                authentication = adAuthenticationProvider.authenticate(authentication);
-            } catch (Exception ex) {
-                LOG.error("Error while AD authentication", ex);
+        } else {
+
+            if (ldapType.equalsIgnoreCase("LDAP")) {
+                try {
+                    authentication = ldapAuthenticationProvider.authenticate(authentication);
+                } catch (Exception ex) {
+                    LOG.error("Error while LDAP authentication", ex);
+                }
+            } else if (ldapType.equalsIgnoreCase("AD")) {
+                try {
+                    authentication = adAuthenticationProvider.authenticate(authentication);
+                } catch (Exception ex) {
+                    LOG.error("Error while AD authentication", ex);
+                }
             }
         }
 
@@ -97,4 +111,15 @@ public class AtlasAuthenticationProvider extends
         throw new AtlasAuthenticationException("Authentication failed.");
     }
 
+    public boolean isSsoEnabled() {
+        return ssoEnabled;
+    }
+
+    public void setSsoEnabled(boolean ssoEnabled) {
+        this.ssoEnabled = ssoEnabled;
+    }
+
+    private Authentication getSSOAuthentication(Authentication authentication) throws AuthenticationException{
+        return authentication;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
index 8654716..31a9ec0 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
+++ b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
@@ -43,6 +43,11 @@ public class AtlasAuthenticationSuccessHandler implements AuthenticationSuccessH
         ObjectMapper mapper = new ObjectMapper();
         json.put("msgDesc", "Success");
 
+        if (request.getSession() != null) { // incase of form based login mark it as local login in session
+            request.getSession().setAttribute("locallogin","true");
+            request.getServletContext().setAttribute(request.getSession().getId(), "locallogin");
+        }
+
         String jsonAsStr = mapper.writeValueAsString(json);
         response.setContentType("application/json");
         response.setStatus(HttpServletResponse.SC_OK);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/resources/spring-security.xml
----------------------------------------------------------------------
diff --git a/webapp/src/main/resources/spring-security.xml b/webapp/src/main/resources/spring-security.xml
index 5395d4e..4ba3025 100644
--- a/webapp/src/main/resources/spring-security.xml
+++ b/webapp/src/main/resources/spring-security.xml
@@ -42,6 +42,7 @@
         <security:session-management
                 session-fixation-protection="newSession" />
         <intercept-url pattern="/**" access="isAuthenticated()" />
+        <custom-filter ref="ssoAuthenticationFilter" after="BASIC_AUTH_FILTER" />
 
         <security:custom-filter ref="krbAuthenticationFilter" after="SERVLET_API_SUPPORT_FILTER" />
         <security:custom-filter ref="CSRFPreventionFilter" after="REMEMBER_ME_FILTER" />
@@ -53,7 +54,7 @@
                 username-parameter="j_username"
                 password-parameter="j_password" />
 
-        <security:logout logout-success-url="/login.jsp" delete-cookies="JSESSIONID"
+        <security:logout logout-success-url="/login.jsp" delete-cookies="ATLASSESSIONID"
                          logout-url="/logout.html" />
         <http-basic />
         <security:custom-filter position="LAST" ref="atlasAuthorizationFilter"/>
@@ -61,7 +62,10 @@
 
     <beans:bean id="krbAuthenticationFilter" class="org.apache.atlas.web.filters.AtlasAuthenticationFilter">
     </beans:bean>
-    
+
+    <beans:bean id="ssoAuthenticationFilter" class="org.apache.atlas.web.filters.AtlasKnoxSSOAuthenticationFilter">
+    </beans:bean>
+
     <beans:bean id="CSRFPreventionFilter" class="org.apache.atlas.web.filters.AtlasCSRFPreventionFilter">
     </beans:bean>
 

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/webapp/src/main/webapp/WEB-INF/web.xml b/webapp/src/main/webapp/WEB-INF/web.xml
index 7c6bc6d..f7e2028 100755
--- a/webapp/src/main/webapp/WEB-INF/web.xml
+++ b/webapp/src/main/webapp/WEB-INF/web.xml
@@ -79,5 +79,14 @@
     </listener>
 
 
+    <session-config>
+        <session-timeout>60</session-timeout>
+        <tracking-mode>COOKIE</tracking-mode>
+        <cookie-config>
+            <name>ATLASSESSIONID</name>
+            <http-only>true</http-only>
+        </cookie-config>
+    </session-config>
+
 	
 </web-app>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/854b7928/webapp/src/test/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/webapp/src/test/webapp/WEB-INF/web.xml b/webapp/src/test/webapp/WEB-INF/web.xml
index 1b152ee..6649043 100755
--- a/webapp/src/test/webapp/WEB-INF/web.xml
+++ b/webapp/src/test/webapp/WEB-INF/web.xml
@@ -73,4 +73,13 @@
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
     </listener>
 
+    <session-config>
+        <session-timeout>60</session-timeout>
+        <tracking-mode>COOKIE</tracking-mode>
+        <cookie-config>
+            <name>ATLASSESSIONID</name>
+            <http-only>true</http-only>
+        </cookie-config>
+    </session-config>
+
 </web-app>