Skip to content

JAAS Cheat Sheet / JAAS 欺骗表

Introduction - What is JAAS authentication / 简介 - 什么是 JAAS 认证

The process of verifying the identity of a user or another system is authentication.

验证用户或另一个系统身份的过程是认证。

JAAS, as an authentication framework manages the authenticated user's identity and credentials from login to logout.

The JAAS authentication lifecycle:

JAAS 认证生命周期:

  1. The application creates a LoginContext using the configured login name and a callback handler.
    中文:应用程序使用配置的登录名和回调处理程序创建一个 LoginContext。
  2. The LoginContext reads the configuration and instantiates the configured LoginModules.
    中文:LoginContext 读取配置并实例化配置的 LoginModule。
  3. The LoginContext calls each module's initialize() with the shared Subject and other context.
    中文:LoginContext 使用共享的 Subject 和其他上下文调用每个模块的 initialize() 方法。
  4. The application calls LoginContext.login(), which invokes the configured modules' login() methods according to their control flags.
    中文:应用程序调用 LoginContext.login(),该方法根据配置模块的控制标志调用各自的 login() 方法。
  5. If overall authentication succeeds, the LoginContext invokes the modules' commit() methods; otherwise, it invokes their abort() methods.
    中文:如果整体认证成功,LoginContext 将调用模块的 commit() 方法;否则,将调用它们的 abort() 方法。

Configuration file / 配置文件

The JAAS configuration file contains a LoginModule stanza for each LoginModule available for logging on to the application.

JAAS 配置文件包含每个可用于登录应用程序的 LoginModule 的 LoginModule 配置段落。

A stanza from a JAAS configuration file:

JAAS 配置文件的一个段落:

Branches
{
    USNavy.AppLoginModule required
    debug=true
    succeeded=true;
}

Note the placement of the semicolons, terminating both LoginModule entries and stanzas.

注意分号的位置,它们终止了 LoginModule 条目和段落。

The word required indicates the LoginContext's login() method must be successful when logging in the user. The LoginModule-specific values debug and succeeded are passed to the LoginModule.

单词 required 表示 LoginContext 的 login() 方法在登录用户时必须成功。LoginModule 特定的值 debug 和 succeeded 被传递给 LoginModule。

They are defined by the LoginModule and their usage is managed inside the LoginModule. Note, Options are Configured using key-value pairing such as debug="true" and the key and value should be separated by a = sign.

这些值由 LoginModule 定义,其使用在 LoginModule 内部管理。注意,选项通过键值对配置,例如 debug="true",键和值之间应以等号 = 分隔。

Main.java (The client) / Main.java(客户端)

  • Execution syntax:
    中文:执行语法:
Java –Djava.security.auth.login.config==packageName/packageName.config
        packageName.Main Stanza1

Where:
    packageName is the directory containing the config file.
    packageName.config specifies the config file in the Java package, packageName.
    packageName.Main specifies Main.java in the Java package, packageName.
    Stanza1 is the name of the stanza Main() should read from the config file.
  • When executed, the 1st command-line argument is the stanza from the config file. The Stanza names the LoginModule to be used. The 2nd argument is the CallbackHandler.
    中文:执行时,第一个命令行参数是来自配置文件的段落。段落命名了要使用的 LoginModule。第二个参数是 CallbackHandler。
  • Create a new LoginContext with the arguments passed to Main.java.
    中文:使用传递给 Main.java 的参数创建一个新的 LoginContext。
    • loginContext = new LoginContext (args[0], new AppCallbackHandler());
  • Call the LoginContext.Login Module:
    中文:调用 LoginContext.login() 模块:
    • loginContext.login();
  • LoginContext.login() returns without a value when authentication succeeds and throws a LoginException when it fails.
    中文:当认证成功时,LoginContext.login() 无返回值,当失败时抛出 LoginException 异常。
  • Retrieve the authenticated Subject using loginContext.getSubject() after successful login.
    中文:使用 loginContext.getSubject() 在登录成功后检索已认证的 Subject。

LoginModule.java

A LoginModule must have the following authentication methods:

一个 LoginModule 必须有以下认证方法:

  • initialize()
  • login()
  • commit()
  • abort()
  • logout()

initialize()

In Main(), after the LoginContext reads the correct stanza from the config file, the LoginContext instantiates the LoginModule specified in the stanza.

在 Main() 中,LoginContext 读取配置文件中的正确stanza后,LoginContext 实例化stanza中指定的 LoginModule。

  • initialize() methods signature:
    中文:initialize() 方法签名:
    • public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options)
  • The arguments above should be saved as follows:
    中文:上述参数应保存如下:
    • this.subject = subject;
    • this.callbackHandler = callbackHandler;
    • this.sharedState = sharedState;
    • this.options = options;
  • What the initialize() method does:
    中文:initialize() 方法的作用是:
    • Stores the supplied shared Subject; successful commit() associates authenticated principals and credentials with that object.
      中文:存储提供的共享 Subject;成功的 commit() 将认证主体和凭证与该对象关联。
    • Sets the CallbackHandler which interacts with the user to gather login information.
      中文:设置与用户交互以收集登录信息的 CallbackHandler。
    • If a LoginContext specifies 2 or more LoginModules, which is legal, they can share information via a sharedState map.
      中文:如果 LoginContext 指定了 2 个或更多 LoginModules,这是合法的,它们可以通过 sharedState 映射共享信息。
    • Saves state information such as debug and succeeded in an options Map.
      中文:在选项 Map 中保存状态信息,如调试和成功。

