You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by me...@apache.org on 2022/05/06 06:29:41 UTC

[ranger] branch master updated (e5efe40df -> 59a5665e7)

This is an automated email from the ASF dual-hosted git repository.

mehul pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


    from e5efe40df RANGER-3736: updated RangerChainedPlugin to support masking and row-filtering
     new 9fb86ce16 RANGER-3739: Add JWT filter in Ranger Admin
     new 59a5665e7 RANGER-3740: Ranger- Add an API to refresh tag cache

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 security-admin/pom.xml                             |   5 +
 .../java/org/apache/ranger/biz/TagDBStore.java     |  13 +++
 .../ranger/common/RangerServiceTagsCache.java      |  44 +++++++
 .../main/java/org/apache/ranger/rest/TagREST.java  |  37 ++++++
 .../security/web/filter/RangerJwtAuthFilter.java   | 127 +++++++++++++++++++++
 .../security/web/filter/RangerJwtAuthWrapper.java  | 125 ++++++++++++++++++++
 6 files changed, 351 insertions(+)
 create mode 100644 security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerJwtAuthFilter.java
 create mode 100644 security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerJwtAuthWrapper.java


[ranger] 01/02: RANGER-3739: Add JWT filter in Ranger Admin

Posted by me...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mehul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit 9fb86ce1689161ff142bfa051e7cbc1ffa18fadb
Author: Kishor Gollapalliwar <ki...@gmail.com>
AuthorDate: Mon May 2 16:37:01 2022 +0530

    RANGER-3739: Add JWT filter in Ranger Admin
    
    Signed-off-by: Mehul Parikh <me...@apache.org>
---
 security-admin/pom.xml                             |   5 +
 .../security/web/filter/RangerJwtAuthFilter.java   | 127 +++++++++++++++++++++
 .../security/web/filter/RangerJwtAuthWrapper.java  | 125 ++++++++++++++++++++
 3 files changed, 257 insertions(+)

