Package org.wicketstuff.security.strategies

Source Code of org.wicketstuff.security.strategies.WaspAuthorizationStrategy

/*
* 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.strategies;

import java.io.Serializable;
import java.util.Map;

import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.Session;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authorization.IAuthorizationStrategy;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.util.string.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wicketstuff.security.WaspApplication;
import org.wicketstuff.security.WaspSession;
import org.wicketstuff.security.actions.WaspAction;
import org.wicketstuff.security.actions.WaspActionFactory;
import org.wicketstuff.security.authentication.LoginException;
import org.wicketstuff.security.checks.ISecurityCheck;
import org.wicketstuff.security.components.ISecureComponent;
import org.wicketstuff.security.components.SecureComponentHelper;
import org.wicketstuff.security.log.AuthorizationErrorKey;
import org.wicketstuff.security.log.AuthorizationMessageSource;
import org.wicketstuff.security.log.IAuthorizationMessageSource;
import org.wicketstuff.security.models.ISecureModel;

/**
* Base class for every strategy. Checks Authorization and authentication at the class, component
* and model levels.
*
* @author marrink
*/
public abstract class WaspAuthorizationStrategy implements IAuthorizationStrategy, Serializable
{
  private static final long serialVersionUID = 1L;

  private static final Logger log = LoggerFactory.getLogger(WaspAuthorizationStrategy.class);

  /**
   * Key used to store the {@link IAuthorizationMessageSource} in the {@link RequestCycle}
   * metadata.
   */
  protected static final AuthorizationErrorKey MESSAGE_KEY = new AuthorizationErrorKey();

  private static final ThreadLocal<StrategyResolver> resolver = new ThreadLocal<StrategyResolver>();

  /**
   * Performs the actual authorization check on the component.
   *
   * @param component
   * @param action
   * @return true if authorized, false otherwise
   */
  public abstract boolean isComponentAuthorized(Component component, WaspAction action);

  /**
   * Performs the actual authorization check on the model of the component.
   *
   * @param model
   *            the model
   * @param component
   *            component 'owning' the model if available
   * @param action
   *            the action to check
   * @return true if authorized, false otherwise
   */
  public abstract boolean isModelAuthorized(ISecureModel<?> model, Component component,
    WaspAction action);

  /**
   * Performs the actual authorization check on the component class.
   *
   * @param clazz
   *            typically a component
   * @param action
   *            the action to check
   * @return true if authorized, false otherwise
   */
  public abstract boolean isClassAuthorized(Class<?> clazz, WaspAction action);

  /**
   * Performs the authentication check.
   *
   * @param component
   *            the wicket component
   *
   * @return true if the user is authenticated, false otherwise
   */
  public abstract boolean isComponentAuthenticated(Component component);

  /**
   * Performs the authentication check.
   *
   * @param model
   *            the (secure) model
   * @param component
   *            the component owning the model
   *
   * @return true if the user is authenticated, false otherwise
   */
  public abstract boolean isModelAuthenticated(IModel<?> model, Component component);

  /**
   * Performs the authentication check.
   *
   * @param clazz
   *            the class of the wicket component
   *
   * @return true if the user is authenticated, false otherwise
   */
  public abstract boolean isClassAuthenticated(Class<?> clazz);

  /**
   * Checks if there is a user logged in at all. This will return true after a successful
   * {@link #login(Object)} and false after a successful {@link #logoff(Object)}. Note that in a
   * multi-login scenario this method returns true until all successful logins are countered with
   * a successful logoff.
   *
   * @return true while a user is logged in, false otherwise
   */
  public abstract boolean isUserAuthenticated();

  /**
   * Attempts to log the user in. Note to implementations: It is generally considered a bad idea
   * to store the context if it contains sensitive data (like a plaintext password).
   *
   * @param context
   *            a not further specified object that provides all the information to log the user
   *            on
   * @throws LoginException
   *             if the login is unsuccessful
   */
  public abstract void login(Object context) throws LoginException;

  /**
   * Log the user off. With the help of a context implementations might facilitate multi level
   * login / logoff.
   *
   * @param context
   *            a not further specified object, might be null
   * @return true if the logoff was successful, false otherwise
   */
  public abstract boolean logoff(Object context);

  /**
   * Called at the end of the sessions lifecycle to perform some clean up.
   */
  public abstract void destroy();

  /**
   *
   * @see org.apache.wicket.authorization.IAuthorizationStrategy#isActionAuthorized(org.apache.wicket.Component,
   *      org.apache.wicket.authorization.Action)
   */
  public boolean isActionAuthorized(Component component, Action action)
  {
    if (component != null)
    {
      ISecurityCheck check = getSecurityCheck(component);
      if (check != null)
      {
        if (check.isActionAuthorized(getActionFactory().getAction(action)))
          return true;
        IAuthorizationMessageSource message = getMessageSource();
        if (message != null)
        {
          message.setComponent(component);
          message.addVariable("wicket.action", action);
          message.addVariable("wasp.action", getActionFactory().getAction(action));
          logMessage(message);
        }
        return false;

      }
      IModel<?> model = component.getDefaultModel();
      if (model instanceof ISecureModel<?>)
      {
        if (((ISecureModel<?>)model).isAuthorized(component,
          getActionFactory().getAction(action)))
          return true;
        IAuthorizationMessageSource message = getMessageSource();
        if (message != null)
        {
          message.setComponent(component);
          message.addVariable("wicket.action", action);
          message.addVariable("wasp.action", getActionFactory().getAction(action));
          logMessage(message);
        }
        return false;
      }
    }
    return true;
  }

