1 可行性分析(配置)
https://github.com/apache/incubator-livy/blob/v0.7.1-incubating-rc1/conf/livy.conf.template
在最新的发布版本,下列配置表明:Livy除了支持Kerberos认证外,还支持自定义的认证过滤器
# Authentication support for Livy server
# Livy has a built-in SPnego authentication support for HTTP requests with below configurations.
# livy.server.auth.type = kerberos
# livy.server.auth.kerberos.principal = <spnego principal>
# livy.server.auth.kerberos.keytab = <spnego keytab>
# livy.server.auth.kerberos.name-rules = DEFAULT
#
# If user wants to use custom authentication filter, configurations are:
# livy.server.auth.type = <custom>
# livy.server.auth.<custom>.class = <class of custom auth filter>
# livy.server.auth.<custom>.param.<foo1> = <bar1>
# livy.server.auth.<custom>.param.<foo2> = <bar2>
2 代码执行逻辑分析
2.1 配置加载入口
org.apache.livy.server.LivyServer
livyConf.get(AUTH_TYPE) match {
**** 中间省略
case customType =>
val authClassConf = s"livy.server.auth.$customType.class"
val authClass = livyConf.get(authClassConf)
require(authClass != null, s"$customType auth requires $authClassConf to be provided")
val holder = new FilterHolder()
holder.setClassName(authClass)
val prefix = s"livy.server.auth.$customType.param."
livyConf.asScala.filter { kv =>
kv.getKey.length > prefix.length && kv.getKey.startsWith(prefix)
}.foreach { kv =>
holder.setInitParameter(kv.getKey.substring(prefix.length), kv.getValue)
}
server.context.addFilter(holder, "/*", EnumSet.allOf(classOf[DispatcherType]))
info(s"$customType auth enabled")
2.2 初始化filter和参数传递
filter在livy.server.auth.<custom>.class中进行配置,需要继承 org.apache.hadoop.security.authentication.server.AuthenticationFilter(这里我直接使用的这个类);
参数都存储在holder的Map<String, String> _initParams中;
2.3 进行filter,指定authHandle
public void init(FilterConfig filterConfig) throws ServletException {
String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX);
configPrefix = (configPrefix != null) ? configPrefix + "." : "";
config = getConfiguration(configPrefix, filterConfig);
String authHandlerName = config.getProperty(AUTH_TYPE, null);
String authHandlerClassName;
if (authHandlerName == null) {
throw new ServletException("Authentication type must be specified: " +
PseudoAuthenticationHandler.TYPE + "|" +
KerberosAuthenticationHandler.TYPE + "|<class>");
}
if (authHandlerName.toLowerCase(Locale.ENGLISH).equals(
PseudoAuthenticationHandler.TYPE)) {
authHandlerClassName = PseudoAuthenticationHandler.class.getName();
} else if (authHandlerName.toLowerCase(Locale.ENGLISH).equals(
KerberosAuthenticationHandler.TYPE)) {
authHandlerClassName = KerberosAuthenticationHandler.class.getName();
} else {
authHandlerClassName = authHandlerName;
}
validity = Long.parseLong(config.getProperty(AUTH_TOKEN_VALIDITY, "36000"))
* 1000; //10 hours
initializeSecretProvider(filterConfig);
initializeAuthHandler(authHandlerClassName, filterConfig);
cookieDomain = config.getProperty(COOKIE_DOMAIN, null);
cookiePath = config.getProperty(COOKIE_PATH, null);
}
调用auth函数
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
boolean unauthorizedResponse = true;
int errCode = HttpServletResponse.SC_UNAUTHORIZED;
AuthenticationException authenticationEx = null;
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
boolean isHttps = "https".equals(httpRequest.getScheme());
try {
boolean newToken = false;
AuthenticationToken token;
try {
token = getToken(httpRequest);
}
catch (AuthenticationException ex) {
LOG.warn("AuthenticationToken ignored: " + ex.getMessage());
// will be sent back in a 401 unless filter authenticates
authenticationEx = ex;
token = null;
}
if (authHandler.managementOperation(token, httpRequest, httpResponse)) {
if (token == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Request [{}] triggering authentication", getRequestURL(httpRequest));
}
token = authHandler.authenticate(httpRequest, httpResponse);
if (token != null && token.getExpires() != 0 &&
token != AuthenticationToken.ANONYMOUS) {
token.setExpires(System.currentTimeMillis() + getValidity() * 1000);
}
newToken = true;
}
3 自定义认证开发(将几个函数实现)
/**
* @author xxx
* @date 2023/3/9 5:33 PM
*/
class LivyUserAuth extends AuthenticationHandler {
val log = LoggerFactory.getLogger(this.getClass)
private var userPassList:mutable.Map[String, String] = mutable.HashMap()
private var hdfsLocation:String = null
private var fileLocation:String = null
private var periodSecond:Int = -1
private var decryptType:String = null
private val CACHE_SIZE:Int = 1000
private var passwordSupplier:Supplier[PasswordStore] = null
override def getType: String = "xxx"
override def init(properties: Properties): Unit = {
}
override def destroy(): Unit = {
}
/**
* return true when the request processing should continue. If false is returned, it means the response has been populated by this method
* @param authenticationToken
* @param httpServletRequest
* @param httpServletResponse
*/
@throws[IOException]
@throws[AuthenticationException]
override def managementOperation(authenticationToken: AuthenticationToken,
httpServletRequest: HttpServletRequest,
httpServletResponse: HttpServletResponse): Boolean = {
return true
}
@throws[IOException]
@throws[AuthenticationException]
override def authenticate(request: HttpServletRequest,
response: HttpServletResponse): AuthenticationToken = {
var token: AuthenticationToken = null
var authorization = request.getHeader("Authorization")
log.info("authorization:" + authorization)
token
}
}
4 打包部署
只需要项目打包即可,依赖不需要(Livy Jars里面已经有了)
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<outputDirectory>${project.build.directory}/jars</outputDirectory>
</configuration>
</plugin>
</plugins>
livy.conf 新增下面的配置
livy.server.auth.type nxb
livy.server.auth.nxb.class org.apache.hadoop.security.authentication.server.AuthenticationFilter
livy.server.auth.nxb.param.file.location xxxxxxxxxx
livy.server.auth.nxb.param.period.second 1800
livy.server.auth.nxb.param.type com.newsbreak.livy.auth.LivyUserAuth
将打包好jar放在/usr/lib/livy/jars/
重启服务
sudo systemctl restart livy-server.service
最后查看日志
浙公网安备 33010602011771号