diff --git a/.env.example b/.env.example
index ccafaf4fb..57e6af6a9 100644
--- a/.env.example
+++ b/.env.example
@@ -67,6 +67,15 @@ LDAP_DN=false
 LDAP_PASS=false
 LDAP_USER_FILTER=false
 LDAP_VERSION=false
+#do you want to sync LDAP groups to BookStack roles for a user
+LDAP_USER_TO_GROUPS=false
+#what is the LDAP attribute for group memberships
+LDAP_GROUP_ATTRIBUTE="memberOf"
+#what LDAP group should the user be a part of to be an admin on BookStack
+LDAP_ADMIN_GROUP="Domain Admins"
+#would you like to remove users from roles on bookstack if they do not match on LDAP
+#if false, the ldap groups-roles sync will only add users to roles
+LDAP_REMOVE_FROM_GROUPS=false
 
 # Mail settings
 MAIL_DRIVER=smtp
diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php
index 106b90524..4c846d0e0 100644
--- a/app/Http/Controllers/Auth/LoginController.php
+++ b/app/Http/Controllers/Auth/LoginController.php
@@ -5,6 +5,7 @@ namespace BookStack\Http\Controllers\Auth;
 use BookStack\Exceptions\AuthException;
 use BookStack\Http\Controllers\Controller;
 use BookStack\Repos\UserRepo;
+use BookStack\Repos\LdapRepo;
 use BookStack\Services\SocialAuthService;
 use Illuminate\Contracts\Auth\Authenticatable;
 use Illuminate\Foundation\Auth\AuthenticatesUsers;
@@ -96,7 +97,14 @@ class LoginController extends Controller
             auth()->login($user);
         }
 
-        $path = session()->pull('url.intended', '/');
+		// ldap groups refresh
+		if (config('services.ldap.user_to_groups') !== false && $request->filled('username')) {
+			$ldapRepo = new LdapRepo($this->userRepo);
+			$ldapRepo->syncGroups($user,$request->input('username'));
+		}
+
+
+		$path = session()->pull('url.intended', '/');
         $path = baseUrl($path, true);
         return redirect($path);
     }
