Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mkdocs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.cache/
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* 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 org.apache.commons.lang3.StringUtils;
import org.apache.ranger.biz.UserMgr;
import org.apache.ranger.common.PropertiesUtil;
import org.apache.ranger.entity.XXPortalUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.web.filter.GenericFilterBean;

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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class RangerHeaderPreAuthFilter extends GenericFilterBean {
private static final Logger LOG = LoggerFactory.getLogger(RangerHeaderPreAuthFilter.class);

public static final String PROP_HEADER_AUTH_ENABLED = "ranger.authn.header.enabled";
public static final String PROP_USERNAME_HEADER_NAME = "ranger.authn.header.username";
public static final String PROP_REQUEST_ID_HEADER_NAME = "ranger.authn.header.requestid";
public static final String DEFAULT_USERNAME_HEADER_NAME = "x-awc-username";
public static final String DEFAULT_REQUEST_ID_HEADER_NAME = "x-awc-requestid";

@Autowired
UserMgr userMgr;

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
Comment thread
kumaab marked this conversation as resolved.

if (!PropertiesUtil.getBooleanProperty(PROP_HEADER_AUTH_ENABLED, false)) {
Comment thread
kumaab marked this conversation as resolved.
Outdated
chain.doFilter(request, response);

return;
}

String username = StringUtils.trimToNull(httpRequest.getHeader(getUsernameHeaderName()));
String requestId = StringUtils.trimToNull(httpRequest.getHeader(getRequestIdHeaderName()));

if (username == null) {
sendUnauthorized(response, "Missing trusted username header");
Comment thread
kumaab marked this conversation as resolved.
Outdated

return;
} else if (requestId == null) {
sendUnauthorized(response, "Missing trusted request-id header");

return;
}

XXPortalUser rangerUser = userMgr.findByLoginId(username);
Comment thread
kumaab marked this conversation as resolved.
Outdated

if (rangerUser == null) {
LOG.warn("Skipping header-based authentication for unknown Ranger user={}", username);
sendUnauthorized(response, "Unknown Ranger user");

return;
}

List<GrantedAuthority> grantedAuthorities = getAuthoritiesFromRanger(username);
final UserDetails principal = new User(username, "", grantedAuthorities);
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(principal, "", grantedAuthorities);

authToken.setDetails(new WebAuthenticationDetails(httpRequest));

SecurityContextHolder.getContext().setAuthentication(authToken);

LOG.debug("Authenticated request using trusted headers for user={}", username);

chain.doFilter(request, response);
}

