31. Java 身份验证和授权服务(JAAS)提供程序

31.1 Overview

Spring Security 提供了一个程序包,可以将身份验证请求委派给 Java 身份验证和授权服务(JAAS)。该软件包将在下面详细讨论。

31.2 AbstractJaasAuthenticationProvider

AbstractJaasAuthenticationProvider是所提供的 JAAS AuthenticationProvider实现的基础。子类必须实现创建LoginContext的方法。 AbstractJaasAuthenticationProvider具有许多可以注入到其中的依赖项,下面将对此进行讨论。

31.2.1 JAAS CallbackHandler

大多数 JAAS LoginModule都需要某种回调。这些回调通常用于从用户获取用户名和密码。

在 Spring Security 部署中,Spring Security 负责此用户交互(通过身份验证机制)。因此,在将身份验证请求委托给 JAAS 时,Spring Security 的身份验证机制将已经完全填充了Authentication对象,其中包含 JAAS LoginModule所需的所有信息。

因此,Spring Security 的 JAAS 包提供了两个默认的回调处理程序JaasNameCallbackHandlerJaasPasswordCallbackHandler。这些回调处理程序中的每一个都实现JaasAuthenticationCallbackHandler。在大多数情况下,无需了解内部机制即可简单地使用这些回调处理程序。

对于需要完全控制回调行为的用户,内部AbstractJaasAuthenticationProvider将这些JaasAuthenticationCallbackHandler换成InternalCallbackHandlerInternalCallbackHandler是实际实现 JAAS 常规CallbackHandler接口的类。每当使用 JAAS LoginModule时,都会向其传递配置了InternalCallbackHandler的应用程序上下文列表。如果LoginModule请求针对InternalCallbackHandler的回调,则该回调又传递给正在包装的JaasAuthenticationCallbackHandler

31.2.2 JAAS AuthorityGranter

JAAS 与校长合作。 JAAS 中甚至将“角色”表示为主体。另一方面,Spring Security 可以处理Authentication个对象。每个Authentication对象包含一个主体和多个GrantedAuthority。为了促进这些不同概念之间的 Map,Spring Security 的 JAAS 软件包包括一个AuthorityGranter接口。

AuthorityGranter负责检查 JAAS 委托人并返回一组String,代表分配给委托人的权限。对于每个返回的授权字符串,AbstractJaasAuthenticationProvider创建一个JaasGrantedAuthority(它实现 Spring Security 的GrantedAuthority接口),其中包含授权字符串和AuthorityGranter传递的 JAAS 主体。 AbstractJaasAuthenticationProvider首先通过使用 JAAS LoginModule成功验证用户的凭据,然后访问它返回的LoginContext,从而获得 JAAS 主体。调用LoginContext.getSubject().getPrincipals(),并将每个结果主体传递给针对AbstractJaasAuthenticationProvider.setAuthorityGranters(List)属性定义的每个AuthorityGranter

鉴于每个 JAAS 主体都具有特定于实现的含义,因此 Spring Security 不包含任何生产AuthorityGranter。但是,单元测试中有一个TestAuthorityGranter演示了一个简单的AuthorityGranter实现。

31.3 DefaultJaasAuthenticationProvider

DefaultJaasAuthenticationProvider允许将 JAAS Configuration对象作为依赖项注入到该对象中。然后,使用注入的 JAAS Configuration创建一个LoginContext。这意味着DefaultJaasAuthenticationProviderJaasAuthenticationProvider一样不受Configuration的任何特定实现的约束。

31.3.1 InMemoryConfiguration

为了便于将Configuration注入DefaultJaasAuthenticationProvider,提供了默认的内存实现InMemoryConfiguration。实现构造函数接受一个Map,其中每个键代表一个登录配置名称,该值代表一个AppConfigurationEntryArrayInMemoryConfiguration还支持AppConfigurationEntry对象的默认Array,如果在提供的Map中找不到 Map,则将使用它们。有关详细信息,请参考InMemoryConfiguration的类级别 javadoc。

31.3.2 DefaultJaasAuthenticationProvider 示例配置

尽管InMemoryConfiguration的 Spring 配置比标准 JAAS 配置文件更冗长,但与DefaultJaasAuthenticationProvider结合使用时,它比JaasAuthenticationProvider更灵活,因为它不依赖于默认的Configuration实现。

以下提供了使用InMemoryConfigurationDefaultJaasAuthenticationProvider的示例配置。请注意,Configuration的自定义实现也可以轻松地注入DefaultJaasAuthenticationProvider

<bean id="jaasAuthProvider"
class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider">
<property name="configuration">
<bean class="org.springframework.security.authentication.jaas.memory.InMemoryConfiguration">
<constructor-arg>
	<map>
	<!--
	SPRINGSECURITY is the default loginContextName
	for AbstractJaasAuthenticationProvider
	-->
	<entry key="SPRINGSECURITY">
	<array>
	<bean class="javax.security.auth.login.AppConfigurationEntry">
		<constructor-arg value="sample.SampleLoginModule" />
		<constructor-arg>
		<util:constant static-field=
			"javax.security.auth.login.AppConfigurationEntry$LoginModuleControlFlag.REQUIRED"/>
		</constructor-arg>
		<constructor-arg>
		<map></map>
		</constructor-arg>
		</bean>
	</array>
	</entry>
	</map>
	</constructor-arg>
</bean>
</property>
<property name="authorityGranters">
<list>
	<!-- You will need to write your own implementation of AuthorityGranter -->
	<bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
</list>
</property>
</bean>

31.4 JaasAuthenticationProvider

JaasAuthenticationProvider假定默认的ConfigurationConfigFile的实例。进行此假设是为了尝试更新ConfigurationJaasAuthenticationProvider然后使用默认的Configuration创建LoginContext

假设我们有一个 JAAS 登录配置文件/WEB-INF/login.conf,其内容如下:

JAASTest {
	sample.SampleLoginModule required;
};

像所有 Spring Security bean 一样,JaasAuthenticationProvider是通过应用程序上下文配置的。以下定义将对应于上述 JAAS 登录配置文件:

<bean id="jaasAuthenticationProvider"
class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="/WEB-INF/login.conf"/>
<property name="loginContextName" value="JAASTest"/>
<property name="callbackHandlers">
<list>
<bean
	class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler"/>
<bean
	class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler"/>
</list>
</property>
<property name="authorityGranters">
	<list>
	<bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
	</list>
</property>
</bean>

31.5 以主题身份运行

如果已配置,则JaasApiIntegrationFilter将尝试在JaasAuthenticationToken上以Subject的身份运行。这意味着可以使用以下命令访问Subject

Subject subject = Subject.getSubject(AccessController.getContext());

可以使用jaas-api-provision属性轻松配置此集成。与依赖于填充 JAAS 主题的旧版或外部 API 集成时,此功能很有用。