diff --git a/app/Repos/LdapRepo.php b/app/Repos/LdapRepo.php
new file mode 100644
index 000000000..33d05ea88
--- /dev/null
+++ b/app/Repos/LdapRepo.php
@@ -0,0 +1,84 @@
+<?php namespace BookStack\Repos;
+
+use BookStack\Services\Ldap;
+use BookStack\Services\LdapService;
+use BookStack\Role;
+use BookStack\Repos\UserRepo;
+
+class LdapRepo
+{
+
+	protected $ldap = null;
+	protected $ldapService = null;
+
+	protected $config;
+
+	/**
+	 * LdapRepo constructor.
+	 * @param \BookStack\Repos\UserRepo $userRepo
+	 */
+	public function __construct(UserRepo $userRepo)
+	{
+		$this->config = config('services.ldap');
+
+		if (config('auth.method') !== 'ldap') {
+			return false;
+		}
+
+		$this->ldapService = new LdapService(new Ldap);
+		$this->userRepo = $userRepo;
+	}
+
+	/**
+	 * If there is no ldap connection, all methods calls to this library will return null
+	 */
+	public function __call($method, $arguments)
+	{
+		if ($this->ldap === null) {
+			return null;
+		}
+
+		return call_user_func_array(array($this,$method),$arguments);
+	}
+
+	/**
+	 * Sync the LDAP groups to the user roles for the current user
+	 * @param \BookStack\User $user
+	 * @param string $userName
+	 * @throws \BookStack\Exceptions\NotFoundException
+	 */
+	public function syncGroups($user,$userName)
+	{
+		$userLdapGroups = $this->ldapService->getUserGroups($userName);
+		$userLdapGroups = $this->groupNameFilter($userLdapGroups);
+		// get the ids for the roles from the names
+		$ldapGroupsAsRoles = Role::whereIn('name',$userLdapGroups)->pluck('id');
+		// sync groups
+		if ($this->config['remove_from_groups']) {
+			$user->roles()->sync($ldapGroupsAsRoles);
+			$this->userRepo->attachDefaultRole($user);
+		} else {
+			$user->roles()->syncWithoutDetaching($ldapGroupsAsRoles);
+		}
+
+		// make the user an admin?
+		if (in_array($this->config['admin'],$userLdapGroups)) {
+			$this->userRepo->attachSystemRole($user,'admin');
+		}
+	}
+
+	/**
+	 * Filter to convert the groups from ldap to the format of the roles name on BookStack
+	 * Spaces replaced with -, all lowercase letters
+	 * @param array $groups
+	 * @return array
+	 */
+	private function groupNameFilter($groups)
+	{
+		$return = [];
+		foreach ($groups as $groupName) {
+			$return[] = str_replace(' ', '-', strtolower($groupName));
+		}
+		return $return;
+	}
+}
\ No newline at end of file
diff --git a/app/Services/LdapService.php b/app/Services/LdapService.php
index 3eb2f2830..e56f45e4e 100644
--- a/app/Services/LdapService.php
+++ b/app/Services/LdapService.php
@@ -11,155 +11,263 @@ use Illuminate\Contracts\Auth\Authenticatable;
 class LdapService
 {
 
-    protected $ldap;
-    protected $ldapConnection;
-    protected $config;
+	protected $ldap;
+	protected $ldapConnection;
+	protected $config;
 
-    /**
-     * LdapService constructor.
-     * @param Ldap $ldap
-     */
-    public function __construct(Ldap $ldap)
-    {
-        $this->ldap = $ldap;
-        $this->config = config('services.ldap');
-    }
+	/**
+	 * LdapService constructor.
+	 * @param Ldap $ldap
+	 */
+	public function __construct(Ldap $ldap)
+	{
+		$this->ldap = $ldap;
+		$this->config = config('services.ldap');
+	}
 
-    /**
-     * Get the details of a user from LDAP using the given username.
-     * User found via configurable user filter.
-     * @param $userName
-     * @return array|null
-     * @throws LdapException
-     */
-    public function getUserDetails($userName)
-    {
-        $ldapConnection = $this->getConnection();
-        $this->bindSystemUser($ldapConnection);
+	/**
+	 * Search for attributes for a specific user on the ldap
+	 * @param string $userName
+	 * @param array $attributes
+	 * @return null|array
+	 * @throws LdapException
+	 */
+	private function getUserWithAttributes($userName,$attributes)
+	{
+		$ldapConnection = $this->getConnection();
+		$this->bindSystemUser($ldapConnection);
 
-        // Find user
-        $userFilter = $this->buildFilter($this->config['user_filter'], ['user' => $userName]);
-        $baseDn = $this->config['base_dn'];
-        $emailAttr = $this->config['email_attribute'];
-        $followReferrals = $this->config['follow_referrals'] ? 1 : 0;
-        $this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
-        $users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', $emailAttr]);
-        if ($users['count'] === 0) {
-            return null;
-        }
+		// Find user
+		$userFilter = $this->buildFilter($this->config['user_filter'], ['user' => $userName]);
+		$baseDn = $this->config['base_dn'];
 
-        $user = $users[0];
-        return [
-            'uid'   => (isset($user['uid'])) ? $user['uid'][0] : $user['dn'],
-            'name'  => $user['cn'][0],
-            'dn'    => $user['dn'],
-            'email' => (isset($user[$emailAttr])) ? (is_array($user[$emailAttr]) ? $user[$emailAttr][0] : $user[$emailAttr]) : null
-        ];
-    }
+		$followReferrals = $this->config['follow_referrals'] ? 1 : 0;
+		$this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
+		$users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, $attributes);
+		if ($users['count'] === 0) {
+			return null;
+		}
 
-    /**
-     * @param Authenticatable $user
-     * @param string          $username
-     * @param string          $password
-     * @return bool
-     * @throws LdapException
-     */
-    public function validateUserCredentials(Authenticatable $user, $username, $password)
-    {
-        $ldapUser = $this->getUserDetails($username);
-        if ($ldapUser === null) {
-            return false;
-        }
-        if ($ldapUser['uid'] !== $user->external_auth_id) {
-            return false;
-        }
+		return $users[0];
+	}
 
-        $ldapConnection = $this->getConnection();
-        try {
-            $ldapBind = $this->ldap->bind($ldapConnection, $ldapUser['dn'], $password);
-        } catch (\ErrorException $e) {
-            $ldapBind = false;
-        }
+	/**
+	 * Get the details of a user from LDAP using the given username.
+	 * User found via configurable user filter.
+	 * @param $userName
+	 * @return array|null
+	 * @throws LdapException
+	 */
+	public function getUserDetails($userName)
+	{
+		$emailAttr = $this->config['email_attribute'];
+		$user = $this->getUserWithAttributes($userName, ['cn', 'uid', 'dn', $emailAttr]);
 
-        return $ldapBind;
-    }
+		if ($user === null) {
+			return null;
+		}
 
-    /**
-     * Bind the system user to the LDAP connection using the given credentials
-     * otherwise anonymous access is attempted.
-     * @param $connection
-     * @throws LdapException
-     */
-    protected function bindSystemUser($connection)
-    {
-        $ldapDn = $this->config['dn'];
-        $ldapPass = $this->config['pass'];
+		return [
+			'uid'   => (isset($user['uid'])) ? $user['uid'][0] : $user['dn'],
+			'name'  => $user['cn'][0],
+			'dn'    => $user['dn'],
+			'email' => (isset($user[$emailAttr])) ? (is_array($user[$emailAttr]) ? $user[$emailAttr][0] : $user[$emailAttr]) : null
+		];
+	}
 
-        $isAnonymous = ($ldapDn === false || $ldapPass === false);
-        if ($isAnonymous) {
-            $ldapBind = $this->ldap->bind($connection);
-        } else {
-            $ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass);
-        }
+	/**
+	 * @param Authenticatable $user
+	 * @param string          $username
+	 * @param string          $password
+	 * @return bool
+	 * @throws LdapException
+	 */
+	public function validateUserCredentials(Authenticatable $user, $username, $password)
+	{
+		$ldapUser = $this->getUserDetails($username);
+		if ($ldapUser === null) {
+			return false;
+		}
+		if ($ldapUser['uid'] !== $user->external_auth_id) {
+			return false;
+		}
 
-        if (!$ldapBind) {
-            throw new LdapException(($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed')));
-        }
-    }
+		$ldapConnection = $this->getConnection();
+		try {
+			$ldapBind = $this->ldap->bind($ldapConnection, $ldapUser['dn'], $password);
+		} catch (\ErrorException $e) {
+			$ldapBind = false;
+		}
 
-    /**
-     * Get the connection to the LDAP server.
-     * Creates a new connection if one does not exist.
-     * @return resource
-     * @throws LdapException
-     */
-    protected function getConnection()
-    {
-        if ($this->ldapConnection !== null) {
-            return $this->ldapConnection;
-        }
+		return $ldapBind;
+	}
 
-        // Check LDAP extension in installed
-        if (!function_exists('ldap_connect') && config('app.env') !== 'testing') {
-            throw new LdapException(trans('errors.ldap_extension_not_installed'));
-        }
+	/**
+	 * Bind the system user to the LDAP connection using the given credentials
+	 * otherwise anonymous access is attempted.
+	 * @param $connection
+	 * @throws LdapException
+	 */
+	protected function bindSystemUser($connection)
+	{
+		$ldapDn = $this->config['dn'];
+		$ldapPass = $this->config['pass'];
 
-        // Get port from server string and protocol if specified.
-        $ldapServer = explode(':', $this->config['server']);
-        $hasProtocol = preg_match('/^ldaps{0,1}\:\/\//', $this->config['server']) === 1;
-        if (!$hasProtocol) {
-            array_unshift($ldapServer, '');
-        }
-        $hostName = $ldapServer[0] . ($hasProtocol?':':'') . $ldapServer[1];
-        $defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389;
-        $ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort);
+		$isAnonymous = ($ldapDn === false || $ldapPass === false);
+		if ($isAnonymous) {
+			$ldapBind = $this->ldap->bind($connection);
+		} else {
+			$ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass);
+		}
 
-        if ($ldapConnection === false) {
-            throw new LdapException(trans('errors.ldap_cannot_connect'));
-        }
+		if (!$ldapBind) {
+			throw new LdapException(($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed')));
+		}
+	}
 
-        // Set any required options
-        if ($this->config['version']) {
-            $this->ldap->setVersion($ldapConnection, $this->config['version']);
-        }
+	/**
+	 * Get the connection to the LDAP server.
+	 * Creates a new connection if one does not exist.
+	 * @return resource
+	 * @throws LdapException
+	 */
+	protected function getConnection()
+	{
+		if ($this->ldapConnection !== null) {
+			return $this->ldapConnection;
+		}
 
-        $this->ldapConnection = $ldapConnection;
-        return $this->ldapConnection;
-    }
+		// Check LDAP extension in installed
+		if (!function_exists('ldap_connect') && config('app.env') !== 'testing') {
+			throw new LdapException(trans('errors.ldap_extension_not_installed'));
+		}
 
-    /**
-     * Build a filter string by injecting common variables.
-     * @param string $filterString
-     * @param array $attrs
-     * @return string
-     */
-    protected function buildFilter($filterString, array $attrs)
-    {
-        $newAttrs = [];
-        foreach ($attrs as $key => $attrText) {
-            $newKey = '${' . $key . '}';
-            $newAttrs[$newKey] = $attrText;
-        }
-        return strtr($filterString, $newAttrs);
-    }
-}
+		// Get port from server string and protocol if specified.
+		$ldapServer = explode(':', $this->config['server']);
+		$hasProtocol = preg_match('/^ldaps{0,1}\:\/\//', $this->config['server']) === 1;
+		if (!$hasProtocol) {
+			array_unshift($ldapServer, '');
+		}
+		$hostName = $ldapServer[0] . ($hasProtocol?':':'') . $ldapServer[1];
+		$defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389;
+		$ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort);
+
+		if ($ldapConnection === false) {
+			throw new LdapException(trans('errors.ldap_cannot_connect'));
+		}
+
+		// Set any required options
+		if ($this->config['version']) {
+			$this->ldap->setVersion($ldapConnection, $this->config['version']);
+		}
+
+		$this->ldapConnection = $ldapConnection;
+		return $this->ldapConnection;
+	}
+
+	/**
+	 * Build a filter string by injecting common variables.
+	 * @param string $filterString
+	 * @param array $attrs
+	 * @return string
+	 */
+	protected function buildFilter($filterString, array $attrs)
+	{
+		$newAttrs = [];
+		foreach ($attrs as $key => $attrText) {
+			$newKey = '${' . $key . '}';
+			$newAttrs[$newKey] = $attrText;
+		}
+		return strtr($filterString, $newAttrs);
+	}
+
+	/**
+	 * Get the groups a user is a part of on ldap
+	 * @param string $userName
+	 * @return array|null
+	 */
+	public function getUserGroups($userName)
+	{
+		$groupsAttr = $this->config['group_attribute'];
+		$user = $this->getUserWithAttributes($userName, [$groupsAttr]);
+
+		if ($user === null) {
+			return null;
+		}
+
+		$userGroups = $this->groupFilter($user);
+		$userGroups = $this->getGroupsRecursive($userGroups,[]);
+		return $userGroups;
+	}
+
+	/**
+	 * Get the parent groups of an array of groups
+	 * @param array $groupsArray
+	 * @param array $checked
+	 * @return array
+	 */
+	private function getGroupsRecursive($groupsArray,$checked) {
+		$groups_to_add = [];
+		foreach ($groupsArray as $groupName) {
+			if (in_array($groupName,$checked)) continue;
+
+			$groupsToAdd = $this->getGroupGroups($groupName);
+			$groups_to_add = array_merge($groups_to_add,$groupsToAdd);
+			$checked[] = $groupName;
+		}
+		$groupsArray = array_unique(array_merge($groupsArray,$groups_to_add), SORT_REGULAR);
+
+		if (!empty($groups_to_add)) {
+			return $this->getGroupsRecursive($groupsArray,$checked);
+		} else {
+			return $groupsArray;
+		}
+	}
+
+	/**
+	 * Get the parent groups of a single group
+	 * @param string $groupName
+	 * @return array
+	 */
+	private function getGroupGroups($groupName)
+	{
+		$ldapConnection = $this->getConnection();
+		$this->bindSystemUser($ldapConnection);
+
+		$followReferrals = $this->config['follow_referrals'] ? 1 : 0;
+		$this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
+
+		$baseDn = $this->config['base_dn'];
+		$groupsAttr = strtolower($this->config['group_attribute']);
+
+		$groups = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, 'CN='.$groupName, [$groupsAttr]);
+		if ($groups['count'] === 0) {
+			return [];
+		}
+
+		$groupGroups = $this->groupFilter($groups[0]);
+		return $groupGroups;
+	}
+
+	/**
+	 * Filter out LDAP CN and DN language in a ldap search return
+	 * Gets the base CN (common name) of the string
+	 * @param string $ldapSearchReturn
+	 * @return array
+	 */
+	protected function groupFilter($ldapSearchReturn)
+	{
+		$groupsAttr = strtolower($this->config['group_attribute']);
+		$ldapGroups = [];
+		$count = 0;
+		if (isset($ldapSearchReturn[$groupsAttr]['count'])) $count = (int) $ldapSearchReturn[$groupsAttr]['count'];
+		for ($i=0;$i<$count;$i++) {
+			$dnComponents = ldap_explode_dn($ldapSearchReturn[$groupsAttr][$i],1);
+			if (!in_array($dnComponents[0],$ldapGroups)) {
+				$ldapGroups[] = $dnComponents[0];
+			}
+		}
+		return $ldapGroups;
+	}
+
+}
\ No newline at end of file
diff --git a/config/services.php b/config/services.php
index 825b1f109..daa160643 100644
--- a/config/services.php
+++ b/config/services.php
@@ -118,6 +118,10 @@ return [
         'version' => env('LDAP_VERSION', false),
         'email_attribute' => env('LDAP_EMAIL_ATTRIBUTE', 'mail'),
         'follow_referrals' => env('LDAP_FOLLOW_REFERRALS', false),
-    ]
+		'user_to_groups' => env('LDAP_USER_TO_GROUPS',false),
+		'group_attribute' => env('LDAP_GROUP_ATTRIBUTE', 'memberOf'),
+		'admin' => env('LDAP_ADMIN_GROUP','Domain Admins'),
+		'remove_from_groups' => env('LDAP_REMOVE_FROM_GROUPS',false),
+	]
 
 ];