diff --git a/security-admin/pom.xml b/security-admin/pom.xml
index eaa8db1c1..33ffc95e2 100644
--- a/security-admin/pom.xml
+++ b/security-admin/pom.xml
@@ -754,6 +754,11 @@
             <artifactId>log4j-to-slf4j</artifactId>
             <version>${log4j2.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.ranger</groupId>
+            <artifactId>ranger-authn</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
     <build>
         <pluginManagement>
diff --git a/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerJwtAuthFilter.java b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerJwtAuthFilter.java
new file mode 100644
index 000000000..f14adaaa8
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerJwtAuthFilter.java
@@ -0,0 +1,127 @@
+/*
+ * 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.ranger.security.web.filter;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+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 org.apache.log4j.Logger;
+import org.apache.ranger.authz.handler.RangerAuth;
+import org.apache.ranger.authz.handler.jwt.RangerDefaultJwtAuthHandler;
+import org.apache.ranger.authz.handler.jwt.RangerJwtAuthHandler;
+import org.apache.ranger.common.PropertiesUtil;
+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;
+
+@Lazy(true)
+@Component
+public class RangerJwtAuthFilter extends RangerDefaultJwtAuthHandler implements Filter {
+    private static final Logger LOG                 = Logger.getLogger(RangerJwtAuthFilter.class);
+    private static final String DEFAULT_RANGER_ROLE = "ROLE_USER";
+
+    @PostConstruct
+    public void initialize() {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("===>>> RangerJwtAuthFilter.initialize()");
+        }
+
+        /**
+         * If this filter is configured in spring security. The
+         * {@link org.springframework.web.filter.DelegatingFilterProxy
+         * DelegatingFilterProxy} does not invoke init method (like Servlet container).
+         */
+        try {
+            Properties config       = new Properties();
+
+            config.setProperty(RangerJwtAuthHandler.KEY_PROVIDER_URL, PropertiesUtil.getProperty(RangerSSOAuthenticationFilter.JWT_AUTH_PROVIDER_URL));
+            config.setProperty(RangerJwtAuthHandler.KEY_JWT_PUBLIC_KEY, PropertiesUtil.getProperty(RangerSSOAuthenticationFilter.JWT_PUBLIC_KEY, ""));
+            config.setProperty(RangerJwtAuthHandler.KEY_JWT_COOKIE_NAME,
+                               PropertiesUtil.getProperty(RangerSSOAuthenticationFilter.JWT_COOKIE_NAME, RangerSSOAuthenticationFilter.JWT_COOKIE_NAME_DEFAULT));
+            config.setProperty(RangerJwtAuthHandler.KEY_JWT_AUDIENCES, PropertiesUtil.getProperty(RangerSSOAuthenticationFilter.JWT_AUDIENCES, ""));
+
+            super.initialize(config);
+        } catch (Exception e) {
+            LOG.error("Failed to initialize Ranger Admin JWT Auth Filter.", e);
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<<<=== RangerJwtAuthFilter.initialize()");
+        }
+    }
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        // Empty method
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("===>>> RangerJwtAuthFilter.doFilter()");
+        }
+
+        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+
+        RangerAuth rangerAuth = authenticate(httpServletRequest);
+
+        if (rangerAuth != null) {
+            final List<GrantedAuthority>   grantedAuths        = Arrays.asList(new SimpleGrantedAuthority(DEFAULT_RANGER_ROLE));
+            final UserDetails              principal           = new User(rangerAuth.getUserName(), "", grantedAuths);
+            final Authentication           finalAuthentication = new UsernamePasswordAuthenticationToken(principal, "", grantedAuths);
+            final WebAuthenticationDetails webDetails          = new WebAuthenticationDetails(httpServletRequest);
+            ((AbstractAuthenticationToken) finalAuthentication).setDetails(webDetails);
+            SecurityContextHolder.getContext().setAuthentication(finalAuthentication);
+        }
+
+        // Log final status of request.
+        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+        if (auth != null) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("<<<=== RangerJwtAuthFilter.doFilter() - user=[" + auth.getPrincipal() + "], isUserAuthenticated? [" + auth.isAuthenticated() + "]");
+            }
+        } else {
+            LOG.warn("<<<=== RangerJwtAuthFilter.doFilter() - Failed to authenticate request using Ranger JWT authentication framework.");
+        }
+    }
+
+    @Override
+    public void destroy() {
+        // Empty method
+    }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerJwtAuthWrapper.java b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerJwtAuthWrapper.java
new file mode 100644
index 000000000..ac69bde26
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerJwtAuthWrapper.java
@@ -0,0 +1,125 @@
+/*
+ * 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.ranger.security.web.filter;
+
+import java.io.IOException;
+
+import javax.annotation.PostConstruct;
+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 org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.ranger.common.PropertiesUtil;
+import org.apache.ranger.common.UserSessionBase;
+import org.apache.ranger.security.context.RangerContextHolder;
+import org.apache.ranger.security.context.RangerSecurityContext;
+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;
+
+@Lazy(true)
+@Component
+public class RangerJwtAuthWrapper extends GenericFilterBean {
+    private static final Logger LOG = Logger.getLogger(RangerJwtAuthWrapper.class);
+
+    private String[] browserUserAgents = new String[] {""}; //Initialize with empty
+
+    @Lazy(true)
+    @Autowired
+    RangerJwtAuthFilter rangerJwtAuthFilter;
+
+    @PostConstruct
+    public void initialize() {
+        //FIXME: Browser agents should be common across ALL filters.
+        String defaultUserAgent = PropertiesUtil.getProperty(RangerSSOAuthenticationFilter.DEFAULT_BROWSER_USERAGENT);
+        String userAgent        = PropertiesUtil.getProperty(RangerSSOAuthenticationFilter.BROWSER_USERAGENT);
+
+        if (StringUtils.isBlank(userAgent) && StringUtils.isNotBlank(defaultUserAgent)) {
+            userAgent = defaultUserAgent;
+        }
+
+        if (StringUtils.isNotBlank(userAgent)) {
+            browserUserAgents = userAgent.split(",");
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("===>>> RangerJwtAuthWrapper.doFilter(" + request + ", " + response + ", " + filterChain + ")");
+        }
+
+        RangerSecurityContext context             = RangerContextHolder.getSecurityContext();
+        UserSessionBase       session             = context != null ? context.getUserSession() : null;
+        boolean               ssoEnabled          = session != null ? session.isSSOEnabled() : PropertiesUtil.getBooleanProperty("ranger.sso.enabled", false);
+        boolean               useJwtAuthMechanism = request != null && !isRequestAuthenticated() && RangerJwtAuthFilter.canAuthenticateRequest(request);
+
+        if (!ssoEnabled && useJwtAuthMechanism) {
+            rangerJwtAuthFilter.doFilter(request, response, filterChain);
+
+            if (!isRequestAuthenticated()) {
+                String userAgent = ((HttpServletRequest) request).getHeader("User-Agent");
+                if (isBrowserAgent(userAgent)) {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Redirecting to login page as request does not have valid JWT auth details.");
+                    }
+                    ((HttpServletResponse) response).sendRedirect("/login.jsp");
+                }
+            }
+        } else {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("===>> RangerJwtAuthWrapper.doFilter() - Skipping JWT auth.");
+            }
+        }
+
+        filterChain.doFilter(request, response); // proceed with filter chain
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<<<=== RangerJwtAuthWrapper.doFilter()");
+        }
+    }
+
+    private boolean isRequestAuthenticated() {
+        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+        return auth != null && auth.isAuthenticated();
+    }
+
+    protected boolean isBrowserAgent(String userAgent) {
+        boolean isBrowserAgent = false;
+
+        if (browserUserAgents.length > 0 && StringUtils.isNotBlank(userAgent)) {
+            for (String ua : browserUserAgents) {
+                if (userAgent.toLowerCase().startsWith(ua.toLowerCase())) {
+                    isBrowserAgent = true;
+                    break;
+                }
+            }
+        }
+
+        return isBrowserAgent;
+    }
+}


[ranger] 02/02: RANGER-3740: Ranger- Add an API to refresh tag cache

Posted by me...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mehul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit 59a5665e7b744606abb626e1dc8f5676a5f9713f
Author: Kishor Gollapalliwar <ki...@gmail.com>
AuthorDate: Thu May 5 14:07:23 2022 +0530

    RANGER-3740: Ranger- Add an API to refresh tag cache
    
    Signed-off-by: Mehul Parikh <me...@apache.org>
---
 .../java/org/apache/ranger/biz/TagDBStore.java     | 13 +++++++
 .../ranger/common/RangerServiceTagsCache.java      | 44 ++++++++++++++++++++++
 .../main/java/org/apache/ranger/rest/TagREST.java  | 37 ++++++++++++++++++
 3 files changed, 94 insertions(+)

diff --git a/security-admin/src/main/java/org/apache/ranger/biz/TagDBStore.java b/security-admin/src/main/java/org/apache/ranger/biz/TagDBStore.java
index e99b38b4a..d8154b7de 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/TagDBStore.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/TagDBStore.java
@@ -477,6 +477,19 @@ public class TagDBStore extends AbstractTagStore {
 		return ret;
 	}
 
+    public boolean resetTagCache(final String serviceName) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> TagDBStore.resetTagCache({})", serviceName);
+        }
+
+        boolean ret = RangerServiceTagsCache.getInstance().resetCache(serviceName);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== TagDBStore.resetTagCache(): ret={}", ret);
+        }
+
+        return ret;
+    }
 
 	@Override
 	public RangerServiceResource createServiceResource(RangerServiceResource resource) throws Exception {
diff --git a/security-admin/src/main/java/org/apache/ranger/common/RangerServiceTagsCache.java b/security-admin/src/main/java/org/apache/ranger/common/RangerServiceTagsCache.java
index 93c283fbc..576546f29 100644
--- a/security-admin/src/main/java/org/apache/ranger/common/RangerServiceTagsCache.java
+++ b/security-admin/src/main/java/org/apache/ranger/common/RangerServiceTagsCache.java
@@ -153,6 +153,50 @@ public class RangerServiceTagsCache {
 		return ret;
 	}
 
+    /**
+     * Reset service tag cache using serviceName if provided.
+     * If serviceName is empty, reset everything.
+     * @param serviceName
+     * @return true if was able to reset service tag cache, false otherwise
+     */
+    public boolean resetCache(final String serviceName) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RangerServiceTagsCache.resetCache({})", serviceName);
+        }
+
+        boolean ret = false;
+        synchronized (this) {
+            if (!serviceTagsMap.isEmpty()) {
+                if (StringUtils.isBlank(serviceName)) {
+                    serviceTagsMap.clear();
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("RangerServiceTagsCache.resetCache(): Removed policy caching for all services.");
+                    }
+                    ret = true;
+                } else {
+                    ServiceTagsWrapper removedServicePoliciesWrapper = serviceTagsMap.remove(serviceName.trim()); // returns null if key not found
+                    ret = removedServicePoliciesWrapper != null;
+
+                    if (ret) {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("RangerServiceTagsCache.resetCache(): Removed policy caching for [{}] service.", serviceName);
+                        }
+                    } else {
+                        LOG.warn("RangerServiceTagsCache.resetCache(): Caching for [{}] service not found, hence reset is skipped.", serviceName);
+                    }
+                }
+            } else {
+                LOG.warn("RangerServiceTagsCache.resetCache(): Policy cache is already empty.");
+            }
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== RangerServiceTagsCache.resetCache(): ret={}", ret);
+        }
+
+        return ret;
+    }
+
 	private class ServiceTagsWrapper {
 		final Long serviceId;
 		ServiceTags serviceTags;
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java b/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
index 8b0baf904..79dbdc76d 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
@@ -25,6 +25,7 @@ import org.apache.ranger.biz.AssetMgr;
 import org.apache.ranger.biz.RangerBizUtil;
 import org.apache.ranger.biz.ServiceDBStore;
 import org.apache.ranger.biz.TagDBStore;
+import org.apache.ranger.common.MessageEnums;
 import org.apache.ranger.common.RESTErrorUtil;
 import org.apache.ranger.db.RangerDaoManager;
 import org.apache.ranger.entity.XXService;
@@ -601,6 +602,42 @@ public class TagREST {
         return ret;
     }
 
+    @GET
+    @Path(TagRESTConstants.TAGS_RESOURCE + "cache/reset")
+    @Produces({ "application/json", "application/xml" })
+    public boolean resetTagCache(@QueryParam("serviceName") String serviceName) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> TagREST.resetTagCache({})", serviceName);
+        }
+
+        // check for ADMIN access
+        if (!bizUtil.isAdmin()) {
+            boolean isServiceAdmin = false;
+            String  loggedInUser   = bizUtil.getCurrentUserLoginId();
+
+            if (StringUtils.isNotEmpty(serviceName)) {
+                try {
+                    RangerService rangerService = svcStore.getServiceByName(serviceName);
+                    isServiceAdmin = bizUtil.isUserServiceAdmin(rangerService, loggedInUser);
+                } catch (Exception e) {
+                    LOG.warn("Failed to find if user [" + loggedInUser + "] has service admin privileges on service [" + serviceName + "]", e);
+                }
+            }
+
+            if (!isServiceAdmin) {
+                throw restErrorUtil.createRESTException("User cannot reset tag cache", MessageEnums.OPER_NO_PERMISSION);
+            }
+        }
+
+        boolean ret = tagStore.resetTagCache(serviceName);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== TagREST.resetTagCache(): ret={}", ret);
+        }
+
+        return ret;
+    }
+
     @POST
     @Path(TagRESTConstants.RESOURCES_RESOURCE)
     @Produces({ "application/json", "application/xml" })