文章目录

  • 1.概述
  • 2. 概念预览
  • 3.SecurityManager应用场景
  • 2. 测试
    • 2.1 无安全测试
    • 2.2 安全测试
      • 2.1 绑定授权策略文件
  • 3. 其他java权限
  • 4.优化
  • 5.再次优化
  • 错误集锦
    • 1.1
    • 1.2

1.概述

Jaas主要负责的是 Authentication 和 Authorization。Java平台提供的认证与授权服务(Java Authentication and Authorization Service (JAAS)),能够控制代码对敏感或关键资源的访问,例如文件系统网络服务系统属性访问等,加强代码的安全性。主要包含认证与授权两部分,认证的目的在于可靠安全地确定当前是谁在执行代码,代码可以是一个应用,applet,bean,servlet;授权的目的在于确定了当前执行代码的用户有什么权限,资源是否可以进行访问

Java Authentication Authorization
Service(JAAS,Java验证和授权API)提供了灵活和可伸缩的机制来保证客户端或服务器端的Java程序。Java早期的安全框架强调的是
通过验证代码的来源和作者,保护用户避免受到下载下来的代码的攻击。JAAS强调的是通过验证谁在运行代码以及他/她的权限来保护系统面受用户的攻击。它
让你能够将一些标准的安全机制,例如Solaris NIS(网络信息服务)、Windows
NT、LDAP(轻量目录存取协议),Kerberos等通过一种通用的,可配置的方式集成到系统中。

2. 概念预览

  1. LoginContextjavax.security.auth.login包里的一个类,它描述了用于验证对象(subjects)的方法。
  2. Subject就是在某个你想去认证和分配访问权限的系统里的一个标识。一个主体(subject)可能是一个用户、一个进程或者是一台机器,它用javax.security.auth.Subject类表示。由于一个Subject可能涉及多个授权(一个网上银行密码和另一个电子邮件系统),
  3. java.security.Principal就被用作在那些关联里的标识。也就是说,该Principal接口是一个能够被用作代表某个实体、公司或者登陆ID的抽象概念。一个Subject可能包含多个Principles.
  4. Principal :当一个Subject认证成功,Principal将会关联到这个SubjectPrincipal表示Subject的身份表示,必须要实现 java.security.Principal 和 java.io.Serializable 接口。Subject section 描述了更新Principal关联到subject的方法。
  5. Credential :并不是主要的Jaas代码,任何类可以表示为Credential,并需要实现Credential的两个接口Refreshable和Destroyable。

3.SecurityManager应用场景

当运行未知的Java程序的时候,该程序可能有恶意代码(删除系统文件、重启系统等),为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时候就要启用Java安全管理器。

2. 测试

新建一个项目JavaJaasTest,路径为:/Users/lcc/IdeaProjects/JavaJaasTest

2.1 无安全测试

新建测试类 com.security.App1

public class App1 {  public static void main(String[] args) {  System.out.println(System.getProperty("java.home"));  }
}

运行结果

/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre

2.2 安全测试

新建测试类 com.security.App2

public class App2 {public static void main(String[] args) {//安装安全管理器System.setSecurityManager(new SecurityManager());System.out.println(System.getProperty("java.home"));}}

运行结果

Exception in thread "main" java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.home" "read")at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)at java.security.AccessController.checkPermission(AccessController.java:884)at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1294)at java.lang.System.getProperty(System.java:717)at com.security.App2.main(App2.java:15)

异常提示没有对java.home的读取权限,系统属性也是一种资源,与文件访问类似;默认情况下对于普通Java应用是没有安装安全管理器,在手动安装安全管理器后,如果没有为应用授权则没有任何权限,所以应用无法访问java.home系统属性。

2.1 绑定授权策略文件

授权的方式是为安全管理器绑定一个授权策略文件。由于我是在IDEA maven Java工程中直接运行main方法,所以就在工程根目录下(/Users/lcc/IdeaProjects/JavaJaasTest/demo.policy)新建一个demo.policy文件,文件内容如下:

grant  {permission java.util.PropertyPermission "java.home", "read";
};

该授权的效果是任何用户运行的任何程序都有对java.home的读权限,policy文件的具体格式请参看:

http://docs.oracle.com/javase/7/docs/technotes/guides/security/PolicyFiles.html

为安全管理器绑定policy文件的方式有两种:

