Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
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,89 @@
/*
* 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.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public class RangerAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 1L;

/**
* Identifies which Ranger authentication mechanism produced this token.
*/
public enum AuthMechanism {
/** Trusted-proxy header auth via RangerHeaderPreAuthFilter */
HEADER
}

private final Object principal;
private final AuthMechanism authMechanism;
private final int authType;
Comment thread
kumaab marked this conversation as resolved.
Outdated
private final String requestId;
Comment thread
kumaab marked this conversation as resolved.
Outdated

public RangerAuthenticationToken(UserDetails principal, Collection<? extends GrantedAuthority> authorities, int authType, AuthMechanism authMechanism) {
this(principal, authorities, authType, authMechanism, null);
}

public RangerAuthenticationToken(UserDetails principal, Collection<? extends GrantedAuthority> authorities, int authType, AuthMechanism authMechanism, String requestId) {
super(authorities);

this.principal = principal;
this.authType = authType;
this.authMechanism = authMechanism;
this.requestId = requestId;

super.setAuthenticated(true);
}

@Override
public Object getPrincipal() {
return principal;
}

@Override
public Object getCredentials() {
return null;
}

/**
* The Ranger authentication mechanism that produced this token.
* Use this to distinguish header auth from SSO, Kerberos, etc.
*/
public AuthMechanism getAuthMechanism() {
return authMechanism;
}

/**
* Maps to XXAuthSession.AUTH_TYPE_* for session/audit recording.
*/
public int getAuthType() {
return authType;
}

/**
* The upstream request ID. Populated only for HEADER auth tokens.
*/
public String getRequestId() {
return requestId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* 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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.ranger.entity.XXAuthSession;
import org.springframework.beans.factory.annotation.Autowired;
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.web.filter.GenericFilterBean;

import javax.annotation.PostConstruct;
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 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.admin.authn.header.enabled";
public static final String PROP_USERNAME_HEADER_NAME = "ranger.admin.authn.header.username";
public static final String PROP_REQUEST_ID_HEADER_NAME = "ranger.admin.authn.header.requestid";

private boolean headerAuthEnabled;
private String userNameHeaderName;
private String requestIdHeaderName;

@Autowired
UserMgr userMgr;

private String username;
Comment thread
kumaab marked this conversation as resolved.
Outdated

@PostConstruct
public void initialize(FilterConfig filterConfig) throws ServletException {
headerAuthEnabled = PropertiesUtil.getBooleanProperty(PROP_HEADER_AUTH_ENABLED, false);
userNameHeaderName = PropertiesUtil.getProperty(PROP_USERNAME_HEADER_NAME);
requestIdHeaderName = PropertiesUtil.getProperty(PROP_REQUEST_ID_HEADER_NAME);
}

@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.
username = StringUtils.trimToNull(httpRequest.getHeader(userNameHeaderName));

if (headerAuthEnabled && StringUtils.isNotBlank(username)) {
String requestId = StringUtils.trimToNull(httpRequest.getHeader(requestIdHeaderName));
List<GrantedAuthority> grantedAuthorities = getAuthoritiesFromRanger(username);
final UserDetails principal = new User(username, "", grantedAuthorities);
RangerAuthenticationToken authToken = new RangerAuthenticationToken(principal, grantedAuthorities, XXAuthSession.AUTH_TYPE_TRUSTED_PROXY, RangerAuthenticationToken.AuthMechanism.HEADER, requestId);

authToken.setDetails(new WebAuthenticationDetails(httpRequest));

SecurityContextHolder.getContext().setAuthentication(authToken);

LOG.debug("Authenticated request using trusted headers for user={}", username);
} else {
LOG.debug("Header-based authentication is disabled or username header is missing/empty!");
}

chain.doFilter(request, response);
}

public boolean isHeaderAuthEnabled() {
Comment thread
kumaab marked this conversation as resolved.
Outdated
Authentication authn = SecurityContextHolder.getContext().getAuthentication();
return authn instanceof RangerAuthenticationToken && ((RangerAuthenticationToken) authn).getAuthMechanism() == RangerAuthenticationToken.AuthMechanism.HEADER;
}

/**
* 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,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 +52,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,15 +117,16 @@ 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 = (auth instanceof RangerAuthenticationToken) ? ((RangerAuthenticationToken) auth).getRequestId() : null;
requestContext.setServerRequestId(requestId != null ? requestId : guidUtil.genGUID());
requestContext.setRequestURL(httpRequest.getRequestURI());
requestContext.setClientTimeOffsetInMinute(clientTimeOffset);

context.setRequestContext(requestContext);

RangerContextHolder.setSecurityContext(context);

int authType = getAuthType(httpRequest);
int authType = getAuthType(auth, httpRequest);
UserSessionBase userSession = sessionMgr.processSuccessLogin(authType, userAgent, httpRequest);

if (userSession != null) {
Expand Down Expand Up @@ -160,25 +165,26 @@ private void setupAdminOpContext(ServletRequest request) {
}
}

private int getAuthType(HttpServletRequest request) {
int authType;
private int getAuthType(Authentication auth, HttpServletRequest request) {
if (auth instanceof RangerAuthenticationToken) {
return ((RangerAuthenticationToken) auth).getAuthType();
}

Object ssoEnabledObj = request.getAttribute("ssoEnabled");
boolean ssoEnabled = ssoEnabledObj != null ? Boolean.parseBoolean(String.valueOf(ssoEnabledObj)) : PropertiesUtil.getBooleanProperty("ranger.sso.enabled", false);

if (ssoEnabled) {
authType = XXAuthSession.AUTH_TYPE_SSO;
return 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;
return XXAuthSession.AUTH_TYPE_TRUSTED_PROXY;
} else {
authType = XXAuthSession.AUTH_TYPE_KERBEROS;
return XXAuthSession.AUTH_TYPE_KERBEROS;
}
} else {
authType = XXAuthSession.AUTH_TYPE_PASSWORD;
}

return authType;
return XXAuthSession.AUTH_TYPE_PASSWORD;
}
}
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.admin.authn.header.enabled</name>
<value>false</value>
</property>
<property>
<name>ranger.admin.authn.header.username</name>
<value>x-awc-username</value>
</property>
<property>
<name>ranger.admin.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