Skip to content

Commit

Permalink
Merge branch 'BookStackApp:release' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
paulhollmann authored Sep 13, 2024
2 parents 3824e96 + b0dda6e commit d9eb54a
Show file tree
Hide file tree
Showing 84 changed files with 2,288 additions and 2,151 deletions.
14 changes: 13 additions & 1 deletion app/Access/Ldap.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,25 @@ public function setVersion($ldapConnection, int $version): bool
*
* @param resource|\LDAP\Connection $ldapConnection
*
* @return resource|\LDAP\Result
* @return \LDAP\Result|array|false
*/
public function search($ldapConnection, string $baseDn, string $filter, array $attributes = null)
{
return ldap_search($ldapConnection, $baseDn, $filter, $attributes);
}

/**
* Read an entry from the LDAP tree.
*
* @param resource|\Ldap\Connection $ldapConnection
*
* @return \LDAP\Result|array|false
*/
public function read($ldapConnection, string $baseDn, string $filter, array $attributes = null)
{
return ldap_read($ldapConnection, $baseDn, $filter, $attributes);
}

/**
* Get entries from an LDAP search result.
*
Expand Down
81 changes: 46 additions & 35 deletions app/Access/LdapService.php
Original file line number Diff line number Diff line change
Expand Up @@ -321,94 +321,105 @@ public function getUserGroups(string $userName): array
return [];
}

$userGroups = $this->groupFilter($user);
$userGroups = $this->extractGroupsFromSearchResponseEntry($user);
$allGroups = $this->getGroupsRecursive($userGroups, []);
$formattedGroups = $this->extractGroupNamesFromLdapGroupDns($allGroups);

if ($this->config['dump_user_groups']) {
throw new JsonDebugException([
'details_from_ldap' => $user,
'parsed_direct_user_groups' => $userGroups,
'parsed_recursive_user_groups' => $allGroups,
'details_from_ldap' => $user,
'parsed_direct_user_groups' => $userGroups,
'parsed_recursive_user_groups' => $allGroups,
'parsed_resulting_group_names' => $formattedGroups,
]);
}

return $allGroups;
return $formattedGroups;
}

protected function extractGroupNamesFromLdapGroupDns(array $groupDNs): array
{
$names = [];

foreach ($groupDNs as $groupDN) {
$exploded = $this->ldap->explodeDn($groupDN, 1);
if ($exploded !== false && count($exploded) > 0) {
$names[] = $exploded[0];
}
}

return array_unique($names);
}

/**
* Get the parent groups of an array of groups.
* Build an array of all relevant groups DNs after recursively scanning
* across parents of the groups given.
*
* @throws LdapException
*/
private function getGroupsRecursive(array $groupsArray, array $checked): array
protected function getGroupsRecursive(array $groupDNs, array $checked): array
{
$groupsToAdd = [];
foreach ($groupsArray as $groupName) {
if (in_array($groupName, $checked)) {
foreach ($groupDNs as $groupDN) {
if (in_array($groupDN, $checked)) {
continue;
}

$parentGroups = $this->getGroupGroups($groupName);
$parentGroups = $this->getParentsOfGroup($groupDN);
$groupsToAdd = array_merge($groupsToAdd, $parentGroups);
$checked[] = $groupName;
$checked[] = $groupDN;
}

$groupsArray = array_unique(array_merge($groupsArray, $groupsToAdd), SORT_REGULAR);
$uniqueDNs = array_unique(array_merge($groupDNs, $groupsToAdd), SORT_REGULAR);

if (empty($groupsToAdd)) {
return $groupsArray;
return $uniqueDNs;
}

return $this->getGroupsRecursive($groupsArray, $checked);
return $this->getGroupsRecursive($uniqueDNs, $checked);
}

/**
* Get the parent groups of a single group.
*
* @throws LdapException
*/
private function getGroupGroups(string $groupName): array
protected function getParentsOfGroup(string $groupDN): array
{
$groupsAttr = strtolower($this->config['group_attribute']);
$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']);

$groupFilter = 'CN=' . $this->ldap->escape($groupName);
$groups = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $groupFilter, [$groupsAttr]);
if ($groups['count'] === 0) {
$read = $this->ldap->read($ldapConnection, $groupDN, '(objectClass=*)', [$groupsAttr]);
$results = $this->ldap->getEntries($ldapConnection, $read);
if ($results['count'] === 0) {
return [];
}

return $this->groupFilter($groups[0]);
return $this->extractGroupsFromSearchResponseEntry($results[0]);
}

/**
* Filter out LDAP CN and DN language in a ldap search return.
* Gets the base CN (common name) of the string.
* Extract an array of group DN values from the given LDAP search response entry
*/
protected function groupFilter(array $userGroupSearchResponse): array
protected function extractGroupsFromSearchResponseEntry(array $ldapEntry): array
{
$groupsAttr = strtolower($this->config['group_attribute']);
$ldapGroups = [];
$groupDNs = [];
$count = 0;

if (isset($userGroupSearchResponse[$groupsAttr]['count'])) {
$count = (int) $userGroupSearchResponse[$groupsAttr]['count'];
if (isset($ldapEntry[$groupsAttr]['count'])) {
$count = (int) $ldapEntry[$groupsAttr]['count'];
}

for ($i = 0; $i < $count; $i++) {
$dnComponents = $this->ldap->explodeDn($userGroupSearchResponse[$groupsAttr][$i], 1);
if (!in_array($dnComponents[0], $ldapGroups)) {
$ldapGroups[] = $dnComponents[0];
$dn = $ldapEntry[$groupsAttr][$i];
if (!in_array($dn, $groupDNs)) {
$groupDNs[] = $dn;
}
}

return $ldapGroups;
return $groupDNs;
}

/**
Expand Down
5 changes: 4 additions & 1 deletion app/Entities/Controllers/BookApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Queries\BookQueries;
use BookStack\Entities\Queries\PageQueries;
use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Tools\BookContents;
use BookStack\Http\ApiController;
Expand All @@ -18,6 +19,7 @@ class BookApiController extends ApiController
public function __construct(
protected BookRepo $bookRepo,
protected BookQueries $queries,
protected PageQueries $pageQueries,
) {
}

Expand Down Expand Up @@ -69,7 +71,8 @@ public function read(string $id)
->withType()
->withField('pages', function (Entity $entity) {
if ($entity instanceof Chapter) {
return (new ApiEntityListFormatter($entity->pages->all()))->format();
$pages = $this->pageQueries->visibleForChapterList($entity->id)->get()->all();
return (new ApiEntityListFormatter($pages))->format();
}
return null;
})->format();
Expand Down
8 changes: 4 additions & 4 deletions app/Uploads/Controllers/AttachmentApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,16 @@ protected function rules(): array
{
return [
'create' => [
'name' => ['required', 'min:1', 'max:255', 'string'],
'name' => ['required', 'string', 'min:1', 'max:255'],
'uploaded_to' => ['required', 'integer', 'exists:pages,id'],
'file' => array_merge(['required_without:link'], $this->attachmentService->getFileValidationRules()),
'link' => ['required_without:file', 'min:1', 'max:2000', 'safe_url'],
'link' => ['required_without:file', 'string', 'min:1', 'max:2000', 'safe_url'],
],
'update' => [
'name' => ['min:1', 'max:255', 'string'],
'name' => ['string', 'min:1', 'max:255'],
'uploaded_to' => ['integer', 'exists:pages,id'],
'file' => $this->attachmentService->getFileValidationRules(),
'link' => ['min:1', 'max:2000', 'safe_url'],
'link' => ['string', 'min:1', 'max:2000', 'safe_url'],
],
];
}
Expand Down
13 changes: 7 additions & 6 deletions app/Users/Controllers/UserApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,28 @@ protected function rules(int $userId = null): array
{
return [
'create' => [
'name' => ['required', 'min:2', 'max:100'],
'name' => ['required', 'string', 'min:2', 'max:100'],
'email' => [
'required', 'min:2', 'email', new Unique('users', 'email'),
'required', 'string', 'email', 'min:2', new Unique('users', 'email'),
],
'external_auth_id' => ['string'],
'language' => ['string', 'max:15', 'alpha_dash'],
'password' => [Password::default()],
'password' => ['string', Password::default()],
'roles' => ['array'],
'roles.*' => ['integer'],
'send_invite' => ['boolean'],
],
'update' => [
'name' => ['min:2', 'max:100'],
'name' => ['string', 'min:2', 'max:100'],
'email' => [
'min:2',
'string',
'email',
'min:2',
(new Unique('users', 'email'))->ignore($userId ?? null),
],
'external_auth_id' => ['string'],
'language' => ['string', 'max:15', 'alpha_dash'],
'password' => [Password::default()],
'password' => ['string', Password::default()],
'roles' => ['array'],
'roles.*' => ['integer'],
],
Expand Down
Loading

0 comments on commit d9eb54a

Please sign in to comment.