  1. 在运行程序的时候加入-Djava.security.policy=demo.policy虚拟机启动参数;
  2. 执行System.setProperty(“java.security.policy”, “demo.policy”);其实两者的效果一样,都是在设置系统属性,其中demo.policy是路径,这里为了简单指定的是相对路径,绝对路径当然也没问题。再次运行程序不再抛出异常,说明程序拥有了对java.home系统属性的读取权限。
public class App3 {public static void main(String[] args) {System.setProperty("java.security.policy", "demo.policy");System.setProperty("java.security.policy", "/Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo.policy");//安装安全管理器System.setSecurityManager(new SecurityManager());System.out.println(System.getProperty("java.home"));}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

这两种方法都是可以得到正确结果的。

3. 其他java权限

在Java中权限有很多,具体可参考

http://docs.oracle.com/javase/7/docs/technotes/guides/security/spec/security-spec.doc3.html#17001

java.security.AllPermission

所有权限的集合

java.util.PropertyPermission

系统/环境属性权限

java.lang.RuntimePermission

运行时权限

java.net.SocketPermission

Socket权限

java.io.FilePermission

文件权限,包括读写,删除,执行

java.io.SerializablePermission

序列化权限

java.lang.reflect.ReflectPermission

反射权限

java.security.UnresolvedPermission

未解析的权限

java.net.NetPermission

网络权限

java.awt.AWTPermission

AWT权限

java.sql.SQLPermission

数据库sql权限

java.security.SecurityPermission

安全控制方面的权限

java.util.logging.LoggingPermission

日志控制权限

javax.net.ssl.SSLPermission

安全连接权限

javax.security.auth.AuthPermission

认证权限

javax.sound.sampled.AudioPermission

音频系统资源的访问权限

4.优化

在上述过程中虽然完成了授权,但授权的针对性不强,在程序绑定了该policy文件后,无论是哪个用户执行都将拥有java.home系统属性的读权限,现在我们希望做更加细粒度的权限控制,这里需要用到认证服务了。

认证服务有点“麻烦”,一般情况下主要都涉及到了LoginContext,LoginModule,CallbackHandler,Principal,后三者还需要开发者自己实现。这里先解释一下这几个类的作用:

