Java 安全认证和 Hadoop UGI 原理解析

Java 安全认证和 UGI 原理解析

在这里插入图片描述

一般来说,Java 安全认证主要通过自定义 Subject、LoginContext、LoginModule、Configuration 在 Java 中进行安全认证。

Subject 可以单独创建并通过 Subject#doAs 方法单独进行登录,但也可以传入 LoginContext 中,等待 LoginContext 登录完将登录后的 敏感凭证存入 Subject 后再进行登录。

LoginContext 定义了登录环境,环境的创建需要三个必要的条件:环境名,Subject、Configuration。

环境名一般用于指定认证的环境,如通过环境名获取简单认证还是安全认证。

Subject 用于在创建并登录 LoginContext 过程中进行认证,认证过程中可以进行一些操作,例如认证完后将一些敏感凭据存入 Subject中,然后 Subject 作为后面登录和使用的主体。

Configuration 用于定义登录环境登录时将进行认证的若干 LoginModule,以及 LoginModule 需要的参数,例如官方的 Krb5LoginModule 模块,以及其相关参数:principal、KeyTab、ticketCache 等等,具体可以查看 Java 源码或者文档。

Java 有若干个 LoginModule 的实现类,如下:

  • JndiLoginModule: 该模块提示输入用户名和密码,然后根据 JNDI 下配置的目录服务中存储的密码验证密码。
  • KeyStoreLoginModule: 提供 JAAS 登录模块,提示输入密钥存储别名并使用别名的主体和凭据填充主题。为主体主体中别名凭据中第一个证书的主体可分辨名称存储X500Principal,在主体公共凭据中存储别名证书路径,以及X500PrivateCredential,其证书是别名证书路径中的第一个证书,其私钥是主题私人凭证中的别名私钥。
  • Krb5LoginModule: 此 LoginModule 使用 Kerberos 协议对用户进行身份验证。
  • LdapLoginModule: 此 LoginModule 执行基于 LDAP 的身份验证。根据存储在 LDAP 目录中的相应用户凭证验证用户名和密码。该模块需要提供的 CallbackHandler 来支持 NameCallback 和 PasswordCallback 。如果身份验证成功,则使用用户的可分辨名称创建一个新的LdapPrincipal ,并使用用户的用户名创建一个新的UserPrincipal ,并且两者都与当前的Subject 相关联。
  • NTLoginModule: 此 LoginModule 将用户的 NT 安全信息呈现为一定数量的 Principal 并将它们与 Subject 相关联。
  • UnixLoginModule: 此 LoginModule 导入用户的 Unix Principal 信息(UnixPrincipal、UnixNumericUserPrincipal 和 UnixNumericGroupPrincipal)并将它们与当前的 Subject 关联。

模块具体的原理以及相关的 Configuration 可以通过查看 Java 官方文档,Javadocs、或者Java 源码。

它们都可以拿来即用,不用我们再一次进行封装。

LoginContext 登录完后,我们再通过 Subject#doAs 方法登录并进行相关操作,该方法为静态方法,需要传入Subject 和 PrivilegedAction, PrivilegedAction 为一个回调方法,也就是在认证完之后进行的一个回调方法。

PrivilegedAction 相当于一个域,可以随处在当前函数里面获取 Subject#doAs 时传入的 Subject。

AccessControlContext context = ;
return Subject.getSubject(context);

这种域中获取 Subject 的操作经常用于一些框架和服务端进行安全认证,常见与 Hadoop 的 UserInformation ,Hadoop 许多客户端在与服务端通信时都会从域中获取 Subject ,然后使用 Subject 里面的安全凭据与服务端通信。

Subject 和 LoginModule 官方解析

Subject 官方描述

Subject 表示单个实体(例如人)的一组相关信息。此类信息包括主体的身份及其与安全相关的属性(例如,密码和加密密钥)。

受试者可能具有多重身份。每个身份都表示为 Subject 中的 Principal。校长只需将名称绑定到 Subject 即可。例如,恰好是一个人 Alice 的 Subject 可能有两个委托人:一个将她驾驶执照上的名字“Alice Bar”绑定到 Subject,另一个绑定“999-99-9999” ,她的学生证上的号码,到Subject。两个 Principal 都引用相同的 Subject,尽管每个 Principal 的名称不同。

