org.wicketstuff.security.components.SecureComponentHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.wicketstuff.security.components.SecureComponentHelper.java

Source

/*
 * 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.wicketstuff.security.components;

import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.Page;
import org.apache.wicket.Session;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.util.string.PrependingStringBuffer;
import org.wicketstuff.security.WaspApplication;
import org.wicketstuff.security.WaspSession;
import org.wicketstuff.security.actions.ActionFactory;
import org.wicketstuff.security.actions.WaspAction;
import org.wicketstuff.security.checks.ISecurityCheck;
import org.wicketstuff.security.checks.WaspKey;
import org.wicketstuff.security.models.ISecureModel;
import org.wicketstuff.security.strategies.SecurityException;
import org.wicketstuff.security.strategies.WaspAuthorizationStrategy;

/**
 * Utility class for secure components.
 * 
 * @author marrink
 * @see ISecurityCheck
 * @see ISecureComponent
 * @see ISecureModel
 */
public final class SecureComponentHelper {

    /**
     * String used to concatenate the parts that make up alias.
     * 
     * @see #alias(Class)
     * @see #alias(Component)
     * @see #containerAlias(MarkupContainer)
     * @see #containerAliasses(Component)
     */
    public static final String PATH_SEPARATOR = "" + Component.PATH_SEPARATOR;

    /**
     * The security check placed on the component or null. This uses the metadata of a component to
     * store or retrieve the {@link ISecurityCheck}.
     * 
     * @param component
     *            if null, null will be returned
     * @return the security check or null if none was placed on the component
     */
    public static ISecurityCheck getSecurityCheck(Component component) {
        if (component != null)
            return component.getMetaData(new WaspKey());
        return null;
    }

    /**
     * Places a security check on a component. This uses the metadata of a component to store or
     * retrieve the {@link ISecurityCheck}.
     * 
     * @param component
     * @param securityCheck
     * @return the component or null if the component was null to begin with.
     */
    public static Component setSecurityCheck(Component component, ISecurityCheck securityCheck) {
        if (component == null)
            return null;
        component.setMetaData(new WaspKey(), securityCheck);
        return component;
    }

    /**
     * We cannot assume everybody uses the here specified public methods to store the
     * {@link ISecurityCheck}, so we check if the component is a {@link ISecureComponent} and if so
     * use the {@link ISecureComponent#getSecurityCheck()} on the secure component else we fall back
     * to the metadata.
     * 
     * @param component
     * @return the security check or null if the component does not have one.
     */
    private static ISecurityCheck saveGetSecurityCheck(Component component) {
        if (component instanceof ISecureComponent)
            return ((ISecureComponent) component).getSecurityCheck();
        return getSecurityCheck(component);
    }

    /**
     * Checks if the component has a {@link ISecureModel}.
     * 
     * @param component
     * @return true if the component has a securemodel, else false.
     */
    public static boolean hasSecureModel(Component component) {
        return component != null && component.getDefaultModel() instanceof ISecureModel<?>;
    }

    /**
     * Gets the {@link ActionFactory}.
     * 
     * @return the actionfactory
     * @throws WicketRuntimeException
     *             if the ActionFactory is not found.
     */
    private static ActionFactory getActionFactory() {
        Application application = Application.get();
        if (application instanceof WaspApplication) {
            WaspApplication app = (WaspApplication) application;
            return app.getActionFactory();
        }
        throw new WicketRuntimeException(application + " is not a " + WaspApplication.class);
    }

    /**
     * Gets the {@link WaspAuthorizationStrategy}.
     * 
     * @return the strategy
     * @throws WicketRuntimeException
     *             if a {@link WaspSession} is not found
     * @throws ClassCastException
     *             if the session does not contain a {@link WaspAuthorizationStrategy}
     */
    private static WaspAuthorizationStrategy getStrategy() {
        Session session = Session.get();
        if (session instanceof WaspSession)
            return (WaspAuthorizationStrategy) session.getAuthorizationStrategy();
        throw new WicketRuntimeException(session + " is not a " + WaspSession.class);
    }

    /**
     * Default implementation for {@link ISecureComponent#isActionAuthorized(String)} and
     * {@link WaspAuthorizationStrategy#isActionAuthorized(Component, org.apache.wicket.authorization.Action)}
     * . First tries to use the {@link ISecurityCheck} from the component if that is not available
     * it tries the {@link ISecureModel} if neither is present the action is authorized on the
     * component.
     * 
     * @param component
     *            the component to check
     * @param action
     *            the required action(s)
     * 
     * @return true, if the component is authorized, false otherwise.
     * @see ISecureComponent#isActionAuthorized(String)
     * @see ISecurityCheck
     * @see ISecureModel
     */
    public static boolean isActionAuthorized(Component component, String action) {
        if (action == null)
            return true;
        ISecurityCheck check = saveGetSecurityCheck(component);
        if (check != null)
            return check.isActionAuthorized(getActionFactory().getAction(action));
        if (hasSecureModel(component))
            return ((ISecureModel<?>) component.getDefaultModel()).isAuthorized(component,
                    getActionFactory().getAction(action));
        return true;
    }

