7 Replies Latest reply on May 18, 2014 1:37 PM by vbchin2

    Security bypass with Subject.getSubject(AccessController.getContext()) returning null

    vbchin2

      I have written a small web application that starts and interacts with embedded infinispan (infinispan-core-7.0.0.Alpha3.jar) on JBoss EAP 6.2. The entire web app context is secured with FORM based authentication backed by a security domain based DatabaseServerLoginModule. I have a ServletContextListener that sets the SecurityManager on Context Initialization.


      The webapp security works as expected. Only allowed roles (web.xml) are permitted to access protected resources of the web app. I am also able to get the Subject by making the call:


      Subject subject = SecurityContextAssociation.getSubject();
      

       

      Based on above call, I can see the associated principals and verify that the Subject is built appropriately. But, here is where the problem lies, regardless of what role principal is tied to the Subject, the Subject is able to perform ALL operations on the Cache and the CacheManager. Upon further digging into Infinispan code, I found:

       

      1. The call Subject.getSubject(AccessController.getContext()) is made to get the subject in the APIs. The same call in my case return null.
      2. Below is the snippet of code from https://github.com/infinispan/infinispan/blob/master/core/src/main/java/org/infinispan/security/impl/AuthorizationManagerImpl.java#L48 . I see during debugging that this portion of the code is executed. But since on line #3, in snippet below the subject is null, the control jumps to #9 below which seems to permit ALL access (that is subject=null and subjectMask=0)
      3. I heard a similar concern about null return value at this post: http://stackoverflow.com/questions/16260460/subject-getsubject-always-return-null-after-jdk1-6-0-39. Perhaps relevant, please check

       

         @Override
         public void checkPermission(AuthorizationPermission perm) {
            Subject subject = Subject.getSubject(AccessController.getContext());
            Integer subjectMask = (subject == null) ? Integer.valueOf(0) : null; //ISPN-4056 subjectRoleMaskCache.get(authCacheScope, subject);
            if (subjectMask == null) {
               subjectMask = AuthorizationHelper.computeSubjectRoleMask(subject, globalConfiguration, configuration);
               //ISPN-4056 subjectRoleMaskCache.put(authCacheScope, subject, subjectMask, globalConfiguration.securityCacheTimeout(), TimeUnit.MILLISECONDS);
            }
            authzHelper.checkPermission(subject, subjectMask, perm);
         }
      

       

      Please help in figuring out where the issue lies and how to get it rectified.

        • 1. Re: Security bypass with Subject.getSubject(AccessController.getContext()) returning null
          nadirx

          Vijay, you ned to wrap your code in Subject.doAs(). The fact that the AccessControllerContext does not have a Subject associated with it is a symptom of this.

          Your interpretation of point 2 is wrong: 0 is equivalent to no permissions. ALL is Integer.MAX_VALUE.

          The Subject.doAs(subject, ...) call should be setting a SubjectDomainCombiner which associates a Subject to the current ProtectionDomain. Can you verify what DomainCombiner is active by debugging inside the Subject.getSubject() call?

          1 of 1 people found this helpful
          • 2. Re: Re: Security bypass with Subject.getSubject(AccessController.getContext()) returning null
            vbchin2

            I seem to have clearly lied, I apologize. Not wrapping any operation within Subject.doAs() results in subject being null. I was messing around with code and ended with one where I had commented the wrapping block.

             

            However the issue still remains. Now that I uncommented the Subject.doAs() block, the subject is not null and is captured as shown below. However based on the attached configuration file, the class AuthorizationManagerImpl class determines the subjectMask to be 0 in method checkPermission(AuthorizationPermission perm). From there on the control is delegated to SecurityManager to check on the permission (AuthorizationPermission.WRITE) and it succeeds.

             

            So the UserPrincipal 'vchintal' succeeds in writing despite being a 'reader', though the expectation is that he would be blocked.

             

            Any thoughts ?

            Subject:

                Principal: vchintal

                Principal: Roles(members:reader)

                Principal: CallerPrincipal(members:vchintal)

             

            @PUT
            @Path("/put")
            @Produces("application/json")
            public String put(final @QueryParam("key") String key,
                    final @QueryParam("value") String value) {
                Subject subject = SecurityContextAssociation.getSubject();
                String entry = Subject.doAs(subject, new PrivilegedAction<String>() {
                    @Override
                    public String run() {
                        Cache<String, String> cache = cm.getCache("secured");
                        return cache.putIfAbsent(key, value);
                    }
                });
                return entry;
            }
            
            • 3. Re: Re: Security bypass with Subject.getSubject(AccessController.getContext()) returning null
              nadirx

              If your security manager is granting ALL permissions to your codesource there is nothing that can be done about it

              • 4. Re: Security bypass with Subject.getSubject(AccessController.getContext()) returning null
                vbchin2

                Okay ... I take that as a hint towards having appropriate policy file for the JVM/Infinispan libraries (?). If Yes, based on this file : https://github.com/infinispan/infinispan/blob/master/core/src/main/release/etc/security.policy, how do I provide the path for the library inside of a WAR file?

                 

                Man ... thought this was going to be straightforward

                • 5. Re: Security bypass with Subject.getSubject(AccessController.getContext()) returning null
                  vbchin2

                  Tristan,

                   

                  Here is the latest update:

                  1. None of the current EAP 6.X are JEE 7 compliant and hence they do not pick up or process permissions.xml in the META-INF folder of the webapp
                  2. The only one that does is Wildfly 8.0+. It currently supports the security manager permissions in two ways (as per the documentation):
                    • With a security-manager subsystem
                    • permissions.xml in META-INF of deployments
                  3. In Wildfly one needn't register a new SecurityManager to System, you just need to enable an extension and it starts a default SecurityManager for the container which cannot be replaced later thru code

                   

                  So, despite various permutations/combinations of permissions, the writes to the cache are still going thru for a user clearly given the role of a reader. If you can think of anything else do let me know. I am attaching the project that is ready to go (apologies for the size, my maven version had issues deploying to Wildfly)

                  • 6. Re: Security bypass with Subject.getSubject(AccessController.getContext()) returning null
                    nadirx

                    Vijay,

                    if you upgrade to Infinispan 7.0.0.Alpha4 you will be able to use authorization without a Security Manager.

                     

                    Tristan

                    1 of 1 people found this helpful
                    • 7. Re: Security bypass with Subject.getSubject(AccessController.getContext()) returning null
                      vbchin2

                      Based on Tristan's last reply, Infinispan 7.0.0.Alpha4 should work in situations where dealing with the SecurityManager becomes a showstopper. Following are some of the things to be noted:

                       

                      First, give Tristan's post on Security a good reading. My infinispan.xml , in the classpath, looks like the one below strictly based on Infinispan 7.0.0.Alpha4. Now follow the steps below for your custom code :

                       

                      <?xml version="1.0" encoding="UTF-8"?>
                      <infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                          xsi:schemaLocation="urn:infinispan:config:7.0 http://www.infinispan.org/schemas/infinispan-config-7.0.xsd"
                          xmlns="urn:infinispan:config:7.0">
                      
                          <cache-container default-cache="secured">
                              <security>
                                  <authorization mapper="org.infinispan.quickstart.securecache.JAASPrincipalRoleMapper">
                                      <role name="admin" permissions="ALL" />
                                      <role name="reader" permissions="READ BULK_READ"/>
                                      <role name="writer" permissions="WRITE" />
                                      <role name="supervisor" permissions="READ WRITE EXEC" />
                                  </authorization>
                              </security>
                              <serialization/>
                              <jmx></jmx>
                              <local-cache  name="secured">
                                  <security>
                                      <authorization enabled="true" roles="admin reader writer" />
                                  </security>
                              </local-cache>
                          </cache-container>
                      </infinispan>
                      
                      
                      

                       

                      1. Make sure you get a handle on a Subject. Using JAAS in EAP 6.2, I was able to do the same with the following line
                      2. Subject subject = SecurityContextAssociation.getSubject();
                        
                      3. Run *all* of your Cache operations within the Subject.doAs block. Sample code shown below:
                        Subject.doAs(subject, new PrivilegedAction<Void>() {
                            @Override
                            public Void run() {
                                cache.putIfAbsent(key, value);
                                return null;
                            }
                        });
                        
                      4. Make sure to implement PrincipalRoleMapper for your case. In my case, using JAAS with a DatabaseServerLoginModule, I had to use a custom PrincipalRoleMapperas shown below:
                        import java.security.Principal;
                        import org.jboss.security.SimpleGroup;
                        import org.jboss.security.SimplePrincipal;
                        import java.util.Enumeration;
                        import java.util.HashSet;
                        import java.util.Set;
                        import org.infinispan.security.PrincipalRoleMapper;
                        import org.infinispan.security.PrincipalRoleMapperContext;
                        
                        public class JAASPrincipalRoleMapper implements PrincipalRoleMapper {
                            @Override
                            public Set principalToRoles(Principal principal) {
                                if(principal instanceof SimpleGroup) {
                                    SimpleGroup sg = (SimpleGroup) principal;
                                    @SuppressWarnings("rawtypes")
                                    Enumeration members = sg.members();
                                    HashSet roles = new HashSet();
                                    while(members.hasMoreElements()) {
                                        Object obj = members.nextElement();
                                        if(obj instanceof SimplePrincipal) {
                                            String role = ((SimplePrincipal) obj).getName();
                                            roles.add(role);
                                        }
                                    }
                                    return roles;
                                } else {
                                    return null;
                                }
                            }
                        
                            @Override
                            public void setContext(PrincipalRoleMapperContext context) {
                        
                            }
                        }