/** * 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.authorize.simple; import javax.servlet.http.HttpServletRequest; import org.apache.atlas.AtlasClient; import org.apache.atlas.authorize.AtlasActionTypes; import org.apache.atlas.authorize.AtlasResourceTypes; import org.apache.atlas.authorize.AtlasAuthorizationException; import org.apache.atlas.authorize.AtlasAuthorizer; import org.apache.atlas.authorize.AtlasAccessRequest; import org.apache.atlas.authorize.AtlasAuthorizerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; public class AtlasAuthorizationUtils { private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthorizationUtils.class); private static boolean isDebugEnabled = LOG.isDebugEnabled(); private static final String BASE_URL = "/" + AtlasClient.BASE_URI; public static String getApi(String contextPath) { if (isDebugEnabled) { LOG.debug("==> getApi({})", contextPath); } if (contextPath.startsWith(BASE_URL)) { contextPath = contextPath.substring(BASE_URL.length()); } else { // strip of leading '/' if (contextPath.startsWith("/")) { contextPath = contextPath.substring(1); } } String[] split = contextPath.split("/", 3); String api = split[0]; if (Pattern.matches("v\\d", api)) { api = split[1]; } if (isDebugEnabled) { LOG.debug("<== getApi({}): {}", contextPath, api); } return api; } public static AtlasActionTypes getAtlasAction(String method) { AtlasActionTypes action = null; switch (method.toUpperCase()) { case "POST": action = AtlasActionTypes.CREATE; break; case "GET": action = AtlasActionTypes.READ; break; case "PUT": action = AtlasActionTypes.UPDATE; break; case "DELETE": action = AtlasActionTypes.DELETE; break; default: if (isDebugEnabled) { LOG.debug("getAtlasAction(): Invalid HTTP method '{}", method); } break; } if (isDebugEnabled) { LOG.debug("<== AtlasAuthorizationFilter getAtlasAction HTTP Method {} mapped to AtlasAction : {}", method, action); } return action; } /** * @param contextPath * @return set of AtlasResourceTypes types api mapped with AtlasResourceTypes.TYPE eg :- /api/atlas/types/* * * gremlin discovery,admin,graph apis are mapped with AtlasResourceTypes.OPERATION eg :-/api/atlas/admin/* * /api/atlas/discovery/search/gremlin /api/atlas/graph/* * * entities,lineage and discovery apis are mapped with AtlasResourceTypes.ENTITY eg :- /api/atlas/lineage/hive/table/* * /api/atlas/entities/{guid}* /api/atlas/discovery/* * * taxonomy API are also mapped to AtlasResourceTypes.TAXONOMY & AtlasResourceTypes.ENTITY and its terms APIs have * added AtlasResourceTypes.TERM associations. * * unprotected types are mapped with AtlasResourceTypes.UNKNOWN, access to these are allowed. */ public static Set<AtlasResourceTypes> getAtlasResourceType(String contextPath) { Set<AtlasResourceTypes> resourceTypes = new HashSet<>(); if (isDebugEnabled) { LOG.debug("==> getAtlasResourceType for {}", contextPath); } String api = getApi(contextPath); if (api.startsWith("types")) { resourceTypes.add(AtlasResourceTypes.TYPE); } else if (api.startsWith("admin") && (contextPath.contains("/session") || contextPath.contains("/version"))) { resourceTypes.add(AtlasResourceTypes.UNKNOWN); } else if ((api.startsWith("discovery") && contextPath.contains("/gremlin")) || api.startsWith("admin") || api.startsWith("graph")) { resourceTypes.add(AtlasResourceTypes.OPERATION); } else if (api.startsWith("entities") || api.startsWith("lineage") || api.startsWith("discovery") || api.startsWith("entity") || api.startsWith("search")) { resourceTypes.add(AtlasResourceTypes.ENTITY); } else if (api.startsWith("taxonomies")) { resourceTypes.add(AtlasResourceTypes.TAXONOMY); // taxonomies are modeled as entities resourceTypes.add(AtlasResourceTypes.ENTITY); if (contextPath.contains("/terms")) { resourceTypes.add(AtlasResourceTypes.TERM); } } else { LOG.error("Unable to find Atlas Resource corresponding to : {}\nSetting {}" , api, AtlasResourceTypes.UNKNOWN.name()); resourceTypes.add(AtlasResourceTypes.UNKNOWN); } if (isDebugEnabled) { LOG.debug("<== Returning AtlasResources {} for api {}", resourceTypes, api); } return resourceTypes; } public static boolean isAccessAllowed(AtlasResourceTypes resourcetype, AtlasActionTypes actionType, String userName, Set<String> groups, HttpServletRequest request) { AtlasAuthorizer authorizer = null; boolean isaccessAllowed = false; Set<AtlasResourceTypes> resourceTypes = new HashSet<>(); resourceTypes.add(resourcetype); AtlasAccessRequest atlasRequest = new AtlasAccessRequest(resourceTypes, "*", actionType, userName, groups, AtlasAuthorizationUtils.getRequestIpAddress(request)); try { authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer(); if (authorizer != null) { isaccessAllowed = authorizer.isAccessAllowed(atlasRequest); } } catch (AtlasAuthorizationException e) { LOG.error("Unable to obtain AtlasAuthorizer. ", e); } return isaccessAllowed; } public static String getRequestIpAddress(HttpServletRequest httpServletRequest) { try { InetAddress inetAddr = InetAddress.getByName(httpServletRequest.getRemoteAddr()); String ip = inetAddr.getHostAddress(); return ip; } catch (UnknownHostException ex) { LOG.error("Error occured when retrieving IP address", ex); return ""; } } }