`
java-mans
  • 浏览: 11710888 次
文章分类
社区版块
存档分类
最新评论

域对象的安全(Domain Object Security)

 
阅读更多

24.1.概述

请注意:2.0.0之前,Spring Security称为AcegiSecurity。老的Acegi Security提供了一个ACL模块,放在org.[acegisecurity/springsecurity].acl包下。这个老的现在已经被抛弃,并可能会在将来的Spring Security发行版中去掉。本章讨论新的ACL模块,官方推荐在Spring Security 2.0.0或更高版本中使用,它被置于org.springframework.security.acls包下。

复杂的应用常常会有需要定义访问权限——不只是在web请求和方法调用水平的控制。而是安全决议需要由“who (Authentication), where (MethodInvocation) and what (SomeDomainObject)”构成。也就是说,授权决议还要考虑方法调用中的实际域对象。

想象你正在为宠物诊所设计一个应用。你的基于Spring的应用主要有两组用户:宠物诊所的职员和客户。职员可以访问所有数据,但客户只能看到自己的客户记录。为了使这个例子更加有趣一点,你的客户可以让其它客户看他们的客户记录,例如他们"puppypreschool"的顾问或本地"Pony Club"的总裁。以Spring Security为基础,你有几个方式可以选择:

1.编写一个自己的业务方法强制安全控制。你可以从Customer域对象中获取一个有访问权限用户的集合。可以用SecurityContextHolder.getContext().getAuthentication()来访问Authentication对象。

2.编写一个AccessDecisionVoter,通过Authentication中储存的GrantedAuthority[]来控制安全检查。这意味着你的AuthenticationManager要把代表用户对域对象访问权限的GrantedAuthority[]填充到Authentication对象中去。

3.编写一个AccessDecisionVoter来强制安全控制,直接打开目标Customer域对象。这意味着你的voter需要访问DAO来获取Customer对象。它接着会访问Customer对象集合来进行安全决议。

这些方法都是合情合理的。但是,第一个方法把你的授权检查和业务代码耦合到一起了。带来的主要问题包括提高了单元测试的难度,以及Customer授权逻辑很难在其它地方重用。从Authentication中获取GrantedAuthority[]是好的,但是面对数量很大的Customers时也是不行的。如果用户访问的Customers数量可能达到5,000个(在这个例子里不大可能,但是想象如果是一个很大的Pony Club里的兽医!),构建Authentication需要耗费的内存和时间可能不是你想要的。最后一种方法,编写代码从外部直接打开Customer,可能是这3个方法里最好的一个。它成功分离了关注点,也没有滥用内存和CPU,但还是效率很低,AccessDecisionVoter和最终的业务方法都要自己来调用DAO方法来获取Customer对象。一次业务方法调用要访问两次DAO很明显也不是你想要的。另外,上面提到的每一种方法你都要自己从头来编写自己的访问控制列表(ACL)持久化和业务逻辑。

幸运地,还有另外一个选择,下面我们来讨论一下这个选择。

24.2.关键概念

Spring SecurityACL服务发布为spring-security-acl-xxx.jar。要使用Spring Security的域对象安全,你要把这个包加入到你的classpath中。

Spring Security的域对象安全以访问控制列表(ACL)为核心概念。你系统里的每个域对象都有自己的ACL,这个ACL记录了谁能或不能访问该域对象。Spring Security为你的应用带来3个主要的ACL相关能力。

·提供一条可以高效地为你所有的域对象获取ACL条目(以及修改ACL)的途径;

·提供一条在方法被调用前保证给定用户有访问你的域对象许可的途径;

·提供一条在方法被调用后保证给定用户有访问你的域对象许可的途径;

正如第一点所说,Spring SecurityACL模块的主要能力之一是提供一个高性能获取ACL的途径。这个ACL repository的能力是非常重要的,因为你系统中的每一个域对象可能有若干个访问控制条目,每个ACL又可能是从其他ACL继承而来——树型结构(这很常用,Spring Security提供了很容易使用的支持)。Spring SecurityACL模块已经很小心的考虑了设计以满足高性能的ACL检索,它利用了可插接的缓存模块,死锁最小化的数据库更新,独立于ORM框架(我们使用直接JDBC),适当的包装,以及透明的数据库更新。

数据库的设计是以ACL模块的操作为中心的,让我们来看看该模块的实现里缺省使用的4个主要数据表。下面列出在一个典型的Spring Security ACL部署中的数据表,以数据量大小排序,行数最多的在最后面:

·ACL_SID使我们能够在系统中唯一定义任何principalauthority(“SID”表示“Security IDentity”)。主键是IDSID的文字表示,以及一个表示该SIDprincipal名还是GrantedAuthority的标识。每个principalGrantedAuthority都有一个对应的记录。当在接受许可的上下文中使用的时候,SID通常被称为“接收者(recipient)”。

·ACL_CLASS使我们能够在系统中唯一定义任何域对象类。主键是ID,然后是CLASSjava类名)。每个我们想要为其存储ACL许可的类有一个记录。

·ACL_OBJECT_IDENTITY存储系统里每个域对象实例的信息。其中的列包括ID;一个到表ACL_CLASS的外键OBJECT_ID_CLASS;一个使我们知道是为哪个ACL_CLASS类实例提供信息的唯一标识OBJECT_ID_IDENTITY;父对象,一个到ACL_SID的外键OWNER_SID表示该域对象的所有者;ENTRIES_INHERITING表示是否允许ACL条目从ACL父条目继承。

·最后,ACL_ENTRY存储为每个recipient分配的权限。它的列包括一个到表ACL_OBJECT_IDENTITY的外键,recipient(例如一个到ACL_SID的外键),是否需要审计,以及一个表示许可是授予还是拒绝的“整数位掩码”(许可可能包括多个方面,如view, edit, delete)。每个recipient对每个域对象的许可都有一个记录


上一段中提到,ACL系统使用了“整数位掩码”。不要担心,你不需要知道这些数字指向的具体位移来使用ACL系统,只需要知道我们有32个开关可以打开或关闭就可以了(一个int数值4byte,共32bits)。每一个位代表一个permission,缺省地,这些permission是:读(bit 0),写(bit 1),创建(bit 2),删除(bit 3)和管理(bit 4)。如果你要使用其他permission,可以很容易的实现自己的permission实例,ACL框架的其余部分不需要具备你定义的扩展的知识,即可完成操作。

明白我们采用这种“整数位掩码”对你的系统中域对象的数量是完全没有影响这一点是很重要的。我们的permission只能使用32bit,但是你可以有数以十亿计的域对象(这也意味着会有数以十亿计的记录在ACL_OBJECT_IDENTITY表中,ACL_ENTRY表的记录则更多)。我们特别说明这一点是因为发现有些用户错误的以为我们要为每个潜在的域对象使用一个bit,这是不对的。

现在我们已经提供了一个ACL系统的基本概览,以及在表结构上看起来的样子,现在让我们来看看关键接口。关键接口列表如下:

·Acl:每一个域对象有且仅有一个ACL的对象,它内部拥有AccessControlEntry,并知道Acl的所有者。Acl不直接指向域对象,而是指向一个ObjectIdentityAcl是存储在ACL_OBJECT_IDENTITY表中的。

·AccessControlEntry:一个Acl包含多个AccessControlEntry,在ACL框架中,我们常常把它简称为ACE。每个ACE都指向一组PermissionSidAclACE可以是grantingnon-granting的,同时包含有审计的相关设置。ACE保存在ACL_ENTRY表中。

·PermissionPermission表示一个不可变的位掩码,并为位掩码机制和信息输出提供方便的功能。上面提到的5个基本的Permission(bits 0 4)包含在BasePermission类中。

·SidACL模块需要参照到principalGrantedAuthority[]Sid接口提供实际安全对象(如principal, role, group等等)和Acl中实际内容的间接联系,简称“安全身份”。普通的实现包括有PrincipalSid(在Authentication中表示一个principal)和GrantedAuthoritySid。安全身份信息放在ACL_SID表中。

·ObjectIdentityACL模块中,内部用ObjectIdentity来表示每个域对象。缺省的实现是ObjectIdentityImpl

·AclService:用于获取ObjectIdentity适用的Acl。在包含的实现(JdbcAclService)中,获取操作委派给LookupStrategyLookupStrategy为获取ACL信息提供高度优化的策略,使用批获取(BasicLookupStrategy),也支持用户实现以提供更好的性能,例如层次化查询和类似的以性能为中心的非ANSI SQL能力。

·MutableAclService:允许修改Acl以便进行持久化,如果不是为了这个可以不必使用这个接口。

请注意我们提供的AclService和相关的数据库类都是使用ANSI SQL的。因此可以工作在所有主流数据库服务器上。在编写本文的时候,已经在Hypersonic SQL, PostgreSQL, Microsoft SQL Server Oracle上测试过。

Spring Security发行包中有两个例子可以用来演示ACL模块。其一是Contacts例子,另外一个是Document ManagementSystem (DMS)。我们建议你仔细看看这些例子。

24.3.入门

要开始使用Spring SecurityACL能力,你需要把你的ACL保存在某个地方。这要通过Spring实例化一个DataSource。然后该数据源被注入到JdbcMutableAclServiceBasicLookupStrategy。后者提供了高性能的ACL获取能力,前者提供了可改变的能力。请参考发行包中任何一个例子来了解如何进行配置。你还需要往上一节中提到的四个表中填充数据(参考ACL例子看相关SQL语句)。

创建所需数据表并实例化JdbcMutableAclService后,你还要确认你的领域模型支持与Spring Security ACL包互操作。很可能ObjectIdentityImpl已经提供了足够的支持,它提供了多种可用的方式。大部分的域对象会包含一个public SerializablegetId()方法。如果返回类型是long,或者和long兼容(例如int),你就不需要烦ObjectIdentity的问题了。ACL模块的很多部分都依赖于long identifier。如果没有使用long(或intbyte等),你有机会要重新实现几个类。我们不打算在Spring Security ACL模块中支持非long identifier,因为long和所有的数据库sequence兼容,也是最为常用的identifier数据类型,同时有足够的长度支持通常的应用场景。

下面的代码展示如何创建一个Acl,或修改一个已存在的Acl

				// Prepare the information we'd like in our access control entry (ACE)
		
				ObjectIdentity oi = new ObjectIdentityImpl(Foo.class, new Long(44));
		
				Sid sid = new PrincipalSid("Samantha");
		
				Permission p = BasePermission.ADMINISTRATION;
		
				// Create or update the relevant ACL
		
				MutableAcl acl = null;
		
				try {
		
				acl = (MutableAcl) aclService.readAclById(oi);
		
				} catch (NotFoundException nfe) {
		
				acl = aclService.createAcl(oi);
		
				}
		
				// Now grant some permissions via an access control entry (ACE)
		
				acl.insertAce(acl.getEntries().length, p, sid, true);
		
				aclService.updateAcl(acl);
		

在上面的例子中,我们获取的ACL是和一个标识(identifer)为44"Foo"域对象联系在一起的。我们增加一个ACE以便一个叫"Samantha"principal"administer"该对象。除了insertAce方法,这段代码不需要再多加说明。它的第一个参数是新的ACE要插入到Acl的什么位置。上面的例子中,我们把它放到最后。最后一个参数是一个表示该ACE授权或拒绝的boolean值。大部分时候应该为授权(true),但是如果为拒绝(false),该permission会被有效的关闭。

Spring Security没有在DAOrepository中为自动创建、更新或删除ACL提供任何特别集成。你要为域对象编写像上面这样的代码。在你的业务层中使用AOP来自动集成ACL信息和你业务层操作是值得考虑的。我们发现这是一种很有效的方式。

一旦你已经使用了上面的技术来在数据库中存储一些ACL信息,下一步就是实际如何使用这些ACL信息作为你的授权决议逻辑的一部分。在这里你有好几个选择。你可以分别在方法调用前和调用后编写自己的AccessDecisionVoterAfterInvocationProvider。这些类应该使用AclService来获取相关ACL,然后调用Acl.isGranted(Permission[]permission, Sid[] sids, boolean administrativeMode)来决定是授权还是拒绝。你也可以使用我们的AclEntryVoterAclEntryAfterInvocationProviderAclEntryAfterInvocationCollectionFilteringProvider类。所有这些类都提供了基于声明的方式,运行时根据这些设定信息来进行评估,把你从编写代码中解放出来。请参考例子应用学习如何使用这些类。

转自:域对象的安全(Domain Object Security)

分享到:
评论

相关推荐

    基于Spring Security的ACL实现与扩展ppt

    Spring Security 的 ACL 实现是基于域对象(Domain Object)的,这意味着它不直接操作数据库表,而是通过处理 POJO 对象来实现权限控制。核心概念包括: 1. **OBJECT_IDENTITY**: 表示一个对象的身份,由对象的类和...

    spring security3.0.4 的acl使用例子

    例如,`@PreAuthorize("hasPermission(#domainObject, 'read')"`会检查用户是否有权读取给定的对象。 在配置文件中,你需要指定使用ACL策略。例如,你可能会有以下配置: ```xml <security:global-method-security...

    thymeleaf-extras-springsecurity-3.0-master.zip

    Finally, there is an attribute for checking authorization using Spring Security's Access Control Lists, which needs the specification of a domain object and the permissions defined on it that we are ...

    源于FLEX中的安全沙箱问题

    - **用户控制**:普通用户可以管理摄像头和麦克风设置,控制SharedObject(恭喜对象),以及使用用户信任目录。 - **网络站点控制**:通过Crossdomain.xml文件,网站可以定义其他域的访问权限。 - **作者控制**:...

    Warning! Service ro_isn needs a SELinux domain defined; please fix!.pdf

    每个安全上下文包括一个域(domain)、类别(category)、类型(type)等信息。其中,**域**是安全上下文中用于表示进程身份的部分,它决定了进程可以访问哪些资源及其权限。 #### 三、警告产生的原因 当在`init....

    AD域分页查询全部域用户数据

    "(objectClass=user)", controls); if (!results.hasMore()) { break; } List<String> users = new ArrayList(); for (int i = 0; i (); i++) { SearchResult user = results.next(); users.add(user....

    springstarter

    - **Domain Object**:应用程序中的业务对象,如用户、文章等,需要进行权限控制。 - **ACL**:存储对象的访问控制信息,包含一系列的ACE(Access Control Entry)。 - **ACE**:访问控制条目,定义了特定主体...

    操作系统安全:selinux配置语言.docx

    类型(Type)是主体(进程)运行的域(Domain),也是客体的角色。每个用户都有相应的角色,角色又与一系列域类型相关联,而域类型定义了对客体类型的访问权限。类型属性是与一组类型相关的特性,它们可以在TE规则中...

    JAVA对接AD域集成.rar

    通过Java与AD域进行集成,开发者可以构建安全、高效的企业级应用程序,确保只有经过验证的用户才能访问特定资源。 首先,了解基本概念: 1. LDAP(Lightweight Directory Access Protocol):是一种轻量级目录访问...

    Pass4side CheckPoint 156-315

    - **The related end-points domain specifies an address range**: 如果相关端点域指定了地址范围,这不会影响VoIP Domain SIP对象的添加。 - **The installed VoIP gateways specify host objects**: 即使安装的...

    selinux权限配置指南.pdf

    在当今移动和网络应用不断演进的背景下,安全管理越来越受到重视,SELinux(Security-Enhanced Linux)作为Linux的一个安全模块,被广泛应用于增强系统的安全性。本文档《selinux权限配置指南.pdf》将重点讲解...

    Acegi_使用.doc

    2. **AspectJ Join Point**:使用AspectJ来管理Domain Object实例的安全,特别适合那些不在Spring Bean容器管理范围内的对象。通过Acegi,可以对标准构造函数(如`new Person()`)进行安全控制。 3. **...

    SELinux安全工具使用详解

    **SELinux(Security-Enhanced Linux)安全工具使用详解** SELinux,全称为安全增强型Linux,是由美国国家安全局(NSA)开发的一种强制访问控制(MAC)机制,旨在提高Linux操作系统的安全性。它通过细粒度的权限...

    安全客 2019Q2.pdf

    - 探索COM(Component Object Model)对象的安全性和利用方法。 19. Datacon2019:恶意DNS流量与DGA分析 - 分析恶意DNS流量和域名生成算法(Domain Generation Algorithms, DGA)。 20. 数据分析与可视化:谁是...

    SeLinux安全模块实验报告

    SeLinux,全称Security-Enhanced Linux,是美国国家安全局(NSA)基于强制访问控制(Mandatory Access Control, MAC)原则开发的一种安全增强机制。它通过精细化的访问控制策略,限制进程仅能访问执行任务所必需的...

    selinux 学习笔记,帮助学习seLinux 使用

    TE定义了进程(domain)与文件和其他对象(object)之间的关系,限制了进程可以访问哪些对象及其可执行的操作。 2.4 Domain Transition 当进程改变其状态或与另一个进程交互时,可能会发生领域转换。这个过程受到...

    SElinux管理及应用

    2. **Security Context**:安全上下文(security context)是描述对象(如文件、进程)安全属性的元数据,包括用户(user)、角色(role)、类型(type)和等级(level)等信息,例如system_u:object_r:httpd_sys_...

Global site tag (gtag.js) - Google Analytics