You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux环境下用PHP/Symfony给AD文件夹添加安全组?

问题与适配方案

问题背景

我有一个部署在公司内部Ubuntu服务器(Apache Web服务器)上的Symfony应用。目前已实现通过icewind/smb创建网络共享文件夹,以及通过Symfony LDAP组件在Active Directory中创建只读(RO)和读写(RW)组,但无法将这些组设置为新文件夹的安全组。现有一段仅在Windows服务器生效的旧代码,需要适配Linux环境。

当前实现代码

public function createLdapFolder(array $data): bool
{

    $prefixMapping = [
        'OU=Section1,OU=_Company,DC=company,DC=local' => 'S1_',
        'OU=Section2,OU=_Company,DC=company,DC=local' => 'S2_',
        'OU=Section3,OU=_Company,DC=company,DC=local' => 'S3_',
        'OU=Section4,OU=_Company,DC=company,DC=local' => 'S4_',
        'general' => 'All_',
        'scan' => 'Scan_',
        'appstorage' => '',
    ];

    $selectPrefix = $data['selectPrefix'];
    $folderName = $data['folderName'];

    if (!preg_match('/^[a-zA-Z0-9_\-]+$/', $folderName)) {
        throw new \InvalidArgumentException('Invalid Foldername.');
    }

    if (!isset($prefixMapping[$selectPrefix])) {
        $this->requestStack->getCurrentRequest()->getSession()->getFlashBag()->add(
        'error',
        'Invalid Section.'
        );
        return false;
    }

    $prefix = $prefixMapping[$selectPrefix];
    $completeFolderName = $prefix . $folderName;

    $serverFactory = new ServerFactory();
    $auth = new BasicAuth($_ENV['LDAP_USERNAME'], 'company', $_ENV['LDAP_PASSWORD']);
    $server = $serverFactory->createServer($_ENV['LDAP_IP'], $auth);

    $shares = $server->listShares();

    foreach ($shares as $shareName) {
        $shareName->getName();
    }

    if ($selectPrefix != 'appstorage') {
        $shareName = $_ENV['LDAP_SHARE_1'];
    } else {
        $shareName = $_ENV['LDAP_SHARE_APPSTORAGE'];
    }

    $share = $server->getShare($shareName);
    $share->mkdir($completeFolderName);
    
    $this->createLdapFolderGroups($folderName);
    
    return true;
    
}

public function createLdapFolderGroups(string $folderName): bool
{
    
    $baseDn = 'OU=Folder,' . $_ENV['LDAP_GLOBAL_GROUPS_BASE_DN'];

    $entryRO = new Entry('cn=GG_Folder_' . $folderName . '-RO,' . $baseDn, [
        'sAMAccountName' => ['GG_Folder_' . $folderName . '-RO'],
        'objectClass' => ['top', 'group'],
        'groupType' => [-2147483646], 
    ]);

    $entryRW = new Entry('cn=GG_Folder_' . $folderName . '-RW,' . $baseDn, [
        'sAMAccountName' => ['GG_Folder_' . $folderName . '-RW'],
        'objectClass' => ['top', 'group'],
        'groupType' => [-2147483646], 
    ]);

    try {

        $this->ldap->getEntryManager()->add($entryRO);
        $this->ldap->getEntryManager()->add($entryRW);


        $this->logger->info("Group GG_Folder_{$folderName}-RO created.");
        $this->logger->info("Group GG_Folder_{$folderName}-RW created.");

        return true;
    } catch (\Exception $e) {

        $this->logger->error("Error by creating group" . $e->getMessage());
        throw new \Exception("Error by creating group" . $e->getMessage());
        return false;
    }

}

仅Windows生效的旧代码

$globalGroupsBaseDN = 'OU=GlobalGroups,DC=testdc,DC=local';
$groupName = 'GG_' . $folderName;

$groupRO = $groupName . '-RO';
$groupRW = $groupName . '-RW';

$newGroupRODN = 'CN=' . $groupRO . ',' . $globalGroupsBaseDN;
$newGroupRWDN = 'CN=' . $groupRW . ',' . $globalGroupsBaseDN;

$newGroupROAttributes['objectClass'] = ['group', 'top'];
$newGroupROAttributes['cn'] = $groupRO;
$newGroupROAttributes['sAMAccountName'] = $groupRO;

$newGroupRWAttributes['objectClass'] = ['group', 'top'];
$newGroupRWAttributes['cn'] = $groupRW;
$newGroupRWAttributes['sAMAccountName'] = $groupRW;

