JAAS 笔记

Introduce

Java身份认证和授权服务 (Java Authentication and Authorization Service,JAAS)

JAAS 可用于两个目的:

  • 认证(对于用户身份验证,可以可靠且安全地确定谁正在执行Java代码,而不管代码是作为应用程序、applet、bean还是servlet运行)
  • 授权(对用户进行授权,以确保他们拥有执行操作所需的访问控制权限)

JAAS 实现了标准可插入的认证模块(PAM: Pluggable Authentication Module )框架的 Java 版本。

传统上,Java 提供了基于代码源的访问控制(基于代码来源和代码签名人的访问控制)。然而,它缺乏根据运行代码的人来增加访问控制的能力。JAAS 提供了一个框架,用这种支持扩展 Java 安全架构。

JAAS 身份验证是以可插拔的方式执行的。这允许应用程序独立于底层的身份验证技术。可以在应用程序下插入新的或更新的身份验证技术,而无需对应用程序本身进行修改。应用程序通过实例化 LoginContext 对象来启用身份验证过程,该对象引用 Configuration 来确定用于执行身份验证的身份验证技术或技术,或 LoginModule。典型的 LoginModules 可能会提示输入并验证用户名和密码。其他人可以阅读和验证声音或指纹样本。

执行代码的用户或服务经过身份验证后,JAAS授权组件与核心Java SE访问控制模型一起工作,以保护对敏感资源的访问。访问控制决策既基于执行代码的 CodeSource,也基于运行代码的用户或服务(由Subject对象表示)。如果身份验证成功,则由带有相关主体和凭据的LoginModule更新主题。

Architecture

Authentication

jaas-authn

Authorization

protdom

Concept

核心类和接口

JAAS 相关的核心类和接口可以分为三类: 通用类身份验证类授权类

通用类

通用类是由 JAAS 身份验证和授权组件共享的类。

关键的 JAAS 类是 javax.security.auth.Subject,它表示单个实体(如个人)的相关信息的分组。它包含实体的主体、公共凭证和私有凭证。

  • Subject

    要授权对资源的访问,应用程序首先需要对请求的源进行身份验证。JAAS 框架定义了 Subject 这个术语来表示请求的来源。Subject 可以是任何实体,如个人或服务。一旦主体被认证,一个 javax.security.auth.Subject 由相关的标识或身份(Principal)填充。

    Subject 还可以拥有与安全性相关的属性,这些属性称为凭据。需要特殊保护的敏感凭据(如私有密钥)存储在私有凭据集中。要共享的凭据(如公钥证书)存储在公共凭据集中。访问和修改不同的凭据集需要不同的权限。

    doAs versus doAsPrivileged

    doAsPrivileged 方法的行为与 doAs 方法完全相同,只是它们没有将提供的 Subject 与当前 Thread 的 AccessControlContext 关联起来,而是使用提供的 AccessControlContext。通过这种方式,可以通过与当前的 AccessControlContexts 不同的方式来限制操作。

  • Principals

    一个主体(Subject)可能会有多个身份(Principal)。

  • Credentials

    除了关联的主体之外,Subject 还可以拥有与安全相关的属性,这些属性称为凭据。凭据可以包含用于对新服务的主题进行身份验证的信息。这些凭据包括密码、 Kerberos 票证和公钥证书。凭据还可能包含仅允许主体执行某些活动的数据。例如,加密密钥表示允许主体签名或加密数据的凭据。公共和私有凭据类不是核心 JAAS 类库的一部分。因此,任何类都可以表示凭据。

    公共和私有凭据类不是核心 JAAS 类库的一部分。然而,开发者可能会选择让他们的凭证类实现与凭证相关的两个接口: Refreshable 和 Destroyable。

    • javax.security.auth.Refreshable 接口提供了凭据刷新自身的功能。
    • javax.security.auth.Destroyable 接口提供了销毁凭证内容的功能。

身份验证类和接口

