PROJECT: OASIS


Overview

Office Assistance Specialized Integration System (OASIS) is an all-in-one app for companies to manage employee’s leave applications, projects and user accounts for each employee. OASIS uses a CLI interface.

This project portfolio summarizes my contributions to the project in terms of coding, documentation for both develoeprs and end-users, as well as testing.

Summary of contributions

The following section shows my major code contributions to OASIS.

Major enhancement: User accounts

  • Major enhancement: Added full fledged functionality for user accounts.

    • What it does: Allows each employee to identify themselves with a username and password, similar to most modern systems. It provides:

      • Username and Password implementation for each employee.

      • Ability to login and logout into each employee’s accounts.

      • A way to secure the employee’s account through the changing of passwords.

      • Complete modern-day security using salted and hashed passwords with 256-byte salts and SHA512 hashing algorithm.

    • Justification: It is critical to ensure the privacy of employees by keeping their private information secure and only viewable by specific people. Thus, this feature allows the use of user accounts to verify that there is appropriate authorization, ensuring that employee data isn’t publicly viewable.

    • Highlights: The password command requires large changes to ensure that passwords input by the user aren’t viewable through the history command. To solve this gacefully, I implemented a feature for LogicManager to have a List of interceptors, which are a FunctionalInterface that allows the processing of a Command. This allows the password changing command to work without adding excessive coupling between Command and LogicManager. Security for each user was essental to ensure that a user cannot read commands entered by another user. This was implemented by clearing user-specific data after logout.

Minor enhancement:

The following section shows all the other minor enhancements done for the project that are not part of my major enhancement above.

  • Code contributed: [Reposense link]

  • Other contributions:

    • Project management:

      • Set up the project on GitHub, including the creation of the organization, labels, auto-publishing of docs, and the team PR

      • Managed releases v1.0 - v1.4 (5 releases) on GitHub

      • Set up RepoSense for the group, allowing for code to be properly attributed #35

    • Documentation:

      • Provided updates to the User Guide: #125

      • Updated documentation based on errors I encountered and how to resolve it to help future contributors #2

    • PR standards:

      • All of my pull requests have referenced clearly to which issues they’re attempt to address and have resulted in no loss of code coverage. Major examples: (#84 #106 #118)

    • Enhancements to existing features:

      • Allow for easier searching of employees by updated the find command to support * and _ as wildcards.

      • Converted the parser to use - instead of / to read arguments, similar to the command line in modern day operating systems.

    • Community:

      • Contributed to forum discussions (example: 1, 2)

      • Reported bugs and suggestions for other teams in the class (examples: 1 2 3)

    • Tools:

      • Integrated Travis CI, AppVeyor and Coveralls to the team repo

Contributions to the User Guide

The following sections represent my contributions to the User Guide. They demonstrate my ability to write end-user documentation.

Edit details of the currently logged in user : myself

Changes the details of the currently logged in user

Format: myself [-p PHONE] [-e EMAIL] [-a ADDRESS] [-t ASSIGNMENT]

  • At least one of the optional fields must be provided.

  • Existing values will be updated to the input values.

  • This command is not usable as admin.

Examples:

Change password : passwd

Changes user password.

Format: passwd

  • The password must contain at least 1 captial letter, one lowercase letter and one digit. It must also be at least 8 characters long.

  • You will be prompted for your current password, and then your new one.

  • The default password for all accounts is Pa55w0rd.

Passwords should not to be supplied in the command line (makes it vulnerable to viewing it through history.)

Contributions to the Developer Guide

The next section serves to showcase my additions to the Developer Guide. They act as an exhibit to show my capability in writing good technical documentation, along with the technical depth of my contributions.

Login/Logout feature

Current Implementation

The Login/Logout feature is facilitated through the use of creating a login screen before the application begins, ensuring that the user starts by logging into his account.

These operations are exposed in the MainWindow class through fillLoginParts(), removeLoginWindow(), removeInnerElements(), processLogin(LoginEvent) and processLogout(LogoutEvent)

While the login screen is displayed, other usual UI elements, such as the browserPanel, PersonListPanel, ResultDisplay, StatusBarFooter, CommandBox are not initialized at all, so they cannot be accessed.
To ensure that most tests still work with a login system, the MainWindowHandle, used by all GUI tests, automatically logs the user in right after the UI element loads.

The following sequence diagram shows a high level overview between the components when a User begins logging into OASIS.

LoginSequenceDiagram
Figure 1. A high level overview of how components interact when a login is performed.

This situation branches if the user’s input of username and password is invalid. The following activity diagram shows the branching case:

LoginActivityDiagram
Figure 2. An activity diagram showing where the login code branches if the input does not match a user.

The communication between UI, Logic and Model is mainly from using EventsCenter and firing events to tell the other components to act. The following detailed steps show how the program works as the user login.:

  1. When the program is started, UIManager creates the MainWindow and tells it to fillLoginParts().

  2. The user enters his details, and clicks login.

  3. This causes the LoginForm to fire a LoginEvent onto the central EventBus, with the username and password saved into the LoginEvent.

  4. The Logic Manager catches the LoginEvent. It then checks if the username and password combination matches a person in the system, or the admin user. To do so, it communicates with the model to retrieve everyone in the system.

    1. If there is no successful match, then a FailedLoginEvent is fired. The LoginForm catches this Event and displays the error message provided by the FailedLoginEvent.

  5. If there is a successful match, then a SuccessfulLoginEvent is fired. This event contains the person that is currently logging in, wrapped in a User object.

  6. The mainWindow class catches the SuccessfulLoginEvent and processes it, removing the login UI Elements and replacing it with fillInnerParts()

When the user wishes to logout, he enters logout, which triggers the following:

  1. The LogoutEvent is fired by the LogoutCommand.

  2. The mainWindow class catches the LogoutCommand and processes it, removing the main UI elements and replacing it with the fillLoginParts()

Design Considerations

Aspect: How the login screen is displayed

The login screen needs to be displayed to the user in some fashion.

  • Alternative 1 (current choice): Create a login screen before initializing other UI elements on the fly.

    • Pros: One single window. Clear to the user which window to focus on. Most applications work this way, so it should be familiar to the majority of our users.

    • Cons: Harder to implement. Need to take into account other possible UI elements, preload only those that are required, and ensure that tests stay supported.

  • Alternative 2: Build another UI Window just for login. Before logging in, this window will popup. Once the user has logged in, the login window will close and the main window will pop up.

    • Pros: Far easier to implement. Login system abstracted away from other functionality.

    • Cons: It will be hard to maintain the same window size as the login window, if the user resizes it. More coupling would be required to maintain the same window size. Very odd and unfamiliar to most users. No application today opens a login window, then on successful login, closes that login window and opens a new one, meant for the user to use. This can cause a lot of user confusion. They may think that:

      • The new window is representing error message, it should not have opened.

      • The application had an error and unexpectedly shutdown.

      • The new window is from another application that the user has running on his computer.

      • They did something wrong (perhaps they pressed the button to close the window instead?)

Aspect: How the UI and Logic elements should communicate.

Whenever a login is done by the User, the UI, Logic and Model elements need to communicate to handle the event.

  • The UI needs to provide the User Input information.

  • The Logic needs to perform the check of whether this is a valid Username and Password combination.

  • The Model needs to provide the data for the logic to do it’s work.

There needs to be a solution to handle this cleanly and without causing unnecessary coupling, as this will likely be required to be extended upon in the long run.

  • Alternative 1 (current choice): Utilize the EventBus to allow UI, Model and Logic to communicate

    • Pros: Reduces coupling, as UI, Model and Logic doesn’t need to know about each other. If required, other classes can also listen for the Event and process accordingly

    • Cons: Needs some work to implement. Requires building up new classes.

  • Alternative 2: Let UI, Logic and Model know about each other, allowing them to call the relevant methods and do the relevant checks

    • Pros: Easy to implement.

    • Cons: Grealy increases coupling. Not a good design decision, as it will make it harder to maintain the code in the future.

  • Alternative 3: Build a command like system (similar to how Commands are implemented in the system) for UI to talk to Logic. Logic then uses the Command system to reply back to UI.

    • Pros: Reduces the amount of coupling added into the system. Provides a way for UI to get Logic to do things, in case more functionality is added that uses UI input.

    • Cons: Very time consuming to implement. Hard to design as there is no clear functionality that might also need this system in the future.

Username and Password storage

To store username and password, the class Person has been extended to include a Username and Password variable as well. These two variables represent the Username and Password stored in the system for that Person.

Admin account

There is a possibility that the entire system is cleared of all employees (i.e when initializing, or an accidental deleting of all employees). To resolve this issue, an admin account is added that will ensure that there is always a user that can login in. The admin account cannot be removed and always has full access rights. By default, the username of the admin account is Admin and the password is Pa55w0rd.

The password of the admin account can be modified through the passwd command.

Design Considerations

Aspect: Where the admin account password can be stored.

Since the admin account would cause the system to be very insecure if it’s password couldn’t be changed, the admin account password must be changeable and stored somewhere, so that it persists across sessions. But where?

  • Alternative 1 (current choice): Place the storage in User Preferences

    • Pros: Easy to implement. A nice, centralized place to store general application information.

    • Cons: If the file is deleted, then the password will revert back to the default, which leaves the admin account vulnerable.

    • As we plan to store the system in a central server, the admin account’s information will be stored in the server, and not locally. As this is intended to change before the final release, we went for the option that is the simplest to implement.

  • Alternative 2: Add it into the address book.xml file

    • Pros: If the password was attempted to be removed through the deletion of the file, then this will also delete everyone in the system as well, thus rendering the access to the admin account useless.

    • Cons: Since the file is stored in an xml format, it is easy for any dedicated attacker to find and remove the password information, reverting it to the default. Harder to implement, as would require large changes in the address book parser.

  • Alternative 3: Store it within environment variables

    • Pros: Somewhat harder to find. Ensures that admin password remains even when the data files are deleted.

    • Cons: The admin password would not transfer over systems for the average user. It would be difficult and require technical knowledge of the user to get it to transfer.

passwd Command

To change the password, a passwd command is required. However, this command is very different from the other commands. Specifically, it requires a chain of input, and subsequent inputs from the user should not be stored in history (otherwise the user’s password are easily retrievable).

This is, however, not easy to handle. This command history is automatically populated by LogicManager, which Command.execute does not have access to. To complicate things further, CommandParser doesn’t handle exceptions like storing a command for future use, or redirecting user input to a specific Command.

To resolve this issue, CommandResult is extended to hold interceptors - a list of ProcessCommand. ProcessCommand is a functional interface, similar to Function except that it can throw a specific error as well. To implement passwd, it returns an implementor of ProcessCommand to CommandResult, which forwards it to LogicManager.

LogicManager now accepts ProcessCommand from CommandResult, adding them to a list. As long as there exists at least one ProcessCommand, further messages are pushed to ProcessCommand instead of processed normally, and they aren’t added to history.

Other possible design considerations are shown below.

Design Considerations

Aspect: How to implement the passwd Command
  • Alternative 1 (current choice): Build a foundation of ProcessCommand that will intercept user input and process it instead. If it does so, LogicManager doesn’t add the command to history.

    • Pros: Doesn’t increase coupling unnecessarily. Allows other functions to utilize this, allowing other commands to also easily extend to a chain of user inputs.

    • Cons: Harder to implement. Somewhat hard to understand, as it requires knowledge of lambdas and functional interfaces.

  • Alternative 2: Apply a hack for passwd where LogicManager checks that if a passwd command is ongoing, it redirects there instead.

    • Pros: Easy to implement.

    • Cons: Greatly increases coupling. If further commands were to require the same functionality, this hack would need to be done again for that function.

Password Security

There is a need to have passwords be stored securely as opposed to being stored in plain text. The standard today is to have password be salted and hashed, which is also the standard that OASIS is implemented in.

All of this is handled within the Password class. API: Password.java

The Password class stores the password in plaintext (if available), the salt and the hash of the password. The salt and the hash are always available.

If the password object was created this session (i.e. the user changed his password this session), the plaintext will be available. Otherwise, if it was read from the saved XML file, then only the salt and hash are available.

When checking if 2 Passwords are the same, it is better to call isSamePassword to verify if the 2 passwords are the same. isSamePassword checks if both passwords would have had the same plaintext. Utilizing .equals would also require the salt to match as well.

Design Considerations

Aspect: How much security is required for the password
  • Alternative 1: Just store and save the password in plaintext.

    • Pros: Very easy to implement. Makes testing significantly easier. Can verify both appropriate input and output.

    • Cons: No security. Anyone who wants to view someone else’s password can just look into the data files and find it easily.

  • Alternative 2: Apply a hash to all passwords (i.e. SHA512).

    • Pros: Still somewhat easy to implement.

    • Cons: Testing becomes slightly harder as test code can no longer rely on getting the password in plaintext. Still not very secure, rainbowtables and hash crackers exist that can easily get back the plaintext password.

  • Alternative 3: (current choice): Apply a salt + hash to all passwords

    • Pros: Full security suite. Ensures that we aren’t storing our user’s passwords, so if the database is compromised, our user’s passwords aren’t easily broken.

    • Cons: Very hard to implement. Testing becomes significantly harder because calling .equals on Passwords that are the same may return false due to differences in salt.