Package com.piercey.app.framework

Source Code of com.piercey.app.framework.ApplicationSecurityInterceptor

package com.piercey.app.framework;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import com.piercey.app.views.ApplicationView;
import com.piercey.app.views.LoginView;
import com.vaadin.navigator.Navigator;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.UI;

public class ApplicationSecurityInterceptor implements MethodInterceptor
{
  private static final ApplicationLogger logger = new ApplicationLogger(ApplicationSecurityInterceptor.class);

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable
  {
    //logger.executionTrace();
   
    final Class<?> classType = invocation.getMethod().getDeclaringClass();
    final Method method = invocation.getMethod();

    final String viewName = classType.getSimpleName();
    final String methodName = String.format("%s.%s", viewName, method.getName());

    long startTime = System.nanoTime();

    try
    {
      final String principal = ApplicationSecurity.getPrincipal();
      CheckRequiresAuthentication(classType, method, principal);
      CheckRequiresUser(classType, method, principal);
      CheckRequiresGuest(classType, method, principal);
      CheckRequiresRoles(classType, method, principal);
      CheckRequiresPermissions(classType, method, principal);

      return invocation.proceed();
    }
    catch (AuthorizationException e)
    {
      final Navigator navigator = UI.getCurrent().getNavigator();
      Notification.show("Authentication Violation", Type.TRAY_NOTIFICATION);
      navigator.navigateTo(LoginView.NAME);
    }
    catch (AuthenticationException e)
    {
      final Navigator navigator = UI.getCurrent().getNavigator();
      Notification.show("Authorization Violation", Type.TRAY_NOTIFICATION);
      navigator.navigateTo(ApplicationView.NAME);
    }
    finally
    {
      final double duration = (System.nanoTime() - startTime) / 1000000.0;
      final String message = String.format("%s took %.3f ms to examine %s",
          getClass().getSimpleName(), duration, methodName);
      logger.debug(message);
    }
   
    return null;
  }

  /**
   * Check for @RequiresAuthentication
   *
   * This annotation requires the current subject to have been authenticated during their current session for the
   * annotated class/instance/method to be accessed or invoked. This is more restrictive than the RequiresUser
   * annotation.
   *
   * This annotation basically ensures that subject.isAuthenticated() === true
   */
  private void CheckRequiresAuthentication(Class<?> runtimeClass, Method method, String userName) throws Throwable
  {
    final String viewName = runtimeClass.getSimpleName();
    final String methodName = String.format("%s.%s", viewName, method.getName());

    boolean requiresAuthentication = false;

    try
    {
      RequiresAuthentication annotation = runtimeClass.getAnnotation(RequiresAuthentication.class);
      requiresAuthentication = (annotation != null);
    }
    catch (NullPointerException e)
    {
      requiresAuthentication = false;
    }

    if (requiresAuthentication && !ApplicationSecurity.isAuthenticated())
    {
      final String message = String.format("Authentication failed for %s on %s", userName, viewName);
      logger.warn(message);
      throw new AuthenticationException(message);
    }

    try
    {
      RequiresAuthentication annotation = method.getAnnotation(RequiresAuthentication.class);
      requiresAuthentication = (annotation != null);
    }
    catch (NullPointerException e)
    {
      requiresAuthentication = false;
    }

    if (requiresAuthentication && !ApplicationSecurity.isAuthenticated())
    {
      final String message = String.format("Authentication failed for %s on %s", userName, methodName);
      logger.warn(message);
      throw new AuthenticationException(message);
    }
  }

  /**
   * Check @RequiresUser at the class level.
   *
   * This annotation requires the current subject to be an application user for the annotated class/instance/method to
   * be accessed or invoked. This is less restrictive than the RequiresAuthentication annotation. Shiro defines a
   * "user" as a Subject that is either "remembered" or authenticated:
   *
   * An authenticated user is a Subject that has successfully logged in (proven their identity) during their current
   * session. A remembered user is any Subject that has proven their identity at least once, although not necessarily
   * during their current session, and asked the system to remember them.
   */
  private void CheckRequiresUser(Class<?> runtimeClass, Method method, String userName) throws Throwable
  {
    final String viewName = runtimeClass.getSimpleName();
    final String methodName = String.format("%s.%s", viewName, method.getName());

    boolean requiresUser = false;

    try
    {
      RequiresUser annotation = runtimeClass.getAnnotation(RequiresUser.class);
      requiresUser = (annotation != null);
    }
    catch (NullPointerException e)
    {
      requiresUser = false;
    }

    if (requiresUser && !(ApplicationSecurity.isRemembered() || ApplicationSecurity.isAuthenticated()))
    {
      final String message = String.format("Authentication failed for %s on %s", userName, viewName);
      logger.warn(message);
      throw new AuthenticationException(message);
    }

    try
    {
      RequiresUser annotation = method.getAnnotation(RequiresUser.class);
      requiresUser = (annotation != null);
    }
    catch (NullPointerException e)
    {
      requiresUser = false;
    }

    if (requiresUser && !(ApplicationSecurity.isRemembered() || ApplicationSecurity.isAuthenticated()))
    {
      final String message = String.format("Authentication failed for %s on %s", userName, methodName);
      logger.warn(message);
      throw new AuthenticationException(message);
    }
  }

