RT3 ActiveDirectory User Attributes Sync

Ok, here is another small script to deal with RT3 and Active Directory. If you apply the apache LDAP auth described previously to your RT3 installation, you will have no problem getting people logged in, but you will still have to adjust their names and emails. Doing this manually is not the best choice, so here is a small script, which can be run from the cron (or manually) to update user info in RT3 according to user attributes in Active Directory:

#!/usr/bin/php
< ?php

# Debug flag. Set to non-zero for verbose output
$debug = 0;

# Settings to use while connecting to active directory
$ldap_host = "10.10.10.1"; # AD server
$ldap_user = "someuser@example.com"; # User in AD with read writes
$ldap_pass = "someuser_password"; # Password for the user above
$ldap_base = "dc=example,dc=com"; # AD base to search (recursivly)

# Settings to use while connecting to rt3 MySQL DB
$sql_host = "127.0.0.1"; # MySQL server
$sql_name = "rt3"; # RT3 DB name in MySQL
$sql_user = "rt3_user"; # User to connect to above DB
$sql_pass = "rt3_pass"; # Password for the user above

# Map of RT3 -> AD attributes
$attr_map = array(
	'RealName'		=> 'displayName',
	'EmailAddress'	=> 'mail'
);

# Connect to AD and authenticate
$ldap = ldap_connect($ldap_host);
if (!$ldap) {
	die ("Failed to connect to LDAP server: " . ldap_error() . "\n");
}
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
if (!ldap_bind($ldap,$ldap_user,$ldap_pass)) {
	die ("Failed to bind to LDAP server: " . ldap_error() . "\n");
}

# Connect to MySQL
$sql = mysql_connect($sql_host,$sql_user,$sql_pass);
if (!$sql) {
	die ("Failed to connect to MySQL server: " . mysql_error() . "\n");
}
if (!mysql_select_db($sql_name)) {
	die ("Failed to select MySQL database: " . mysql_error() . "\n");
}

# Get a list of RT3 users from MySQL
$users = get_rt3_users();

# Update attributes for each RT3 user according to AD attributes
foreach ($users as $user) {
	set_rt3_user_info($user,get_ldap_user_attr($user));
}

# Close the connections to MySQL and AD
mysql_close($sql);
ldap_unbind($ldap);

# Gets a list of RT3 users from MySQL
function get_rt3_users () {
	global $sql;

	# Skips the external users (the ones that look like email address)
	$result = mysql_query("SELECT Name FROM Users WHERE Name NOT LIKE '%@%'",$sql);
	$users = array();
	while ($user = mysql_fetch_array($result)) {
		array_push($users,$user[0]);
	}
	return $users;
}

# Gets AD attributes for the given user
function get_ldap_user_attr ($user) {
	global $ldap,$ldap_base,$attr_map,$debug;

	if ($debug) { print "Searching for user $user\n"; }
	$result = ldap_search($ldap,$ldap_base,"(sAMAccountName=$user)");
	$entries = array();
	if ($result) {
		$entries = ldap_get_entries($ldap,$result);
	} else {
		die("Failed to search LDAP: " . ldap_error($ldap) . "\n");
	}
	return $entries;
}

# Updates RT3 user in MySQL with given AD attributes
function set_rt3_user_info ($user,$attr) {
	global $sql,$attr_map;

	# Construct an update SQL query arguments
	$query = "";
	foreach ($attr_map as $k => $v) {

		# Update field only if it is set and non empty
		if (isset($attr[0][strtolower($v)][0]) and $attr[0][strtolower($v)][0] != "") {
			$query .= ",$k='" . mysql_escape_string($attr[0][strtolower($v)][0]) . "'";
		}
	}

	# Run the actual query
	$query = "UPDATE Users SET ".substr($query,1)." WHERE Name='".mysql_escape_string($user)."';";
	mysql_query($query);
}

?>

Now each time a new user logs in to RT3 and his username appears in RT3 database, this script will update his/her name and email. You can extend a list of mapped attributes to have more info updated if you want so.

Apache MS Active Directory Auth

I know there are plenty of methods to apache auth through active directory, but recently I found out that some of them didn’t work for me or didn’t do well. The more or less successfull one was perl Apache2::AuthenNTLM, but when you have a lot of users, this one blocks apache now and then and causes some real problems.

Like always, found out about apache mod_authnz_external and ended up writing my own authentication script. Here is how to make things work:

