第一二章见:
http://blog.csdn.net/youyou1543724847/article/details/78377914
第三四章见:
http://blog.csdn.net/youyou1543724847/article/details/78406754
5.用户鉴权、操作权限检查管理
Ambari支持多种认证方式(包括kerberos,Pam,Ldap等),默认使用的是HTTP基本认证方式。
5.1.HTTP基本认证
Http基本认证的方式就是将认证信息放到Header的Authentication字段中。这种认证方式的优点就是比较简单,缺点就是在发送用户信息时,采用的是Base64编码,攻击者很容易获取http请求,然后解码请求就可以获取用户名和密码,没有安全性可言。
HTTP基本认证的过程:
① 客户端发送request给服务端,
② 因为request中没有包含Authorization header,服务器会返回一个401错误给客户端。
③ 客户端把用户名和密码用base64编码之后(编码之后的格式为“Basic base64_string”,其中base64_string为将“user:password”使用base64编码后的串),放在Authorization header中发送给服务器,认证成功。
④ 服务端将Authorization header中的用户名和密码取出来,进行验证,如果验证通过将根据需求发送资源给客户端。
5.2.从Ambari-Server用户基本认证之Servlet Filter
Ambari-Server中注册了10个自定义的Filter(这AmbariServer.run函数中进行注册),下面先对这10个Filter进行简单的说明:
① AmbariServerSecurityHeaderFilter:如果Request在设置了Deny_Header_Override属性,则删除属性;否则,设置Response的某些头部参数。
② AmbariVidwSecurityHeaderFilter:为Ambari 视图类请求的响应增加安全相关的头部;
③ ViewThrottleFilter:视图类请求检查(具体功能没看);
④ AmbariViewsMDCLoggingFilter:为视图类请求增加MDC信息日志;
⑤ AmbariPersistFilter:请求事务化;
⑥ MethodOverrideFilter:request的Header处理(只处理设置了“X-Http-Method-Override”头部的请求);
⑦ AmbariUserAuthorizationFilter: 在spring-security.xml中配置,下面会进行详细说明;
⑧ AmbariDelegatingAuthenticationFilter:在spring-security.xml中配置,下面会进行详细说明;
⑨ AmbariAuthorizationFilter:在spring-security.xml中配置,下面会进行详细说明;
⑩ UserNameOverrideFilter:只对/api/v1/users/*请求进行处理。
整个Filter链如下图所示:
AmbariUserAuthorizationFilter、AmbariDelegatingAuthenticationFilter、AmbariAuthorizationFilter三个Filter在spring-security.xml中配置,然后整体作为一个Filter在AmbariServer.run函数中进行注册。这三个Fitler是用户鉴权认证的主要涉及的Filter,在对他们进行详细介绍前,先看看spring-security.xml文件。
5.2.1.关于spring-security.xml
Spring-security.xml的主要如如下所示:
<http use-expressions="true"
disable-url-rewriting="true" entry-point-ref="ambariEntryPoint">
<intercept-url pattern="/**" access="isAuthenticated()"/>
<custom-filter ref="ambariUserAuthorizationFilter" before="BASIC_AUTH_FILTER"/>
<custom-filter ref="ambariDelegatingAuthenticationFilter" position="BASIC_AUTH_FILTER"/>
<custom-filter ref="ambariAuthorizationFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="ambariLocalAuthenticationProvider"/>
<authentication-provider ref="ambariPamAuthenticationProvider"/>
<authentication-provider ref="ambariLdapAuthenticationProvider"/>
<authentication-provider ref="ambariInternalAuthenticationProvider"/>
<authentication-provider ref="kerberosServiceAuthenticationProvider"/>
authentication-manager>
<beans:bean id="ambariEntryPoint" class="org.apache.ambari.server.security.AmbariEntryPoint">
<beans:constructor-arg ref="ambariConfiguration"/>
beans:bean>
其他涉及到的Bean配置
spring-security.xml中主要分为4部分:
① 定义AuthenticationFilter配置。这里的Filter配置为对所有的URL进行过滤处理。AuthenticationFilter会持有一个AuthenticationManager引用,在具体验证时,会调用AuthenticationManager进行用户验证;这里3个Filter按照ambariUserAuthorizationFilter -> ambariDelegatingAuthenticationFilter -> ambariAuthorizationFilter的顺序进行,如果都验证通过,最后会将程序控制流程转入到Request的Jetty Handler中(Spring会插入一些默认的Filter,如org.springframework.security.web.context.SecurityContextPersistenceFilter,org.springframework.security.web.savedrequest.RequestCacheAwareFilter等);
② AuthenticationManager配置。AuthenticationManager顾名思义,验证管理器,负责验证的,但AuthenticationManager本身并不做具体的验证工作,AuthenticationManager持有一个AuthenticationProvider集合,AuthenticationProvider才是做验证工作的组件。在具体Filter进行验证时,会调用AuthenticationProvider的support方法检查Authentication的类型是不是这个AuthenticationProvider支持的,如果支持则调用该Provider进行验证。如果AuthenticationProvider验证失败或是不支持该Authentication,则AuthenticationManager会继续检查Provider集合中的下一个AuthenticationProvider进行验证,重复该过程,直到找到一个支持该Authentication类型的AuthenticationProvider、且能验证成功的(或是集合中Provider都验证失败,则验证失败),返回一个Authentication子类,表明验证成功(该Authentication最后会放入到Servlet Context中)。
③ Spring EntryPoint定义配置,该EntryPoint用来做Response多出口的。
关于Authentication对象:
Authentication对象是Spring Security使用的进行安全访问控制用户信息安全对象。实际上,Authentication对象有未认证和已认证两种状态,在作为参数传入认证管理器(AuthenticationManager)的authenticate方法时,是一个未认证的对象,它从客户端获取用户的身份信息(如用户名,密码),可以是从一个登录页面,也可以从Cookie中获取,并由系统自动构造成一个Authentication对象。Spring Security要做的就是将这个未认证的Authentication对象和后端的用户信息进行匹配,成功后将后端的用户信息中的用户权限信息拷贝到Authentication中组成一个完整的Authentication对象。
Spring security认证的过程如下图所示:
5.2.2.AmbariUserAuthorizationFilter
对设置了“X-Internal-Token”Header属性的请求进行认证处理。
5.2.3.AmbariDelegatingAuthenticationFilter
包含三个子Filter:AmbariBasicAuthenticFilter(默认使用该Filter进行处理,使用AmbariLocalUserProvider完成认证,返回AmbariUserAuthentication对象。AmbariLocalUserProvider自己的filter方法没有实际内容,认证通过父类BasicAuthenticationFilter进行。BasicAuthenticationFilter检测 header中的用户名/密码。BasicAuthenticationFilter认证是通过调用authenticationManager.authenticate方法来进行认证。认证成功,则将Authentication放入到SecurityContextHolder中)、AmbariKerberosFilter和AmbariJWTAuthenticFilter。
处理逻辑:对子Filter集合中的每个Fitler进行检测,如果当前Filter可以进行认证,则使用该Filter进行认证,完成认证逻辑;否则,对继续对下一个Filter继续同样的处理。如果轮训完了所有的Filter,且所有的Filter都不能进行测试,则将程序转向下一个在AmbariServer.run()函数中注册的Filter。
5.2.4.AmbariAuthorizationFilter
该Filte的处理过程如下所示:
① 检验Authentication是否存在(AmbariDelegatingAuthenticationFilter中如果通过校验,则会将Authentication对象放到Servlet context中);如果没有或是Authentication为匿名认证的Token,则走匿名认证流程,创建默认的认证信息;
② Authentiaction校验,进行如下分支判断:
a)如果Authentication中数据为空或是属于匿名认证,则继续判定:进行检验Request是否在Header中设置了X-Internal-Token值,如果设置了,则进入该认证流程;否则对于View Request,重定向到Login页面,对于其他类型Request,调用EntryPoint的commence方法,进行错误的多出口处理(返回403 response);
b)否则,如果请求属于内部鉴权请求,直接设置已认证标记;
c)否则,根据Authentication,检测是否有进行该Request的权限,并根据检测结果,设置认证标记;
③ 如果认证标记为空,则返回403Error;否则,将控制流转向下一个流程(这里因为没有其他的Filter了,则将控制转到Jetty Handler中)。
内部鉴权请求包括(不完全列表):
① /api/v[0-9]/clusters/.*?/upgrades.
② /api/v[0-9]/users.*
③ /api/v[0-9]/requests.*
④ /api/v[0-9]/guoups.*
⑤ /api/v[0-9]/clusters/.?/requests.
⑥ /api/v[0-9]/clusters/.?/services.
⑦ /api/v[0-9]/clusters/.?/alert.
⑧ /api/v[0-9]/views.*
⑨ /api/v[0-9]/clusters/.?/hosts.
⑩ /api/v[0-9]/clusters/.?/configurations.
⑪ /api/v[0-9]/clusters/.?/components.
⑫ /api/v[0-9]/clusters/.?/host_components.
5.3.操作权限检查
如果Request为内部鉴权操作,则AmbariAuthorizationFilter就不做权限检查。后续的权限检查分为两部分:
① 在AbstractAuthorizedResourceProvider中做粗力度的权限检测;
② 在具体的真正执行操作时,会在进行一部分细粒度的权限检测。并不是所有的内部鉴权操作都会有这部分检查,有的可能就不需要进行细粒度的权限检测。该部分的检验和①中的检查方式、调用的检查函数相同。在这里还有一部分检测的原因(而不是一并在①中做细粒度的检验)是到了具体的Provider处理逻辑才知道该Request需要那些细粒度的权限,而AbstractAuthorizedResourceProvider是所有的资源的Provider的父类,所有不知道具体的细粒度权限列表,只能做通用的权限检测。
5.4.用户鉴权检查总结
Ambari Server对用户鉴权默认使用的是HTTP基本认证方式,请求需要加上认证信息。
总体来说,Ambari Server鉴权分为三步:
① 用户名、密码验证(在Filter中实现);
② 操作权限检测(粗力度,在AbstractAuthorizedResourceProvider实现);
③ 操作权限检测(细力度,在具体的Provider(或是集群控制器中)中实现),该步骤不是所有的操作都需要。
5.5.用户登录
通过web端进行操作Ambari时,首先需要进行登陆。登陆时,采用HTTP基本认证方式进行验证。如果用户名、密码正确,通过HTTP基本认证成功,Server返回的response的Header中携带Set-cookie,其中包含AMBARISESSIONID。以后所有的操作都通过该AMBARISESSIONID进行认证。
Ambari用户登陆请求为:curl -u admin:admin http://192.169.34.130:8080/api/v1/users/admin?fields=*,privileges/PrivilegeInfo/cluster_name,privileges/PrivilegeInfo/permission_name
请求-响应Header:
Session使用逻辑:通过HTTP基本认证通过后(通过AmbariBasicAuthenticFilter进行),会生出一个Authentication对象,将该对象放入到SecurityContextHolder中,供后续流程使用。最后处理结束后,会将该Authentication放入到Session中。
Web进行后续请求时,请求中携带SessionID。通过org.springframework.security.web.context.SecurityContextPersistenceFilter进行处理。SecurityContextPersistenceFilter处理过程如下:
(1)通过securityContextRepository.loadContext()返回一个securityContext。加载securitycontext的逻辑是先从session中找,如果没有则生成一个新的。
(2)将securitycontext放入到SecuritycontextHolder中;
(3)继续执行下面的过滤器chain.doFilter()
(在测试通过SessionID进行认证的流程时,首先通过Web端进行登陆,登陆成功后,记录该用户的SessionId,然后关闭浏览器,通过curl发出Rest请求,通过curl发送请求的情形为:curl –cookie “AMBARISESSIONID=1o2huv4zljrqo7i72wi32tbam” -i -H ‘X-Requested-By:ambari’ http://node1:8080/api/….)
5.6.用户登出
用户登出请求API为 Get :http://node1:8080/api/v1/logout
登出处理Handler为LogoutService。具体处理就是清除request中sessionId所指定的session。