Architecture & Design Protecting Data through Object Oriented Programming

Protecting Data through Object Oriented Programming



 

 

Introduction

 

This is the eight installment in a series of articles
about fundamental object-oriented (OO) concepts. The material presented in these
articles is based on material from the second edition of my book,

The Object-Oriented
Thought Process
, 2nd edition. The Object-Oriented
Thought Process
is intended for anyone who needs to understand the basic
object-oriented concepts before jumping into the code. Click

here
to start
at the beginning of the series.

 

In keeping with the code examples used in the previous articles, Java will
be the language used to implement the concepts in code. One of the reasons that
I like to use Java is because you can download the Java compiler for personal
use at the Sun Microsystems Web site

http://java.sun.com/
.
You can download the

J2SE 1.4.2 SDK

(software development kit) to compile and execute these applications and will
provide the code listings for all examples in this article. I have the SDK 1.4.0
loaded on my machine. I will provide figures and the output for these examples.
See previous articles in this series for detailed descriptions for compiling
and running all the code examples in this series.

 

Checking Account
Example

 

In this column we will focus on how to
protect data from either unintentional mistakes or intentional malicious
behavior. To accomplish this we will continue in our development of an ATM
example. In the previous column, we developed a simple checking account example.
Let’s do a quick review of this class before we proceed.

 

Figure 1 shows the UML class diagram that corresponds to our
latest design.

 


Figure 1:
UML
Diagram for Checking Account Class

 

Listing 1 displays the code that corresponds directly to
the class in Figure 1.

 

class CheckingAccount {
 
   private double balance = 0;
 
   private void setBalance(double bal) {
 
      balance = bal;
 
   };
 
   public double getBalance(){
 
      return balance;
 
   };
 
   public void deposit(double dep){
 
        setBalance(balance + dep);
 
 
   };
 
   public void withdrawal(double with){
 
        setBalance(balance - with);
 
 
   };
 
}

Listing 1:
CheckingAccount.java

In effect we now have the following components to our CheckingAccount
class.

 

  1. The private attributes
    1. balance
  2. The private implementation
    1. setBalance()
  3. The public interfaces
    1. deposit()
    2. withdrawal()
    3. getBalance()

 

Now that we have developed the CheckingAccount class –
let’s use the class in an actual application.

 

Creating an
Application

 

It is important to realize that an application must be
created before utilizing a class. In Java, an application is defined by a method
called main(). Technically, everything in Java is considered a class
(except for some primitives like int and float). To get a
application up and running we will create 2 Java files and each of these files
will contain a class. These 2 files will contain the CheckingAccount class and the
main
() application class (I put only one class per each file). We have already seen the CheckingAccount class,
the barebones main() application class is contained in listing 2.

 

class TestCheckingAccount {
    public static void main(String args[]) {

    }
}

Listing 2:
TestCheckingAccount.java

The line of code that contains main() defines this
as an application – basically the entry point to the applications. Notice that the file names must match the class names. Thus,
the class TestCheckingAccount is contained in a file called
TestCheckingAccount.java. At this point the TestCheckingAccount application will
execute but it doesn’t do anything. What we want it to do is utilize the
CheckingAccount class that we have created. We can instantiate a CheckingAccount
object in our application by adding the code in Listing 3.

 

class TestCheckingAccount {
    public static void main(String args[]) {

        CheckingAccount myAccount = new
CheckingAccount();

    }
}

 

Listing 3:
TestCheckingAccount.java

When this code is executed
an actual CheckingAccount object, called myAccount,  is created;
however,
we still have yet to do anything with it. To illustrate what we can do with the
newly created object, let’s examine what the value of the current balance is.
Since we initialized it to 0, we should expect that to be the value.

This is a great opportunity
to explore how data in an object is actually protected. Consider the possibility
that a rogue employee decides to write an application which will inspect the
balances of all checking accounts. At first, this seems like a very simple
problem to solve – simply write code that inspects the attribute balance
directly. The code may look something like Listing 4.

class TestCheckingAccount {
    public static void main(String args[]) {

        CheckingAccount myAccount = new
CheckingAccount();

       
System.out.println("balance = " + myAccount.balance);

    }
}

