7 Replies Latest reply on Nov 6, 2014 5:33 PM by cobraflow

    ModeShape Authorization Providers and ACLs

    ma6rl

      I am looking into the different options we have for authorizing a users actions in a repository and have some questions. I have read Authentication and authorization - ModeShape 4 - Project Documentation Editor and Custom authentication providers - ModeShape 3 - Project Documentation Editor, I have also stepped through the latest source code in order to get a feel for how things work.

       

      The current requirements I have are:

       

      - Restrict Read/Write access to nodes based on a users organization, where organization is a parent node and content belonging to an organization are a hierarchy of child nodes under the organization node.

      - Restrict Read/Write access to nodes based on libraries within an organization. a node may belong to multiple libraries within an organization. Given this it will not be modeled as a hierarchy instead library id/name will be a property on node containing a list of library ids/names that the node belongs to.

      - Avoid having to create fine grained roles for each organization/library e.g. org1-read, org1-readwrite, org1-library1-read, etc ....

       

      Given these requirements the default corse-grain roles and authorization provided by ModeShape will not suffice, instead I am looking into either using a custom AuthorizationProvider, ACLs, or both. In order to determine what approach will best meet my needs I have the following questions:

       

      1. How do I package and configure a custom AuthorizationProvider when using the ModeShape 4.0 subsystem  in Wildfly. I am assuming I can not package it my my application WAR and will need to install it as a Wildfly Module, is this correct?

       

      2. Steeping through the code I can see how AuthorizationProvider implementations and ACLs are applied when determining what actions can be performed either on a specific node or on the repository as a whole but I can not determine how they are used when returning the results of the query, given this:

      a) Are AuthorizationProvider/AdvancedAuthorizationProvider implementations used to restrict the results of a query to only nodes that a user is authorized to read? If so what sort of overhead does this add to the query?

       

      b) How are ACL's used to restrict the results of a query to only nodes that a user is authorized to read and what sort of overhead does this add to the query?

       

      Many thanks in advance.

       

        • 1. Re: ModeShape Authorization Providers and ACLs
          ma6rl

          I was able to implement and configure a custom ModeShape AuthorizationProvider using Wildfly 8 and the the ModeShape 4.0 subsystem using the following steps. I am documenting the process here as I was not able to find a definitive guide on how to do this and had to pull the information from several sources as well as discover some of the steps by trial and error.

           

          1. In order to implement a custom AuthorizationProvider you need to implement the following:

          - A custom AuthenticationProvider that authenticates the user and sets a custom SecurityContext on the ExecutionContext. Have a look at JaasProvider and ServletProvider for some examples of how to do this. (I modeled my implementation after ServletProvider as I am currently using Servlet Authentication which uses the default modeshape-security realm)

          - A custom SecurityContext that implements either the AuthorizationProvider or AdvancedAuthorizationProvider interface and implements the hasPermission method with your custom authorization logic.

           

          2. I also had to provide a custom Credentials implementation because if I used any of the provided ones, one of the default AuthenticationProvider implementations would be able to log me in and my custom implementation would never be used. (Again I modeled my implementation after ServletCredentials as I am current using Servlet authentication)

           

          3. I had to package my custom AuthorizationProvider, SecurityContext and Credentials in it's own JAR file and configure it as a Wildfly module by adding it to <wildfly-home>/modules/system/layers/base/com/example/main. I also had to add a module.xml with the following configuration:

           

          <?xml version="1.0" encoding="UTF-8"?>
          <module xmlns="urn:jboss:module:1.1" name="com.example">
              <resources>
                  <resource-root path="example.jar"/>
              </resources>
              <dependencies>
                  <module name="javax.jcr"/>
                  <module name="org.modeshape.jcr.api" services="import"/>
                  <module name="org.modeshape" services="import"/>
                  <module name="org.apache.log4j"/>
                  <module name='javax.servlet.api'/>
              </dependencies>
          </module>
          
          
          
          

           

          I needed to add javax.servlet.api in order to use HttpServletRequest

           

          4. I also had to add the JAR as a provided dependency to my application (WAR) so that I could use my custom Credentials implementation. I am using maven and I did this my having separate modules for the application (WAR) and the module (JAR) and adding the JAR as a provided dependency in my applications pom.xml. I also needed to my module as a dependency in my applications jboss-deployment-structure.xml

           

          <jboss-deployment-structure>
              <deployment>
                  <dependencies>
                      <module name="javax.jcr"/>
                      <module name="org.modeshape.jcr.api" services="import"/>
                      <module name="org.modeshape" services="import"/>
                      <module name="org.apache.log4j"/>
                      <module name="com.example">
                      </module>
                  </dependencies>
              </deployment>
          </jboss-deployment-structure>
          
          
          
          

           

          5. In order to configure ModeShape to use my AuthenticationProvider I had to add the following to my standalone.xml configuration

           

          <subsystem xmlns="urn:jboss:domain:modeshape:2.0">
               <repository name="example-repo" cache-name="examplee-repo" cache-container="modeshape-example">
                   <authenticators>
                       <authenticator name="custom" classname="com.example.TestAuthenticationProvider" module="com.example"/>
                   </authenticators>
              </repository>
          </subsystem>
          
          
          
          

           

          6. I was then able to use my custom authentication and authorization providers by calling login on the repository passing in my custom TestCredentials.

           

          I am not sure if there is a simpler way and if any of the ModeShape dev's have any feedback or comments about this process it would be great to hear from them. This answers my first question form my original post but I still haven't been able to get definitive answers for my second question.

          1 of 1 people found this helpful
          • 2. Re: ModeShape Authorization Providers and ACLs
            ma6rl

            After some experimentation and digging I found a simpler way to implement a custom AuthenticationProvider and AuthorizationProvider:


            - You do not need to create a separate JBoss Module, the custom implementations can be bundled in the EAR/WAR deployment. You can configure ModeShape to access the implementations in the deployment by setting the module attribute in the above example to the runtime deployment name e.g. deployment.myapp.war (see ModeShape 4.0 Sub-System Class Loader for more information on this).

             

            - You do not need to implement custom credentials to force your authenticator to be used. You can control the order of the authenticators in the ModeShape sub-system configuration as per the example below:

             

            <subsystem xmlns="urn:jboss:domain:modeshape:2.0">

                 <repository name="example-repo" cache-name="examplee-repo" cache-container="modeshape-example">

                     <authenticators>

                         <authenticator name="custom" classname="com.example.TestAuthenticationProvider" module="com.example"/>

                         <authenticator name="jaas" classname="org.modeshape.jcr.security.JaasProvider"/>

                         <authenticator name="anonymous" classname="org.modeshape.jcr.security.AnonymousProvider"/>

                     </authenticators>

                </repository>

            </subsystem>

             

            This forces ModeShape to try the custom implementation before the default JAAS and Anonymous ones,

            • 3. Re: ModeShape Authorization Providers and ACLs
              rhauch

              Great information and example. Thanks!

              a) Are AuthorizationProvider/AdvancedAuthorizationProvider implementations used to restrict the results of a query to only nodes that a user is authorized to read? If so what sort of overhead does this add to the query?

               

              b) How are ACL's used to restrict the results of a query to only nodes that a user is authorized to read and what sort of overhead does this add to the query?

               

              Before the QueryResult object returns a node or any of its properties as part of a row, it determines whether the session can read the node using the session's normal permission checks in 4.x (the 'master' branch) and in 3.8.x, which uses both the AuthProvider/AdvAuthProvider and/or ACL checks. Note that the providers require only information that we already have about the node, so for the providers these checks do not necessarily require the node be loaded from persistent storage. But if ACLs are enabled then these checks may have to walk up the path of ancestors until an ACL is found that grants read permission, or the permission check fails. (What is required to "load" an ancestor? It basically is about 90% of the work to get the node from the Session; there are a few shortcuts we take, but for the most part it still requires materializing the node from persistent storage if it is not already in the cache. Oh, and each ACL is stored as a separate hidden child of the controlled node. This means that if there are ACLs applied to two ancestors, we might have to load one or both of those extra ACL nodes.)

               

              If the session does not have permission for the node, that corresponding row is transparently dropped from the results; the user never sees it.

               

              Hope this helps.

              • 4. Re: ModeShape Authorization Providers and ACLs
                cobraflow

                Richard,

                 

                I have tried to use the WAR module idea, but to no avail!

                 

                I am using WildFly 8.1.0.FINAL. I found the module name from the end of the standalone.xml while the server is running with the application deployed. (I assume that this is the correct name!)

                 

                I set the module name to "deployment.my_war_name-1.0-SNAPSHOT.war". This looks correct from my research!

                 

                My provider relies on my own WEB-INF/lib/MyProvider.jar and a host of others also in the WEB-INF/lib.

                 

                I get no errors/warnings at all on startup, but authentication errors when I try to connect. I have a debugger running and my classes are not even loaded.

                 

                When I create a module, it works as expected.

                 

                The reason that I need it to use the WAR classloader is that I also have to use the other jars in my web app. (Spring and SpringSecurity). There are a lot of dependencies to move these all to an external module!!!

                 

                Any ideas?

                 

                Cheers

                • 5. Re: Re: ModeShape Authorization Providers and ACLs
                  ma6rl

                  cobraflow, it looks like you have set it up correctly. I have included my configuration below in case that helps. The only difference I see is that your implementation is in a JAR in web-inf/lib and mine is is in web-inf/classes. I don' think this should matter as if my understanding of Wildfly class loading is correct the contents of web-inf/lib is treated the same as web-inf/classes.

                   

                          <subsystem xmlns="urn:jboss:domain:modeshape:2.0">
                              <repository name="app-repo" cache-name="app-repo" cache-container="modeshape" security-domain="app-security">
                                  <workspaces>
                                      <workspace name="default">
                                      </workspace>
                                  </workspaces>
                                  <authenticators>
                                      <authenticator name="custom" classname="com.example.modeshape.CustomAuthenticationProvider" module="deployment.application-0.2.0-SNAPSHOT.war"/>
                                  </authenticators>
                              </repository>
                          </subsystem>
                  
                  

                   

                  Hope this helps.

                  • 6. Re: Re: ModeShape Authorization Providers and ACLs
                    cobraflow

                    Thanks Richard.

                     

                    I shall continue on this path as it *should* work!!!

                    • 7. Re: ModeShape Authorization Providers and ACLs
                      cobraflow

                      Richard,

                       

                      Just following up on this. I now use SpringSecurity to provide an authenticator for ModeShape. The whole lot is deployed in a .WAR... and it just works!

                       

                      Thanks for your help!!