First of all download and install mod_authnz_external (google for the package and installation instructions).

Then put the next script somewhere on the apache server (for example /etc/httpd/conf/ad_login.php):

< ?php

// AD server IP address
$ldap_host = "10.10.10.1";

// AD Base
$ldap_base = "dc=example,dc=com";

// AD domain
$ldap_domain = "example.com";

// Connect to AD server
$stderr = fopen("php://stderr","w");
$ldap = @ldap_connect($ldap_host);
if (!$ldap) {
	fwrite($stderr,"AD Auth: Failed to connect to $ldap_host\n");
	fclose($stderr);
	exit(1);
}
@ldap_set_option($ldap, LDAP_OPT_PROTOCOLO_VERSION, 3);
@ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);

// Try to login with the supplied username and password
// (using environment to pass the stuff)
if (!@ldap_bind($ldap,$_ENV['USER'] . '@' . $ldap_domain,$_ENV['PASS'])) {
	fwrite($stderr,"AD Auth: Failed to authenticate " . $_ENV['USER'] . "\n");
	fclose($stderr);

	// if failed - exit with 1
	exit(1);
}

ldap_unbind($ldap);
fclose($stderr);

// exit with 0 on success
exit(0);

?>

Next, add the following into VirtualHost (or similar) definition in apache config:

AddExternalAuth ad "/usr/bin/php -f /etc/httpd/conf/ad_login.php"
SetExternalAuthMethod ad environment

# This can go into Location or Directory sections
AuthType basic
AuthName "My Closed Zone"
AuthBasicProvider external
AuthExternal "ad"
require valid-user

Restart apache and you are done.

How does it work? Simple. Each time apache will need to authenticate a user, it will start a script (ad_login.php) and pass it username and password as environment variables. The script, in turn, will try to connect to AD and authenticate itself as given user. If that fails – login fails, otherwise – login ok. So basically, if a user has writes to connect to AD, (s)he has write to login to apache.

And of course you can extend the PHP script with some extras, like additional checks on username, caching and so on.

FreeNX and MS Active Directory

I have managed to set up FreeNX to work quite smoothly with MS Active Directory authentication. Here are few steps to be done (assuming Fedora Core 5 as a FreeNX server):

1. Make the linux server where FreeNX will be installed an AD member

For this we will need samba and kerberos stuff which are either installed or easily retrieved with yum. So I will not bother describing on how to get packages :) If some configs mentioned below are missing, then obviously you are missing some packages
In /etc/samba/smb.conf:

[global]
netbios name = myhost
realm = mydomain.int
workgroup = mydomain
security = ADS
password server = pdc.mydomain.int bdc.mydomain.int
socket options = TCP_NODELAY SO_RCVBUF=16384 SO_SNDBUF=16384
idmap uid = 10000-20000
winbind enum users = yes
winbind uid = 10000-20000
winbind gid = 10000-20000
winbind separator = +
winbind use default domain = yes
encrypt passwords = yes
log level = 3 passdb:5 auth:10 winbind:5
template shell = /bin/bash

In /etc/krb5.conf

[libdefaults]
ticket_lifetime = 600
default_realm = mydomain.int
default_tkt_enctypes = des3-hmac-sha1 des-cbc-crc
default_tgs_enctypes = des3-hmac-sha1 des-cbc-crc
dns_lookup_realm = false
dns_lookup_kdc = false

[realms]
mydomain.int = {
kdc = pdc.mydomain.int:88
kdc = bdc.mydomain.int:88
admin_server = pdc.mydomain.int:749
default_domain = mydomain.int
}

[domain_realm]
.mydomain.int = pdc.mydomain.int
mydomain.int = pdc.mydomain.int

[kdc]
profile = /etc/krb5kdc/kdc.conf

[logging]
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmin.log
default = FILE:/var/log/krb5lib.log

This is enough to be a member of AD. Just make sure that smbd and winbindd are running. To join the domain, use net join ads command with required options (see net help join for more info)

2. Make domain users be able to login to linux server with SSH

I suppose there are many ways to do this, but I went with modifying the /etc/pam.d/ssh the next way

#%PAM-1.0
#auth include system-auth
#account required pam_nologin.so
#account include system-auth
#password include system-auth

