{{announcement.body}}
{{announcement.title}}

Secure Your Method Using AOP

DZone 's Guide to

Secure Your Method Using AOP

In this article, we take a look at how you can secure your methods using aspect-oriented programming.

· Java Zone ·
Free Resource

In this article we learn how to secure our methods the easy way!

We basically use the Before Advice of aspect-oriented programming (AOP) to achieve our goal. The article even illustrates how easy it is to use AOP to implement a crosscutting concern such as security. Let's get started

Pre-requisites:

  • Knowledge of Spring Framework.
  • Overview of AOP

What is AOP?

Spring AOP enables Aspect-Oriented Programming in Spring applications. In AOP, aspects enable the modularization of concerns such as transaction management, logging, or security that cut across multiple types and objects (often called crosscutting concerns). 

What Is an Advice?

Advice is an action taken by an aspect at a particular join point. Different types of advice include “around,” “before” and “after” advice. 

What is Before advice?

Before advice: Advice that executes before a join point, but which does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception).  

The following code snippet shows the  SecureMessage class. This is the class that we will be securing using AOP.

Java
 




x


1
public class SecureMessage
2
{
3
  public void writeSecureMessage() 
4
  {
5
    System.out.println("100 pushup and 100 situp is the key to success-Saitama");
6
  }
7
}


Because this example requires users to authenticate, we are going to need to store their details. The following code snippet shows the UserInfo class we can use to store a user’s credentials:

Java
 




x


1
public class UserInfo 
2
{
3
  private String userName;
4
  private String password;
5
  public UserInfo(String userName, String password)
6
  {
7
    this.userName = userName;
8
    this.password = password;
9
    }
10
    public String getPassword() {
11
        return password;
12
    }
13
    public String getUserName() {
14
        return userName;
15
    }
16
  }
17
}



This class simply holds data about the user so that we can use it to validate the user. The following code snippet shows the SecurityManager class, which is responsible for authenticating users and storing their credentials for later retrieval:

Java
 




xxxxxxxxxx
1
13


1
public class SecurityManager {
2
  private static ThreadLocal<UserInfo>
3
  threadLocal = new ThreadLocal<>();
4
  public void login(String userName, String password) {
5
    threadLocal.set(new UserInfo(userName, password));
6
  }
7
  public void logout() {
8
    threadLocal.set(null);
9
  }
10
  public UserInfo getLoggedOnUser() {
11
    return threadLocal.get();
12
  }
13
}



Please note, in a real application, the  login() method would probably check the supplied credentials against a database or LDAP directory, but here we check  and assign against static values.

  • login(): method creates a  UserInfo  object for the user and stores it on the current thread by using ThreadLocal. 
  • logout(): method sets any value that might be stored in  ThreadLocal  to null. 
  • getLoggedOnUser(): method returns the  UserInfo object for the currently authenticated user. This method returns null if no user is authenticated.

Now we get to the interesting stuff.

To check whether a user is authenticated and, if so, whether the user is permitted to access the methods on SecureMessage, we need to create advice that executes before the method and checks the UserInfo object returned by SecurityManager.getLoggedOnUser() against the set of credentials for allowed users. The code for this advice, SecurityAdvice, is shown as follows:

Java
 




x


1
import java.lang.reflect.Method;
2
import org.springframework.aop.MethodBeforeAdvice;
3
public class SecurityAdvice implements MethodBeforeAdvice {
4
  private SecurityManager securityManager;
5
  public SecurityAdvice() {
6
    this.securityManager = new SecurityManager();
7
  }
8
  @Override
9
  public void before(Method method, Object[] args, Object target)
10
  throws Throwable {
11
    UserInfo user = securityManager.getLoggedOnUser();
12
    if (user == null) {
13
      System.out.println("No user authenticated");
14
      throw new SecurityException(
15
      "You must login before attempting to invoke the method: "
16
      + method.getName());
17
    } else if ("Saitama".equals(user.getUserName())) {
18
        System.out.println("Logged in user is Saitama - OKAY!");
19
    } else {
20
      System.out.println("Logged in user is " + user.getUserName()
21
      + " NOT GOOD :(");
22
      throw new SecurityException("User " + user.getUserName()
23
      + " is not allowed access to method " + method.getName());
24
  }
25
}


before() method, we perform a simple check to see whether the username of the authenticated user is Saitama. If so, we allow the user access; otherwise, an exception is raised. Also notice that we check for a null UserInfo object, which indicates that the current user is not authenticated.

In the following code snippet, you can see a sample application that uses the SecurityAdvice class to secure the SecureMessage class:

Java
 




x


1
import org.springframework.aop.framework.ProxyFactory;
2
 
          
3
public class SecurityDemo {
4
    public static void main(String... args) {
5
        SecurityManager mgr = new SecurityManager();
6
        SecureMessage bean = getSecureBean();
7
        mgr.login("Saitama", "pwd");
8
        System.out.println("---Scenario 1---");
9
        bean.writeSecureMessage();
10
        mgr.logout();
11
        try {
12
            mgr.login("invalid user", "pwd");
13
            System.out.println("---Scenario 2---");
14
            bean.writeSecureMessage();
15
        } catch (SecurityException ex) {
16
            System.out.println("Exception Caught: " + ex.getMessage());
17
        } finally {
18
            mgr.logout();
19
        }
20
        try {
21
            System.out.println("---Scenario 3---");
22
            bean.writeSecureMessage();
23
        } catch (SecurityException ex) {
24
            System.out.println("Exception Caught: " + ex.getMessage());
25
        }
26
    }
27
 
          
28
    private static SecureBean getSecureBean() {
29
        SecureMessage target = new SecureMessage();
30
        SecurityAdvice advice = new SecurityAdvice();
31
        ProxyFactory factory = new ProxyFactory();
32
        factory.setTarget(target);
33
        factory.addAdvice(advice);
34
        SecureMessage proxy = (SecureMessage) factory.getProxy();
35
        return proxy;
36
    }
37
}


Output:

---Scenario 1---

Logged in user is Saitama - OKAY!

100 pushup and 100 situp is the key to success-Saitama

---Scenario 2---

Logged in user is invalid user NOT GOOD.

Exception Caught: User invalid user is not allowed access to method writeSecureMessage

---Scenario 3---
No user authenticated

Exception Caught: You must login before attempting to invoke the method: writeSecureMessage

Explanation

In the  getSecureBean() method, we create a proxy of the  SecureMessage  class that is advised using an instance of SecurityAdvice. This proxy is returned to the caller. When the caller invokes any method on this proxy, the call is first routed to the instance of SecurityAdvice for a security check. In the  main()  method, we test three scenarios, invoking the  SecureMessage.writeSecureMessage()  method with two sets of user credentials and then no user credentials at all. Because SecurityAdvice allows method calls to proceed only if the currently authenticated user is Saitama, we can expect that the only successful scenario in the previous code is the first.

As you can see, only the first invocation of  SecureMessage.writeSecureMessage() was allowed to proceed. The remaining invocations were prevented by the  SecurityException  exception thrown by  SecurityAdvice . This example is simple, but it does highlight the usefulness of before advice. Security is a typical example of before advice, but we also find it useful when a scenario demands the modification of arguments passed to the method.ALU

Topics:
aop, aspect oriented programming, java, java 1.8, security, spring framework

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}