How to retrieve permissions from web.xml

596 Views Asked by At

I would like to know if there is a better way (without reflection) to get the java.security.Permissions for a specific URL and Role.

for example:

 boolean canAccess = SecurityController.isAllowedToAccessUrl("/pages/confirmOrders.action", Collections.singletonList(new UserPrincipal("Dave")));

would work with the following constraint (web.xml):

<security-constraint>
 <web-resource-collection>
   <web-resource-name></web-resource-name>
   <url-pattern>/pages/confirmOrders.action</url-pattern>
 </web-resource-collection>
 <auth-constraint>
   <role-name>Dave</role-name>
 </auth-constraint>

The code, I wrote bellow works well. What I don't like is that I have to use reflection to invoke getContextPolicy from DelegatingPolicy.getInstance() and invoke getPermissionsForRole from ContextPolicy.

import org.jboss.security.jacc.ContextPolicy;
import org.jboss.security.jacc.DelegatingPolicy;

import javax.security.jacc.PolicyConfigurationFactory;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebResourcePermission;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Permissions;
import java.security.Principal;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SecurityController {
  private static final Logger LOG  = Logger.getLogger(SecurityController.class.getName());

  static boolean isAllowedToAccessUrl(final String url, final List<Principal> principalRoles) {
    initializeConfigurationInService();

    boolean result = false;
    for (Principal principalRole : principalRoles) {
      try{
        final ContextPolicy contextPolicy = getContextPolicy();
        final Permissions permissions = getPermissionsFromContextPolicy(contextPolicy, principalRole.getName());
        result |= permissions.implies(new WebResourcePermission(url, new String[] {"GET","POST"}));
      }catch (Exception e){
        LOG.log(Level.SEVERE, "checkAllowed failed checking if : ", e);
      }
    }
    return result;
  }

  private static void initializeConfigurationInService() {
    try {
      final PolicyConfigurationFactory policyConfigurationFactory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
      policyConfigurationFactory.getPolicyConfiguration(PolicyContext.getContextID(), false);
    } catch (PolicyContextException | ClassNotFoundException e) {
      LOG.log(Level.INFO, "initializeConfigurationInService", e);
    }
  }

  private static Permissions getPermissionsFromContextPolicy(ContextPolicy contextPolicy, String loginName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    final Method getPermissionsForRole = contextPolicy.getClass().getDeclaredMethod("getPermissionsForRole", String.class);
    getPermissionsForRole.setAccessible(true);
    return (Permissions) getPermissionsForRole.invoke(contextPolicy, loginName);
  }


  private static ContextPolicy getContextPolicy() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    final DelegatingPolicy delegatingPolicy = DelegatingPolicy.getInstance();
    final Method getContextPolicy = delegatingPolicy.getClass().getDeclaredMethod("getContextPolicy", String.class);
    getContextPolicy.setAccessible(true);
    return (ContextPolicy) getContextPolicy.invoke(delegatingPolicy, PolicyContext.getContextID());
  }
}

I read programmatically retrieve security constraints from web.xml but found it not very useful.

Any comments, ideas are really welcome. Thanks!

2

There are 2 best solutions below

0
On

Thanks to the comment of Uux I was able to shorten my code and get rid of using reflection. I am now able to verify if a specific role is allowed to access a specific URL in my code.

workable code below:

import javax.security.jacc.WebResourcePermission;
import java.security.CodeSource;
import java.security.Policy;
import java.security.Principal;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SecurityController {
  private static final Logger LOG = Logger.getLogger(SecurityController.class.getName());

  static boolean isAllowedToAccessUrl(final String url, final List<Principal> principalRoles) {
    try {
      final CodeSource codesource = new CodeSource(null, (Certificate[]) null);
      final Principal[] principals = principalRoles.toArray(new Principal[0]);
      final ProtectionDomain domain = new ProtectionDomain(codesource, null, null, principals);
      return Policy.getPolicy().implies(domain, (new WebResourcePermission(url, new String[] {"GET", "POST"})));
    } catch (Exception e) {
      LOG.log(Level.SEVERE, "checkAllowed failed checking if : ", e);
    }
    return false;
  }
}
0
On

A similar standard method to do the 'isAllowedToAccessUrl` function is available in Java EE 8.

boolean hasAccessToWebResource(String resource, String... methods)

Checks whether the caller has access to the provided "web resource" using the given methods, as specified by section 13.8 of the Servlet specification. A caller has access if the web resource is either not protected (constrained), or when it is protected by a role and the caller is in that role.

See: SecurityContext#hasAccessToWebResource