Package jeeves.server.overrides

Source Code of jeeves.server.overrides.OverridesMetadataSource

package jeeves.server.overrides;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.RegexRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;

import static java.lang.Math.max;

public class OverridesMetadataSource implements FilterInvocationSecurityMetadataSource {
    private LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> _requestMap;
    private DefaultFilterInvocationSecurityMetadataSource _baseSource;

    @SuppressWarnings("unchecked")
    public OverridesMetadataSource(FilterInvocationSecurityMetadataSource metadataSource) {
        assertKnownType(metadataSource);
        Field field = ReflectionUtils.findField(metadataSource.getClass(), "requestMap");
        if (field == null) {
            throw new IllegalArgumentException("The implementation of " + FilterInvocationSecurityMetadataSource.class.getName()
                    + " has changed an now this class must be updated to work with new implementation");
        }

        field.setAccessible(true);
        _requestMap = (LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>) ReflectionUtils.getField(field, metadataSource);
    }

    private void assertKnownType(FilterInvocationSecurityMetadataSource metadataSource) {
        if (!(metadataSource instanceof DefaultFilterInvocationSecurityMetadataSource)) {
            throw new IllegalArgumentException("Modifying the interceptUrls can only be done when the metadataSource is an instanceof "
                    + DefaultFilterInvocationSecurityMetadataSource.class.getName() + ". Instead the metadataSource was a "
                    + metadataSource.getClass().getName());
        }
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return getDelegateSource().getAllConfigAttributes();
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) {
        return getDelegateSource().getAttributes(object);
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return getDelegateSource().supports(clazz) || FilterInvocation.class.isAssignableFrom(clazz);
    }

    /**
     * Add a new mapping to this metadata source.
     *
     * @param pattern the url pattern.  It is used to check for existing matchers to this pattern and and the new one to the existing matcher
     * @param matcher the matcher to add if the apping does not exist.
     * @param access the new access rights for this metcher
     * @param position the position to add the new rule.  if < 1 then it will be first rule.  If >= numberOfRules() then it will be the last rule
     */
    public synchronized void addMapping(final String pattern, final RequestMatcher matcher, final String access, final int position) {
        _baseSource = null;
        final Collection<ConfigAttribute> attributes = createAttributes(matcher, access);

        RequestMatcher requestMatcher = findMatchingRequestMatcher(pattern);
        if(requestMatcher == null) {
            requestMatcher = matcher;
        }
        Collection<ConfigAttribute> allAttributes = _requestMap.get(requestMatcher);
        if (allAttributes == null) {
            allAttributes = new LinkedList<ConfigAttribute>();
        }

        allAttributes.addAll(attributes);
        _requestMap.remove(requestMatcher);
       
        if(position > numberOfRules()) {
            _requestMap.put(requestMatcher, allAttributes);
        } else {
            final int finalPos = max(0, position);
            LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> newMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
            int i = 0;
            for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : _requestMap.entrySet()) {
                if(i == finalPos) {
                    newMap.put(requestMatcher, allAttributes);
                }
                newMap.put(entry.getKey(), entry.getValue());
                i++;
            }
            _requestMap = newMap;
        }
    }

    /**
     * Change the existing mapping.
     * @param pattern the URL pattern to update.  This is used to remove the old matcher and attributes
     * @param access the new access permissions
     * @throws IllegalArgumentException thrown in pattern does not find a match
     */
    public synchronized void setMapping(String pattern, final String access) throws IllegalArgumentException {
        _baseSource = null;
        RequestMatcher oldMatcher = findMatchingRequestMatcher(pattern);
        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : _requestMap.entrySet()) {
            if(entry.getKey() == oldMatcher) {
                entry.setValue(createAttributes(oldMatcher, access));
                break;
            }
        }
    }

    private synchronized DefaultFilterInvocationSecurityMetadataSource getDelegateSource() {
        if (_baseSource == null) {
            DefaultFilterInvocationSecurityMetadataSource ms = new DefaultFilterInvocationSecurityMetadataSource(_requestMap);
            _baseSource = ms;
        }
        return _baseSource;
    }

    private Collection<ConfigAttribute> createAttributes(RequestMatcher matcher, String access) {
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
        Collection<ConfigAttribute> atts = new LinkedList<ConfigAttribute>();
        map.put(matcher, atts);

        atts.add(new SecurityConfig(access));

        ExpressionBasedFilterInvocationSecurityMetadataSource ms = new ExpressionBasedFilterInvocationSecurityMetadataSource(map,
                new DefaultWebSecurityExpressionHandler());
       
        return ms.getAllConfigAttributes();
    }

    public synchronized RequestMatcher removeMapping(String pattern) {
        _baseSource = null;
        RequestMatcher toRemove = findMatchingRequestMatcher(pattern);
        if(toRemove == null) {
            throw new IllegalArgumentException(pattern+" has not been found.");
        } else {
            _requestMap.remove(toRemove);
        }
        return toRemove;
    }

    private @Nullable RequestMatcher findMatchingRequestMatcher(String pattern) {
        for (RequestMatcher requestMatcher : _requestMap.keySet()) {
            if (requestMatcher instanceof RegexRequestMatcher) {
                RegexRequestMatcher regexMatcher = (RegexRequestMatcher) requestMatcher;
                Object otherPattern = getPattern(regexMatcher);
                if (pattern.equals(otherPattern.toString())) {
                    return regexMatcher;
                }
            }
        }
        return null;
    }

    private Object getPattern(RegexRequestMatcher regexMatcher) {
        Field field = ReflectionUtils.findField(RegexRequestMatcher.class, "pattern");
        if (field == null) {
            throw new IllegalArgumentException("The implementation of " + RegexRequestMatcher.class.getName()
                    + " has changed an now this class must be updated to work with new implementation");
        }
       
        field.setAccessible(true);
        Object otherPattern = ReflectionUtils.getField(field, regexMatcher);
        return otherPattern;
    }

    /**
     * Return the number of rules.
     */
    public synchronized int numberOfRules() {
        return _requestMap.size();
    }
}
TOP

Related Classes of jeeves.server.overrides.OverridesMetadataSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.