001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.web.deployment;
019    
020    import java.io.File;
021    import java.io.IOException;
022    import java.net.URI;
023    import java.net.URISyntaxException;
024    import java.net.URL;
025    import java.security.Permission;
026    import java.security.PermissionCollection;
027    import java.security.Permissions;
028    import java.util.Collection;
029    import java.util.Collections;
030    import java.util.Enumeration;
031    import java.util.HashMap;
032    import java.util.HashSet;
033    import java.util.Iterator;
034    import java.util.LinkedList;
035    import java.util.Map;
036    import java.util.Set;
037    import java.util.List;
038    import java.util.ArrayList;
039    import java.util.jar.JarFile;
040    import java.util.zip.ZipEntry;
041    
042    import javax.security.jacc.WebResourcePermission;
043    import javax.security.jacc.WebRoleRefPermission;
044    import javax.security.jacc.WebUserDataPermission;
045    import javax.xml.namespace.QName;
046    
047    import org.apache.commons.logging.Log;
048    import org.apache.commons.logging.LogFactory;
049    import org.apache.geronimo.common.DeploymentException;
050    import org.apache.geronimo.deployment.util.DeploymentUtil;
051    import org.apache.geronimo.deployment.ModuleIDBuilder;
052    import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
053    import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
054    import org.apache.geronimo.deployment.xbeans.ServiceDocument;
055    import org.apache.geronimo.gbean.AbstractName;
056    import org.apache.geronimo.gbean.AbstractNameQuery;
057    import org.apache.geronimo.j2ee.deployment.EARContext;
058    import org.apache.geronimo.j2ee.deployment.Module;
059    import org.apache.geronimo.j2ee.deployment.ModuleBuilder;
060    import org.apache.geronimo.j2ee.deployment.NamingBuilder;
061    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
062    import org.apache.geronimo.kernel.Kernel;
063    import org.apache.geronimo.kernel.Naming;
064    import org.apache.geronimo.kernel.config.ConfigurationModuleType;
065    import org.apache.geronimo.kernel.config.ConfigurationStore;
066    import org.apache.geronimo.kernel.repository.Artifact;
067    import org.apache.geronimo.kernel.repository.Environment;
068    import org.apache.geronimo.kernel.repository.ImportType;
069    import org.apache.geronimo.security.jacc.ComponentPermissions;
070    import org.apache.geronimo.security.util.URLPattern;
071    import org.apache.geronimo.xbeans.j2ee.FilterMappingType;
072    import org.apache.geronimo.xbeans.j2ee.HttpMethodType;
073    import org.apache.geronimo.xbeans.j2ee.RoleNameType;
074    import org.apache.geronimo.xbeans.j2ee.SecurityConstraintType;
075    import org.apache.geronimo.xbeans.j2ee.SecurityRoleRefType;
076    import org.apache.geronimo.xbeans.j2ee.SecurityRoleType;
077    import org.apache.geronimo.xbeans.j2ee.ServletMappingType;
078    import org.apache.geronimo.xbeans.j2ee.ServletType;
079    import org.apache.geronimo.xbeans.j2ee.UrlPatternType;
080    import org.apache.geronimo.xbeans.j2ee.WebAppType;
081    import org.apache.geronimo.xbeans.j2ee.WebResourceCollectionType;
082    import org.apache.geronimo.xbeans.j2ee.WebAppDocument;
083    import org.apache.geronimo.xbeans.geronimo.j2ee.GerSecurityDocument;
084    import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter;
085    import org.apache.geronimo.schema.SchemaConversionUtils;
086    import org.apache.xmlbeans.XmlObject;
087    import org.apache.xmlbeans.XmlException;
088    import org.apache.xmlbeans.XmlCursor;
089    import org.apache.xmlbeans.XmlDocumentProperties;
090    
091    /**
092     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
093     */
094    public abstract class AbstractWebModuleBuilder implements ModuleBuilder {
095        private static final Log log = LogFactory.getLog(AbstractWebModuleBuilder.class);
096        private static final QName TAGLIB = new QName(SchemaConversionUtils.J2EE_NAMESPACE, "taglib");
097        private static final String LINE_SEP = System.getProperty("line.separator");
098    
099        protected static final AbstractNameQuery MANAGED_CONNECTION_FACTORY_PATTERN;
100        private static final AbstractNameQuery ADMIN_OBJECT_PATTERN;
101        protected static final AbstractNameQuery STATELESS_SESSION_BEAN_PATTERN;
102        protected static final AbstractNameQuery STATEFUL_SESSION_BEAN_PATTERN;
103        protected static final AbstractNameQuery ENTITY_BEAN_PATTERN;
104        protected final Kernel kernel;
105        protected final NamespaceDrivenBuilderCollection securityBuilders;
106        protected final NamespaceDrivenBuilderCollection serviceBuilders;
107        protected final ResourceEnvironmentSetter resourceEnvironmentSetter;
108    
109        protected final NamingBuilder namingBuilders;
110    
111        private static final QName SECURITY_QNAME = GerSecurityDocument.type.getDocumentElementName();
112        private static final QName SERVICE_QNAME = ServiceDocument.type.getDocumentElementName();
113    
114        /**
115         * Manifest classpath entries in a war configuration must be resolved relative to the war configuration, not the
116         * enclosing ear configuration.  Resolving relative to he war configuration using this offset produces the same
117         * effect as URI.create(module.targetPath()).resolve(mcpEntry) executed in the ear configuration.
118         */
119        private static final URI RELATIVE_MODULE_BASE_URI = URI.create("../");
120    
121        protected AbstractWebModuleBuilder(Kernel kernel, Collection securityBuilders, Collection serviceBuilders, NamingBuilder namingBuilders, ResourceEnvironmentSetter resourceEnvironmentSetter) {
122            this.kernel = kernel;
123            this.securityBuilders = new NamespaceDrivenBuilderCollection(securityBuilders);
124            this.serviceBuilders = new NamespaceDrivenBuilderCollection(serviceBuilders);
125            this.namingBuilders = namingBuilders;
126            this.resourceEnvironmentSetter = resourceEnvironmentSetter;
127        }
128    
129        static {
130            MANAGED_CONNECTION_FACTORY_PATTERN = new AbstractNameQuery(null, Collections.singletonMap(NameFactory.J2EE_TYPE, NameFactory.JCA_MANAGED_CONNECTION_FACTORY));
131            ADMIN_OBJECT_PATTERN = new AbstractNameQuery(null, Collections.singletonMap(NameFactory.J2EE_TYPE, NameFactory.JCA_ADMIN_OBJECT));
132            STATELESS_SESSION_BEAN_PATTERN = new AbstractNameQuery(null, Collections.singletonMap(NameFactory.J2EE_TYPE, NameFactory.STATELESS_SESSION_BEAN));
133            STATEFUL_SESSION_BEAN_PATTERN = new AbstractNameQuery(null, Collections.singletonMap(NameFactory.J2EE_TYPE, NameFactory.STATEFUL_SESSION_BEAN));
134            ENTITY_BEAN_PATTERN = new AbstractNameQuery(null, Collections.singletonMap(NameFactory.J2EE_TYPE, NameFactory.ENTITY_BEAN));
135    
136        }
137    
138        public NamingBuilder getNamingBuilders() {
139            return namingBuilders;
140        }
141    
142        //TODO configid these need to be converted to ReferencePatterns
143        protected Set findGBeanDependencies(EARContext earContext) {
144            Set dependencies = new HashSet();
145            dependencies.addAll(earContext.listGBeans(MANAGED_CONNECTION_FACTORY_PATTERN));
146            dependencies.addAll(earContext.listGBeans(ADMIN_OBJECT_PATTERN));
147            dependencies.addAll(earContext.listGBeans(STATELESS_SESSION_BEAN_PATTERN));
148            dependencies.addAll(earContext.listGBeans(STATEFUL_SESSION_BEAN_PATTERN));
149            dependencies.addAll(earContext.listGBeans(ENTITY_BEAN_PATTERN));
150            return dependencies;
151        }
152    
153        public Module createModule(File plan, JarFile moduleFile, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
154            return createModule(plan, moduleFile, ".", null, true, null, null, naming, idBuilder);
155        }
156    
157        public Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment environment, Object moduleContextInfo, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
158            return createModule(plan, moduleFile, targetPath, specDDUrl, false, (String) moduleContextInfo, earName, naming, idBuilder);
159        }
160    
161        protected abstract Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, boolean standAlone, String contextRoot, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException;
162    
163        /**
164         * Some servlets will have multiple url patterns.  However, webservice servlets
165         * will only have one, which is what this method is intended for.
166         *
167         * @param webApp
168         * @param contextRoot
169         * @return map of servlet names to path mapped to them.  Possibly inaccurate except for web services.
170         */
171        protected Map buildServletNameToPathMap(WebAppType webApp, String contextRoot) {
172            contextRoot = "/" + contextRoot;
173            Map map = new HashMap();
174            ServletMappingType[] servletMappings = webApp.getServletMappingArray();
175            for (int j = 0; j < servletMappings.length; j++) {
176                ServletMappingType servletMapping = servletMappings[j];
177                String servletName = servletMapping.getServletName().getStringValue().trim();
178                map.put(servletName, contextRoot + servletMapping.getUrlPattern().getStringValue().trim());
179            }
180            return map;
181        }
182    
183        protected String determineDefaultContextRoot(WebAppType webApp, boolean isStandAlone, JarFile moduleFile, String targetPath) {
184    
185            if (webApp != null && webApp.getId() != null) {
186                return webApp.getId();
187            }
188    
189            if (isStandAlone) {
190                // default configId is based on the moduleFile name
191                return trimPath(new File(moduleFile.getName()).getName());
192            }
193    
194            // default configId is based on the module uri from the application.xml
195            return trimPath(targetPath);
196        }
197    
198        private String trimPath(String path) {
199    
200            if (path == null) {
201                return null;
202            }
203    
204            if (path.endsWith(".war")) {
205                path = path.substring(0, path.length() - 4);
206            }
207            if (path.endsWith("/")) {
208                path = path.substring(0, path.length() - 1);
209            }
210    
211            return path;
212        }
213    
214        public void installModule(JarFile earFile, EARContext earContext, Module module, Collection configurationStores, ConfigurationStore targetConfigurationStore, Collection repositories) throws DeploymentException {
215            EARContext moduleContext;
216            if (module.isStandAlone()) {
217                moduleContext = earContext;
218            } else {
219                Environment environment = module.getEnvironment();
220                Artifact earConfigId = earContext.getConfigID();
221                Artifact configId = new Artifact(earConfigId.getGroupId(), earConfigId.getArtifactId() + "_" + module.getTargetPath(), earConfigId.getVersion(), "car");
222                environment.setConfigId(configId);
223                environment.addDependency(earConfigId, ImportType.ALL);
224                File configurationDir = new File(earContext.getBaseDir(), module.getTargetPath());
225                configurationDir.mkdirs();
226    
227                // construct the web app deployment context... this is the same class used by the ear context
228                try {
229                    File inPlaceConfigurationDir = null;
230                    if (null != earContext.getInPlaceConfigurationDir()) {
231                        inPlaceConfigurationDir = new File(earContext.getInPlaceConfigurationDir(), module.getTargetPath());
232                    }
233                    moduleContext = new EARContext(configurationDir,
234                            inPlaceConfigurationDir,
235                            environment,
236                            ConfigurationModuleType.WAR,
237                            module.getModuleName(),
238                            earContext);
239                } catch (DeploymentException e) {
240                    cleanupConfigurationDir(configurationDir);
241                    throw e;
242                }
243            }
244            module.setEarContext(moduleContext);
245            module.setRootEarContext(earContext);
246    
247            try {
248    
249                // add the warfile's content to the configuration
250                JarFile warFile = module.getModuleFile();
251                Enumeration entries = warFile.entries();
252                List libs = new ArrayList();
253                while (entries.hasMoreElements()) {
254                    ZipEntry entry = (ZipEntry) entries.nextElement();
255                    URI targetPath = new URI(null, entry.getName(), null);
256                    if (entry.getName().equals("WEB-INF/web.xml")) {
257                        moduleContext.addFile(targetPath, module.getOriginalSpecDD());
258                    } else if (entry.getName().startsWith("WEB-INF/lib") && entry.getName().endsWith(".jar")) {
259                        // keep a collection of all libs in the war
260                        // libs must be installed after WEB-INF/classes which must be installed after this copy phase
261                        libs.add(entry);
262                    } else {
263                        moduleContext.addFile(targetPath, warFile, entry);
264                    }
265                }
266    
267                // always add WEB-INF/classes to the classpath regardless of whether
268                // any classes exist.  This must be searched BEFORE the WEB-INF/lib jar files,
269                // per the servlet specifications.
270                moduleContext.getConfiguration().addToClassPath("WEB-INF/classes/");
271    
272                // install the libs
273                for (Iterator iterator = libs.iterator(); iterator.hasNext();) {
274                    ZipEntry entry = (ZipEntry) iterator.next();
275                    URI targetPath = new URI(null, entry.getName(), null);
276                    moduleContext.addInclude(targetPath, warFile, entry);
277                }
278    
279                // add the manifest classpath entries declared in the war to the class loader
280                // we have to explicitly add these since we are unpacking the web module
281                // and the url class loader will not pick up a manifest from an unpacked dir
282                moduleContext.addManifestClassPath(warFile, RELATIVE_MODULE_BASE_URI);
283    
284            } catch (IOException e) {
285                throw new DeploymentException("Problem deploying war", e);
286            } catch (URISyntaxException e) {
287                throw new DeploymentException("Could not construct URI for location of war entry", e);
288            } finally {
289                if (!module.isStandAlone()) {
290                    try {
291                        moduleContext.flush();
292                    } catch (IOException e) {
293                        throw new DeploymentException("Problem closing war context", e);
294                    }
295                }
296            }
297        }
298    
299        protected void addUnmappedJSPPermissions(Set securityRoles, Map rolePermissions) {
300            for (Iterator iter = securityRoles.iterator(); iter.hasNext();) {
301                String roleName = (String) iter.next();
302                addPermissionToRole(roleName, new WebRoleRefPermission("", roleName), rolePermissions);
303            }
304        }
305    
306        protected ComponentPermissions buildSpecSecurityConfig(WebAppType webApp, Set securityRoles, Map rolePermissions) {
307            Map uncheckedPatterns = new HashMap();
308            Map uncheckedResourcePatterns = new HashMap();
309            Map uncheckedUserPatterns = new HashMap();
310            Map excludedPatterns = new HashMap();
311            Map rolesPatterns = new HashMap();
312            Set allSet = new HashSet();   // == allMap.values()
313            Map allMap = new HashMap();   //uncheckedPatterns union excludedPatterns union rolesPatterns.
314    
315            SecurityConstraintType[] securityConstraintArray = webApp.getSecurityConstraintArray();
316            for (int i = 0; i < securityConstraintArray.length; i++) {
317                SecurityConstraintType securityConstraintType = securityConstraintArray[i];
318                Map currentPatterns;
319                if (securityConstraintType.isSetAuthConstraint()) {
320                    if (securityConstraintType.getAuthConstraint().getRoleNameArray().length == 0) {
321                        currentPatterns = excludedPatterns;
322                    } else {
323                        currentPatterns = rolesPatterns;
324                    }
325                } else {
326                    currentPatterns = uncheckedPatterns;
327                }
328    
329                String transport = "";
330                if (securityConstraintType.isSetUserDataConstraint()) {
331                    transport = securityConstraintType.getUserDataConstraint().getTransportGuarantee().getStringValue().trim().toUpperCase();
332                }
333    
334                WebResourceCollectionType[] webResourceCollectionTypeArray = securityConstraintType.getWebResourceCollectionArray();
335                for (int j = 0; j < webResourceCollectionTypeArray.length; j++) {
336                    WebResourceCollectionType webResourceCollectionType = webResourceCollectionTypeArray[j];
337                    UrlPatternType[] urlPatternTypeArray = webResourceCollectionType.getUrlPatternArray();
338                    for (int k = 0; k < urlPatternTypeArray.length; k++) {
339                        UrlPatternType urlPatternType = urlPatternTypeArray[k];
340                        String url = urlPatternType.getStringValue().trim();
341                        URLPattern pattern = (URLPattern) currentPatterns.get(url);
342                        if (pattern == null) {
343                            pattern = new URLPattern(url);
344                            currentPatterns.put(url, pattern);
345                        }
346    
347                        URLPattern allPattern = (URLPattern) allMap.get(url);
348                        if (allPattern == null) {
349                            allPattern = new URLPattern(url);
350                            allSet.add(allPattern);
351                            allMap.put(url, allPattern);
352                        }
353    
354                        HttpMethodType[] httpMethodTypeArray = webResourceCollectionType.getHttpMethodArray();
355                        if (httpMethodTypeArray.length == 0) {
356                            pattern.addMethod("");
357                            allPattern.addMethod("");
358                        } else {
359                            for (int l = 0; l < httpMethodTypeArray.length; l++) {
360                                HttpMethodType httpMethodType = httpMethodTypeArray[l];
361                                //TODO is trim OK?
362                                String method = httpMethodType.getStringValue().trim();
363                                pattern.addMethod(method);
364                                allPattern.addMethod(method);
365                            }
366                        }
367                        if (currentPatterns == rolesPatterns) {
368                            RoleNameType[] roleNameTypeArray = securityConstraintType.getAuthConstraint().getRoleNameArray();
369                            for (int l = 0; l < roleNameTypeArray.length; l++) {
370                                RoleNameType roleNameType = roleNameTypeArray[l];
371                                String role = roleNameType.getStringValue().trim();
372                                if (role.equals("*")) {
373                                    pattern.addAllRoles(securityRoles);
374                                } else {
375                                    pattern.addRole(role);
376                                }
377                            }
378                        }
379    
380                        pattern.setTransport(transport);
381                    }
382                }
383            }
384    
385            PermissionCollection excludedPermissions = new Permissions();
386            PermissionCollection uncheckedPermissions = new Permissions();
387    
388            Iterator iter = excludedPatterns.keySet().iterator();
389            while (iter.hasNext()) {
390                URLPattern pattern = (URLPattern) excludedPatterns.get(iter.next());
391                String name = pattern.getQualifiedPattern(allSet);
392                String actions = pattern.getMethods();
393    
394                excludedPermissions.add(new WebResourcePermission(name, actions));
395                excludedPermissions.add(new WebUserDataPermission(name, actions));
396            }
397    
398            iter = rolesPatterns.keySet().iterator();
399            while (iter.hasNext()) {
400                URLPattern pattern = (URLPattern) rolesPatterns.get(iter.next());
401                String name = pattern.getQualifiedPattern(allSet);
402                String actions = pattern.getMethods();
403                WebResourcePermission permission = new WebResourcePermission(name, actions);
404    
405                for (Iterator names = pattern.getRoles().iterator(); names.hasNext();) {
406                    String roleName = (String) names.next();
407                    addPermissionToRole(roleName, permission, rolePermissions);
408                }
409            }
410    
411            iter = uncheckedPatterns.keySet().iterator();
412            while (iter.hasNext()) {
413                URLPattern pattern = (URLPattern) uncheckedPatterns.get(iter.next());
414                String name = pattern.getQualifiedPattern(allSet);
415                String actions = pattern.getMethods();
416    
417                addOrUpdatePattern(uncheckedResourcePatterns, name, actions);
418            }
419    
420            iter = rolesPatterns.keySet().iterator();
421            while (iter.hasNext()) {
422                URLPattern pattern = (URLPattern) rolesPatterns.get(iter.next());
423                String name = pattern.getQualifiedPattern(allSet);
424                String actions = pattern.getMethodsWithTransport();
425    
426                addOrUpdatePattern(uncheckedUserPatterns, name, actions);
427            }
428    
429            iter = uncheckedPatterns.keySet().iterator();
430            while (iter.hasNext()) {
431                URLPattern pattern = (URLPattern) uncheckedPatterns.get(iter.next());
432                String name = pattern.getQualifiedPattern(allSet);
433                String actions = pattern.getMethodsWithTransport();
434    
435                addOrUpdatePattern(uncheckedUserPatterns, name, actions);
436            }
437    
438            /**
439             * A <code>WebResourcePermission</code> and a <code>WebUserDataPermission</code> must be instantiated for
440             * each <tt>url-pattern</tt> in the deployment descriptor and the default pattern "/", that is not combined
441             * by the <tt>web-resource-collection</tt> elements of the deployment descriptor with ever HTTP method
442             * value.  The permission objects must be contructed using the qualified pattern as their name and with
443             * actions defined by the subset of the HTTP methods that do not occur in combination with the pattern.
444             * The resulting permissions that must be added to the unchecked policy statements by calling the
445             * <code>addToUncheckedPolcy</code> method on the <code>PolicyConfiguration</code> object.
446             */
447            iter = allSet.iterator();
448            while (iter.hasNext()) {
449                URLPattern pattern = (URLPattern) iter.next();
450                String name = pattern.getQualifiedPattern(allSet);
451                String actions = pattern.getComplementedMethods();
452    
453                if (actions.length() == 0) {
454                    continue;
455                }
456    
457                addOrUpdatePattern(uncheckedResourcePatterns, name, actions);
458                addOrUpdatePattern(uncheckedUserPatterns, name, actions);
459            }
460    
461            URLPattern pattern = new URLPattern("/");
462            if (!allSet.contains(pattern)) {
463                String name = pattern.getQualifiedPattern(allSet);
464                String actions = pattern.getComplementedMethods();
465    
466                addOrUpdatePattern(uncheckedResourcePatterns, name, actions);
467                addOrUpdatePattern(uncheckedUserPatterns, name, actions);
468            }
469    
470            //Create the uncheckedPermissions for WebResourcePermissions
471            iter = uncheckedResourcePatterns.keySet().iterator();
472            while (iter.hasNext()) {
473                UncheckedItem item = (UncheckedItem) iter.next();
474                String actions = (String) uncheckedResourcePatterns.get(item);
475    
476                uncheckedPermissions.add(new WebResourcePermission(item.getName(), actions));
477            }
478            //Create the uncheckedPermissions for WebUserDataPermissions
479            iter = uncheckedUserPatterns.keySet().iterator();
480            while (iter.hasNext()) {
481                UncheckedItem item = (UncheckedItem) iter.next();
482                String actions = (String) uncheckedUserPatterns.get(item);
483    
484                uncheckedPermissions.add(new WebUserDataPermission(item.getName(), actions));
485            }
486    
487            return new ComponentPermissions(excludedPermissions, uncheckedPermissions, rolePermissions);
488    
489        }
490    
491        protected void addPermissionToRole(String roleName, Permission permission, Map rolePermissions) {
492            PermissionCollection permissionsForRole = (PermissionCollection) rolePermissions.get(roleName);
493            if (permissionsForRole == null) {
494                permissionsForRole = new Permissions();
495                rolePermissions.put(roleName, permissionsForRole);
496            }
497            permissionsForRole.add(permission);
498        }
499    
500        private void addOrUpdatePattern(Map patternMap, String name, String actions) {
501            UncheckedItem item = new UncheckedItem(name, actions);
502            String existingActions = (String) patternMap.get(item);
503            if (existingActions != null) {
504                patternMap.put(item, actions + "," + existingActions);
505                return;
506            }
507    
508            patternMap.put(item, actions);
509        }
510    
511        protected static Set collectRoleNames(WebAppType webApp) {
512            Set roleNames = new HashSet();
513    
514            SecurityRoleType[] securityRoles = webApp.getSecurityRoleArray();
515            for (int i = 0; i < securityRoles.length; i++) {
516                roleNames.add(securityRoles[i].getRoleName().getStringValue().trim());
517            }
518    
519            return roleNames;
520        }
521    
522        protected static void check(WebAppType webApp) throws DeploymentException {
523            checkURLPattern(webApp);
524            checkMultiplicities(webApp);
525        }
526    
527        private static void checkURLPattern(WebAppType webApp) throws DeploymentException {
528    
529            FilterMappingType[] filterMappings = webApp.getFilterMappingArray();
530            for (int i = 0; i < filterMappings.length; i++) {
531                if (filterMappings[i].isSetUrlPattern()) {
532                    checkString(filterMappings[i].getUrlPattern().getStringValue().trim());
533                }
534            }
535    
536            ServletMappingType[] servletMappings = webApp.getServletMappingArray();
537            for (int i = 0; i < servletMappings.length; i++) {
538                checkString(servletMappings[i].getUrlPattern().getStringValue().trim());
539            }
540    
541            SecurityConstraintType[] constraints = webApp.getSecurityConstraintArray();
542            for (int i = 0; i < constraints.length; i++) {
543                WebResourceCollectionType[] collections = constraints[i].getWebResourceCollectionArray();
544                for (int j = 0; j < collections.length; j++) {
545                    UrlPatternType[] patterns = collections[j].getUrlPatternArray();
546                    for (int k = 0; k < patterns.length; k++) {
547                        checkString(patterns[k].getStringValue().trim());
548                    }
549                }
550            }
551        }
552    
553        protected static void checkString(String pattern) throws DeploymentException {
554            //j2ee_1_4.xsd explicitly requires preserving all whitespace. Do not trim.
555            if (pattern.indexOf(0x0D) >= 0) throw new DeploymentException("<url-pattern> must not contain CR(#xD)");
556            if (pattern.indexOf(0x0A) >= 0) throw new DeploymentException("<url-pattern> must not contain LF(#xA)");
557        }
558    
559        private static void checkMultiplicities(WebAppType webApp) throws DeploymentException {
560            if (webApp.getSessionConfigArray().length > 1) throw new DeploymentException("Multiple <session-config> elements found");
561            if (webApp.getJspConfigArray().length > 1) throw new DeploymentException("Multiple <jsp-config> elements found");
562            if (webApp.getLoginConfigArray().length > 1) throw new DeploymentException("Multiple <login-config> elements found");
563        }
564    
565        private boolean cleanupConfigurationDir(File configurationDir)
566        {
567            LinkedList cannotBeDeletedList = new LinkedList();
568    
569            if (!DeploymentUtil.recursiveDelete(configurationDir,cannotBeDeletedList)) {
570                // Output a message to help user track down file problem
571                log.warn("Unable to delete " + cannotBeDeletedList.size() +
572                        " files while recursively deleting directory "
573                        + configurationDir + LINE_SEP +
574                        "The first file that could not be deleted was:" + LINE_SEP + "  "+
575                        ( !cannotBeDeletedList.isEmpty() ? cannotBeDeletedList.getFirst() : "") );
576                return false;
577            }
578            return true;
579        }
580    
581        protected void processRoleRefPermissions(ServletType servletType, Set securityRoles, Map rolePermissions) {
582            String servletName = servletType.getServletName().getStringValue().trim();
583            //WebRoleRefPermissions
584            SecurityRoleRefType[] securityRoleRefTypeArray = servletType.getSecurityRoleRefArray();
585            Set unmappedRoles = new HashSet(securityRoles);
586            for (int j = 0; j < securityRoleRefTypeArray.length; j++) {
587                SecurityRoleRefType securityRoleRefType = securityRoleRefTypeArray[j];
588                String roleName = securityRoleRefType.getRoleName().getStringValue().trim();
589                String roleLink = securityRoleRefType.getRoleLink().getStringValue().trim();
590                //jacc 3.1.3.2
591                /*   The name of the WebRoleRefPermission must be the servlet-name in whose
592                * context the security-role-ref is defined. The actions of the  WebRoleRefPermission
593                * must be the value of the role-name (that is the  reference), appearing in the security-role-ref.
594                * The deployment tools must  call the addToRole method on the PolicyConfiguration object to add the
595                * WebRoleRefPermission object resulting from the translation to the role
596                * identified in the role-link appearing in the security-role-ref.
597                */
598                addPermissionToRole(roleLink, new WebRoleRefPermission(servletName, roleName), rolePermissions);
599                unmappedRoles.remove(roleName);
600            }
601            for (Iterator iterator = unmappedRoles.iterator(); iterator.hasNext();) {
602                String roleName = (String) iterator.next();
603                addPermissionToRole(roleName, new WebRoleRefPermission(servletName, roleName), rolePermissions);
604            }
605    //        servletData.setAttribute("webRoleRefPermissions", webRoleRefPermissions);
606        }
607    
608        protected void buildSubstitutionGroups(XmlObject gerWebApp, boolean hasSecurityRealmName, Module module, EARContext earContext) throws DeploymentException {
609            XmlObject[] securityElements = XmlBeansUtil.selectSubstitutionGroupElements(SECURITY_QNAME, gerWebApp);
610            if (securityElements.length > 0 && !hasSecurityRealmName) {
611                throw new DeploymentException("You have supplied a security configuration for web app " + module.getName() + " but no security-realm-name to allow login");
612            }
613            securityBuilders.build(gerWebApp, earContext, module.getEarContext());
614            serviceBuilders.build(gerWebApp, earContext, module.getEarContext());
615        }
616    
617        protected static WebAppDocument convertToServletSchema(XmlObject xmlObject) throws XmlException {
618            if (WebAppDocument.type.equals(xmlObject.schemaType())) {
619                XmlBeansUtil.validateDD(xmlObject);
620                return (WebAppDocument) xmlObject;
621            }
622            XmlCursor cursor = xmlObject.newCursor();
623            try {
624                cursor.toStartDoc();
625                cursor.toFirstChild();
626                if (SchemaConversionUtils.J2EE_NAMESPACE.equals(cursor.getName().getNamespaceURI())) {
627                    XmlObject result = xmlObject.changeType(WebAppDocument.type);
628                    XmlBeansUtil.validateDD(result);
629                    return (WebAppDocument) result;
630                }
631    
632                XmlDocumentProperties xmlDocumentProperties = cursor.documentProperties();
633                String publicId = xmlDocumentProperties.getDoctypePublicId();
634                if ("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN".equals(publicId) ||
635                        "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN".equals(publicId)) {
636                    XmlCursor moveable = xmlObject.newCursor();
637                    try {
638                        moveable.toStartDoc();
639                        moveable.toFirstChild();
640                        String schemaLocationURL = "http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd";
641                        String version = "2.4";
642                        SchemaConversionUtils.convertToSchema(cursor, SchemaConversionUtils.J2EE_NAMESPACE, schemaLocationURL, version);
643                        cursor.toStartDoc();
644                        cursor.toChild(SchemaConversionUtils.J2EE_NAMESPACE, "web-app");
645                        cursor.toFirstChild();
646                        SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.J2EE_NAMESPACE, cursor, moveable);
647                        SchemaConversionUtils.convertToJNDIEnvironmentRefsGroup(SchemaConversionUtils.J2EE_NAMESPACE, cursor, moveable);
648                        cursor.push();
649                        if (cursor.toNextSibling(TAGLIB)) {
650                            cursor.toPrevSibling();
651                            moveable.toCursor(cursor);
652                            cursor.beginElement("jsp-config", SchemaConversionUtils.J2EE_NAMESPACE);
653                            while (moveable.toNextSibling(TAGLIB)) {
654                                moveable.moveXml(cursor);
655                            }
656                        }
657                        cursor.pop();
658                        do {
659                            String name = cursor.getName().getLocalPart();
660                            if ("filter".equals(name) || "servlet".equals(name) || "context-param".equals(name)) {
661                                cursor.push();
662                                cursor.toFirstChild();
663                                SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.J2EE_NAMESPACE, cursor, moveable);
664                                while (cursor.toNextSibling(SchemaConversionUtils.J2EE_NAMESPACE, "init-param")) {
665                                    cursor.push();
666                                    cursor.toFirstChild();
667                                    SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.J2EE_NAMESPACE, cursor, moveable);
668                                    cursor.pop();
669                                }
670                                cursor.pop();
671                            }
672                        } while (cursor.toNextSibling());
673                    } finally {
674                        moveable.dispose();
675                    }
676                }
677            } finally {
678                cursor.dispose();
679            }
680            XmlObject result = xmlObject.changeType(WebAppDocument.type);
681            if (result != null) {
682                XmlBeansUtil.validateDD(result);
683                return (WebAppDocument) result;
684            }
685            XmlBeansUtil.validateDD(xmlObject);
686            return (WebAppDocument) xmlObject;
687        }
688    
689        class UncheckedItem {
690            final static int NA = 0x00;
691            final static int INTEGRAL = 0x01;
692            final static int CONFIDENTIAL = 0x02;
693    
694            private int transportType = NA;
695            private String name;
696    
697            public UncheckedItem(String name, String actions) {
698                setName(name);
699                setTransportType(actions);
700            }
701    
702            public boolean equals(Object o) {
703                UncheckedItem item = (UncheckedItem) o;
704                return item.getKey().equals(this.getKey());
705            }
706    
707            public String getKey() {
708                return (name + transportType);
709            }
710    
711            public int hashCode() {
712                return getKey().hashCode();
713            }
714    
715            public String getName() {
716                return name;
717            }
718    
719            public void setName(String name) {
720                this.name = name;
721            }
722    
723            public int getTransportType() {
724                return transportType;
725            }
726    
727            public void setTransportType(String actions) {
728                String[] tokens = actions.split(":", 2);
729                if (tokens.length == 2) {
730                    if (tokens[1].equals("INTEGRAL")) {
731                        this.transportType = INTEGRAL;
732                    } else if (tokens[1].equals("CONFIDENTIAL")) {
733                        this.transportType = CONFIDENTIAL;
734                    }
735                }
736            }
737        }
738    }