13 Replies Latest reply on Jun 7, 2010 9:11 AM by Robert Raksi

    How to check 'read' permission

    Roman Timushev Newbie

      Is there any way to check if 'read' permission is granted on entity?


      I cannot write s:hasPermission(object, 'read') as it requires object to be already read. How can I do hasReadPermission(Entity.class, entityId)?

        • 1. Re: How to check 'read' permission
          Adrien Orsier Newbie

          You can grant the read permission the class itself, I think it's what you need.

          • 2. Re: How to check 'read' permission
            Roman Timushev Newbie

            No, different objects of the class can have different permissions. The example situation is the following: I have a list of object identifiers and want to display them all as a list. For those, that are readable by the current user, I want to add a link to object details page.

            • 3. Re: How to check 'read' permission
              Gavin King Master

              s:hasPermission('Account', 'read', id)

              • 4. Re: How to check 'read' permission
                Roman Timushev Newbie

                This doesn't work. It adds id itself to working memory, but doesn't add Entity with this id.
                Perhaps I will have to call EntityManager.find and catch security exceptions.

                • 5. Re: How to check 'read' permission
                  Shane Bryzak Master

                  Use PermissionMapper.filterByPermission().

                  • 6. Re: How to check 'read' permission
                    Shane Bryzak Master

                    Actually, this is wrapped by Identity so use Identity.filterByPermission() instead.

                    • 7. Re: How to check 'read' permission
                      Roman Timushev Newbie

                      As I understand, I will anyway have to load the entity before passing it to filterByPermission.
                      Perhaps, I can use RunAsOperation for that. Than there is no difference — hasPermission or filterByPermission.


                      I just was wondering if thee is a ready-to-use solution for checking read permission. I will write my own utility, no problems. Thank you anyway for your help.

                      • 8. Re: How to check 'read' permission
                        Konstantin Larionov Newbie

                        Hi!


                        So, as far as I understood, I can't query EntityManager for list of, let's say Document entities, when I do not have read permission for some of them?


                        After getting acquainted with Seam Security I thought that in this case EntityManager will return Entities with granted read permission only. But after executing several tests and reading this thread I see that exception will be thrown instead.


                        Am I right?
                        Is it possible to make EntityManager work as described in my message somehow?

                        • 9. Re: How to check 'read' permission
                          Gavin King Master

                          This is the kind of thing that Hibernate filters are used for.

                          • 10. Re: How to check 'read' permission
                            Roman Timushev Newbie

                            Hibernate filter could be a nice solution, but they are incompatible with rule-based permission.


                            The answer for Kontantin's question could be RunAsOperation. It will allow to load all entities and then filter out objects with no 'read' permission.

                            • 11. Re: How to check 'read' permission
                              Konstantin Larionov Newbie

                              Gavin King wrote on Sep 18, 2009 18:10:


                              This is the kind of thing that Hibernate filters are used for.


                              Hello Gavin


                              I just started investigating this stuff and found that it is quite difficult to understand how Hibernate Filters may be use with Seam Security.


                              I have Permission entity, which is defined as follows:




                              @Entity
                              public class Permission {
                                  @Id
                                  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
                                  private Long permissionId;
                              
                                  @PermissionUser
                                  @ManyToOne
                                  private MyUser recipientUser;
                              
                                  @PermissionRole
                                  @ManyToOne
                                  private MyRole recipientRole;
                              
                                  @PermissionTarget
                                  private String target;
                              
                                  @PermissionAction
                                  private String action;
                              
                                  @PermissionDiscriminator
                                  private String discriminator;
                              
                              ... getters and setters ...
                              
                              }





                              And Department entity:




                              @Entity
                              @Restrict
                              public class Department {
                                  @Id
                                  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
                                  private Long departmentId;
                              
                                  @Column(length = 200)
                                  private String name;
                              }





                              So, there is no connection between the Department and Permission entities.


                              Can you, please, explain, how Hibernate filters can be used in order to retrieve list of Departments with read permission granted for some user or role?


                              I checked Seam and Hibernate manual and did not find any way to define criteria on un-connected entities. All examples in these manuals are for very simple cases.


                              Is it really possible to use Hibernate Filters as you suggest?

                              • 12. Re: How to check 'read' permission
                                Konstantin Larionov Newbie

                                Roman Timushev wrote on Sep 24, 2009 19:50:


                                The answer for Kontantin's question could be RunAsOperation. It will allow to load all entities and then filter out objects with no 'read' permission.


                                Thank you, Roman. I think it should work.


                                And what about entities list paging?


                                I want to split list of entities onto several pages and let the user switch between them by pressing Next page, Previous page links.


                                So, I need to know how many Entities will be displayed for the end user taking into account all permissions.


                                Is there any way to achieve it?

                                • 13. Re: How to check 'read' permission
                                  Robert Raksi Newbie

                                  I'll share my experiences on this topic as I recently had to implement such feature in one of our products. Maybe someone more wise can shed some light on possible errors regarding the implementation and/or concept.


                                  For starters, the problem to be solved: implement read permission checks on a lower level then entity listeners/EntityQuery/drools to avoid loading of unnecessary entities.


                                  As Gavin suggested on possible way is to use hibernate filters. The benefits of this approach is that no unwanted entities are created, it's good for performance because the filtering is on database level, no changes needed in the EntityQuery. The drawback is that it's not possible (at least I don't know how) to integrate it with drools and one has to implement the permission resolver logic on database level.


                                  I started with this tutorial: How to use Hibernate filters in Seam. The tutorial does not contain example with multiple filter parameters but the xml format is deductible from the xsd. It looks like this:


                                  <persistence:parameters>
                                    <key>param1</key>
                                    <value>value1</value>
                                    <key>param2</key>
                                    <value>value2</value>
                                  </persistence:parameters>
                                  



                                  In the enabled attribute of persistence:filter I used a logic based on the actual viewId and some other stuff but any logic is possible here.


                                  As I mentioned earlier you need to implement the permission resolver logic in the database. This is the point where all hell breaks loose (great soundtrack by the way :) ).


                                  The @FilterDef's defaultCondition accepts SQL code but it does all kinds of transformations on it. Wrong. I use Oracle database and for the permission logic I needed a hierarchical query but as mentioned in this hibernate JIRA entry there are some bugs regarding hierarchical keywords. As a workaround I put the logic in a stored procedure hiding the query.
                                  Seam's default EntityIdentifierStrategy uses the someName:id format for the generated identifier but the filterdef doesn't like the colon either. As a workaround I made a custom strategy replacing the colon with a semicolon and enabling it with the @Identifier annotation on the entity. This is where I ran into this bug. Of course there are workarounds for this issue too.


                                  This little adventure took me about two days but it finally works! :)


                                  I don't know if there are better solutions for this problem, if there are please share :)


                                  Sorry for not posting actual code, I didn't have time to make a 'demo'.