ldap_add($ldapConnection, $newGroupRODN, $newGroupROAttributes);
ldap_add($ldapConnection, $newGroupRWDN, $newGroupRWAttributes);


// Add security group to folder
$groupAttributeRO = [
'member' => [$newGroupRWDN]
];

$groupAttributeRW = [
'member' => [$newGroupRODN]
];

ldap_mod_add($ldapConnection, $existingFolderPath, $groupAttributeRO);
ldap_mod_add($ldapConnection, $existingFolderPath, $groupAttributeRW);

var_dump($existingFolderPath).'<br>';
var_dump($groupAttributeRO); exit;

// Set security
$permissionsRO = [
    'read',
    'list',
    'read_property',
    'execute',
];

$permissionsRW = [
    'write',
    'read',
    'list',
    'read_property',
    'execute',
    'delete',
];

$securityDescriptor = 'D:P(' . implode(',', $permissionsRO) . ')';
ldap_mod_replace($ldapConnection, $existingFolderPath, ['ntSecurityDescriptor' => [$securityDescriptor]]);

$securityDescriptorRW = 'D:P(' . implode(',', $permissionsRW) . ')';
ldap_mod_replace($ldapConnection, $existingFolderPath, ['ntSecurityDescriptor' => [$securityDescriptorRW]]);

Linux环境适配方案

适配原理

旧代码直接操作LDAP的ntSecurityDescriptor属性,仅适用于Windows环境下直接管理AD中的文件对象。在Linux环境下,通过SMB创建的文件夹需要通过SMB协议设置权限,无法直接修改LDAP属性,我们可以借助smbclient工具来完成权限配置。

具体实现步骤

  1. 安装依赖工具
    在Ubuntu服务器上安装smbclient:

    sudo apt-get update && sudo apt-get install smbclient
    
  2. 扩展Symfony代码,添加权限设置方法
    在现有createLdapFolder方法中,创建文件夹并生成组后,新增权限设置逻辑:

    public function createLdapFolder(array $data): bool
    {
        // ... 原有代码保持不变 ...
        
        $share->mkdir($completeFolderName);
        
        $this->createLdapFolderGroups($folderName);
        // 新增:设置SMB文件夹权限
        $this->setSmbFolderPermissions($shareName, $completeFolderName, $folderName);
        
        return true;
    }
    
    private function setSmbFolderPermissions(string $shareName, string $folderPath, string $folderName): void
    {
        $roGroup = 'GG_Folder_' . $folderName . '-RO';
        $rwGroup = 'GG_Folder_' . $folderName . '-RW';
        
        // 构建只读权限设置命令
        $roCmd = sprintf(
            'smbclient //%s/%s -U %s%%%s -c "setacl "%s" "ACL:%s:ALLOWED/I/READ""',
            $_ENV['LDAP_IP'],
            $shareName,
            $_ENV['LDAP_USERNAME'],
            $_ENV['LDAP_PASSWORD'],
            $folderPath,
            $roGroup
        );
        
        // 构建读写权限设置命令
        $rwCmd = sprintf(
            'smbclient //%s/%s -U %s%%%s -c "setacl "%s" "ACL:%s:ALLOWED/I/CHANGE""',
            $_ENV['LDAP_IP'],
            $shareName,
            $_ENV['LDAP_USERNAME'],
            $_ENV['LDAP_PASSWORD'],
            $folderPath,
            $rwGroup
        );
        
        // 执行命令并检查结果
        exec($roCmd, $roOutput, $roExitCode);
        exec($rwCmd, $rwOutput, $rwExitCode);
        
        if ($roExitCode !== 0 || $rwExitCode !== 0) {
            $this->logger->error(
                'SMB权限设置失败:RO组退出码' . $roExitCode . ',RW组退出码' . $rwExitCode
            );
            throw new \RuntimeException('文件夹权限设置失败');
        }
        
        $this->logger->info('文件夹' . $folderPath . '的SMB权限已配置完成');
    }
    
  3. 注意事项

    • 确保Apache运行用户(通常是www-data)有权限执行smbclient命令
    • 配置的LDAP用户需要拥有修改目标SMB共享文件夹权限的权限
    • 可根据需求调整ACL权限项,比如添加DELETE权限可将CHANGE替换为FULL

内容的提问来源于stack exchange,提问作者TheQuestionmark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:19:58