身份验证代表验证主体身份的过程,并且必须以安全的方式执行; 否则犯罪者可能冒充他人以获得对系统的访问权。认证通常涉及主体提供某种形式的凭证来证明其身份。这种证据可能是只有当事人可能知道或拥有的信息(如密码或指纹) ,也可能是只有当事人可以提供的信息(如使用私人钥匙签名的数据)。

  • LoginContext

    LoginContext 类提供了用于对 Subject 进行身份验证的基本方法,并提供了一种独立于底层身份验证技术的应用程序开发方法。LoginContext 查询 Configuration 以确定为特定应用程序配置的身份验证服务或 LoginModule。因此,可以在应用程序下插入不同的 LoginModule,而不需要对应用程序本身进行任何修改。

  • LoginModule

    LoginModule 接口使开发人员能够实现应用程序下可以插入的各种身份验证技术。例如,一种类型的 LoginModule 可能执行基于用户名/密码的身份验证形式。其他的 LoginModule 可以与硬件设备接口,如智能卡或生物识别设备。

  • CallbackHandler

    在某些情况下,LoginModule 必须与用户通信以获取身份验证信息。

    应用程序实现 CallbackHandler 接口并将其传递给 LoginContext,后者直接将其转发给底层 LoginModules。LoginModule 使用 CallbackHandler 收集用户的输入(例如密码或智能卡密码) ,或者向用户提供信息(例如状态信息)。通过允许应用程序指定 CallbackHandler,底层 LoginModules 可以保持独立于应用程序与用户交互的不同方式。

    LoginModule 向 CallbackHandler handle 方法传递一个适当的 Callbacks 数组,例如用于用户名的 NameCallback 和用于密码的 PasswordCallback,CallbackHandler 执行请求的用户交互并在 Callbacks 中设置适当的值。例如,要处理 NameCallback,CallbackHandler 可能会提示输入名称,从用户检索值,并调用 NameCallback 的 setName 方法来存储名称。

  • Callback

    LoginModules 可以直接将 Callback 数组传递给 CallbackHandler 的 handle 方法。

授权类

要使 JAAS 授权发生,授予访问控制权限不仅要基于运行的代码,还要基于运行代码的人,需要以下几点:

  1. 必须经过身份验证

  2. 身份验证结果的主体(Subject)必须与访问控制上下文关联

  3. 必须在安全策略中配置基于身份(Principal)的项

  • Policy

    策略类是用于表示系统范围的访问控制策略的抽象类。策略 API 支持基于身份(Principal)的查询。

    缺省情况下,JDK 提供了一个基于文件的子类实现,它被升级为支持策略文件中基于身份的授权条目。

  • AuthPermission
    当前,AuthPermission 对象用于保护对 Policy、 Subject、 LoginContext 和 Configuration 对象的访问。

java.Security Properties 文件中的 JAAS 设置

许多与 JAAS 相关的设置可以在 java.Security 主安全属性文件中配置,该文件位于 JDK 的 conf/Security 目录中。

  • Login Configuration Provider

    默认的 JAAS 登录配置实现可以通过在 login.configuration.provider 属性中指定替代的 provider 类实现来替换。

    1
    login.configuration.provider=com.foo.Config

    如果没有找到 Security 属性 login.configuration.provider,或者没有指定,那么它将被设置为缺省值:

    1
    login.configuration.provider=com.sun.security.auth.login.ConfigFile

    注意,没有办法从命令行动态设置登录配置提供程序。

  • Login Configuration URLs

    如果使用的登录配置实现期望在文件中指定配置信息,则可以通过在 login.configurl.n 属性中指定各自的 url 静态设置登录配置文件的位置。N’是一个连续编号的整数,从1开始。如果指定了多个配置文件(如果 n > = 2) ,它们将被读取并合并为单个配置。

    1
    2
    login.config.url.1=file:C:/config/.java.login.config
    login.config.url.2=file:C:/users/foo/.foo.login.config

    如果配置文件的位置没有在 java.security 属性文件中设置,也没有在命令行中动态指定(通过-Djava.security.auth.login.config 选项) ,JAAS 将尝试从 file:${user.home}/.java.login.config 加载默认配置。

  • Policy Provider

    可以通过在 policy.provider 属性中指定替代提供程序类实现来替换默认策略实现。

    1
    policy.provider=com.foo.Policy

    如果找不到 Security 属性 Policy.provider,或者未指定,则策略将设置为默认值:

    1
    policy.provider=sun.security.provider.PolicyFile

    请注意,不存在从命令行动态设置策略提供程序的方法。

  • Policy File URLs

    通过在 auth.policy.url.n 属性中指定各自的 url,可以静态设置访问控制策略文件的位置。N 是一个连续编号的整数,从1开始。如果指定了多个策略(如果 n > = 2) ,它们将被读取并合并为一个策略。

    1
    2
    policy.url.1=file:C:/policy/.java.policy
    policy.url.2=file:C:/users/foo/.foo.policy

    如果策略文件的位置没有在 java.security 属性文件中设置,也没有从命令行(通过 -Djava.security.policy 选项)动态指定,那么访问控制策略默认为与 JDK 安装的系统策略文件相同的策略。

    • 将所有权限授予标准扩展
    • 允许任何人监听非特权端口
    • 允许任何代码读取某些不敏感于安全性的“标准”属性,如 os.name 和 file.separator 属性。

JAAS 教程和示例程序

https://github.com/shankai/sample-jaas

References

https://docs.oracle.com/en/java/javase/11/security/java-authentication-and-authorization-service-jaas1.html