org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser.java

Source

/*
 * Copyright 2002-2018 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.security.config.method;

import static org.springframework.security.config.Elements.*;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.config.AopNamespaceUtils;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
import org.springframework.security.access.annotation.Jsr250Voter;
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
import org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice;
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource;
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Elements;
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;

/**
 * Processes the top-level "global-method-security" element.
 *
 * @author Ben Alex
 * @author Luke Taylor
 * @author Rob Winch
 * @since 2.0
 */
public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {

    private final Log logger = LogFactory.getLog(getClass());

    private static final String ATT_AUTHENTICATION_MANAGER_REF = "authentication-manager-ref";
    private static final String ATT_ACCESS = "access";
    private static final String ATT_EXPRESSION = "expression";
    private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
    private static final String ATT_RUN_AS_MGR = "run-as-manager-ref";
    private static final String ATT_USE_JSR250 = "jsr250-annotations";
    private static final String ATT_USE_SECURED = "secured-annotations";
    private static final String ATT_USE_PREPOST = "pre-post-annotations";
    private static final String ATT_REF = "ref";
    private static final String ATT_MODE = "mode";
    private static final String ATT_ADVICE_ORDER = "order";
    private static final String ATT_META_DATA_SOURCE_REF = "metadata-source-ref";

    public BeanDefinition parse(Element element, ParserContext pc) {
        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
                pc.extractSource(element));
        pc.pushContainingComponent(compositeDef);

        Object source = pc.extractSource(element);
        // The list of method metadata delegates
        ManagedList<BeanMetadataElement> delegates = new ManagedList<>();

        boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
        boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
        boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST));
        boolean useAspectJ = "aspectj".equals(element.getAttribute(ATT_MODE));

        BeanDefinition preInvocationVoter = null;
        ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<>();

        // Check for an external SecurityMetadataSource, which takes priority over other
        // sources
        String metaDataSourceId = element.getAttribute(ATT_META_DATA_SOURCE_REF);

        if (StringUtils.hasText(metaDataSourceId)) {
            delegates.add(new RuntimeBeanReference(metaDataSourceId));
        }

        if (prePostAnnotationsEnabled) {
            Element prePostElt = DomUtils.getChildElementByTagName(element, INVOCATION_HANDLING);
            Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, EXPRESSION_HANDLER);

            if (prePostElt != null && expressionHandlerElt != null) {
                pc.getReaderContext().error(
                        INVOCATION_HANDLING + " and " + EXPRESSION_HANDLER + " cannot be used together ", source);
            }

            BeanDefinitionBuilder preInvocationVoterBldr = BeanDefinitionBuilder
                    .rootBeanDefinition(PreInvocationAuthorizationAdviceVoter.class);
            // After-invocation provider to handle post-invocation filtering and
            // authorization expression annotations.
            BeanDefinitionBuilder afterInvocationBldr = BeanDefinitionBuilder
                    .rootBeanDefinition(PostInvocationAdviceProvider.class);
            // The metadata source for the security interceptor
            BeanDefinitionBuilder mds = BeanDefinitionBuilder
                    .rootBeanDefinition(PrePostAnnotationSecurityMetadataSource.class);

            if (prePostElt != null) {
                // Customized override of expression handling system
                String attributeFactoryRef = DomUtils
                        .getChildElementByTagName(prePostElt, INVOCATION_ATTRIBUTE_FACTORY).getAttribute("ref");
                String preAdviceRef = DomUtils.getChildElementByTagName(prePostElt, PRE_INVOCATION_ADVICE)
                        .getAttribute("ref");
                String postAdviceRef = DomUtils.getChildElementByTagName(prePostElt, POST_INVOCATION_ADVICE)
                        .getAttribute("ref");

                mds.addConstructorArgReference(attributeFactoryRef);
                preInvocationVoterBldr.addConstructorArgReference(preAdviceRef);
                afterInvocationBldr.addConstructorArgReference(postAdviceRef);
            } else {
                // The default expression-based system
                String expressionHandlerRef = expressionHandlerElt == null ? null
                        : expressionHandlerElt.getAttribute("ref");

                if (StringUtils.hasText(expressionHandlerRef)) {
                    logger.info(
                            "Using bean '" + expressionHandlerRef + "' as method ExpressionHandler implementation");
                    RootBeanDefinition lazyInitPP = new RootBeanDefinition(
                            LazyInitBeanDefinitionRegistryPostProcessor.class);
                    lazyInitPP.getConstructorArgumentValues().addGenericArgumentValue(expressionHandlerRef);
                    pc.getReaderContext().registerWithGeneratedName(lazyInitPP);

                    BeanDefinitionBuilder lazyMethodSecurityExpressionHandlerBldr = BeanDefinitionBuilder
                            .rootBeanDefinition(LazyInitTargetSource.class);
                    lazyMethodSecurityExpressionHandlerBldr.addPropertyValue("targetBeanName",
                            expressionHandlerRef);

                    BeanDefinitionBuilder expressionHandlerProxyBldr = BeanDefinitionBuilder
                            .rootBeanDefinition(ProxyFactoryBean.class);
                    expressionHandlerProxyBldr.addPropertyValue("targetSource",
                            lazyMethodSecurityExpressionHandlerBldr.getBeanDefinition());
                    expressionHandlerProxyBldr.addPropertyValue("proxyInterfaces",
                            MethodSecurityExpressionHandler.class);

                    expressionHandlerRef = pc.getReaderContext()
                            .generateBeanName(expressionHandlerProxyBldr.getBeanDefinition());

                    pc.registerBeanComponent(new BeanComponentDefinition(
                            expressionHandlerProxyBldr.getBeanDefinition(), expressionHandlerRef));
                } else {
                    RootBeanDefinition expressionHandler = registerWithDefaultRolePrefix(pc,
                            DefaultMethodSecurityExpressionHandlerBeanFactory.class);

                    expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler);
                    pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
                    logger.info(
                            "Expressions were enabled for method security but no SecurityExpressionHandler was configured. "
                                    + "All hasPermision() expressions will evaluate to false.");
                }

                BeanDefinitionBuilder expressionPreAdviceBldr = BeanDefinitionBuilder
                        .rootBeanDefinition(ExpressionBasedPreInvocationAdvice.class);
                expressionPreAdviceBldr.addPropertyReference("expressionHandler", expressionHandlerRef);
                preInvocationVoterBldr.addConstructorArgValue(expressionPreAdviceBldr.getBeanDefinition());

                BeanDefinitionBuilder expressionPostAdviceBldr = BeanDefinitionBuilder
                        .rootBeanDefinition(ExpressionBasedPostInvocationAdvice.class);
                expressionPostAdviceBldr.addConstructorArgReference(expressionHandlerRef);
                afterInvocationBldr.addConstructorArgValue(expressionPostAdviceBldr.getBeanDefinition());

                BeanDefinitionBuilder annotationInvocationFactory = BeanDefinitionBuilder
                        .rootBeanDefinition(ExpressionBasedAnnotationAttributeFactory.class);
                annotationInvocationFactory.addConstructorArgReference(expressionHandlerRef);
                mds.addConstructorArgValue(annotationInvocationFactory.getBeanDefinition());
            }

            preInvocationVoter = preInvocationVoterBldr.getBeanDefinition();
            afterInvocationProviders.add(afterInvocationBldr.getBeanDefinition());
            delegates.add(mds.getBeanDefinition());
        }

        if (useSecured) {
            delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SecuredAnnotationSecurityMetadataSource.class)
                    .getBeanDefinition());
        }

        if (jsr250Enabled) {
            RootBeanDefinition jsrMetadataSource = registerWithDefaultRolePrefix(pc,
                    Jsr250MethodSecurityMetadataSourceBeanFactory.class);
            delegates.add(jsrMetadataSource);
        }

        // Now create a Map<String, ConfigAttribute> for each <protect-pointcut>
        // sub-element
        Map<String, List<ConfigAttribute>> pointcutMap = parseProtectPointcuts(pc,
                DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));

        if (pointcutMap.size() > 0) {
            if (useAspectJ) {
                pc.getReaderContext().error("You can't use AspectJ mode with protect-pointcut definitions", source);
            }
            // Only add it if there are actually any pointcuts defined.
            BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(
                    MapBasedMethodSecurityMetadataSource.class);
            BeanReference ref = new RuntimeBeanReference(
                    pc.getReaderContext().generateBeanName(mapBasedMetadataSource));

            delegates.add(ref);
            pc.registerBeanComponent(new BeanComponentDefinition(mapBasedMetadataSource, ref.getBeanName()));
            registerProtectPointcutPostProcessor(pc, pointcutMap, ref, source);
        }

        BeanReference metadataSource = registerDelegatingMethodSecurityMetadataSource(pc, delegates, source);

        // Check for additional after-invocation-providers..
        List<Element> afterInvocationElts = DomUtils.getChildElementsByTagName(element,
                Elements.AFTER_INVOCATION_PROVIDER);

        for (Element elt : afterInvocationElts) {
            afterInvocationProviders.add(new RuntimeBeanReference(elt.getAttribute(ATT_REF)));
        }

        String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);

        if (!StringUtils.hasText(accessManagerId)) {
            accessManagerId = registerAccessManager(pc, jsr250Enabled, preInvocationVoter);
        }

        String authMgrRef = element.getAttribute(ATT_AUTHENTICATION_MANAGER_REF);

        String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR);
        BeanReference interceptor = registerMethodSecurityInterceptor(pc, authMgrRef, accessManagerId,
                runAsManagerId, metadataSource, afterInvocationProviders, source, useAspectJ);

        if (useAspectJ) {
            BeanDefinitionBuilder aspect = BeanDefinitionBuilder.rootBeanDefinition(
                    "org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
            aspect.setFactoryMethod("aspectOf");
            aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            aspect.addPropertyValue("securityInterceptor", interceptor);
            String id = pc.getReaderContext().registerWithGeneratedName(aspect.getBeanDefinition());
            pc.registerBeanComponent(new BeanComponentDefinition(aspect.getBeanDefinition(), id));
        } else {
            registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
            AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
        }

        pc.popAndRegisterContainingComponent();

        return null;
    }

    /**
     * Register the default AccessDecisionManager. Adds the special JSR 250 voter jsr-250
     * is enabled and an expression voter if expression-based access control is enabled.
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private String registerAccessManager(ParserContext pc, boolean jsr250Enabled, BeanDefinition expressionVoter) {

        BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
        ManagedList voters = new ManagedList(4);

        if (expressionVoter != null) {
            voters.add(expressionVoter);
        }
        voters.add(new RootBeanDefinition(RoleVoter.class));
        voters.add(new RootBeanDefinition(AuthenticatedVoter.class));

        if (jsr250Enabled) {
            voters.add(new RootBeanDefinition(Jsr250Voter.class));
        }

        accessMgrBuilder.addConstructorArgValue(voters);

        BeanDefinition accessManager = accessMgrBuilder.getBeanDefinition();
        String id = pc.getReaderContext().generateBeanName(accessManager);
        pc.registerBeanComponent(new BeanComponentDefinition(accessManager, id));

        return id;
    }

    @SuppressWarnings("rawtypes")
    private BeanReference registerDelegatingMethodSecurityMetadataSource(ParserContext pc, ManagedList delegates,
            Object source) {
        RootBeanDefinition delegatingMethodSecurityMetadataSource = new RootBeanDefinition(
                DelegatingMethodSecurityMetadataSource.class);
        delegatingMethodSecurityMetadataSource.setSource(source);
        delegatingMethodSecurityMetadataSource.getConstructorArgumentValues().addGenericArgumentValue(delegates);

        String id = pc.getReaderContext().generateBeanName(delegatingMethodSecurityMetadataSource);
        pc.registerBeanComponent(new BeanComponentDefinition(delegatingMethodSecurityMetadataSource, id));

        return new RuntimeBeanReference(id);
    }

    private void registerProtectPointcutPostProcessor(ParserContext parserContext,
            Map<String, List<ConfigAttribute>> pointcutMap, BeanReference mapBasedMethodSecurityMetadataSource,
            Object source) {
        RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
        ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        ppbp.setSource(source);
        ppbp.getConstructorArgumentValues().addGenericArgumentValue(mapBasedMethodSecurityMetadataSource);
        ppbp.getPropertyValues().addPropertyValue("pointcutMap", pointcutMap);
        parserContext.getReaderContext().registerWithGeneratedName(ppbp);
    }

    private Map<String, List<ConfigAttribute>> parseProtectPointcuts(ParserContext parserContext,
            List<Element> protectPointcutElts) {
        Map<String, List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String, List<ConfigAttribute>>();

        for (Element childElt : protectPointcutElts) {
            String accessConfig = childElt.getAttribute(ATT_ACCESS);
            String expression = childElt.getAttribute(ATT_EXPRESSION);

            if (!StringUtils.hasText(accessConfig)) {
                parserContext.getReaderContext().error("Access configuration required",
                        parserContext.extractSource(childElt));
            }

            if (!StringUtils.hasText(expression)) {
                parserContext.getReaderContext().error("Pointcut expression required",
                        parserContext.extractSource(childElt));
            }

            String[] attributeTokens = StringUtils.commaDelimitedListToStringArray(accessConfig);
            List<ConfigAttribute> attributes = new ArrayList<>(attributeTokens.length);

            for (String token : attributeTokens) {
                attributes.add(new SecurityConfig(token));
            }

            pointcutMap.put(expression, attributes);
        }

        return pointcutMap;
    }

    private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String authMgrRef,
            String accessManagerId, String runAsManagerId, BeanReference metadataSource,
            List<BeanMetadataElement> afterInvocationProviders, Object source, boolean useAspectJ) {
        BeanDefinitionBuilder bldr = BeanDefinitionBuilder.rootBeanDefinition(
                useAspectJ ? AspectJMethodSecurityInterceptor.class : MethodSecurityInterceptor.class);
        bldr.getRawBeanDefinition().setSource(source);
        bldr.addPropertyReference("accessDecisionManager", accessManagerId);
        RootBeanDefinition authMgr = new RootBeanDefinition(AuthenticationManagerDelegator.class);
        authMgr.getConstructorArgumentValues().addGenericArgumentValue(authMgrRef);
        bldr.addPropertyValue("authenticationManager", authMgr);
        bldr.addPropertyValue("securityMetadataSource", metadataSource);

        if (StringUtils.hasText(runAsManagerId)) {
            bldr.addPropertyReference("runAsManager", runAsManagerId);
        }

        if (!afterInvocationProviders.isEmpty()) {
            BeanDefinition afterInvocationManager;
            afterInvocationManager = new RootBeanDefinition(AfterInvocationProviderManager.class);
            afterInvocationManager.getPropertyValues().addPropertyValue("providers", afterInvocationProviders);
            bldr.addPropertyValue("afterInvocationManager", afterInvocationManager);
        }

        BeanDefinition bean = bldr.getBeanDefinition();
        String id = pc.getReaderContext().generateBeanName(bean);
        pc.registerBeanComponent(new BeanComponentDefinition(bean, id));

        return new RuntimeBeanReference(id);
    }

    private void registerAdvisor(ParserContext parserContext, BeanReference interceptor,
            BeanReference metadataSource, Object source, String adviceOrder) {
        if (parserContext.getRegistry().containsBeanDefinition(BeanIds.METHOD_SECURITY_METADATA_SOURCE_ADVISOR)) {
            parserContext.getReaderContext().error("Duplicate <global-method-security> detected.", source);
        }
        RootBeanDefinition advisor = new RootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);

        if (StringUtils.hasText(adviceOrder)) {
            advisor.getPropertyValues().addPropertyValue("order", adviceOrder);
        }

        // advisor must be an infrastructure bean as Spring's
        // InfrastructureAdvisorAutoProxyCreator will ignore it
        // otherwise
        advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        advisor.setSource(source);
        advisor.getConstructorArgumentValues().addGenericArgumentValue(interceptor.getBeanName());
        advisor.getConstructorArgumentValues().addGenericArgumentValue(metadataSource);
        advisor.getConstructorArgumentValues().addGenericArgumentValue(metadataSource.getBeanName());

        parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_METADATA_SOURCE_ADVISOR,
                advisor);
    }

    private RootBeanDefinition registerWithDefaultRolePrefix(ParserContext pc,
            Class<? extends AbstractGrantedAuthorityDefaultsBeanFactory> beanFactoryClass) {
        RootBeanDefinition beanFactoryDefinition = new RootBeanDefinition(beanFactoryClass);
        String beanFactoryRef = pc.getReaderContext().generateBeanName(beanFactoryDefinition);
        pc.getRegistry().registerBeanDefinition(beanFactoryRef, beanFactoryDefinition);

        RootBeanDefinition bean = new RootBeanDefinition();
        bean.setFactoryBeanName(beanFactoryRef);
        bean.setFactoryMethodName("getBean");
        return bean;
    }

    /**
     * Delays the lookup of the AuthenticationManager within MethodSecurityInterceptor, to
     * prevent issues like SEC-933.
     *
     * @author Luke Taylor
     * @since 3.0
     */
    static final class AuthenticationManagerDelegator implements AuthenticationManager, BeanFactoryAware {
        private AuthenticationManager delegate;
        private final Object delegateMonitor = new Object();
        private BeanFactory beanFactory;
        private final String authMgrBean;

        AuthenticationManagerDelegator(String authMgrBean) {
            this.authMgrBean = StringUtils.hasText(authMgrBean) ? authMgrBean : BeanIds.AUTHENTICATION_MANAGER;
        }

        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            synchronized (delegateMonitor) {
                if (delegate == null) {
                    Assert.state(beanFactory != null, () -> "BeanFactory must be set to resolve " + authMgrBean);
                    try {
                        delegate = beanFactory.getBean(authMgrBean, AuthenticationManager.class);
                    } catch (NoSuchBeanDefinitionException e) {
                        if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) {
                            throw new NoSuchBeanDefinitionException(BeanIds.AUTHENTICATION_MANAGER,
                                    AuthenticationManagerFactoryBean.MISSING_BEAN_ERROR_MESSAGE);
                        }
                        throw e;
                    }
                }
            }

            return delegate.authenticate(authentication);
        }

        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            this.beanFactory = beanFactory;
        }
    }

    static class Jsr250MethodSecurityMetadataSourceBeanFactory extends AbstractGrantedAuthorityDefaultsBeanFactory {
        private Jsr250MethodSecurityMetadataSource source = new Jsr250MethodSecurityMetadataSource();

        public Jsr250MethodSecurityMetadataSource getBean() {
            source.setDefaultRolePrefix(this.rolePrefix);
            return source;
        }
    }

    static class DefaultMethodSecurityExpressionHandlerBeanFactory
            extends AbstractGrantedAuthorityDefaultsBeanFactory {
        private DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();

        public DefaultMethodSecurityExpressionHandler getBean() {
            handler.setDefaultRolePrefix(this.rolePrefix);
            return handler;
        }
    }

    static abstract class AbstractGrantedAuthorityDefaultsBeanFactory implements ApplicationContextAware {
        protected String rolePrefix = "ROLE_";

        @Override
        public final void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            String[] grantedAuthorityDefaultsBeanNames = applicationContext
                    .getBeanNamesForType(GrantedAuthorityDefaults.class);
            if (grantedAuthorityDefaultsBeanNames.length == 1) {
                GrantedAuthorityDefaults grantedAuthorityDefaults = applicationContext
                        .getBean(grantedAuthorityDefaultsBeanNames[0], GrantedAuthorityDefaults.class);
                this.rolePrefix = grantedAuthorityDefaults.getRolePrefix();
            }
        }
    }

    /**
     * Delays setting a bean of a given name to be lazyily initialized until after all the
     * beans are registered.
     *
     * @author Rob Winch
     * @since 3.2
     */
    private static final class LazyInitBeanDefinitionRegistryPostProcessor
            implements BeanDefinitionRegistryPostProcessor {
        private final String beanName;

        private LazyInitBeanDefinitionRegistryPostProcessor(String beanName) {
            this.beanName = beanName;
        }

        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            if (!registry.containsBeanDefinition(beanName)) {
                return;
            }
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
            beanDefinition.setLazyInit(true);
        }

        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        }
    }
}