auth required /lib/security/pam_securetty.so
auth required /lib/security/pam_nologin.so
auth sufficient /lib/security/pam_winbind.so
auth required /lib/security/pam_unix.so use_first_pass shadow nullok
account sufficient /lib/security/pam_winbind.so
account required pam_nologin.so
account include system-auth
session include system-auth
session required pam_loginuid.so

and now make system look for AD users by modifying the /etc/nsswitch.conf to contain the next lines:

passwd: files winbind
shadow: files
group: files winbind

#hosts: db files nisplus nis DNS
hosts: files DNS winbind
From now on the system will allow domain users to login with SSH.

3. Make it work

Now just install freenx:

# yum install freenx

Optionally make it work with default nomachine keys (so that clients will have less configurations to do) by reconfiguring freenx:

# nxsetup --override --install --setup-nomachine-key --clean --purge)

start nxserver

# nxserver --start

create home for desired domain users

# mkdir /home/mydomain/myusername

and finally allow the user to use FreeNX

# nxserver --adduser mydomain+myusername

4. Troubleshooting
All problems are seen in log files under /var/log

5. Other benefits

The way the samba is configured now, it is very easy to add SQUID with NTLM auth ;) If you are interested in this - just let me know in the comments - I will post the samples of config files.

Things missing in Linux

For the past few months I’ve been working a lot with Linux and M$ in parallels and most of the times I was migrating different things from M$ to Linux. During this months I realized why so many people are still stick to M$.

The idea is that it is true that you can replace any functionality of M$ by Linux including servers/desktops/terminals and whatever but the problem is that it is still a bit hard to set up a replacement since there is a lack of GUI (kind of easy usable configuration tools) and all the software comes from different vendors what makes it a bit hard setting it to work together.

For instance, let’s take the combination of Active Directory + Domain + M$ Exchange: it provides a directory server with all those easy administration, data replication and whatever else, plus the whole collaboration package from M$ Exchange. It is known that Active Directory can be replaced with OpenLDAP, Domain can be [almost fully] handled by Samba and M$ Exchange can be replaced by putting together MTA, IMAP, POP and whatever else required. All of the applications can work with OpenLDAP to have a centralized username/passwords and other stuff and it seems that the whole combination is replaced, but not. Have you ever tried butting all of these together? If yes – how long did it take you and finally – how easy is it to administrate? I mean if there is a common place [ok - two] where you can go to do any tasks related to the package above?

I know, there is a major plus in Linux way – a matter of choice. You can choose an MTA you like (Sendmail, Exim, Postfix, Courier, whatever) as well as any IMAP, POP, and even LDAP server can vary from OpenLDAP to Netscap Directory Server or new RedHat/Fedora Directory Server of similar SuSE product. This is what you will never get with M$. But on the other hand it still kinda difficult to set it up and even more difficult to watch it afterwards.

Of course there were some attempts to create some kind of centralized panels for administration [like Webmin or even linuxconf tool] but they all suck at some points. The major problem with them [from my point of view] is that they are modular and different modules are contributed by different people and most of the time there is a problem with compatibility.

The whole post above is not to tell that M$ is better that Linux [although in some cases it might be] but to try and figure out what is missing in Linux to make it easier for people to get used to it.

As an example to confirm the above I would describe the next situation: a while ago a was setting up a simple Linux firewall with a bunch of network services that I usually add to these kind of boxes like [iptables, squid, dhcp, caching DNS and some others] and a guy, who asked me to make this installation was very upset since he can not control this box in a comfortable way (lets say using web interface to have a centralized administration) and the only way for him to change something in the settings was to either call me to SSH to the box and re-configure it or use a bunch of small tools that left him each for changing different settings.

Fedora Directory Server (part 3)

Ok, lets continue with the Fedora Directory Server.

First of all I have some screenshots. They do not cover the whole GUI but instead show main windows and tabs and some dialogs.

Second: while reading the docs I found out not only that the directory feels good with import/export of LDIF (I have tried with standard OpenLDAP migration tools) but can also syncronize with M$ Active Directory and (EVEN) with M$ NT4 Domain PDC (for user/group information). This seems to be cool since I know that even M$ Active Directory has some problems communicating with NT4.

I have tried to set up SSL with self singed certificates and found out that there is a whole chapter in the docs describing how to do it and a couple of tools/scripts are provided with the installation to help with generation of the certificates. All the management of the certificates can be easily done through GUI.

I would also like to note that although I ignored a message of low RAM on my machine (128MB) during the installation – everything works fast and good.