11 Replies Latest reply on Jan 28, 2010 5:41 PM by Leon Vet

    Enforce CRUD security by using Drools

    Leon Vet Newbie
      For a few days now i've been stuggling with an user case and i was wondering if anyone could give me some hints on how to solve it.

      The end goal is to grant CRUD permissions to an entity (especially the 'read' permission) by using a drools rulebase, without any changes to ejbql query statements.

      So far i've got an entity Department, annotated with @Restrict, an entitylistener in the orm.xml, a drools debugger class to see what objects are inserted into the working memory and a simple departmentList entityquery which returns all departments. Two users are registered, one with the role 'admin' and one with the 'user' role.

      As a test i've defined a rule to grant read access to a Department:

      rule "admins can read anything"
      when
      d : Department()
      c : PermissionCheck( target == d, action == "read", granted == false )
      Role( name == "admin" )
      then
      c.grant()
      end


      This rule works great, my admin user can execute the departmentList query and all Department entities are returned. My non-admin user get's an empty list. So far everything is fine.

      Now i want to implement a very simple restriction for my non-admin user that he can read the 'Finance' department, but nothing else. ( In the real world application this would be something along the lines of user can see department if he's an employee of this department and ....) I've added this rule:

      rule "user can see finance department"
      when
      d : Department( name == "Finance" )
      c : PermissionCheck( target == d, action == "read", granted == false )
      Role( name == "user" )
      then
      c.grant()
      end


      Now the non-admin user executes the departmentList query and nothing is returned. In the output of the drools debugger class i can see that the Finance department is inserted into the working memory ( it is also the first record in my department table ). The 'user can see finance department' rule is fired and access is granted. Great! This is what i need, but now the second department is added to the working memory and no matching rule is found, so the permissioncheck returns a NotAuthorized exception. This is also fine since the user is not allowed to read this department entity.

      The problem with this is that the execution of the departmentList query is immediately halted and the query result is empty!

      I know i can create a different departmentList statement, or use restrictions on the statement, but that is not my end goal. In the end there will be around 18 different user roles in this application ( finance, manager, employee, helpdesk, etc.. ) all with very different access to a whole host of different entities. I would really like to confine all crud security checks to a rulebase and only define crude ejbql statements ( like select all departments where customer = user.customer ) so the rules can filter the query results ( for example: "only show only departments that are descendants of the employee's department" ).


      Is there any way i can accomplish this ? Any suggestion is appreciated.


      Leon
        • 1. Re: Enforce CRUD security by using Drools
          Leon Vet Newbie

          I forgot to mention the tools i'm using, so here it is:
          Jboss 5.1.0 GA, Seam 2.2.0 GA ( with included Drools 5 ), GraniteDS 2.0.0 GA, Flex SDK 3.3

          • 2. Re: Enforce CRUD security by using Drools
            Leon Vet Newbie

            I can't believe i'm the only one trying to use (or the only one who doesn't get it ) the @postload / @read annotations to restrict loading of entities.


            I've used my own entitylistener (based on the deafult seam entitylistener) with a try / catch around the invocation of the permissionresolver during a @postload. I can catch the unauthorized error, but i can not get the entityquery to remove the entity from it's result list.


            Anybody got a tip how to handle this scenario?



            Thanks,


            Leon

            • 3. Re: Enforce CRUD security by using Drools
              Francisco Jose Peredo Noguez Master

              Leon Vet wrote on Sep 04, 2009 12:57:


              I can't believe i'm the only one trying to use (or the only one who doesn't get it ) the @postload / @read annotations to restrict loading of entities.


              restrict loading of entities? AFAIK @Postload happens after loading... and therefore seems like a really inefficient way of handling this for tables with a non-trivial number of rows.



              I've used my own entitylistener (based on the deafult seam entitylistener) with a try / catch around the invocation of the permissionresolver during a @postload. I can catch the unauthorized error, but i can not get the entityquery to remove the entity from it's result list.


              Sound likes the begining of a clever (and non scalable and inneficient) implementation of security



              Anybody got a tip how to handle this scenario?


              Use different queries.

              • 4. Re: Enforce CRUD security by using Drools
                Francisco Jose Peredo Noguez Master

                Leon Vet wrote on Aug 26, 2009 09:40:


                For a few days now i've been stuggling with an user case and i was wondering if anyone could give me some hints on how to solve it.

                The end goal is to grant CRUD permissions to an entity (especially the 'read' permission) by using a drools rulebase, without any changes to ejbql query statements.

                So far i've got an entity Department, annotated with @Restrict, an entitylistener in the orm.xml, a drools debugger class to see what objects are inserted into the working memory and a simple departmentList entityquery which returns all departments. Two users are registered, one with the role 'admin' and one with the 'user' role.



                I have exactly zero experience with Drools, but i can tell you this, unless it alters the SQL that is being sent to the database, this approach is going to bite back by giving you sluggish performance for tables with a non trivial amount of rows.

                • 5. Re: Enforce CRUD security by using Drools
                  Leon Vet Newbie
                  Francisco,

                  Thank you for looking into this problem. I understand that it´s best to create sql queries that match the required result as close as possible and additional checks on postload will be a burden on the server and performance may suffer.

                  What i want to accomplish is a solid way to protect unauthorized users reading data that was not intended for them. For example, the application sends out an e-mail with a link  to a page with personal details (e.g. ww.myapp.com/preferences?id=45).

                  I want the user to be logged in (no problem here) AND be allowed to view this entity. A sure way to do this is adding a rule that acts on a ´read´ action, as fired by the PostLoad annotation. The downside is that this rule also fires when executing an entityquery, resulting in notauthorized exceptions.


                  Sure i am overloking something here, but isn´t this the way drools rules are ment to be used ?


                  Regards,

                  Leon
                  • 6. Re: Enforce CRUD security by using Drools
                    Leon Vet Newbie
                    The main reason for using rules over sql statements are the size of our application, the number of customers and the ever changing customer requirements.

                    Our system is currently deployed on Lotus Domino, an application platform with integrated read & edit entity permission (in Domino this is called document based reader / author access), mail, data clustering and rad development tools. What is lacking is rdbms functionality like triggers, cascading deletes, rollback etc, strongly typed links between persistent data and the web based ui and it is difficult to scale performance because it is a database and web server in one, which is why i am looking into seam as a possible platform to extend the lifespan of this application.

                    All in all there are about 250 entities and +/- 18 user roles ( a user can have almost every combination of roles ), spread over several installments for different customers. Each customer has it´s own set of workflow processes, required fields, optional fields, reporting requirements, message/translation sets etc.

                    It is almost impossible to cater for all the different customer and application needs by hardcoding the needed sql statements. For every customer we´d have to develop and test over half of the sytem again. The end goal is one code base and all of the customer specific stored in separated configuration data. Currently we use an inhouse developed solution, which is working great, except for the fact that Domino does not keep track of changes in master / detail relationships. This means that whenever for example the manager of a department changes, all related security settings in every linked entity have to be changed by custom code. This is all done in nightly batch processing and a cause for problems.

                    This is where drools comes into play. I want to see if it is possible to let drools worry about the security and workflow settings by putting all these rules into rule files instead of hard coding this in sql statements ( wether or not these sql statements are in the java code or in external xml files makes no difference ) I don´t want to implement all the security restraints in different places and certainly do not want to repeat the same restrictions (which can become quite complex) in slighlty different sql statements over and over again.

                    Sorry for the long post, but i wanted to make my case somewhat clearer.


                    Leon

                    P.S. I´ve been busy with custom entitylisteners and can catch the authorization exception, but not remove the failed entity from the query result. After reading the excellent ´Seam in action´ book i still have not got the feeling that i am any closer to a satisfying solution for this specific problem.
                    • 7. Re: Enforce CRUD security by using Drools
                      Francisco Jose Peredo Noguez Master

                      Leon Vet wrote on Sep 08, 2009 21:52:


                      The main reason for using rules over sql statements are the size of our application, the number of customers and the ever changing customer requirements.


                      I see no reason for using the rules (of course I do not have a lot of experience with them, so I may be biased agaist them, but I feel like they exist only because java does not have an option to run in interpreted mode... if something like JavaRebel was included in java by default (or if you are working in Groovy), what advantages would you get from using something like Drools?. IMO none. For my systems I implemented a custom permission resolved that read permissions from a table, one permission for each possible action, easy and simple.



                      Our system is currently deployed on Lotus Domino, an application platform with integrated read & edit entity permission (in Domino this is called document based reader / author access), mail, data clustering and rad development tools. What is lacking is rdbms functionality like triggers, cascading deletes, rollback etc, strongly typed links between persistent data and the web based ui and it is difficult to scale performance because it is a database and web server in one, which is why i am looking into seam as a possible platform to extend the lifespan of this application.


                      Seems like a good idea, just drop the Drools.



                      All in all there are about 250 entities and +/- 18 user roles ( a user can have almost every combination of roles ), spread over several installments for different customers. Each customer has it´s own set of workflow processes, required fields, optional fields, reporting requirements, message/translation sets etc.


                      Sorry to hear that, I guess those roles are used for security (instead of using permissions) so that your code looks like (pseudocode):


                      if(user.is("Administrator){
                      
                      }
                      



                      instead of the much more flexible permission approach (in this approach roles are only used to group permissions, and code is always written against permissions not roles):



                      if(user.hasPermission("CanDeletePurchaseOrders"){
                      
                      }
                      





                      It is almost impossible to cater for all the different customer and application needs by hardcoding the needed sql statements. For every customer we´d have to develop and test over half of the system again. The end goal is one code base and all of the customer specific stored in separated configuration data. Currently we use an inhouse developed solution, which is working great, except for the fact that Domino does not keep track of changes in master / detail relationships. This means that whenever for example the manager of a department changes, all related security settings in every linked entity have to be changed by custom code. This is all done in nightly batch processing and a cause for problems.


                      Awful problem. Maybe Hibernate filters can help you (since they do modify the SQL that is sent to database they will not suffer from the huge performance penalties of your Drools approach, but I am not sure if will be flexible enough )



                      This is where drools comes into play. I want to see if it is possible to let drools worry about the security and workflow settings by putting all these rules into rule files instead of hard coding this in sql statements ( wether or not these sql statements are in the java code or in external xml files makes no difference ) I don´t want to implement all the security restraints in different places and certainly do not want to repeat the same restrictions (which can become quite complex) in slighlty different sql statements over and over again.

                      Sorry for the long post, but i wanted to make my case somewhat clearer.


                      Seems like a sluggish, idea, I would avoid it (seems nice, until a query that gives your all the purchase orders for all the buyers in the company (10000) needs to be filtered inside java instead of the database so that the 3 purchase orders of the current user are the only ones available to work.




                      Leon

                      P.S. I´ve been busy with custom entitylisteners and can catch the authorization exception, but not remove the failed entity from the query result. After reading the excellent ´Seam in action´ book i still have not got the feeling that i am any closer to a satisfying solution for this specific problem.


                      Yes, I can see how you can belive that, but remember, this solution will not scale, and the performace issues will it will kill you application performance (by your description of your application sounds like it deals with a fair amount of data, if it were a tiny little thing maybe this approach could be a good idea, but if not Hibernate filters, or separate queries are your only options).

                      • 8. Re: Enforce CRUD security by using Drools
                        Leon Vet Newbie

                        Francisco,


                        Thanks again for your answers. You are right about the user roles being used for security, but the intention is to assign permissions (like caneditdepartment, canapproveinvoice etc) to different userroles (admin,finance,hr,employee etc.) This way the assignment of permissions remains flexible and we are able to configure it for each customer. The persistent permission resolver in seam looks like a valid option, but i am afraid it will return us to the nightmare of having to update all the permissions when a user roles changes.


                        The attraction towards drools for me is in the centralized storage of all the security settings and the execution can be off loaded to external servers. It may be overkill or yust not feasible because of performance penalties, i yust would like to see it work for the postload operations. All the other stuff (create, update, delete and permissions) work fine with drools. Perhaps i must skip the postload restriction and add a separate permission on the entityhome.instance methods.


                        I will look into hibernate filters (does look a lot like the restrictions in an entityquery).


                        Thanks again for taking the time to help.



                        Leon

                        • 9. Re: Enforce CRUD security by using Drools
                          Francisco Jose Peredo Noguez Master

                          Leon Vet wrote on Sep 09, 2009 11:27:


                          Francisco,

                          Thanks again for your answers. You are right about the user roles being used for security, but the intention is to assign permissions (like caneditdepartment, canapproveinvoice etc) to different userroles (admin,finance,hr,employee etc.) This way the assignment of permissions remains flexible and we are able to configure it for each customer.


                          Exactly.



                          The persistent permission resolver in seam looks like a valid option, but i am afraid it will return us to the nightmare of having to update all the permissions when a user roles changes.


                          I do not see why that would happen, if you have a permission CanDoXXX for every action that  the user can do, and you group them by role (using a many2many relationship between roles and permissions) you can change what a particular roles means as much as you customer wants (you just rearrange the permissions for the role). Maybe if you explain me what limitation you seen in this approach for your particular case?



                          The attraction towards drools for me is in the centralized storage of all the security settings and the execution can be off loaded to external servers.


                          External servers? I do not get what do you mean.... what better place to store security information than the database?



                          It may be overkill or yust not feasible because of performance penalties, i yust would like to see it work for the postload operations.


                          Would be nice as an experiment, but believe me, it will kill your performance, it is just a very bad idea, I have seen similar approaches, people filtering stuff manually after it has been fetched from the database, not with Drools, but with plain java code (which btw is much faster than Drools), those systems just collapsed under load and had to be rewritten from scratch, please, avoid it like a plague.



                          All the other stuff (create, update, delete and permissions) work fine with drools. Perhaps i must skip the postload restriction and add a separate permission on the entityhome.instance methods.


                          I do not see how that will prevent you from fetching stuff that you don't really need.. can you elaborate?



                          I will look into hibernate filters (does look a lot like the restrictions in an entityquery).



                          Yes, but the difference it that filters are enforced at a lower level, so once activated there is now way to bypass them, AFAIK they are much more flexible and powerful, maybe you can somehow create a relationship between a particular hiberante filter configuration and the permisssions of the current user, that, I think would be the best solution for your problem.

                          • 10. Re: Enforce CRUD security by using Drools
                            Radu B Newbie

                            Leon, I think you are looking for an enterprise feature in a non-enterprise framework like seam.


                            As easy as seam is on doing simple stuff, you will be stuck trying to do more complex things.
                            You will not be able to find real-life examples and if you ask questions like this on the forum, you see the answer you got from Francisco (no offense):


                            External servers? Rules files? Real Enterprise and complex stuff?



                            it is just a very bad idea.

                            The problem I see is that he is right. Otherwise, in two weeks any team member from SEAM dev team would have said that security rules are not so bad and that there is at least one reason for which you want to use them... (take a look on wiki example from seam distribution and see the security algorithm. No difference on how you would have doing it 10 years ago, without seam)


                            I see the use of SEAM only in punctual projects where you have clear requirements and you will never sell the application to another customer.
                            And you don't want to use PHP or whatever else because of the Enterprise from JEE.


                            To do serious applications that you can sell and have something close to Lotus flexibility, you will need to build a platform. You expect to have different requirements from each customer. At some point, the customer will want to be able to do customizations by himself. Or you want to concentrate on developing and selling the application and let your partners do the implementation and customization (without access to source code).


                            If you did any consultancy or implementation job for medium to large accounts, you know that an enterprise application must have:



                            • flexibility to adapt database schema by each customer needs (add or remove fields and tables in the database without re-compilation)

                            • flexibility in defining security rules and restrictions

                            • flexibility in changing business rules and flows

                            • easy customizable view layer totally separated from database and business rules layer

                            • a decent visual components library (at least a lookup component...)



                            IMHO, JPA and JSF are not meant for this and do not satisfy any point from above without starting from 0 or without paying for something like Oracle ADF.


                            I suggest you take a look on Aribaweb. A framework created by a company who sells real enterprise applications.


                            Or Spring Roo, which will have cloud environments support...

                            • 11. Re: Enforce CRUD security by using Drools
                              Leon Vet Newbie

                              Radu,


                              You are 100% correct in the list of requirements for an enterprise application. I've worked on the software development team for a fortune 500 company and these are definitely must haves (and every day reality) in any large application.


                              This topic was just started to see if anyone ever tried to do the same so i don't have to reinvent the wheel. I do have high hopes for the whole cdi/weld/jee6 stack and don't mind starting from scratch with a custom security framework. I did get a tip from someone outside this forum, don't use drools to check the result from a sql query but use drools to build the query/add restrictions to the query before it is executed. Haven't tried it yet, but is seems feasible.


                              Will look into the aribaweb product. As far as flexible uis are concerned , although jsf2 looks promising, my preference goes to a flex based ui. This in combination with graniteds (type-safe remoting) and cdi could be worth while to invest some more time into.


                              Regards,


                              Leon