VisualSVN server – Script to convert SVN-based permission file (authz) to Windows-based permission file (authz-windows)
This article introduce a script to Script to convert SVN-based permission file (authz) to Windows-based permission file (authz-windows) in VisualSVN server.
VisualSVN Server is a good SVN server for Windows-based. By default, authentication in VisualSVN server is based on 2 files: authorization file (password is encoded with htpassword) and permission file. If later, we intend to use Windows/AD-based authentication for SVN server, then how can we keep all granted permission for users along all SVN repositories?
An example of authz file is as follows
[/] user1=rw [RD:/] user2=rw [RD:/analytics] user2=rw user3=rw user4=rw
An exmple of authz.windows is as follows:
[/] S-1-5-21-3028427551-2588925682-1401053627-1114=rw [RD:/] S-1-5-21-3028427551-2588925682-1401053627-1734=rw [RD:/analytics] S-1-5-21-3028427551-2588925682-1401053627-1734=rw S-1-5-21-3028427551-2588925682-1401053627-1868=rw S-1-5-21-3028427551-2588925682-1401053627-1855=rw
We can write a PHP script to convert authz -> authz-windows by generating Windows SID from current username:
<?php
define('SVN_REPOSITORY_ROOT_FOLDER','/data/www/test');
define('SOURCE_AUTHZ_FILE', 'authz');
define('DEST_AUTHZ_WINDOWS_FILE', 'authz-windows');
doProcess();
/**
* Convert a username to an AD-based SID.
* NOTE: Stupid processing method, since we establish 1 connection per username. But who cares when the amount of users is not too large :D/
*/
function convertUsernameToSID($bind_username_to_search = "BIND_USER_NAME")
{
$suffix ="@YOURDOMAIN.com";
$base_dn = "ou=YOUR_OU_Users,dc=YOURDOMAIN,dc=com";
$server = "ldaps://www.YOUR_WEBSITE.com:636";
$bind_username = "binduser";
$bind_password = "bindpassword";
$ds = ldap_connect($server);
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
$r = ldap_bind($ds, $bind_username.$suffix, $bind_password);
$sr = ldap_search($ds, $base_dn, "(samaccountname=".$bind_username_to_search.")");
@$entries = ldap_get_entries($ds, $sr);
if (empty($entries))
return '';//-- find nothing T__T
// All SID's begin with S-
$sid = "S-";
// Convert Bin to Hex and split into byte chunks
@$sidinhex = str_split(bin2hex($entries[0]['objectsid'][0]), 2);
// Byte 0 = Revision Level
@$sid = $sid.hexdec($sidinhex[0])."-";
// Byte 1-7 = 48 Bit Authority
@$sid = $sid.hexdec($sidinhex[6].$sidinhex[5].$sidinhex[4].$sidinhex[3].$sidinhex[2].$sidinhex[1]);
// Byte 8 count of sub authorities - Get number of sub-authorities
@$subauths = hexdec($sidinhex[7]);
//Loop through Sub Authorities
for($i = 0; $i < $subauths; $i++)
{
$start = 8 + (4 * $i);
// X amount of 32Bit (4 Byte) Sub Authorities
@$sid = $sid."-".hexdec($sidinhex[$start+3].$sidinhex[$start+2].$sidinhex[$start+1].$sidinhex[$start]);
}
return $sid;
}
/**
* Main process: Read each lines of file, do covert if needed, and write to the target file
*/
function doProcess()
{
$filearray = file(SVN_REPOSITORY_ROOT_FOLDER . DIRECTORY_SEPARATOR . SOURCE_AUTHZ_FILE);
if (!($filearray))
{
echo "Cannot read file!!!!";
return;
}
$group_name_mapping = array
(
'@group1custom' => 'GROUP-NAME-1',
'@group2custom' => 'GROUP-NAME-2',
); //-- map pre-defined groups in SVN server to AD-based group name
$permission_pattern = '/(@?[0-9a-zA-Z]+)s?=s?([a-z]*)/';
$prev_mapped_username = array();
$str_output_to_write = '';
while (list(,$oneline) = each($filearray))
{
if (preg_match_all($permission_pattern, $oneline, $matches))
{
if (isset($matches[1]) && isset($matches[2]))
{
$object_name = $matches[1][0];
$permission = $matches[2][0];
//-- If it is a pre-defined group: (1) retrieved according group in AD (2) convert the name to SID
if (substr($object_name, 0, 1) == '@')
{
if (isset($prev_mapped_username[$object_name]))
{
$group_sid = $prev_mapped_username[$object_name];
}
else
{
if (isset($group_name_mapping[$object_name]))
{
$group_sid = convertUsernameToSID($group_name_mapping[$object_name]);
$prev_mapped_username[$object_name] = $user_sid;
}
}
if (!empty($group_sid))
{
$str_output_to_write .= $group_sid . '=' . $permission . PHP_EOL;
}
}
else
{
if (isset($prev_mapped_username[$object_name]))
{
$user_sid = $prev_mapped_username[$object_name];
}
else
{
$user_sid = convertUsernameToSID($object_name);
$prev_mapped_username[$object_name] = $user_sid;
}
if (!empty($user_sid) && @strlen($user_sid) >= 20) //-- TRICK: Remove non-valid SIDs
{
$str_output_to_write .= $user_sid . '=' . $permission . PHP_EOL;
}
}
}
else
{
$str_output_to_write .= $oneline;
}
}
else
{
if (substr($oneline, 0, 1) == '*')
{
continue; //-- Remove ALL * access. To be improved: Might replace with Everyone?
}
else
{
$str_output_to_write .= $oneline;
}
}
//echo $oneline . '<br />';
}
if (!empty($str_output_to_write))
{
$fp = fopen(SVN_REPOSITORY_ROOT_FOLDER . DIRECTORY_SEPARATOR . DEST_AUTHZ_WINDOWS_FILE, 'w');
if (!empty($fp))
{
fwrite($fp, $str_output_to_write);
fclose($fp);
echo 'DONE!!';
}
else
{
echo 'Cannot open ' . SVN_REPOSITORY_ROOT_FOLDER . DIRECTORY_SEPARATOR . DEST_AUTHZ_WINDOWS_FILE;
}
}
}