    /**
     * Default implementation for {@link ISecureComponent#isActionAuthorized(WaspAction)} and
     * {@link WaspAuthorizationStrategy#isActionAuthorized(Component, org.apache.wicket.authorization.Action)}
     * . First tries to use the {@link ISecurityCheck} from the component if that is not available
     * it tries the {@link ISecureModel} if neither is present the action is authorized on the
     * component.
     * 
     * @param component
     *            the component to check
     * @param action
     *            the required action(s)
     * 
     * @return true, if the component is authorized, false otherwise.
     * @see ISecureComponent#isActionAuthorized(WaspAction)
     * @see ISecurityCheck
     * @see ISecureModel
     */
    public static boolean isActionAuthorized(Component component, WaspAction action) {
        if (action == null)
            return true;
        ISecurityCheck check = saveGetSecurityCheck(component);
        if (check != null)
            return check.isActionAuthorized(action);
        if (hasSecureModel(component))
            return ((ISecureModel<?>) component.getDefaultModel()).isAuthorized(component, action);
        return true;
    }

    /**
     * Default implementation for {@link ISecureComponent#isAuthenticated()}. First tries to use the
     * {@link ISecurityCheck} from the component if that is not available it tries the
     * {@link ISecureModel} if neither is present the user is authenticated if
     * {@link WaspAuthorizationStrategy#isUserAuthenticated()} returns true.
     * 
     * @param component
     *            the component to check
     * 
     * @return true, if the user is authenticated, false otherwise.
     * @see ISecureComponent#isAuthenticated()
     * @see ISecurityCheck
     * @see ISecureModel
     */
    public static boolean isAuthenticated(Component component) {
        ISecurityCheck check = saveGetSecurityCheck(component);
        if (check != null)
            return check.isAuthenticated();
        if (hasSecureModel(component))
            return ((ISecureModel<?>) component.getDefaultModel()).isAuthenticated(component);
        return getStrategy().isUserAuthenticated();
    }

    /**
     * Builds a 'unique' name for the component. The name is based on the page class alias and the
     * relative path to the page (if not a page itself). Note that although it is unlikely, it is
     * not impossible for two components to have the same alias.
     * 
     * @param component
     * @return an alias.
     * @throws SecurityException
     *             if the component is null, or if the page of the component is not available.
     */
    public static String alias(Component component) {
        // might be useful in wicket core itself
        if (component == null)
            throw new SecurityException("Specified component is null");
        Page page = null;
        try {
            page = component.getPage();
        } catch (IllegalStateException e) {
            throw new SecurityException("Unable to create alias for component: " + component, e);
        }
        String alias = alias(page.getClass());
        String relative = component.getPageRelativePath();
        if (relative == null || "".equals(relative))
            return alias;
        return alias + PATH_SEPARATOR + relative;
    }

    /**
     * Builds an alias for a class.
     * 
     * @param class1
     * @return an alias
     */
    public static String alias(Class<?> class1) {
        if (class1 == null)
            throw new SecurityException("Specified class is null");
        return class1.getName();
    }

    /**
     * Builds an alias string for {@link MarkupContainer}s.
     * 
     * @param container
     * @return an alias
     */
    public static String containerAlias(MarkupContainer container) {
        if (container == null)
            throw new SecurityException("specified markupcontainer is null");
        MarkupContainer parent = container;
        PrependingStringBuffer buffer = new PrependingStringBuffer(150);
        while (parent != null) {
            if (buffer.length() > 0)
                buffer.prepend(PATH_SEPARATOR);
            buffer.prepend(parent.getClass().getName());
            parent = parent.getParent();
        }
        return buffer.toString();
    }

    /**
     * Builds a set of aliases for this component. Each alias can be used as name in Permission.
     * 
     * @param component
     * @return an array with aliases for this component
     */
    public static String[] containerAliasses(Component component) {
        if (component == null)
            throw new SecurityException("specified component is null");
        MarkupContainer parent = null;
        if (component instanceof MarkupContainer)
            parent = (MarkupContainer) component;
        else
            parent = component.getParent();
        if (parent == null)
            return new String[0];
        String alias = containerAlias(parent);
        String[] split = alias.split(PATH_SEPARATOR);
        String[] result = new String[split.length + (split.length - 1)];
        PrependingStringBuffer buffer = new PrependingStringBuffer(200);
        int index = result.length - 1;
        for (int i = split.length - 1; i >= 0; i--) {
            if (i < split.length - 1) {
                result[index] = split[i];
                index--;
                buffer.prepend(PATH_SEPARATOR);
            }
            buffer.prepend(split[i]);
            result[index] = buffer.toString();
            index--;
        }
        return result;
    }
}