Package org.apache.deltaspike.jsf.impl.util

Source Code of org.apache.deltaspike.jsf.impl.util.SecurityUtils

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.deltaspike.jsf.impl.util;

import org.apache.deltaspike.core.api.config.view.DefaultErrorView;
import org.apache.deltaspike.core.api.config.view.ViewConfig;
import org.apache.deltaspike.core.api.config.view.metadata.ConfigDescriptor;
import org.apache.deltaspike.core.api.config.view.metadata.ViewConfigDescriptor;
import org.apache.deltaspike.core.api.config.view.metadata.ViewConfigResolver;
import org.apache.deltaspike.core.api.provider.BeanProvider;
import org.apache.deltaspike.core.api.config.view.navigation.ViewNavigationHandler;
import org.apache.deltaspike.security.api.authorization.AccessDecisionState;
import org.apache.deltaspike.security.api.authorization.AccessDeniedException;
import org.apache.deltaspike.security.api.authorization.ErrorViewAwareAccessDeniedException;
import org.apache.deltaspike.security.api.authorization.Secured;
import org.apache.deltaspike.security.api.authorization.SecurityViolation;
import org.apache.deltaspike.security.spi.authorization.EditableAccessDecisionVoterContext;
import org.apache.deltaspike.security.spi.authorization.SecurityViolationHandler;

import javax.enterprise.inject.Typed;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Typed()
public abstract class SecurityUtils
{
    public static void invokeVoters(EditableAccessDecisionVoterContext accessDecisionVoterContext,
                                    ConfigDescriptor<?> viewConfigDescriptor)
    {
        if (viewConfigDescriptor == null)
        {
            return;
        }

        List<Secured> securedMetaData = viewConfigDescriptor.getMetaData(Secured.class);

        if (securedMetaData.isEmpty())
        {
            return;
        }

        Secured.Descriptor securedDescriptor = viewConfigDescriptor
                .getExecutableCallbackDescriptor(Secured.class, Secured.Descriptor.class);

        AccessDecisionState voterState = AccessDecisionState.VOTE_IN_PROGRESS;
        try
        {
            accessDecisionVoterContext.setState(voterState);

            List<Set<SecurityViolation>> violations = securedDescriptor.execute(accessDecisionVoterContext);
            Set<SecurityViolation> allViolations = createViolationResult(violations);

            if (!allViolations.isEmpty())
            {
                voterState = AccessDecisionState.VIOLATION_FOUND;
                for (SecurityViolation violation : allViolations)
                {
                    accessDecisionVoterContext.addViolation(violation);
                }

                Class<? extends ViewConfig> errorView = securedMetaData.iterator().next().errorView();
                throw new ErrorViewAwareAccessDeniedException(allViolations, errorView);
            }
        }
        finally
        {
            if (AccessDecisionState.VOTE_IN_PROGRESS.equals(voterState))
            {
                voterState = AccessDecisionState.NO_VIOLATION_FOUND;
            }

            accessDecisionVoterContext.setState(voterState);
        }
    }

    private static Set<SecurityViolation> createViolationResult(List<Set<SecurityViolation>> violations)
    {
        if (violations == null || violations.isEmpty())
        {
            return Collections.emptySet();
        }

        Set<SecurityViolation> result = new HashSet<SecurityViolation>();

        for (Set<SecurityViolation> securityViolationSet : violations)
        {
            result.addAll(securityViolationSet);
        }
        return result;
    }

    /**
     * Processes a security violation without triggering the navigation to the error page
     *
     * @param exception current exception
     * @return error view which can be used e.g. for manual navigation
     */
    public static Class<? extends ViewConfig> handleSecurityViolationWithoutNavigation(RuntimeException exception)
    {
        return tryToHandleSecurityViolation(exception, false);
    }

    /**
     * Processes a security violation including the navigation to the error page
     *
     * @param exception current exception
     */
    public static void tryToHandleSecurityViolation(RuntimeException exception)
    {
        tryToHandleSecurityViolation(exception, true);
    }

    private static Class<? extends ViewConfig> tryToHandleSecurityViolation(RuntimeException runtimeException,
                                                                            boolean allowNavigation)
    {
        ErrorViewAwareAccessDeniedException exception = extractException(runtimeException);

        if (exception == null)
        {
            throw runtimeException;
        }

        Class<? extends ViewConfig> errorView = null;

        Class<? extends ViewConfig> inlineErrorView = exception.getErrorView();

        if (inlineErrorView != null && !DefaultErrorView.class.getName().equals(inlineErrorView.getName()))
        {
            errorView = inlineErrorView;
        }

        if (errorView == null)
        {
            ViewConfigResolver viewConfigResolver = BeanProvider.getContextualReference(ViewConfigResolver.class);
            ViewConfigDescriptor errorPageDescriptor = viewConfigResolver.getDefaultErrorViewConfigDescriptor();

            if (errorPageDescriptor != null)
            {
                errorView = errorPageDescriptor.getConfigClass();
            }
        }

        if (errorView == null)
        {
            throw exception;
        }

        processApplicationSecurityException(exception, errorView, allowNavigation);
        return errorView;
    }

    private static ErrorViewAwareAccessDeniedException extractException(Throwable exception)
    {
        if (exception == null)
        {
            return null;
        }

        if (exception instanceof ErrorViewAwareAccessDeniedException)
        {
            return (ErrorViewAwareAccessDeniedException) exception;
        }

        return extractException(exception.getCause());
    }

    private static void processApplicationSecurityException(AccessDeniedException exception,
                                                            Class<? extends ViewConfig> errorView,
                                                            boolean allowNavigation)
    {
        SecurityViolationHandler securityViolationHandler =
                BeanProvider.getContextualReference(SecurityViolationHandler.class, true);

        if (securityViolationHandler != null)
        {
            //optional (custom handler) - allows to handle custom implementations of SecurityViolation
            securityViolationHandler.processSecurityViolations(exception.getViolations());
        }
        else
        {
            addViolationsAsMessage(exception.getViolations());
        }

        if (allowNavigation)
        {
            BeanProvider.getContextualReference(ViewNavigationHandler.class).navigateTo(errorView);
        }
    }

    private static void addViolationsAsMessage(Set<SecurityViolation> violations)
    {
        String message;
        for (SecurityViolation violation : violations)
        {
            //TODO discuss it (with CODI handling such messages was easier)
            message = violation.getReason();
            FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message);
            FacesContext.getCurrentInstance().addMessage(null, facesMessage);
        }
    }
}
TOP

Related Classes of org.apache.deltaspike.jsf.impl.util.SecurityUtils

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.