Subject 也可能拥有与安全相关的属性,这些属性被称为凭证。需要特殊保护的敏感凭据(例如私人加密密钥)存储在私人凭据 Set 中。用于共享的凭据(例如公钥证书或 Kerberos 服务票证)存储在公共凭据 Set 中。访问和修改不同的凭证集需要不同的权限。

要检索与 Subject 关联的所有主体,请调用 getPrincipals 方法。要检索属于 Subject 的所有公共或私有凭证,请分别调用 getPublicCredentials 方法或 getPrivateCredentials 方法。要修改返回的 Set of Principals 和凭据,请使用 Set 类中定义的方法。例如:

Subject 类实现了 Serializable。虽然与 Subject 关联的主体被序列化,但与 Subject 关联的凭据没有。请注意,java.security.Principal 类未实现 Serializable。因此,与 Subjects 关联的所有具体 Principal 实现都必须实现 Serializable

LoginModule 官方描述

身份验证技术提供商的服务提供者接口。 LoginModules 在应用程序下插入以提供特定类型的身份验证。

当应用程序写入 LoginContext API 时,身份验证技术提供商会实现 LoginModule 接口。 Configuration 指定要与特定登录应用程序一起使用的登录模块。因此,可以在应用程序下插入不同的登录模块,而无需对应用程序本身进行任何修改。

LoginContext 负责读取 Configuration 并实例化适当的登录模块。每个 LoginModule 都使用 SubjectCallbackHandler 、共享 LoginModule 状态和特定于 LoginModule 的选项进行初始化。

Subject 表示当前正在验证的 Subject,如果验证成功,则会使用相关凭证进行更新。 LoginModules 使用CallbackHandler 与用户进行通信。例如,CallbackHandler 可用于提示输入用户名和密码。请注意,CallbackHandler 可能是 null。绝对需要 CallbackHandler 来验证 Subject 的登录模块可能会抛出 LoginException。 LoginModule 可选择使用共享状态在它们之间共享信息或数据。

LoginModule 特定的选项表示管理员或用户在登录 Configuration 中为此 LoginModule 配置的选项。选项由 LoginModule 本身定义并控制其中的行为。例如,LoginModule 可以定义支持调试/测试功能的选项。选项使用键值语法定义,例如调试=真LoginModule 将选项存储为 Map,以便可以使用密钥检索值。请注意,LoginModule 选择定义的选项数量没有限制。

调用应用程序将身份验证过程视为单个操作。然而,LoginModule 中的身份验证过程分两个不同的阶段进行。在第一阶段,LoginModule 的 login 方法被 LoginContext 的 login 方法调用。 LoginModulelogin 方法随后执行实际身份验证(例如提示并验证密码)并将其身份验证状态保存为私有状态信息。完成后,LoginModule 的 login 方法要么返回 true(如果成功)或 false(如果应该忽略),要么抛出 LoginException 以指定失败。在失败的情况下,LoginModule 不得重试身份验证或引入延迟。此类任务的责任属于应用程序。如果应用程序尝试重试身份验证,则将再次调用 LoginModule 的 login 方法。

在第二阶段,如果 LoginContext 的整体身份验证成功(相关的 REQUIRED、REQUISITE、SUFFICIENT 和 OPTIONAL LoginModules 成功),则调用 LoginModulecommit 方法。 LoginModulecommit 方法检查其私人保存的状态,以查看其自身的身份验证是否成功。如果整体 LoginContext 身份验证成功并且 LoginModule 自己的身份验证成功,则 commit 方法将相关的主体(经过身份验证的身份)和凭证(身份验证数据,例如加密密钥)与位于 LoginModule 中的 Subject 相关联。

如果 LoginContext 的整体身份验证失败(相关的 REQUIRED、REQUISITE、SUFFICIENT 和 OPTIONAL LoginModule 未成功),则调用每个 LoginModuleabort 方法。在这种情况下,LoginModule 会删除/销毁最初保存的任何身份验证状态。

注销 Subject 仅涉及一个阶段。 LoginContext 调用 LoginModule 的 logout 方法。 LoginModulelogout 方法然后执行注销过程,例如从 Subject 或记录会话信息中删除主体或凭据。