  /**
   * Logs a message indication an action was denied. The message is retrieved through localization
   * with the following resource key:"authorization.denied" (no quotes). This method removes the
   * messagesource from the requestcycle.
   *
   * @param message
   *            messagesource
   * @see #logMessage(String, Map, IAuthorizationMessageSource, boolean)
   */
  protected final void logMessage(IAuthorizationMessageSource message)
  {
    logMessage("authorization.denied", null, message, true);
  }

  /**
   * Logs a message indication an action was denied. The message is retrieved through localization
   * with the specified resource key. Optionally the message can be removed from the requestcycle,
   * if it is not removed the message might be processed multiple times (which might be what you
   * want if you want to use different resource keys). This invokes
   * {@link #logMessage(String, Map, IAuthorizationMessageSource)}
   *
   *
   * @param key
   *            the resource key to lookup the message
   * @param variables
   *            optional map containing additional variables that can be used during the message
   *            lookup
   * @param message
   *            messagesource
   * @param remove
   *            flag indicating if the message should be removed or not
   * @see #removeMessageSource()
   * @see #logMessage(String, Map, IAuthorizationMessageSource)
   */
  protected final void logMessage(String key, Map<String, Object> variables,
    IAuthorizationMessageSource message, boolean remove)
  {
    if (message == null || Strings.isEmpty(key))
    {
      if (remove)
        removeMessageSource();
      return;
    }
    logMessage(key, variables, message);
    if (remove)
      removeMessageSource();
  }

  /**
   * Logs a message indication an action was denied. The message is retrieved through localization
   * with the specified resource key. This default implementation simply does something like
   * <code>log.debug(...)</code> Overwrite this method if you want for example wicket to print
   * feedback messages with something like <code>Session.get().error(...)</code>
   *
   * @param key
   *            the resource key for the message
   * @param variables
   *            optional map containing additional variables that can be used during message
   *            construction
   * @param message
   *            the messagesource
   */
  protected void logMessage(String key, Map<String, Object> variables,
    IAuthorizationMessageSource message)
  {
    String msg = message.getMessage(key, variables);
    if (!Strings.isEmpty(msg))
                    log.debug(msg);
  }

  /**
   * Removes the message from the {@link RequestCycle}'s metadata.
   */
  protected final void removeMessageSource()
  {
    RequestCycle.get().setMetaData(MESSAGE_KEY, null);
  }

  /**
   * Retrieves the messagesource from the {@link RequestCycle}'s metadata.
   *
   * @return the messagesource or null if there is none
   */
  protected final IAuthorizationMessageSource getMessageSource()
  {
    return getMessageSource(false);
  }

  /**
   * Retrieves the messagesource from the {@link RequestCycle}'s metadata. optionally creating a
   * new one if there is not already one.
   *
   * @param create
   * @return the messagesource or null if there is none and the create flag was false
   */
  protected final IAuthorizationMessageSource getMessageSource(boolean create)
  {
    IAuthorizationMessageSource resource = null;
    if (RequestCycle.get() != null)
      resource = RequestCycle.get().getMetaData(MESSAGE_KEY);
    if (resource == null && create)
    {
      resource = createMessageSource();
      RequestCycle.get().setMetaData(MESSAGE_KEY, resource);
    }
    return resource;
  }

  /**
   * Creates a new {@link IAuthorizationMessageSource}. Subclasses can override this to return
   * there own implementation.
   *
   * @return a new IErrorMessageSource, never null
   */
  protected IAuthorizationMessageSource createMessageSource()
  {
    return new AuthorizationMessageSource();
  }

  /**
   * Indicates if messages about denied actions should be logged. Default is to use the slf4 log
   * implementation checking if debug messages should be printed. for example using log4j as the
   * logging implementation for slf4j logging could be turned on by putting the following line in
   * your log4.properties</br> <code>
   * log4j.category.org.wicketstuff.security.strategies.WaspAuthorizationStrategy=DEBUG
   * </code>
   *
   * @return true if messages should be logged, false otherwise
   */
  protected boolean logMessages()
  {
    return log.isDebugEnabled();
  }

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

  /**
   * Shortcut to the actionfactory.
   *
   * @return the actionfactory from the application
   */
  protected final WaspActionFactory getActionFactory()
  {
    return ((WaspApplication)Application.get()).getActionFactory();
  }

  /**
   * Returns the WaspAuthorizationStrategy. This defaults to
   * {@link WaspSession#getAuthorizationStrategy()}, but a different implementation can be
   * registered via a {@link StrategyResolver}.
   *
   * @return
   */
  public static WaspAuthorizationStrategy get()
  {
    StrategyResolver threadResolver = resolver.get();
    return threadResolver == null
      ? (WaspAuthorizationStrategy)((WaspSession)Session.get()).getAuthorizationStrategy()
      : threadResolver.getStrategy();
  }

  /**
   * Sets the StrategyResolver for the current thread
   *
   * @param threadResolver
   */
  public static void setStrategyResolver(StrategyResolver threadResolver)
  {
    resolver.set(threadResolver);
  }
}
TOP

Related Classes of org.wicketstuff.security.strategies.WaspAuthorizationStrategy

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.