package org.jboss.web;
import java.util.Iterator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.ArrayList;
import java.util.Collection;
import javax.security.jacc.PolicyConfiguration;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebResourcePermission;
import javax.security.jacc.WebUserDataPermission;
import javax.security.jacc.WebRoleRefPermission;
import org.jboss.metadata.WebMetaData;
import org.jboss.metadata.WebSecurityMetaData;
import org.jboss.metadata.SecurityRoleRefMetaData;
import org.jboss.logging.Logger;
public class WebPermissionMapping
{
static Logger log = Logger.getLogger(WebPermissionMapping.class);
private static final int PREFIX = 1;
private static final int EXTENSION = 2;
private static final int DEFAULT = 3;
private static final int EXACT = 4;
public static void createPermissions(WebMetaData metaData, PolicyConfiguration pc)
throws PolicyContextException
{
HashMap patternMap = qualifyURLPatterns(metaData);
log.debug("Qualified url patterns: "+patternMap);
Iterator constraints = metaData.getSecurityContraints();
while( constraints.hasNext() )
{
WebSecurityMetaData wsmd = (WebSecurityMetaData) constraints.next();
String transport = wsmd.getTransportGuarantee();
if( wsmd.isExcluded() || wsmd.isUnchecked() )
{
Iterator resources = wsmd.getWebResources().values().iterator();
while( resources.hasNext() )
{
WebSecurityMetaData.WebResourceCollection wrc = (WebSecurityMetaData.WebResourceCollection) resources.next();
String[] httpMethods = wrc.getHttpMethods();
String[] urlPatterns = wrc.getUrlPatterns();
for(int n = 0; n < urlPatterns.length; n ++)
{
String url = urlPatterns[n];
PatternInfo info = (PatternInfo) patternMap.get(url);
if( wsmd.isExcluded() )
{
info.addExcludedMethods(httpMethods);
}
info.addTransport(transport, httpMethods);
}
}
}
else
{
Iterator resources = wsmd.getWebResources().values().iterator();
while( resources.hasNext() )
{
WebSecurityMetaData.WebResourceCollection wrc = (WebSecurityMetaData.WebResourceCollection) resources.next();
String[] httpMethods = wrc.getHttpMethods();
String[] urlPatterns = wrc.getUrlPatterns();
for(int n = 0; n < urlPatterns.length; n ++)
{
String url = urlPatterns[n];
PatternInfo info = (PatternInfo) patternMap.get(url);
Iterator roles = wsmd.getRoles().iterator();
HashSet mappedRoles = new HashSet();
while( roles.hasNext() )
{
String role = (String) roles.next();
if( role.equals("*") )
{
Iterator allRoles = metaData.getSecurityRoleNames().iterator();
while( allRoles.hasNext() )
{
role = (String) allRoles.next();
mappedRoles.add(role);
}
}
else
{
mappedRoles.add(role);
}
}
info.addRoles(mappedRoles, httpMethods);
}
}
}
}
Iterator iter = patternMap.values().iterator();
while( iter.hasNext() )
{
PatternInfo info = (PatternInfo) iter.next();
String qurl = info.getQualifiedPattern();
if( info.isOverriden == true )
{
log.debug("Dropping overriden pattern: "+info);
continue;
}
String[] httpMethods = info.getExcludedMethods();
if( httpMethods != null )
{
WebResourcePermission wrp = new WebResourcePermission(qurl, httpMethods);
WebUserDataPermission wudp = new WebUserDataPermission(qurl,
httpMethods, null);
pc.addToExcludedPolicy(wrp);
pc.addToExcludedPolicy(wudp);
}
Iterator roles = info.getRoleMethods();
while( roles.hasNext() )
{
Map.Entry roleMethods = (Map.Entry) roles.next();
String role = (String) roleMethods.getKey();
HashSet methods = (HashSet) roleMethods.getValue();
httpMethods = new String[methods.size()];
methods.toArray(httpMethods);
WebResourcePermission wrp = new WebResourcePermission(qurl, httpMethods);
pc.addToRole(role, wrp);
}
httpMethods = info.getMissingMethods();
if( httpMethods.length > 0 )
{
WebResourcePermission wrp = new WebResourcePermission(qurl, httpMethods);
pc.addToUncheckedPolicy(wrp);
}
info.getTransportMethods();
while( roles.hasNext() )
{
Map.Entry transportMethods = (Map.Entry) roles.next();
String transport = (String) transportMethods.getKey();
HashSet methods = (HashSet) transportMethods.getValue();
httpMethods = new String[methods.size()];
methods.toArray(httpMethods);
WebUserDataPermission wudp = new WebUserDataPermission(qurl, httpMethods, transport);
pc.addToUncheckedPolicy(wudp);
}
}
Set unreferencedRoles = metaData.getSecurityRoleNames();
Map servletRoleRefs = metaData.getSecurityRoleRefs();
Iterator roleRefsIter = servletRoleRefs.keySet().iterator();
while( roleRefsIter.hasNext() )
{
String servletName = (String) roleRefsIter.next();
ArrayList roleRefs = (ArrayList) servletRoleRefs.get(servletName);
for(int n = 0; n < roleRefs.size(); n ++)
{
SecurityRoleRefMetaData roleRef = (SecurityRoleRefMetaData) roleRefs.get(n);
String roleName = roleRef.getLink();
WebRoleRefPermission wrrp = new WebRoleRefPermission(servletName, roleRef.getName());
pc.addToRole(roleName, wrrp);
wrrp = new WebRoleRefPermission(servletName, roleName);
pc.addToRole(roleRef.getName(), wrrp);
unreferencedRoles.remove(roleName);
}
}
Set servletNames = metaData.getServletNames();
Iterator names = servletNames.iterator();
while( names.hasNext() )
{
String servletName = (String) names.next();
Iterator roles = unreferencedRoles.iterator();
while( roles.hasNext() )
{
String role = (String) roles.next();
WebRoleRefPermission wrrp = new WebRoleRefPermission(servletName, role);
pc.addToRole(role, wrrp);
}
}
}
static int getPatternType(String urlPattern)
{
int type = EXACT;
if( urlPattern.startsWith("*.") )
type = EXTENSION;
else if( urlPattern.startsWith("/") && urlPattern.endsWith("/*") )
type = PREFIX;
else if( urlPattern.equals("/") )
type = DEFAULT;
return type;
}
static HashMap qualifyURLPatterns(WebMetaData metaData)
{
ArrayList prefixList = new ArrayList();
ArrayList extensionList = new ArrayList();
ArrayList exactList = new ArrayList();
HashMap patternMap = new HashMap();
PatternInfo defaultInfo = null;
Iterator constraints = metaData.getSecurityContraints();
while( constraints.hasNext() )
{
WebSecurityMetaData wsmd = (WebSecurityMetaData) constraints.next();
Iterator resources = wsmd.getWebResources().values().iterator();
while( resources.hasNext() )
{
WebSecurityMetaData.WebResourceCollection wrc = (WebSecurityMetaData.WebResourceCollection) resources.next();
String[] urlPatterns = wrc.getUrlPatterns();
for(int n = 0; n < urlPatterns.length; n ++)
{
String url = urlPatterns[n];
int type = getPatternType(url);
PatternInfo info = (PatternInfo) patternMap.get(url);
if( info == null )
{
info = new PatternInfo(url, type);
patternMap.put(url, info);
switch( type )
{
case PREFIX:
prefixList.add(info);
break;
case EXTENSION:
extensionList.add(info);
break;
case EXACT:
exactList.add(info);
break;
case DEFAULT:
defaultInfo = info;
break;
}
}
}
}
}
for(int i = 0; i < prefixList.size(); i ++)
{
PatternInfo info = (PatternInfo) prefixList.get(i);
for(int j = 0; j < prefixList.size(); j ++)
{
if( i == j )
continue;
PatternInfo other = (PatternInfo) prefixList.get(j);
if( info.matches(other) )
info.addQualifier(other);
}
for(int j = 0; j < exactList.size(); j ++)
{
PatternInfo other = (PatternInfo) exactList.get(j);
if( info.matches(other) )
info.addQualifier(other);
}
}
for(int i = 0; i < extensionList.size(); i ++)
{
PatternInfo info = (PatternInfo) extensionList.get(i);
for(int j = 0; j < prefixList.size(); j ++)
{
PatternInfo other = (PatternInfo) prefixList.get(j);
{
info.addQualifier(other);
}
}
for(int j = 0; j < exactList.size(); j ++)
{
PatternInfo other = (PatternInfo) exactList.get(j);
if( info.isExtensionFor(other) )
info.addQualifier(other);
}
}
if( defaultInfo == null )
{
defaultInfo = new PatternInfo("/", DEFAULT);
patternMap.put("/", defaultInfo);
}
Iterator iter = patternMap.values().iterator();
while( iter.hasNext() )
{
PatternInfo info = (PatternInfo) iter.next();
if( info == defaultInfo )
continue;
defaultInfo.addQualifier(info);
}
return patternMap;
}
static class PatternInfo
{
static final HashMap ALL_TRANSPORTS = new HashMap();
static
{
ALL_TRANSPORTS.put("NONE", WebSecurityMetaData.ALL_HTTP_METHODS);
}
String pattern;
String qpattern;
ArrayList qualifiers = new ArrayList();
int type;
HashSet excludedMethods;
HashMap roles;
HashMap transports;
HashSet allMethods = new HashSet();
boolean isOverriden;
PatternInfo(String pattern, int type)
{
this.pattern = pattern;
this.type = type;
}
void addExcludedMethods(String[] httpMethods)
{
Collection methods = Arrays.asList(httpMethods);
if( methods.size() == 0 )
methods = WebSecurityMetaData.ALL_HTTP_METHODS;
if( excludedMethods == null )
excludedMethods = new HashSet();
excludedMethods.addAll(methods);
allMethods.addAll(methods);
}
public String[] getExcludedMethods()
{
String[] httpMethods = null;
if( excludedMethods != null )
{
httpMethods = new String[excludedMethods.size()];
excludedMethods.toArray(httpMethods);
}
return httpMethods;
}
public void addRoles(HashSet mappedRoles, String[] httpMethods)
{
Collection methods = Arrays.asList(httpMethods);
if( methods.size() == 0 )
methods = WebSecurityMetaData.ALL_HTTP_METHODS;
allMethods.addAll(methods);
if( roles == null )
roles = new HashMap();
Iterator iter = mappedRoles.iterator();
while( iter.hasNext() )
{
String role = (String) iter.next();
HashSet roleMethods = (HashSet) roles.get(role);
if( roleMethods == null )
{
roleMethods = new HashSet();
roles.put(role, roleMethods);
}
roleMethods.addAll(methods);
}
}
public Iterator getRoleMethods()
{
HashMap tmp = roles;
if( tmp == null )
tmp = new HashMap(0);
Iterator iter = tmp.entrySet().iterator();
return iter;
}
void addTransport(String transport, String[] httpMethods)
{
Collection methods = Arrays.asList(httpMethods);
if( methods.size() == 0 )
methods = WebSecurityMetaData.ALL_HTTP_METHODS;
if( transports == null )
transports = new HashMap();
HashSet transportMethods = (HashSet) transports.get(transport);
if( transportMethods == null )
{
transportMethods = new HashSet();
transports.put(transport, transportMethods);
}
transportMethods.addAll(methods);
}
public Iterator getTransportMethods()
{
HashMap tmp = transports;
if( tmp == null )
tmp = ALL_TRANSPORTS;
Iterator iter = tmp.entrySet().iterator();
return iter;
}
public String[] getMissingMethods()
{
String[] httpMethods = {};
if( allMethods.size() == 0 )
{
httpMethods = WebSecurityMetaData.ALL_HTTP_METHOD_NAMES;
}
else
{
httpMethods = WebSecurityMetaData.getMissingHttpMethods(allMethods);
}
return httpMethods;
}
void addQualifier(PatternInfo info)
{
if( qualifiers.contains(info) == false )
{
if( info.type == PREFIX && info.matches(this) )
isOverriden = true;
qualifiers.add(info);
}
}
public String getQualifiedPattern()
{
if( qpattern == null )
{
StringBuffer tmp = new StringBuffer(pattern);
for(int n = 0; n < qualifiers.size(); n ++)
{
tmp.append(':');
PatternInfo info = (PatternInfo) qualifiers.get(n);
tmp.append(info.pattern);
}
qpattern = tmp.toString();
}
return qpattern;
}
public int hashCode()
{
return pattern.hashCode();
}
public boolean equals(Object obj)
{
PatternInfo pi = (PatternInfo) obj;
return pattern.equals(pi.pattern);
}
public boolean matches(PatternInfo other)
{
int matchLength = pattern.length()-2;
boolean matches = pattern.regionMatches(0, other.pattern, 0, matchLength);
return matches;
}
public boolean isExtensionFor(PatternInfo other)
{
int offset = other.pattern.lastIndexOf('.');
int length = pattern.length() - 1;
boolean isExtensionFor = false;
if( offset > 0 )
{
isExtensionFor = pattern.regionMatches(1, other.pattern, offset, length);
}
return isExtensionFor;
}
public String toString()
{
StringBuffer tmp = new StringBuffer("PatternInfo[");
tmp.append("pattern=");
tmp.append(pattern);
tmp.append(",type=");
tmp.append(type);
tmp.append(",isOverriden=");
tmp.append(isOverriden);
tmp.append(",qualifiers=");
tmp.append(qualifiers);
tmp.append("]");
return tmp.toString();
}
}
}