Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
163 views
in Technique[技术] by (71.8m points)

java - How do i use the mask field in acl_entry table in Spring Security 3.1?

I use the Spring Security 3.1 ACL implementation. So based on a tutorial i have created a acl databse with the following tables:

CREATE TABLE IF NOT EXISTS `acl_class` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `class` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_uk_2` (`class`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `acl_entry` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `acl_object_identity` bigint(20) NOT NULL,
  `ace_order` int(11) NOT NULL,
  `sid` bigint(20) NOT NULL,
  `mask` int(11) NOT NULL,
  `granting` tinyint(1) NOT NULL,
  `audit_success` tinyint(1) NOT NULL,
  `audit_failure` tinyint(1) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_uk_4` (`acl_object_identity`,`ace_order`),
  KEY `foreign_fk_5` (`sid`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `acl_object_identity` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `object_id_class` bigint(20) NOT NULL,
  `object_id_identity` bigint(20) NOT NULL,
  `parent_object` bigint(20) DEFAULT NULL,
  `owner_sid` bigint(20) DEFAULT NULL,
  `entries_inheriting` tinyint(1) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_uk_3` (`object_id_class`,`object_id_identity`),
  KEY `foreign_fk_1` (`parent_object`),
  KEY `foreign_fk_3` (`owner_sid`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `acl_sid` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `principal` tinyint(1) NOT NULL,
  `sid` varchar(100) NOT NULL,
  `password` varchar(255) NOT NULL,
  `salt` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

This works fine with Anntotations like:

@PreAuthorize("hasPermission(#element, 'WRITE')")
@PostAuthorize("hasPermission(returnObject, 'READ')")

The rights "Read" and "Write" are set in the table acl_entry to the field mask. As i understood 1 means "READ", 2 means "Write", 4 means "Create", 8 means "Delete" and 16 means "Administer", because it seems to be a bitwise authentication method.

  1. Question: Do i have correctly understood the granting of rights?
  2. Question: How do i specify combined rights like "Read/Write"? Can i "set" the bit 0 (which is int 1) and 1 (which is int 2) so i get the mask value 1+2=3?

Now i have to create single entries for the "READ" and "Write" permission, that's not pretty handy.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

According to Spring Security 3.1 by PacktPub:

Unfortunately, the actual implementation of AclImpl directly compares the permission specified in our SpEL expression in our [@PostFilter] annotation, and the permission stored on the ACE in the database, without using bitwise logic. The Spring Security community is in debate about whether this is unintentional or working as intended. . .

The example in that book tries to do exactly what you're describing -- it specifies a user with a role of 3 for read/write, but the user is denied access to an object with a permission mask of 1 for read.

The solution is to write your own custom permission evaluator.

MyPermissionEvaluator.java:

public class MyPermissionEvaluator implements PermissionEvaluator {

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object requiredPermissions) {
        //some way to access your user's assigned permission mask
        int permissionMask = MyUserDetails.getMask();

        //the requiredPermissions object must be cast as a String, and then
        //converted to an integer, even though it is an integer in the ACL table
        int permissionsRequired = Integer.valueOf(requiredPermissions.toString());

        //a simple bitwise OR will identify whether the user has the required permissions
        return ((permissionMask | permissionsRequired) == permissionMask);
    }

    . . .

}

To actually use this custom permission evaluator, edit your security.xml file:

<security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="expressionHandler"/>
</security:global-method-security>

<bean id="espressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <property name="permissionEvaluator" ref="permissionEvaluator"/>
</bean>

<bean id="permissionEvaluator" class="my.project.package.MyPermissionEvaluator"/>

Finally, whenever a method or class requires a certain permission level:

@PreAuthorize("hasPermission(#this, '4')")
public void mySecuredMethod() { //some secured method
}

Now you can set the permission mask in the ACL table to whatever corresponds to your organizational needs (bitwise), and do the same in whatever way you identify each individual user's permissions. For example,

user    site_admin_bit    database_admin_bit    edit_data_bit    write_data_bit    read_data_bit
nancy        0                   1                   1                 0                1

Nancy thus has a permission mask of 13 (out of a possible 31) as stored in your user details implementation. If she tries to access an object with a permission requirement of edit_data, her permissions would be checked against a mask requirement of 4, and a bitwise OR evaluation (permissionMask | permissionsRequired == permissionMask) would evaluate to true.

This is, in my estimation, the easiest way to implement an organization-specific bitwise permissions mask (with 32 bits to play with, which should be enough, I should think). According to the referenced book, the hasPermission SpEL expression used in Spring annotations evaluates the user's permissions as a complete unit; if the user has a permission set at 3 for read/write, but the annotation only evaluates against read (1), the user will be denied access.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...