  /**
   * Check @RequiresGuest at the class level.
   *
   * This annotation requires the current Subject to be a "guest", that is, they are not authenticated or remembered
   * from a previous session for the annotated class/instance/method to be accessed or invoked.
   *
   * This annotation is the logical inverse of the RequiresUser annotation. That is, RequiresUser == !RequiresGuest,
   * or more accurately,
   *
   * RequiresGuest === subject.getPrincipal() == null.
   */
  private void CheckRequiresGuest(Class<?> runtimeClass, Method method, String userName) throws Throwable
  {
    final String viewName = runtimeClass.getSimpleName();
    final String methodName = String.format("%s.%s", viewName, method.getName());

    boolean requiresGuest = false;

    try
    {
      RequiresGuest annotation = runtimeClass.getAnnotation(RequiresGuest.class);
      requiresGuest = (annotation != null);
    }
    catch (NullPointerException e)
    {
      requiresGuest = false;
    }

    if (requiresGuest && !ApplicationSecurity.isGuest())
    {
      final String message = String.format("Guest role is required for %s on %s", userName, viewName);
      logger.warn(message);
      throw new AuthenticationException(message);
    }

    try
    {
      RequiresGuest annotation = method.getAnnotation(RequiresGuest.class);
      requiresGuest = (annotation != null);
    }
    catch (NullPointerException e)
    {
      requiresGuest = false;
    }

    if (requiresGuest && !ApplicationSecurity.isGuest())
    {
      final String message = String.format("Guest role is required for %s on %s", userName, methodName);
      logger.warn(message);
      throw new AuthenticationException(message);
    }
  }

  /**
   * Check @RequiresRoles at the class level.
   *
   * This annotation requires the currently executing Subject to have all of the specified roles. If they do not have
   * the role(s), the method will not be executed and an AuthorizationException is thrown.
   */
  private void CheckRequiresRoles(Class<?> runtimeClass, Method method, String userName) throws Throwable
  {
    final String viewName = runtimeClass.getSimpleName();
    final String methodName = String.format("%s.%s", viewName, method.getName());

    boolean requiresRoles = false;
    List<String> requiredRoles = null;

    try
    {
      RequiresRoles annotation = runtimeClass.getAnnotation(RequiresRoles.class);
      requiresRoles = (annotation != null);
      requiredRoles = Arrays.asList(annotation.value());
    }
    catch (NullPointerException e)
    {
      requiresRoles = false;
    }

    if (requiresRoles && requiredRoles != null && !ApplicationSecurity.hasAllRoles(requiredRoles))
    {
      final String message = String.format("Insufficient role membership for %s on %s", userName, viewName);
      logger.warn(message);
      throw new AuthorizationException(message);
    }

    try
    {
      RequiresRoles annotation = method.getAnnotation(RequiresRoles.class);
      requiresRoles = (annotation != null);
      requiredRoles = Arrays.asList(annotation.value());
    }
    catch (NullPointerException e)
    {
      requiresRoles = false;
    }

    if (requiresRoles && requiredRoles != null && !ApplicationSecurity.hasAllRoles(requiredRoles))
    {
      final String message = String.format("Insufficient role membership for %s on %s", userName, methodName);
      logger.warn(message);
      throw new AuthorizationException(message);
    }
  }

  /**
   * Check @RequiresPermissions at the class level.
   *
   * This annotation requires the current executor's Subject to imply a particular permission in order to execute the
   * annotated method. If the executor's associated Subject determines that the executor does not imply the specified
   * permission, the method will not be executed.
   */
  private void CheckRequiresPermissions(Class<?> runtimeClass, Method method, String userName) throws Throwable
  {
    final String viewName = runtimeClass.getSimpleName();
    final String methodName = String.format("%s.%s", viewName, method.getName());

    boolean requiresPermissions = false;
    List<String> requiredPermissions = null;

    try
    {
      RequiresPermissions annotation = runtimeClass.getAnnotation(RequiresPermissions.class);
      requiresPermissions = (annotation != null);
      requiredPermissions = Arrays.asList(annotation.value());
    }
    catch (NullPointerException e)
    {
      requiresPermissions = false;
    }

    if (requiresPermissions && requiredPermissions != null
        && !ApplicationSecurity.hasAllPermissions(requiredPermissions))
    {
      final String message = String.format("Insufficient permission for %s on %s", userName, viewName);
      logger.warn(message);
      throw new AuthorizationException(message);
    }

    try
    {
      RequiresPermissions annotation = method.getAnnotation(RequiresPermissions.class);
      requiresPermissions = (annotation != null);
      requiredPermissions = Arrays.asList(annotation.value());
    }
    catch (NullPointerException e)
    {
      requiresPermissions = false;
    }

    if (requiresPermissions && requiredPermissions != null
        && !ApplicationSecurity.hasAllPermissions(requiredPermissions))
    {
      final String message = String.format("Insufficient permission for %s on %s", userName, methodName);
      logger.warn(message);
      throw new AuthorizationException(message);
    }
  }
 
  public class AuthenticationException extends Exception
  {
    private static final long serialVersionUID = -7385155171164478603L;

    public AuthenticationException()
    {
      super();
    }

    public AuthenticationException(String message, Throwable cause)
    {
      super(message, cause);
    }

    public AuthenticationException(String message)
    {
      super(message);
    }

    public AuthenticationException(Throwable cause)
    {
      super(cause);
    }
  }

  public class AuthorizationException extends Exception
  {
    private static final long serialVersionUID = -7385155171164478603L;

    public AuthorizationException()
    {
      super();
    }

    public AuthorizationException(String message, Throwable cause)
    {
      super(message, cause);
    }

    public AuthorizationException(String message)
    {
      super(message);
    }

    public AuthorizationException(Throwable cause)
    {
      super(cause);
    }
  }
}

TOP

Related Classes of com.piercey.app.framework.ApplicationSecurityInterceptor

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.