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 aFunctionalInterface
that allows the processing of a Command. This allows the password changing command to work without adding excessive coupling betweenCommand
andLogicManager
. 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:
-
Documentation:
-
PR standards:
-
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:
-
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.
Examples:
-
myself -p 91234567 -e johndoe@example.com
-
myself -n James
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.
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.
This situation branches if the user’s input of username and password is invalid. The following activity diagram shows the branching case:
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.:
-
When the program is started, UIManager creates the MainWindow and tells it to
fillLoginParts()
. -
The user enters his details, and clicks login.
-
This causes the
LoginForm
to fire aLoginEvent
onto the central EventBus, with the username and password saved into theLoginEvent
. -
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.-
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.
-
-
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. -
The
mainWindow
class catches theSuccessfulLoginEvent
and processes it, removing the login UI Elements and replacing it withfillInnerParts()
When the user wishes to logout, he enters logout, which triggers the following:
-
The
LogoutEvent
is fired by theLogoutCommand
. -
The
mainWindow
class catches theLogoutCommand
and processes it, removing the main UI elements and replacing it with thefillLoginParts()
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
andLogic
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.
-