diff --git a/README.md b/README.md
index 3c8f16fec588355b46e33426816a1fd82c161934..1daaad109b8c232503c79723ff37933d1c12c7b1 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,10 @@ The `-u` and `-p` parameters are required, as is the username to query
 (obviously). The information above can be displayed at any time by
 running the software with the `-?` or `--help` arguments.
 
+If you do not want to give the program your password in plain text (you shouldn't)
+then you can use an encrypted form by prefixing it with `{crypt}` and
+encrypting it by following [these instructions](https://www.openldap.org/faq/data/cache/344.html).
+
 ## License and limitation of liability
 
 This program is free software: you can redistribute it and/or modify
@@ -57,4 +61,14 @@ file.
 To put it briefly, I was not sure how the University would react to me
 using their LDAP server for this purpose (although one could argue that
 if they didn't want me to use it, then I should not have access!), hence
-the project can only be viewed internally on the University's Git service.
\ No newline at end of file
+the project can only be viewed internally on the University's Git service.
+
+## Things that could be improved
+
+As there is no reason anyone would actually use this software, there is
+no real reason to modify it in the future. The following is a list of things
+that could be improved to make the software better.
+
+- Right now it is not possible to specify the LDAP server hostname or port.
+This means if the University decides to change their hostname or port, the
+program will break.
diff --git a/pom.xml b/pom.xml
index 99ec00e0fae09916d98fe21e35fe7ccf3b422220..6d0f5d65501b273a7ff88c4f0b8757d3a14acf22 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,8 +13,8 @@
 
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <maven.compiler.source>1.17</maven.compiler.source>
-    <maven.compiler.target>1.17</maven.compiler.target>
+    <maven.compiler.source>17</maven.compiler.source>
+    <maven.compiler.target>17</maven.compiler.target>
   </properties>
 
   <dependencies>
@@ -58,8 +58,17 @@
           <version>2.22.1</version>
         </plugin>
         <plugin>
-          <artifactId>maven-jar-plugin</artifactId>
-          <version>3.0.2</version>
+          <artifactId>maven-assembly-plugin</artifactId>
+          <configuration>
+            <archive>
+              <manifest>
+                <mainClass>com.gpeppard.ecsuserfetcher.Main</mainClass>
+              </manifest>
+            </archive>
+            <descriptorRefs>
+              <descriptorRef>jar-with-dependencies</descriptorRef>
+            </descriptorRefs>
+          </configuration>
         </plugin>
         <plugin>
           <artifactId>maven-install-plugin</artifactId>
@@ -78,16 +87,20 @@
           <artifactId>maven-project-info-reports-plugin</artifactId>
           <version>3.0.0</version>
         </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-javadoc-plugin</artifactId>
+          <version>3.3.1</version>
+          <configuration>
+            <show>private</show>
+          </configuration>
+        </plugin>
       </plugins>
     </pluginManagement>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <source>17</source>
-          <target>17</target>
-        </configuration>
       </plugin>
     </plugins>
   </build>
diff --git a/src/main/java/com/gpeppard/ecsuserfetcher/EcsUserFetcher.java b/src/main/java/com/gpeppard/ecsuserfetcher/EcsUserFetcher.java
index c58b760f148636fce799cc782fccb1b7005d4c06..c06dcc17504cae1b63e55bc613b01dbcf67f6d5e 100644
--- a/src/main/java/com/gpeppard/ecsuserfetcher/EcsUserFetcher.java
+++ b/src/main/java/com/gpeppard/ecsuserfetcher/EcsUserFetcher.java
@@ -1,9 +1,21 @@
 package com.gpeppard.ecsuserfetcher;
 
+import com.gpeppard.ecsuserfetcher.models.Person;
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.cursor.EntryCursor;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
+
+import java.io.IOException;
+
 /**
  * A single instance of the program.
  *
- * @author George Peppard <gjp1g21@soton.ac.uk>
+ * @author George Peppard {@literal <gjp1g21@soton.ac.uk>}
  */
 public class EcsUserFetcher {
   private final String ldapUsername;
@@ -12,9 +24,9 @@ public class EcsUserFetcher {
   private final boolean detailed;
 
   /**
-   * Constructs a new instance of SCWebScraper.
+   * Constructs a new instance of EcsUserFetcher.
    *
-   * We do not want everything to be static so instead, we use this object instead to hold (or
+   * <p>We do not want everything to be static so instead, we use this object instead to hold (or
    * call) the majority of program code.
    *
    * @param ldapUsername the LDAP username of the user accessing the data
@@ -29,10 +41,146 @@ public class EcsUserFetcher {
     this.detailed = detailed;
   }
 
+  /** Run the application. */
+  public void run() {
+    Person person = fetchUser(query);
+
+    if (person == null) {
+      System.err.println("There was an error whilst trying to fetch this user.");
+      return;
+    }
+
+    outputUserInformation(person);
+  }
+
   /**
-   * Run the application.
+   * Fetches a {@link Person} from the LDAP server.
+   *
+   * @param mailNickname the mailNickname attribute of the person you want to search for
+   * @return the Person who has been returned, or {@code null} if they do not exist or an error occurs
    */
-  public void run() {
+  private Person fetchUser(String mailNickname) {
+    /* Connect to the LDAP server and bind credentials */
+    LdapConnection connection = new LdapNetworkConnection("ldap.soton.ac.uk", 389);
+    try {
+      connection.bind(ldapUsername, ldapPassword);
+    } catch (LdapException e) {
+      System.err.println("Failed to connect to the LDAP server: " + e.getMessage());
+      System.err.println("Are your credentials correct?");
+
+      try {
+        connection.close();
+      } catch(IOException ex) {
+        ex.printStackTrace();
+      }
+
+      return null;
+    }
+
+    /* Search for the user by mailNickname */
+    EntryCursor cur;
+    try {
+      cur = connection.search(
+              "OU=fp,OU=fp,OU=ek,OU=User,DC=soton,DC=ac,DC=uk", "(mailNickname=" + query + ")", SearchScope.SUBTREE, "*");
+    } catch(LdapException e) {
+      try {
+        connection.close();
+      } catch(IOException ex) {
+        ex.printStackTrace();
+      }
+
+      System.err.println("An error occurred whilst searching for the user: " + e.getMessage());
+      return null;
+    }
+
+    /* Check to make sure this object exists */
+    try {
+      if (!cur.next()) {
+        System.err.println("There were no results for that email nickname. Does the user exist?");
+
+        try {
+          connection.close();
+        } catch(IOException ex) {
+          ex.printStackTrace();
+        }
+
+        return null;
+      }
+    } catch(LdapException | CursorException e) {
+      /* this should never happen */
+      e.printStackTrace();
+      return null;
+    }
+
+    /* Get first (there should only ever be one) object from server and then close connection */
+    Entry entry;
+    try {
+      entry = cur.get();
+    } catch(CursorException e) {
+      /* this should never happen so we just print the stack trace */
+      e.printStackTrace();
 
+      try {
+        connection.close();
+      } catch(IOException ex) {
+        ex.printStackTrace();
+      }
+
+      return null;
+    }
+
+    try {
+      connection.unBind();
+      connection.close();
+    } catch (LdapException | IOException e) {
+      System.err.println("An exception occurred when closing the LDAP connection: " + e.getMessage());
+    }
+
+    /* Move information from the LDAP object into a new Person */
+    Person person;
+    try {
+      person = new Person(
+              entry.get("mailNickname").getString(),
+              entry.get("givenName").getString(),
+              entry.get("sn").getString(),
+              entry.get("title").getString(),
+              entry.get("department").getString()
+      );
+    } catch (LdapInvalidAttributeValueException e) {
+      System.err.println("Could not get required attributes for this person. Is it an actual person?");
+      return null;
+    }
+
+    /* Return the Person */
+    return person;
+  }
+
+  /**
+   * Outputs the user information to the console.
+   */
+  private void outputUserInformation(Person person) {
+    if (detailed) {
+      outputDetailedUserInformation(person);
+    } else {
+      outputBriefUserInformation(person);
+    }
+  }
+
+  /**
+   * Outputs the user name to the console.
+   */
+  private void outputBriefUserInformation(Person person) {
+    System.out.println("User: " + person.getMailName());
+    System.out.println("Full name: " + person.getGivenName() + " " + person.getSurname());
+  }
+
+  /**
+   * Outputs detailed user information to the console.
+   */
+  private void outputDetailedUserInformation(Person person) {
+    System.out.println("User: " + person.getMailName());
+    System.out.println("Full name: " + person.getGivenName() + " " + person.getSurname());
+    System.out.println("Position title: " + person.getJobTitle());
+    System.out.println("Department: " + person.getDepartment());
   }
 }
diff --git a/src/main/java/com/gpeppard/ecsuserfetcher/Main.java b/src/main/java/com/gpeppard/ecsuserfetcher/Main.java
index 324352fe57d7f40a7fab793d2498839296cd0f86..3a41ba4e269dd4d8237fb13345d7241ad3bc2e52 100644
--- a/src/main/java/com/gpeppard/ecsuserfetcher/Main.java
+++ b/src/main/java/com/gpeppard/ecsuserfetcher/Main.java
@@ -5,7 +5,7 @@ import org.apache.commons.cli.*;
 /**
  * Main application class.
  *
- * @author George Peppard <gjp1g21@soton.ac.uk>
+ * @author George Peppard {@literal <gjp1g21@soton.ac.uk>}
  */
 public class Main {
   /**
diff --git a/src/main/java/com/gpeppard/ecsuserfetcher/models/Person.java b/src/main/java/com/gpeppard/ecsuserfetcher/models/Person.java
new file mode 100644
index 0000000000000000000000000000000000000000..41d2d5777b5583b99a04f4b79c851399c45d71f2
--- /dev/null
+++ b/src/main/java/com/gpeppard/ecsuserfetcher/models/Person.java
@@ -0,0 +1,76 @@
+package com.gpeppard.ecsuserfetcher.models;
+
+/**
+ * A single person whose data is stored in the LDAP server.
+ *
+ * @author George Peppard {@literal <gjp1g21@soton.ac.uk>}
+ */
+public class Person {
+    private final String mailName;
+    private final String givenName;
+    private final String surname;
+    private final String jobTitle;
+    private final String department;
+
+    /**
+     * Constructs a new instance of {@code Person}.
+     *
+     * @param mailName the mail nickname of the person
+     * @param givenName the first name of the person
+     * @param surname the surname of the person
+     * @param jobTitle the position title of the person
+     * @param department the department of the person
+     */
+    public Person(String mailName, String givenName, String surname, String jobTitle, String department) {
+        this.mailName = mailName;
+        this.givenName = givenName;
+        this.surname = surname;
+        this.jobTitle = jobTitle;
+        this.department = department;
+    }
+
+    /**
+     * Gets the mail nickname of the person.
+     *
+     * @return the mail nickname of the person
+     */
+    public String getMailName() {
+        return mailName;
+    }
+
+    /**
+     * Gets the first name of the person.
+     *
+     * @return the first name of the person
+     */
+    public String getGivenName() {
+        return givenName;
+    }
+
+    /**
+     * Gets the surname of the person.
+     *
+     * @return the surname of the person
+     */
+    public String getSurname() {
+        return surname;
+    }
+
+    /**
+     * Gets the position title of the person.
+     *
+     * @return the position title of the person
+     */
+    public String getJobTitle() {
+        return jobTitle;
+    }
+
+    /**
+     * Gets the department of the person.
+     *
+     * @return the department of the person
+     */
+    public String getDepartment() {
+        return department;
+    }
+}
diff --git a/src/main/java/com/gpeppard/ecsuserfetcher/models/User.java b/src/main/java/com/gpeppard/ecsuserfetcher/models/User.java
deleted file mode 100644
index 6c826d98a0060faeb41d9fd5f4c6267286741358..0000000000000000000000000000000000000000
--- a/src/main/java/com/gpeppard/ecsuserfetcher/models/User.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.gpeppard.ecsuserfetcher.models;
-
-public class User {
-}
diff --git a/src/test/java/com/gpeppard/AppTest.java b/src/test/java/com/gpeppard/AppTest.java
deleted file mode 100644
index c69dcf31e3e2b9a038bf93e16b949af59cd21a99..0000000000000000000000000000000000000000
--- a/src/test/java/com/gpeppard/AppTest.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.gpeppard;
-
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-/**
- * Unit test for simple App.
- */
-public class AppTest 
-{
-    /**
-     * Rigorous Test :-)
-     */
-    @Test
-    public void shouldAnswerWithTrue()
-    {
-        assertTrue( true );
-    }
-}