LoginModule 实现必须有一个不带参数的构造函数。这允许加载 LoginModule 的类对其进行实例化。

自定义安全认证案例

public class TestLoginModule {@Testvoid testSuccess() throws LoginException {Subject subject = new Subject();Set<Object> privateCredentials = subject.getPrivateCredentials();privateCredentials.add(new UserPrincipal("admin", "123456"));LoginContext loginContext = new LoginContext("custom",subject,null,new CustomConfiguration());loginContext.login();Subject.doAs(subject, (PrivilegedAction<?>) () -> {CustomServer.doSomething();return null;});}@Testvoid testLoginModuleAuthenticateFailed() throws LoginException {Subject subject = new Subject();Set<Object> privateCredentials = subject.getPrivateCredentials();privateCredentials.add(new UserPrincipal("hello", "123456"));LoginContext loginContext = new LoginContext("custom",subject,null,new CustomConfiguration());Assertions.assertThrows(Exception.class, loginContext::login);}@Testvoid testServerAuthenticateFailed() {Subject subject = new Subject();Set<Object> privateCredentials = subject.getPrivateCredentials();privateCredentials.add(new UserPrincipal("hello", "123456"));Assertions.assertThrows(Exception.class, () ->Subject.doAs(subject, (PrivilegedAction<?>)() -> {CustomServer.doSomething();return null;}));}public static class CustomServer {private static void doSomething() {Subject currentSubject = getCurrentSubject();Set<UserTicket> privateCredentials = currentSubject.getPrivateCredentials(UserTicket.class);for (UserTicket privateCredential : privateCredentials) {if (SecurityCenter.authenticate(privateCredential.getCredit())) {System.out.println("Doing something");return;}}throw new RuntimeException("Authenticate failed");}}private static Subject getCurrentSubject() {AccessControlContext context = AccessController.getContext();return Subject.getSubject(context);}public static class CustomConfiguration extends javax.security.auth.login.Configuration {// 模块认证时的参数private static final Map<String, String> BASIC_OPTIONS =new HashMap<>();// 自定义认证模块private static final AppConfigurationEntry LOGIN =new AppConfigurationEntry(CustomLoginModule.class.getName(),AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,BASIC_OPTIONS);// 需要认证的模块private static final AppConfigurationEntry[] SIMPLE_CONF =new AppConfigurationEntry[]{LOGIN};@Overridepublic AppConfigurationEntry[] getAppConfigurationEntry(String name) {return SIMPLE_CONF;}}public static class CustomLoginModule implements LoginModule {private Subject subject;private String credit;@Overridepublic void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {this.subject = subject;System.out.println(subject);}@Overridepublic boolean login() throws LoginException {Set<UserPrincipal> principals = subject.getPrivateCredentials(UserPrincipal.class);for (UserPrincipal principal : principals) {String signature = SecurityCenter.login(principal.getName(), principal.getPassword());if (signature != null) {credit = signature;return true;}}return false;}@Overridepublic boolean commit() throws LoginException {Set<Object> privateCredentials = subject.getPrivateCredentials();UserTicket userTicket = new UserTicket(credit);privateCredentials.add(userTicket);return true;}public boolean abort() throws LoginException {System.out.println("abort");return false;}@Overridepublic boolean logout() throws LoginException {System.out.println("logout");return true;}}public static class UserPrincipal implements Principal {private final String name;private final String password;UserPrincipal(String name, String password) {this.name = name;this.password = password;}public String getPassword() {return password;}@Overridepublic String getName() {return name;}@Overridepublic String toString() {return "UserPrincipal{" +"name='" + name + '\'' +", password='" + password + '\'' +'}';}}public static class UserTicket implements Destroyable, Refreshable {private final String credit;public UserTicket(String credit) {this.credit = credit;}public String getCredit() {return credit;}@Overridepublic boolean isCurrent() {return false;}@Overridepublic void refresh() throws RefreshFailedException {}}public static class SecurityCenter {public static Set<String> cache = new HashSet<>();private static String login(String username, String password) {if (username.equals("admin") && "123456".equals(password)) {String uuid = UUID.randomUUID().toString();cache.add(uuid);return uuid;}return null;}private static boolean authenticate(String credit) {return cache.contains(credit);}}
}

参考:

  • Java LoginModule 类官方文档: https://doc.qzxdp.cn/jdk/20/zh/api/java.base/javax/security/auth/spi/LoginModule.html

  • Java Subject 类官方文档: https://doc.qzxdp.cn/jdk/20/zh/api/java.base/javax/security/auth/Subject.html

  • Hadoop UserGroupInformation 类官方文档: https://hadoop.apache.org/docs/stable/api/org/apache/hadoop/security/UserGroupInformation.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/150596.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

在Java中,关于final、static关键字与方法的重写和继承【易错点】

在Java中&#xff0c;关于final、static关键字与方法的重写和继承【易错点】 1.final方法不能被重写2.static方法不是重写&#xff0c;而是遮蔽3.final与static的组合4.final与继承5.static与继承 1.final方法不能被重写 如果父类中的方法被声明为final&#xff0c;那么这个方法…

Codeforces Beta Round 2 B. The least round way(线性DP/数论)

题目&#xff1a; There is a square matrix n  n, consisting of non-negative integer numbers. You should find such a way on it that starts in the upper left cell of the matrix;each following cell is to the right or down from the current cell;the way ends…

Facebook对现代社交互动的影响

自2004年成立以来&#xff0c;Facebook已经成为全球最大的社交媒体平台之一&#xff0c;改变了人们的交流方式和社交互动模式。作为一个数字平台&#xff0c;Facebook不仅为用户提供了分享生活点滴的空间&#xff0c;也深刻影响了现代社交互动的各个方面。本文将探讨Facebook如…

Lesson6 Python基础语法_5

列表和元组的概念 列表、元组&#xff1a;程序员在代码中批量表示数据的方式列表和元组的大部分功能都是相同的&#xff0c;但是有一个明显的差别&#xff1a;列表可以修改&#xff0c;但是元组不能修改列表相当于散装辣条&#xff0c;元组相当于袋装辣条 列表的创建和下标访问…

网络安全-jsp绕过

一、思路(这里给出jsp的WebShell样本) 1.1 加载字节码getshell <% page import"com.sun.org.apache.bcel.internal.util.ClassLoader" %> <html> <body> <h2>BCEL字节码的JSP Webshell</h2> <%String bcelCode "$$BCEL$$$l…

Java | Leetcode Java题解之第434题字符串中的单词数

题目&#xff1a; 题解&#xff1a; class Solution {public int countSegments(String s) {int segmentCount 0;for (int i 0; i < s.length(); i) {if ((i 0 || s.charAt(i - 1) ) && s.charAt(i) ! ) {segmentCount;}}return segmentCount;} }

loadrunner个人笔记

创建场景配置&#xff1a; 两个同时 去四&#xff1a;日志、时间、模拟、其他自动事务 加一&#xff1a;首选项 1、写脚本&#xff0c;沟通官方、文件打印扫描 MFI-sw.support.gsd.imsc.sda.globalopentext.com support.casemicrofocus.com 支持资源 | Micro Focus | OpenT…

Vue3:shallowRef与shallowReactive

目录 一.shallowRef 和 shallowReactive 1.shallowRef 2.shallowReactive 二.ref 和 reactive 1. ref 2. reactive 三.各自使用场景 1.shallowRef 2.shallowReactive 3.ref 4.reactive 四.shallowRef 使用 五.shallowReactive使用 六.效果 一.shallowRef 和 shal…

多维时序 | GWO-VMD-SSA-LSTM灰狼优化变分模态分解联合麻雀优化长短期记忆网络多变量时间序列光伏功率预测(Matlab)

多维时序 | GWO-VMD-SSA-LSTM灰狼优化变分模态分解联合麻雀优化长短期记忆网络多变量时间序列光伏功率预测 目录 多维时序 | GWO-VMD-SSA-LSTM灰狼优化变分模态分解联合麻雀优化长短期记忆网络多变量时间序列光伏功率预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 …

数据结构 ——— 数组 nums 包含了从 0 到 n 的所有整数,但是其中缺失了一个,请编写代码找出缺失的整数,并且在O(N)时间内完成

目录 题目要求 代码实现 方法1&#xff08;异或法&#xff09;&#xff1a; 异或算法的时间复杂度&#xff1a; 方法2&#xff08;等差数列公式&#xff09;&#xff1a; 等差数列公式的时间复杂度&#xff1a; 题目要求 整型数组 nums 包含了从 0 到 n 的所有整数&…

C#测试调用FreeSpire.PDFViewer浏览PDF文件

Free Spire.PDFViewer是商业版Spire.PDFViewer的社区版本&#xff0c;支持以控件形式打开并查看PDf文件&#xff0c;但由于是免费版本&#xff0c;存在使用限制&#xff0c;打开的PDF文档只显示前10页内容。如果日常操作的pdf文件都不超过10页&#xff0c;可以考虑使用Free Spi…

【车联网安全】车端网络攻击及检测的框架/模型

参考标准&#xff1a; 《汽车数据安全管理若干规定&#xff08;试行&#xff09;》ISO/SAE 21434《道路车辆 网络安全工程》威胁分析和风险评估&#xff08;TARA&#xff09;ISO/DIS 24089R155法规的国标转换&#xff1a;《汽车整车信息安全技术要求》&#xff08;UN R155&…

①无需编程 独立通道 Modbus主站EtherNet/IP转ModbusRTU/ASCII工业EIP网关串口服务器

Modbus主站EtherNet/IP转ModbusRTU/ASCII工业EIP网关串口服务器https://item.taobao.com/item.htm?ftt&id743840591638 EtherNet/IP 串口网关 EtherNet/IP 转 RS485 型号 2路总线EIP网关 MS-A1-2021 4路总线EIP网关 MS-A1-2041 4路总线EIP网关&#xff08;双网口&am…

solidwork中查看装配体螺丝或零件

假设我的PETG打印件到了&#xff0c;想知道这个螺丝的型号&#xff0c;怎么办 解决办法&#xff1a; 第一步先看看有没有固定的字样 如果固定的话是不行的。需要这样做&#xff1a; 把这里给关了 接下来第二步&#xff0c;点击你想查看的螺丝 然后就会跳到零件图 可以看到直径…

【会议征稿通知】第三届图像处理、计算机视觉与机器学习国际学术会议(ICICML 2024)

第三届图像处理、计算机视觉与机器学习国际学术会议(ICICML 2024) 2024 3rd International Conference on Image Processing, Computer Vision and Machine Learning 重要信息 大会官网&#xff1a;2024 3rd International Conference on Image Processing, Computer Vision…

逆向推理+ChatGPT,让论文更具说服力

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 使用ChatGPT辅助“逆向推理”技巧&#xff0c;可以显著提升论文的质量和说服力。逆向推理从结论出发&#xff0c;倒推所需的证据和论点&#xff0c;确保整个论证过程逻辑严密且无漏洞。…

每日论文2——用于锁相环应用的0.025%直流电流失配电荷泵

《A 0.025% DC Current Mismatch Charge Pump for PLL Applications 》2021 IEEE International Midwest Symposium on Circuits and Systems (MWSCAS) The Key Lab of micro-nano electronics and system integration of Xian city, Xian 本文结构主要不同是仅用了一个OPA&…

【Linux-基础IO】文件描述符重定向原理缓冲区

文件描述符 文件描述符的概念和原理 通过上述内容&#xff0c;我们知道使用 open 系统调用打开文件时&#xff0c;系统会返回一个文件描述符。这个描述符用于后续的文件操作。 在C语言中默认会打开三个输入输出流&#xff0c;分别是stdin&#xff0c;stdout&#xff0c;stde…

算法工程师重生之第十四天(找树左下角的值 路径总和 从中序与后序遍历序列构造二叉树 )

参考文献 代码随想录 一、找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7提示: 二叉树的节…

打靶记录18——narak

靶机: https://download.vulnhub.com/ha/narak.ova 推荐使用 VM Ware 打开靶机 难度&#xff1a;中 目标&#xff1a;取得 root 权限 2 Flag 攻击方法&#xff1a; 主机发现端口扫描信息收集密码字典定制爆破密码Webdav 漏洞PUT 方法上传BF 语言解码MOTD 注入CVE-2021-3…