private void sendUnauthorized(ServletResponse response, String message) throws IOException {
((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED, message);
}

/**
* Loads authorities from Ranger DB
*/
private List<GrantedAuthority> getAuthoritiesFromRanger(String username) {
List<GrantedAuthority> ret = new ArrayList<>();
Collection<String> roleList = userMgr.getRolesByLoginId(username);

if (roleList != null) {
for (String role : roleList) {
if (StringUtils.isNotBlank(role)) {
ret.add(new SimpleGrantedAuthority(role));
}
}
}

return ret;
}

private String getUsernameHeaderName() {
return PropertiesUtil.getProperty(PROP_USERNAME_HEADER_NAME, DEFAULT_USERNAME_HEADER_NAME);
}

private String getRequestIdHeaderName() {
return PropertiesUtil.getProperty(PROP_REQUEST_ID_HEADER_NAME, DEFAULT_REQUEST_ID_HEADER_NAME);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/
package org.apache.ranger.security.web.filter;

import org.apache.commons.lang3.StringUtils;
import org.apache.ranger.biz.SessionMgr;
import org.apache.ranger.biz.XUserMgr;
import org.apache.ranger.common.GUIDUtil;
Expand All @@ -33,6 +34,8 @@
import org.apache.ranger.security.context.RangerContextHolder;
import org.apache.ranger.security.context.RangerSecurityContext;
import org.apache.ranger.util.RestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
Expand All @@ -50,6 +53,8 @@
import java.io.IOException;

public class RangerSecurityContextFormationFilter extends GenericFilterBean {
private static final Logger LOG = LoggerFactory.getLogger(RangerSecurityContextFormationFilter.class);

public static final String AKA_SC_SESSION_KEY = "AKA_SECURITY_CONTEXT";
public static final String USER_AGENT = "User-Agent";

Expand Down Expand Up @@ -113,7 +118,8 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
requestContext.setIpAddress(reqIP);
requestContext.setUserAgent(userAgent);
requestContext.setDeviceType(httpUtil.getDeviceType(httpRequest));
requestContext.setServerRequestId(guidUtil.genGUID());
String requestId = getServerRequestId(httpRequest);
requestContext.setServerRequestId(requestId != null ? requestId : guidUtil.genGUID());
requestContext.setRequestURL(httpRequest.getRequestURI());
requestContext.setClientTimeOffsetInMinute(clientTimeOffset);

Expand Down Expand Up @@ -165,11 +171,13 @@ private int getAuthType(HttpServletRequest request) {
Object ssoEnabledObj = request.getAttribute("ssoEnabled");
boolean ssoEnabled = ssoEnabledObj != null ? Boolean.parseBoolean(String.valueOf(ssoEnabledObj)) : PropertiesUtil.getBooleanProperty("ranger.sso.enabled", false);

if (ssoEnabled) {
if (isHeaderAuthenticated()) {
authType = XXAuthSession.AUTH_TYPE_TRUSTED_PROXY;
Comment thread
kumaab marked this conversation as resolved.
Outdated
} else if (ssoEnabled) {
authType = XXAuthSession.AUTH_TYPE_SSO;
} else if (request.getAttribute("spnegoEnabled") != null && Boolean.parseBoolean(String.valueOf(request.getAttribute("spnegoEnabled")))) {
if (request.getAttribute("trustedProxyEnabled") != null && Boolean.parseBoolean(String.valueOf(request.getAttribute("trustedProxyEnabled")))) {
logger.debug("Setting auth type as trusted proxy");
LOG.debug("Setting auth type as trusted proxy");

authType = XXAuthSession.AUTH_TYPE_TRUSTED_PROXY;
} else {
Expand All @@ -181,4 +189,14 @@ private int getAuthType(HttpServletRequest request) {

return authType;
}

private boolean isHeaderAuthenticated() {
return PropertiesUtil.getBooleanProperty(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED, false);
Comment thread
kumaab marked this conversation as resolved.
Outdated
}

private String getServerRequestId(HttpServletRequest request) {
String headerName = PropertiesUtil.getProperty(RangerHeaderPreAuthFilter.PROP_REQUEST_ID_HEADER_NAME, RangerHeaderPreAuthFilter.DEFAULT_REQUEST_ID_HEADER_NAME);

return StringUtils.trimToNull(request.getHeader(headerName));
}
}
14 changes: 14 additions & 0 deletions security-admin/src/main/resources/conf.dist/ranger-admin-site.xml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,20 @@
<value>Mozilla,chrome</value>
</property>
<!-- SSO Properties Ends-->
<!-- Trusted header auth properties start -->
<property>
<name>ranger.authn.header.enabled</name>
Comment thread
kumaab marked this conversation as resolved.
Outdated
<value>false</value>
</property>
<property>
<name>ranger.authn.header.username</name>
<value>x-awc-username</value>
</property>
<property>
<name>ranger.authn.header.requestid</name>
<value>x-awc-requestid</value>
</property>
<!-- Trusted header auth properties end -->
<!-- Kerberos Properties starts-->
<property>
<name>ranger.admin.kerberos.token.valid.seconds</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd">
</security:headers>
<security:session-management session-fixation-protection="newSession" />
<intercept-url pattern="/**" access="isAuthenticated()"/>
<security:custom-filter position="PRE_AUTH_FILTER" ref="headerPreAuthFilter" />
<custom-filter ref="ssoAuthenticationFilter" after="BASIC_AUTH_FILTER" />
<security:custom-filter ref="rangerJwtAuthWrapper" before="SERVLET_API_SUPPORT_FILTER" />
<security:custom-filter ref="krbAuthenticationFilter" after="SERVLET_API_SUPPORT_FILTER" />
Expand Down Expand Up @@ -115,6 +116,9 @@ http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd">
<beans:bean id="mdcFilter" class="org.apache.ranger.security.web.filter.RangerMDCFilter">
</beans:bean>

<beans:bean id="headerPreAuthFilter" class="org.apache.ranger.security.web.filter.RangerHeaderPreAuthFilter">
</beans:bean>

<beans:bean id="ssoAuthenticationFilter" class="org.apache.ranger.security.web.filter.RangerSSOAuthenticationFilter">
</beans:bean>

Expand Down
Loading
Loading