login()

Captures user supplied login information. The code snippet below declares an array of two callback objects which, when passed to the callbackHandler.handle method in the callbackHandler.java program, will be loaded with a username and password provided interactively by the user:

捕获用户提供的登录信息。下面的代码片段声明了一个包含两个回调对象的数组,当将它们传递给 callbackHandler.handle 方法(在 callbackHandler.java 程序中)时,将加载用户通过交互提供的用户名和密码:

NameCallback nameCB = new NameCallback("Username");
PasswordCallback passwordCB = new PasswordCallback ("Password", false);
Callback[] callbacks = new Callback[] { nameCB, passwordCB };
callbackHandler.handle (callbacks);
  • Authenticates the user
    中文:验证用户身份
  • Retrieves the user supplied information from the callback objects:
    中文:从回调对象中检索用户提供的信息:
    • String ID = nameCallback.getName ();
    • char[] tempPW = passwordCallback.getPassword ();
  • Compare name and tempPW to values stored in a repository such as LDAP.
    中文:将name和tempPW与存储在如LDAP的存储库中的值进行比较。
  • Set the value of the variable succeeded and return to Main().
    中文:设置succeeded变量的值并返回到Main()。

commit()

Once the users credentials are successfully verified during login(), the JAAS authentication framework associates the credentials, as needed, with the subject.

一旦在login()过程中成功验证了用户的凭据,JAAS认证框架将根据需要将凭据与主题关联。

A Subject separates credentials by their protection and sharing requirements:

【主题】通过保护和共享要求来分隔凭据(Subject)(https://docs.oracle.com/en/java/javase/11/docs/api/java.base/javax/security/auth/Subject.html):

  • Public credentials are intended to be shared, such as public key certificates.
    中文:公共凭据旨在共享,例如公钥证书。
  • Private credentials require special protection, such as passwords and private cryptographic keys.
    中文:私有凭据需要特殊保护,例如密码和私有加密密钥。

Principals (i.e. Identities the subject has other than their login name) such as employee number or membership ID in a user group are added to the subject.

主体(即除了登录名之外的主体身份,例如)如员工编号或用户组中的会员ID被添加到主体中。

Implement commit() using the authentication state saved by login(). Associate principals and credentials with the shared Subject only when this module's authentication succeeded; otherwise, clean up its saved state. Return true on success, false when the module is ignored, or throw LoginException on failure.

使用login()保存的认证状态实现commit()(https://docs.oracle.com/en/java/javase/11/docs/api/java.base/javax/security/auth/spi/LoginModule.html#commit())。只有在此模块的认证成功时,才将主体和凭据与共享的Subject关联;否则,清理其保存的状态。成功时返回true,当模块被忽略时返回false,或者在失败时抛出LoginException。

abort()

The abort() method is called when authentication doesn't succeed. Before the abort() method exits the LoginModule, care should be taken to reset state including the username and password input fields.

当认证不成功时调用abort()方法。在abort()方法退出LoginModule之前,应小心重置状态,包括用户名和密码输入字段。

logout()

The release of the users principals and credentials when LoginContext.logout is called:

当调用 LoginContext.logout 时释放用户主体和凭证:

public boolean logout() {
    if (!subject.isReadOnly()) {
        Set principals = subject.getPrincipals(UserGroupPrincipal.class);
        subject.getPrincipals().removeAll(principals);
        Set creds = subject.getPublicCredentials(UsernameCredential.class);
        subject.getPublicCredentials().removeAll(creds);
        return true;
    } else {
        return false;
    }
}

CallbackHandler.java

The callbackHandler is in a source (.java) file separate from any single LoginModule so that it can service a multitude of LoginModules with differing callback objects:

将 callbackHandler 放置在源(.java)文件中,与任何单个 LoginModule 分离,以便它可以服务于具有不同回调对象的多个 LoginModule:

  • Creates instance of the CallbackHandler class and has only one method, handle().
    中文:创建 CallbackHandler 类的实例,并只有一个方法,handle()。
  • A CallbackHandler servicing a LoginModule requiring username & password to login:
    中文:为需要用户名和密码登录的 LoginModule 提供服务的 CallbackHandler:
public void handle(Callback[] callbacks) {
    for (int i = 0; i < callbacks.length; i++) {
        Callback callback = callbacks[i];
        if (callback instanceof NameCallback) {
            NameCallback nameCallBack = (NameCallback) callback;
            nameCallBack.setName(username);
    }  else if (callback instanceof PasswordCallback) {
            PasswordCallback passwordCallBack = (PasswordCallback) callback;
            passwordCallBack.setPassword(password.toCharArray());
        }
    }
}
  • JAAS in Action, Michael Coté, posted on September 27, 2009, URL as 5/14/2012.
  • Pistoia Marco, Nagaratnam Nataraj, Koved Larry, Nadalin Anthony from book "Enterprise Java Security" - Addison-Wesley, 2004.
    中文:Pistoia Marco, Nagaratnam Nataraj, Koved Larry, Nadalin Anthony 著,收录于《企业Java安全》一书 - Addison-Wesley,2004年链接。

Disclosure / 披露

All of the code in the attached JAAS cheat sheet has been copied verbatim from this free source.

附带的 JAAS 技巧表中的所有代码都是直接从本 免费资源 复制的。

References / 参考