Listing 4:
TestCheckingAccount.java

The logic of this code dictates that the balance will be printed when the
println
() is executed.

       
System.out.println("balance = " + myAccount.balance);

This line attempts to access the attribute balance of the myAccount
object. In a proper object-oriented design, it is unacceptable for an
application to have uncontrolled access to an attribute. This is a security
issue. You never want uncontrolled access to data in an object. In fact, this
data protection is already designed into the CheckingAccount class. Remember
that the balance attribute was declared as private. Thus, when we try to
compile the code in Listing 4 the compiler acts as a security guard and will not
let the code compile. The compiler produces the following error:

TestCheckingAccountTestCheckingAccount.java:6: balance has private
access in CheckingAccount
System.out.println("balance = " + myAccount.balance);
 

Pay special attention to the word private. Since we (properly)
declared balance as private, the attribute is protected from uncontrolled
access. You may be wondering what the term uncontrolled access actually means
since we have used it several times already.

Data Protection

Consider what happens when you use an ATM and you want to inspect your
account balance. After you swipe your card, do you have uncontrolled access to
your balance at that time? No. You still need to do at least one more thing –
enter your PIN. It is only after you enter your PIN that you gain access to you
account and start posting transactions. This is what is meant by uncontrolled
access. In the vast majority of  business transactions, controlled access
to data is vital – even required by law. This is why attributes in an object are
accessed via methods and not referenced directly. We have no mechanism to
control access to public attributes. However, we can insert code into methods to
control access to attributes in objects. Perhaps the most common example would
be that of passwords – which are similar to the PIN example.

Consider your email client. What happens when you want to change your
password? Are you able to directly change your password? Absolutely not. You
must execute a change password routine to accomplish the task. In fact, it is
not quite as simple as that. You not only have to execute the change password
routine, you must also know your original password. This is an obvious security
issue. You don’t want to walk away from your computer for a break and then have
someone sit down at your machine and directly reset your password. What you do
want is for a change password routine to require the original password be
entered before the new password is set.

We will explore this password issue later, however; we can now return to the
problem of how to inspect the balance. At this point the answer should be
obvious. The answer is a method and in this case the getBalance() method.
This code is shown in Listing 5.

class TestCheckingAccount {
    public static void main(String args[]) {

        CheckingAccount myAccount = new
CheckingAccount();

       
System.out.println("balance = " + myAccount.getBalance());

    }
}

Listing 5:
TestCheckingAccount.java

Thus, the way to access (inspect) the balance attribute is through the 
method getBalance().

       
System.out.println("balance = " + myAccount.getBalance());
 

When this code executes, the output produced is presented in Figure 2. Here
we can see that the initial value of balance is indeed 0.


Figure 2:

TestCheckingAccount Application

There is one more level of data protection that was designed into the
CheckingAccount class. Consider that our rogue programmer figures out pretty
quickly that there is absolutely no way to directly access the balance
attribute. If we need to access via a method that is what we will do. There is a
method called setBalance() so let’s set the balance to $1000. Consider the code
in Listing 6.

class TestCheckingAccount {
    public static void main(String args[]) {

        CheckingAccount myAccount = new
CheckingAccount();

        System.out.println("balance = " +
myAccount.getBalance());

       
myAccount.setBalance(1000);

    }
}

Listing 6:
TestCheckingAccount.java

Here the programmer attempts to set the balance through the setBalance()
method. However, the compiler will flag this as well because the method was
declared as private. Basically , the designers of the CheckingAccount class
wanted this method to be used only by objects of this class.

       
myAccount.setBalance(1000);
 

This code produces the following compiler error:

TestCheckingAccountTestCheckingAccount.java:8: setBalance(double) has
private access in CheckingAccount
myAccount.setBalance(1000);
 

Thus, while we can say that all attributes should be private, we
cannot say that all methods are public. Perhaps most methods will be
public; however,  there are appropriate design situations for private
methods. In the case of the CheckingAccount class, the only way to change the
balance
attribute is to either make a deposit or a withdrawal.

In Listing 7 the code is included to make a deposit and then a withdrawal.

