/* * Copyright 2012 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *       http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.uberfire.security.server;import java.io.InputStream;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.HashMap;import java.util.HashSet;import java.util.List;import java.util.Map;import java.util.Set;import java.util.concurrent.ConcurrentHashMap;import org.uberfire.security.Resource;import org.uberfire.security.ResourceManager;import org.uberfire.security.Role;import org.uberfire.security.impl.RoleImpl;// BUG: CWE-264 Permissions, Privileges, and Access Controls// import org.uberfire.security.server.util.AntPathMatcher;// FIXED:import org.uberfire.commons.regex.util.AntPathMatcher;import org.yaml.snakeyaml.Yaml;import static java.util.Collections.*;import static org.uberfire.commons.validation.PortablePreconditions.checkNotNull;import static org.uberfire.commons.validation.Preconditions.*;import static org.uberfire.security.server.SecurityConstants.*;public class URLResourceManager implements ResourceManager {    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();    private static final Collection<Class<? extends Resource>> SUPPORTED_TYPES = new ArrayList<Class<? extends Resource>>( 1 ) {{        add( URLResource.class );    }};    private static final String DEFAULT_CONFIG = "exclude:\n" +            "   - /*.ico\n" +            "   - /image/**\n" +            "   - /css/**";    private String configFile = URL_FILTER_CONFIG_YAML;    private final Resources resources;    private final Set<String> excludeCache = Collections.newSetFromMap( new ConcurrentHashMap<String, Boolean>() );    public URLResourceManager( final String configFile ) {        if ( configFile != null && !configFile.isEmpty() ) {            this.configFile = configFile;        }        this.resources = loadConfigData();    }    private Resources loadConfigData() {        final Yaml yaml = new Yaml();        final InputStream stream = URLResourceManager.class.getClassLoader().getResourceAsStream( this.configFile );        final Map result;        if ( stream != null ) {            result = (Map) yaml.load( stream );        } else {            result = (Map) yaml.load( DEFAULT_CONFIG );        }        return new Resources( result );    }    @Override    public boolean supports( final Resource resource ) {        if ( resource instanceof URLResource ) {            return true;        }        return false;    }    @Override    public boolean requiresAuthentication( final Resource resource ) {        final URLResource urlResource;        try {            urlResource = checkInstanceOf( "context", resource, URLResource.class );        } catch ( IllegalArgumentException e ) {            return false;        }        if ( !excludeCache.contains( urlResource.getURL() ) ) {            boolean isExcluded = false;            for ( String excluded : resources.getExcludedResources() ) {                if ( ANT_PATH_MATCHER.match( excluded, urlResource.getURL() ) ) {                    isExcluded = true;                    excludeCache.add( urlResource.getURL() );                    break;                }            }            if ( isExcluded ) {                return false;            }        } else {            return false;        }        return true;    }    public List<Role> getMandatoryRoles( final URLResource urlResource ) {        for ( Map.Entry<String, List<Role>> activeFilteredResource : resources.getMandatoryFilteredResources().entrySet() ) {            if ( ANT_PATH_MATCHER.match( activeFilteredResource.getKey(), urlResource.getURL() ) ) {                return activeFilteredResource.getValue();            }        }        return emptyList();    }    private static class Resources {        private final Map<String, List<Role>> filteredResources;        private final Map<String, List<Role>> mandatoryFilteredResources;        private final Set<String> excludedResources;        private Resources( final Map yaml ) {            checkNotNull( "yaml", yaml );            final Object ofilter = yaml.get( "filter" );            if ( ofilter != null ) {                final List<Map<String, String>> filter = checkInstanceOf( "ofilter", ofilter, List.class );                this.filteredResources = new HashMap<String, List<Role>>( filter.size() );                this.mandatoryFilteredResources = new HashMap<String, List<Role>>( filter.size() );                for ( final Map<String, String> activeFilter : filter ) {                    final String pattern = activeFilter.get( "pattern" );                    final String access = activeFilter.get( "access" );                    checkNotNull( "pattern", pattern );                    final List<Role> roles;                    if ( access != null ) {                        final String[] textRoles = access.split( "," );                        roles = new ArrayList<Role>( textRoles.length );                        for ( final String textRole : textRoles ) {                            roles.add( new RoleImpl( textRole ) );                        }                        mandatoryFilteredResources.put( pattern, roles );                    } else {                        roles = emptyList();                    }                    filteredResources.put( pattern, roles );                }            } else {                this.filteredResources = emptyMap();                this.mandatoryFilteredResources = emptyMap();            }            final Object oexclude = yaml.get( "exclude" );            final List exclude = checkInstanceOf( "exclude", oexclude, List.class );            this.excludedResources = new HashSet<String>( exclude );        }        public Map<String, List<Role>> getFilteredResources() {            return filteredResources;        }        public Set<String> getExcludedResources() {            return excludedResources;        }        public Map<String, List<Role>> getMandatoryFilteredResources() {            return mandatoryFilteredResources;        }    }}