  1. LoginContext:认证核心类,也是入口类,用于触发登录认证,具体的登录模块由构造方法name参数指定
  2. LoginModule:登录模块,封装具体的登录认证逻辑,如果认证失败则抛出异常,成为则向Subject中添加一个Principal
  3. CallbackHandler:回调处理器,用于搜集认证信息
  4. Principal:代表程序用户的某一身份,与其密切相关的为Subject,用于代表程序用户,而一个用户可以多种身份,授权时可以针对某用户的多个身份分别授权

下面看一个认证例子:

package com.security;import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;/*** @Author: chuanchuan.lcc* @CreateDate: 2018/12/28 PM4:30* @Version: 1.0* @Description: java类作用描述:*/
public class App4 {public static void main(String[] args) {System.setProperty("java.security.auth.login.config", "/Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo.config");System.setProperty("java.security.policy", "/Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo.policy");System.setSecurityManager(new SecurityManager());try {//创建登录上下文LoginContext context = new LoginContext("demo", new DemoCallbackHander());//进行登录,登录不成功则系统退出context.login();} catch (LoginException le) {System.err.println("Cannot create LoginContext. " + le.getMessage());System.exit(-1);} catch (SecurityException se) {System.err.println("Cannot create LoginContext. " + se.getMessage());System.exit(-1);}//访问资源System.out.println(System.getProperty("java.home"));}
}
package com.security;import java.io.IOException;import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;public class DemoCallbackHander implements CallbackHandler {@Overridepublic void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {NameCallback nameCallback = (NameCallback) callbacks[0];PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];//设置用户名与密码nameCallback.setName(getUserFromSomeWhere());passwordCallback.setPassword(getPasswordFromSomeWhere().toCharArray());}//为简单起见用户名与密码写死直接返回,真实情况可以由用户输入等具体获取public String getUserFromSomeWhere() {return "zhangsan";}public String getPasswordFromSomeWhere() {return "zhangsan";}
}
package com.security;import java.io.IOException;
import java.security.Principal;
import java.util.Iterator;
import java.util.Map;import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;public class DemoLoginModule implements LoginModule {private Subject subject;private CallbackHandler callbackHandler;private boolean success = false;private String user;private String password;public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {this.subject = subject;this.callbackHandler = callbackHandler;}public boolean login() throws LoginException {NameCallback nameCallback = new NameCallback("请输入用户名");PasswordCallback passwordCallback = new PasswordCallback("请输入密码", false);Callback[] callbacks = new Callback[]{nameCallback, passwordCallback};try {//执行回调,回调过程中获取用户名与密码callbackHandler.handle(callbacks);//得到用户名与密码user = nameCallback.getName();password = new String(passwordCallback.getPassword());} catch (IOException | UnsupportedCallbackException e) {success = false;throw new FailedLoginException("用户名或密码获取失败");}//为简单起见认证条件写死if(user.length()>3 && password.length()>3) {success = true;//认证成功}return true;}public boolean commit() throws LoginException {if(!success) {return false;} else {//如果认证成功则得subject中添加一个Principal对象//这样某身份用户就认证通过并登录了该应用,即表明了谁在执行该程序this.subject.getPrincipals().add(new DemoPrincipal(user));return true;}}public boolean abort() throws LoginException {logout();return true;}public boolean logout() throws LoginException {//退出时将相应的Principal对象从subject中移除Iterator<Principal> iter = subject.getPrincipals().iterator();while(iter.hasNext()) {Principal principal = iter.next();if(principal instanceof DemoPrincipal) {if(principal.getName().equals(user)) {iter.remove();break;}}}return true;}}
package com.security;import java.security.Principal;public class DemoPrincipal implements Principal {private String name;public DemoPrincipal(String name) {this.name = name;}@Overridepublic String getName() {return this.name;}}

使用认证服务时,需要绑定一个认证配置文件,在例子中通过System.setProperty(“java.security.auth.login.config”, “demo.config”);实现,当然也可以设置虚拟属性-Djava.security.auth.login.config=demo.config实现。配置文件内容如下:

/Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo.config

demo {com.security.DemoLoginModule required debug=true;
};

其中demo为配置名称,其内容指定了需要使用到哪登录模块(LoginModule),认证配置文件具体格式请参看:http://docs.oracle.com/javase/6/docs/technotes/guides/security/jgss/tutorials/LoginConfigFile.html

前面说到认证与授权密不可分,这里就可以说明,在创建LoginContext对象时就需要有createLoginContext.demo的认证权限,demo就是认证配置文件中的配置名称,该名称在构造LoginContext对象时指定。由于在DemoLoginModule中修改了Subject的principals集合,还需要有modifyPrincipals认证权限,所以授权策略文件内容变为:

/Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo.policy

grant  {permission javax.security.auth.AuthPermission "createLoginContext.demo";permission javax.security.auth.AuthPermission "modifyPrincipals";permission java.util.PropertyPermission "java.home", "read";
};

再次运行程序,java.home系统属性正常输出

5.再次优化

主类修改

package com.security;import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.security.Principal;
import java.security.PrivilegedAction;/*** @Author: chuanchuan.lcc* @CreateDate: 2018/12/28 PM4:47* @Version: 1.0* @Description: java类作用描述:*/
public class App5 {public static void main(String[] args) {System.setProperty("java.security.auth.login.config", "/Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo5.config");System.setProperty("java.security.policy", "/Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo5.policy");System.setSecurityManager(new SecurityManager());LoginContext context = null;try {//创建登录上下文context = new LoginContext("Demo", new DemoCallbackHander());//进行登录,登录不成功则系统退出context.login();} catch (LoginException le) {System.err.println("Cannot create LoginContext. " + le.getMessage());System.exit(-1);} catch (SecurityException se) {System.err.println("Cannot create LoginContext. " + se.getMessage());System.exit(-1);}//访问资源Subject subject = context.getSubject();System.out.println(subject);for (Principal principal : subject.getPrincipals()) {System.out.println("\t" + principal.toString());}DemoPrivilegedAction demoPrivilegedAction = new DemoPrivilegedAction();//该方法调用需要"doAsPrivileged"权限Subject.doAsPrivileged(subject, new PrivilegedAction<Object>() {@Overridepublic Object run() {System.out.println(System.getProperty("java.home"));return null;}}, null);}
}

在运行这段代码时,后台进行了以下的工作。

  1. 当初始化时,LoginContext对象首先在JAAS配置文件中找到myperson
    项,然后更具该项的内容决定该加载哪个LoginModule对象。
  2. 在登录时,LoginContext对象调用每个LoginModule对象的login()
    法。
  3. 每个login()方法进行验证操作或获得一个CallbackHandle对象。
  4. CallbackHandle对象通过使用一个或多个CallBack方法同用户进行交互
    ,获得用户输入。
  5. 向一个新的Subject对象中填入验证信息

配置

# 路径 /Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo5.configDemo {com.security.DemoLoginModule required debug=true;
};

配置

# 路径 /Users/lcc/IdeaProjects/JavaJaasTest/src/main/resources/demo5.policygrant  {permission javax.security.auth.AuthPermission "createLoginContext.Demo";permission javax.security.auth.AuthPermission "modifyPrincipals";permission javax.security.auth.AuthPermission "doAsPrivileged";
};
// JAAS 授权,授权给指定的用户或身份
grant Principal com.security.DemoPrincipal "zhangsan" {permission java.util.PropertyPermission "java.home", "read";
};

报错

Exception in thread "main" java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.home" "read")at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)at java.security.AccessController.checkPermission(AccessController.java:884)at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1294)at java.lang.System.getProperty(System.java:717)at com.security.App5$1.run(App5.java:46)at java.security.AccessController.doPrivileged(Native Method)at javax.security.auth.Subject.doAsPrivileged(Subject.java:483)at com.security.App5.main(App5.java:43)

这个原因是因为com.security.DemoPrincipal需要覆写·equals 和 hashCode方法,修改类

package com.security;import java.security.Principal;public class DemoPrincipal implements Principal {private String name;public DemoPrincipal(String name) {this.name = name;}@Overridepublic String getName() {return this.name;}public boolean equals(Object o) {if (o == null)return false;if (this == o)return true;if (!(o instanceof DemoPrincipal))return false;DemoPrincipal that = (DemoPrincipal) o;if (this.getName().equals(that.getName()))return true;return false;}public int hashCode() {return name.hashCode();}@Overridepublic String toString() {return "DemoPrincipal{" +"name='" + name + '\'' +'}';}
}

然后运行成功

主体: 主用户: DemoPrincipal{name='zhangsan'}DemoPrincipal{name='zhangsan'}
/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre

错误集锦

1.1

Cannot create LoginContext. access denied ("javax.security.auth.AuthPermission" "createLoginContext.myperson")

1.2

javax.security.auth.login.LoginException: 没有为CountFiles配置 LoginModules

参考:
https://blog.csdn.net/xiaolangfanhua/article/details/52835920
https://www.ibm.com/developerworks/cn/java/j-javaauth/
https://www.programcreek.com/java-api-examples/index.php?api=java.security.PrivilegedExceptionAction

java的Jaas授权与鉴权相关推荐

  1. 【java】java的Jaas授权与鉴权

    文章目录 1.概述 2. 概念预览 3.SecurityManager应用场景 2. 测试 2.1 无安全测试 2.2 安全测试 2.1 绑定授权策略文件 3. 其他java权限 4.优化 5.再次优 ...

  2. 【安全】java的Jaas授权与鉴权

    文章目录 1.概述 2. 概念预览 2.1 文件格式 2.2 LoginModule 2.3 flag 2.4 options 2.5 使用 3.SecurityManager应用场景 2. 测试 2 ...

  3. 【Spring Cloud Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权

    一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间这里只贴出关键部分代码的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证 ...

  4. 认证、授权、鉴权、权限控制

    目录 0x01 概念 0x02 前端-后端授权/鉴权方案 2.1 Http Basic Authentication 2.2 session-cookie 2.3 token 2.4 JWT(Json ...

  5. [Asp.Net Core]鉴权授权

    鉴权授权 为了拦截一些操作: 传统的授权方式:session/Cookies来完成: 1.在请求某个Action之前去做校验,验证当前操作者是否登录过,登录过就有权限 2.如果没有权限就跳转到登录页中 ...

  6. 钉钉企业内部应用授权免登+鉴权

    一.创建应用 在钉钉管理后台-应用开发-企业内部开发-创建应用(我们这边创建的是H5微应用) 创建好了之后,会拿到应用凭证:AgentId,AppKey,AppSecret 这三个值在开发中会用到 二 ...

  7. 注册登录鉴权以及购物车常见管理

    这里写自定义目录标题 注册鉴权以及购物车系统相关知识点 对称加密和非对称加密: **jwt**包含三部分: **登录**分为**授权和鉴权** 注册鉴权以及购物车系统相关知识点 ** 对称加密和非对称 ...

  8. 请求令牌 接口_时序图说明JWT用户认证及接口鉴权的细节

    JWT用户认证及接口鉴权的细节以及原理 一.回顾JWT的授权及鉴权流程 在笔者的上一篇文章中,已经为大家介绍了JWT以及其结构及使用方法.其授权与鉴权流程浓缩为以下两句话: 授权:使用可信用户信息(用 ...

  9. dispatch作用 react_「React系列」手把手带你撸后台系统(Redux与路由鉴权)

    [React系列]手把手带你撸后台系统(Redux与路由鉴权) 来源:https://juejin.im/post/5d9b5ddee51d45781b63b8f7 上一篇我们介绍了系统架构,这一篇将 ...

  10. 开放平台中的鉴权的实现

    转载请注明:http://blog.csdn.net/HEL_WOR/article/details/51660979 在描述鉴权和流控之前,可能需要先描述为什么需要搭建开放平台. 开放平台最先由FB ...

最新文章

  1. lstm timestep一般是多少_用LSTM中的不同时间步长预测使用keras
  2. 【转载】Linux修改文件权限
  3. 21天舞动西浦报名失败的教训:先下手为强
  4. Visual Studio 字体抗锯齿插件 Text Sharp
  5. git gui管理服务器配置文件,从 Git Gui 管理的Repository(库) 提交更改到 Bonobo服务器管理的Repository(库)...
  6. Linux Ubuntu16.04界面美化
  7. python3 虚拟环境 pip 版本_【python知识】 - Python3之PIPENV虚拟环境及封装
  8. 教你怎么使用Jmail发送匿名的邮件(不要身份认证)
  9. 高并发编程-07-JDK提供的原子类操作及原理
  10. C/C++ —— signed 与 unsigned 有符号和无符号数及其移位
  11. grafana zabbix 模板_【Grafana教程】安装Grafana并配置Zabbix数据源
  12. 项目进度管理-活动历时估算工具技术:三点估算
  13. 【教程】 如何在linux/mac下安装pascal
  14. Android图片转化黑白图片,图像二值化,生成图像二值化后的黑白图像和图像矩阵(无压缩0,1矩阵),可灵活设置二值化值域
  15. 路由器 刷rom php,路由器刷固件常用命令Openwrt 之mtd/mtd_write烧写固件
  16. Hub设备、网桥、二层交换机设备概述
  17. LeetCode 5855. 找出数组中的第 K 大整数(自定义排序函数)
  18. 易观CTO郭炜:开源,不是天才的甜点,而是勤奋者的盛宴
  19. 多态的实现机制是什么?
  20. java.sql.SQLException: The server time zone value‘xxxxxxxx‘ is unrecognized

热门文章

  1. unity 地图画格_[蛮牛译馆]UnityC#教程—六边形地图系列之创建网格(中)
  2. 西瓜播放器xgplayer的简单使用demo
  3. 用Wineskin在Mac上运行exe文件
  4. DirectX修复工具(DirectX Repair)是一款系统级工具软件,简便易用。本程序为绿色版,无需安装,可直接运行。 本程序的主要功能是检测当前系统的DirectX状态,如果发现异常
  5. 在线json解析工具 在线js解析加密混合工具
  6. jieba java_【NLP】【一】中文分词之jieba
  7. Web服务器性能压力测试工具
  8. 记录一下Android 长截屏功能
  9. axure rp10安装教程,axurerp10安装步骤
  10. 西门子s300编程实例_数控车床加工编程典型实例分析(西门子802S数控系统编程教学)...