class TestCheckingAccount {
    public static void main(String args[]) {

        CheckingAccount myAccount = new
CheckingAccount();

        System.out.println("balance = " +
myAccount.getBalance());

        myAccount.deposit(1000);

        myAccount.withdrawal(100);

        System.out.println("balance = " +
myAccount.getBalance());

   
    }
}

Listing 7:
TestCheckingAccount.java

In Listing 7 we make a deposit of $1000 and then withdrawal $100. This should
leave us with a balance of $900. By executing the application we can verify
this. Figure 3 shows what happens when we do execute this application.


Figure 3:

TestCheckingAccount Application

Note: You may be wondering why our rogue programmer would even know the names
of private attributes and methods. The answer is that the programmer would not –
or at least should not.
If the application environment is properly designed, the application programmer
would not have access to the design or the source code of the CheckingAccount class. The
programmer’s use of the CheckingAccount class would be via class packages (in
some ways analogous to libraries). Only the documentation of the public methods
would be made available to the programmer. In theory, the programmer would not
even know the name of the balance attribute or the setBalance()
method. You may not even want to choose common names for these attributes and
methods.

Adding a Password

Finally, let’s implement a simple password example to demonstrate some of the
data protection concepts discussed earlier. This will be a very primitive
example, but it illustrates the point.

Listing 8 includes new code in the CheckingAccount class that implements a
method to change a password attribute. The password is initially set to a
blank.

class CheckingAccount {

    private double balance = 0;
    private String password = " ";

    public void setPassword(String s1, String s2) {
        if (password = = s1) {
            password =
s2;
           
System.out.println("Password changed");
        } else {
           
System.out.println("Bad password");
        }
    };
    private void setBalance(double bal) {
        balance = bal;
    };
    public double getBalance(){
        return balance;
    };
    public void deposit(double dep){
        setBalance(balance + dep);
    };
    public void withdrawal(double with){
        setBalance(balance – with);
    };

}

Listing 8:
CheckingAccount.java

This is a very simplistic implementation intended to illustrate the concepts. In this code, we call
setPassword() with
2 parameters. The first is the old password and the second is the new password.
If the old password is incorrect, an error message is printed. If the old
password in entered correctly , then the password is changed and a message
indicating this is printed.

    public void setPassword(String s1, String s2) {
        if (password = = s1) {
            password =
s2;
           
System.out.println("Password changed");
        } else {
           
System.out.println("Bad password");
        }
    };

This is a good example of how access to an attribute is controlled. And this
entire article is all about stressing the importance of controlling access to
all
attributes. Listing 9 shows the an application that does not use the
proper old password.

class TestCheckingAccount {
    public static void main(String args[]) {

        CheckingAccount myAccount = new
CheckingAccount();

        myAccount.setPassword("x", "1234");

    }
}

Listing 9:
TestCheckingAccount.java

As we can see when we run the application, the class will not allow the
password to be changed if the old password is incorrectly entered. figure 4
shows the output.


Figure 4:

TestCheckingAccount Application

Conclusion

In this month’s article, we continued our discussion about encapsulation
and data hiding. Controlling access to all attributes is one of the most
important concepts of object-oriented design. By using methods to control access
to attributes we can provide a much higher
level of security for your class as well as providing many programming
advantages.

Next month we will discuss the importance of putting an
object into what is called a safe state. Not only is it important for an
object to have the appropriate security, but the object must also be robust.

About the Author

Matt Weisfeld
is an Assistant Professor at Cuyahoga Community College (Tri-C) in Cleveland,
Ohio. Matt is a part of the Information Technology department, teaching
programming languages such as C++, Java, and C# .NET as well as various Web
technologies. Prior to joining Tri-C, Matt spent 20 years in the information
technology industry gaining experience in software development, project
management, business development, corporate training, and part-time teaching.
Matt holds an MS in computer science and an MBA in project management.

The articles in this series are adapted from


The Object-Oriented
Thought Process

2nd Edition
(published by

Sams Publishing
).
Matt has published two other computer books, and more than a dozen articles in
magazines and journals such as Dr. Dobb’s Journal, The C/C++ Users
Journal
, Software Development Magazine, Java Report, and the
international journal Project Management. Matt has presented at
conferences throughout the United States and Canada.

Latest Posts

Related Stories