blob: 62363ab064222a3cce3940af5bdbc59c2ee7d1aa [file] [log] [blame]
/**
* 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.authorization.knox;
import java.io.IOException;
import java.security.AccessController;
import java.security.Principal;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.security.auth.Subject;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.knox.gateway.filter.AbstractGatewayFilter;
import org.apache.knox.gateway.security.GroupPrincipal;
import org.apache.knox.gateway.security.ImpersonatedPrincipal;
import org.apache.knox.gateway.security.PrimaryPrincipal;
import org.apache.ranger.audit.provider.MiscUtil;
import org.apache.ranger.authorization.knox.KnoxRangerPlugin.RequestBuilder;
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
import org.apache.ranger.plugin.policyengine.RangerAccessResult;
import org.apache.ranger.plugin.util.RangerPerfTracer;
public class RangerPDPKnoxFilter implements Filter {
private static final Log LOG = LogFactory.getLog(RangerPDPKnoxFilter.class);
private static final Log PERF_KNOXAUTH_REQUEST_LOG = RangerPerfTracer.getPerfLogger("knoxauth.request");
private static final String KNOX_GATEWAY_JASS_CONFIG_SECTION = "com.sun.security.jgss.initiate";
private String resourceRole = null;
private static volatile KnoxRangerPlugin plugin = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
resourceRole = getInitParameter(filterConfig, "resource.role");
KnoxRangerPlugin me = plugin;
if(me == null) {
synchronized (RangerPDPKnoxFilter.class) {
me = plugin;
if(me == null) {
try {
MiscUtil.setUGIFromJAASConfig(KNOX_GATEWAY_JASS_CONFIG_SECTION);
LOG.info("LoginUser=" + MiscUtil.getUGILoginUser());
} catch (Throwable t) {
LOG.error("Error while setting UGI for Knox Plugin...", t);
}
LOG.info("Creating KnoxRangerPlugin");
plugin = new KnoxRangerPlugin();
plugin.init();
}
}
}
}
private String getInitParameter(FilterConfig filterConfig, String paramName) {
return filterConfig.getInitParameter(paramName.toLowerCase());
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String sourceUrl = (String) request
.getAttribute(AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME);
String topologyName = getTopologyName(sourceUrl);
String serviceName = getServiceName();
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_KNOXAUTH_REQUEST_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_KNOXAUTH_REQUEST_LOG, "RangerPDPKnoxFilter.doFilter(url=" + sourceUrl + ", topologyName=" + topologyName + ")");
}
Subject subject = Subject.getSubject(AccessController.getContext());
Principal primaryPrincipal = (Principal) subject.getPrincipals(
PrimaryPrincipal.class).toArray()[0];
String primaryUser = primaryPrincipal.getName();
String impersonatedUser = null;
Object[] impersonations = subject.getPrincipals(
ImpersonatedPrincipal.class).toArray();
if (impersonations != null && impersonations.length > 0) {
impersonatedUser = ((Principal) impersonations[0]).getName();
}
String user = (impersonatedUser != null) ? impersonatedUser
: primaryUser;
if (LOG.isDebugEnabled()) {
LOG.debug("Checking access primaryUser: " + primaryUser + ", impersonatedUser: "
+ impersonatedUser + ", effectiveUser: " + user);
}
Object[] groupObjects = subject.getPrincipals(GroupPrincipal.class)
.toArray();
Set<String> groups = new HashSet<String>();
for (Object obj : groupObjects) {
groups.add(((Principal) obj).getName());
}
String clientIp = request.getRemoteAddr();
List<String> forwardedAddresses = getForwardedAddresses(request);
if (LOG.isDebugEnabled()) {
LOG.debug("Checking access primaryUser: " + primaryUser
+ ", impersonatedUser: " + impersonatedUser
+ ", effectiveUser: " + user + ", groups: " + groups
+ ", clientIp: " + clientIp + ", remoteIp: " + clientIp + ", forwardedAddresses: " + forwardedAddresses);
}
RangerAccessRequest accessRequest = new RequestBuilder()
.service(serviceName)
.topology(topologyName)
.user(user)
.groups(groups)
.clientIp(clientIp)
.remoteIp(clientIp)
.forwardedAddresses(forwardedAddresses)
.build();
boolean accessAllowed = false;
if (plugin != null) {
RangerAccessResult result = plugin.isAccessAllowed(accessRequest);
accessAllowed = result != null && result.getIsAllowed();
}
if (LOG.isDebugEnabled()) {
LOG.debug("Access allowed: " + accessAllowed);
}
RangerPerfTracer.log(perf);
if (accessAllowed) {
chain.doFilter(request, response);
} else {
sendForbidden((HttpServletResponse) response);
}
}
private List<String> getForwardedAddresses(ServletRequest request) {
List<String> forwardedAddresses = null;
if (request instanceof HttpServletRequest) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String xForwardedFor = httpRequest.getHeader("X-Forwarded-For");
if(xForwardedFor != null) {
forwardedAddresses = Arrays.asList(xForwardedFor.split(","));
}
}
return forwardedAddresses;
}
private void sendForbidden(HttpServletResponse res) {
sendErrorCode(res, 403);
}
private void sendErrorCode(HttpServletResponse res, int code) {
try {
res.sendError(code);
} catch (IOException e) {
LOG.error("Error while redirecting:", e);
}
}
private String getTopologyName(String requestUrl) {
if (requestUrl == null) {
return null;
}
String url = requestUrl.trim();
String[] tokens = url.split("/");
if (tokens.length > 2) {
return tokens[2];
} else {
return null;
}
}
private String getServiceName() {
return resourceRole;
}
}