Transparent Squid authentication with SquidTrust III (ACL’s based on NDS or AD group membership.) This article and the provided scripts are an update to the original tools located at: http://www.novell.com/communities/node/12886/squid-authentication-novell-client-akasquidtrust I felt that there were enough differences and new features that it warranted a new article, and some detailed instructions. Updates/differences: -- Netware user name calls now made via NDS rather than bindry. -- Ability to return Netware user and Group Membership information. -- Ability to return Active Directory user and Group Membership information -- Port changed from 6399 to 2199 -- Removed “who am I” from icon menu. The difference between this solution and most other solutions is that most of the “heavy lifting” is done on the workstation, rather than tying up cycles on the Squid Proxy server. For the NDS username, this version makes a call to the Novell client files that come with the Novell workstation client32. No tree walking or directory searching. This version also has the ability to return a users’ group membership information based on an LDAP call from the workstation to an eDirectory LDAP server. Native Windows and Active Directory information is pulled from the machine via a small VB script. Source code and a precompiled binary (SquidTrustIII.exe) are available at http://sourceforge.net/projects/squidtrust/ (look for version III) To test: Run the SquidTrustIII.exe (or the uncompiled script using Autohotkey http://www.autohotkey.com/). From the command prompt telnet to the workstation on port 2199. Pressing a “1” will get the netware username returned. Pressing a “2” will get the computer name returned. Pressing a “3” will get the windows username returned. Pressing a “4” will get a bunch of computer info returned. (ComputerName,WindowsUserName,NWuserName,ip,macaddr,SN,modNum,YYYYMM-DD Hour:Min) Pressing a “5” will return the current Netware users name followed by all of the groups that the user is a member of (If the prerequisites are configured correctly). Pressing a “6” will return the current Active Directory users name followed by all of the groups that the user is a member of (If not a Domain member, just the local groups will be returned). Pressing a “7” will return the current Netware username and groups if the Novell client32 is installed on the workstation, otherwise, the Active Directory users name followed by all of the groups that the user is a member of (If not on a Domain, just the local groups) will be returned. BASIC USAGE: Exactly like the previous version. 1. Run the SquidTrustIII.exe on the workstation 2. Run the Perl Authentication helper on the Squid Proxy server. 3. See http://www.novell.com/communities/node/12886/squid-authenticationnovell-client-aka-squidtrust for instructions. 4. SquidTrustII runs off port 2199, don’t forget to make the appropriate changes in firewalls etc…and don’t forget to chmod the script to 7777 BASIC PERL HELPER Basic Perl auth. Helper code for SquidTrustIII: [code] #!/usr/bin/perl use IO::Socket; $|=1; ## Main loop (START), sets the loop to wait for an input <STDIN> and sets the input to $host (clients IP address) START: while ($host = <STDIN>) { ## Sets up the socket connection to the client computer $port = 2199; $sock = new IO::Socket::INET(PeerAddr => $host, PeerPort => $port, Proto => 'tcp', Timeout => '1',); ## if - else section to either print OK or ERR based on weather a successful connection was made if ($sock =~ /IO::Socket/) { #send a command to the workstation $cmd = "1"; print $sock $cmd; # print workstation response $nwusername = <$sock>; if ( length $nwusername > 0 ) { print "OK user=$nwusername\n"; close $sock; next START; } else { print "ERR\n"; close $sock; next START; } } else { print "ERR\n"; close $sock; } next START; } [/code] The above procedure should work pretty much exactly like the previous version. The above script is set to send a “1” ($cmd = "1";). To get a different response from the SquidtrustIII.exe, just change that value. You should only use 1,2, or 3 as values in the above script. The “Advanced” section, Squid ACL’s based on NDS/AD Group Membership: In this section I will show how to use the SquidTrustIII.exe to return a Netware users name and group memberships. I will then show how to apply Squid ACL’s based on a user’s group membership. SquidtrustIII uses a LDAP call from the workstation to a Novell LDAP server to return the current users name and group memberships. There are 5 Prerequisites: 1. An eDirectory LDAP server 2. Your LDAP server must allow anonymous connections on port 389. SquidTrustIII has no built in support for LDAP login/password, proxy access, or secure connections (port 636). If you want/need these things, the code is open source…. 3. The NDS attribute “Group Membership” must be mapped to the LDAP attribute “groupMembership” – this is done under “Attribute mappings” of your LDAP Group object. 4. The Group Membership attribute must be “readable” by “public”. This is done under the properties of the root of your NDS tree. Make sure that it is marked as “inheritable”. This is exposing your group memberships to any anonymous connections, please make sure you understand the security ramifications. To test that the attributes are set correctly, and that they are publicly viewable, connect to your LDAP server with an LDAP browser as an “anonymous” connection and make sure you can browse the LDAP directory, and see the groupMembership attribute. (Apache studio, and Softerra LDAP browser version 2.6 are both good LDAP browsers with easy to use GUI’s…) You must be able to see these attributes as an anonymous user, or SquidTrustIII will not be able to pull the NDS group memberships. 5. DNS resolution. By default, the SquidTrustIII.exe is hard coded to look for a DNS name of “SQDLDAP”. The name “SQDLDAP” is expected to resolve to your eDirectory LDAP server. In most cases, simply adding a DNS entry to a DNS forwarder/server would be the easiest and best solution. If you are running a Squid Proxy, chances are you have access to some sort of name resolution process…. You could also add the entry to the client machines “hosts” file. Ie: # For example: # # 102.54.94.97 rhino.acme.com # source server # 38.25.63.10 x.acme.com # x client host 127.0.0.1 localhost 10.1.3.175 freenasBACKUP.local 10.1.1.7 sqdldap The last option would be to run the SquidTrustIII.exe file with an argument. By default the exe will accept a single IP address (of your LDAP server) as an argument. like… This method very convenient for testing, but probably not really a production ready solution. To test that DNS resolution is working, you should be able to ping “sqdldap” from your workstations, and have it resolve to your eDirectory LDAP server So…..DNS is not truly “required”, but it is by far the preferred method. If all 5 of the prerequisites are met: and setup correctly, the SquidtrustIII.exe should return the NDS user name and all of the group memberships of that user when sent a “5”. Nested groups may or may not work……untested. If the machine is logged into a windows domain, sending a “6” should return the domain user name, and all of the group memberships of that user. ActiveDirectory (sending a “6” ) NDS (sending a “5” ) The returns are pretty much in the same format of “<username>,<Group1>,<Group2>,<GroupX..> Groups are separated by spaces in the NDS return, and by commas in the AD return. Now we just use a Perl Authentication helper on the Squid Proxy to parse, and return the information we want. The helper is really pretty simple: 1. It waits for an IP address from a workstations http request 2. In the following code the helper sends back a “7” to the workstation on port 2199 3. the workstations SquidtrustIII.exe agent does it’s magic and sends the squid helper back a string that contains the users name and group memberships. 4. split the string into an array 5. array[0] is always the username 6. search for group names defined in the if-else section 7. output the appropriate response (OK, ERR) 8. Start listening again. “Advanced” Authentication helper Perl code: Comments and code notes are included in the code. (please note: code formatting may be off due to the cut/paste into a word processing document) You will have to modify the code for your particular environment. [code] #!/usr/bin/perl ## Authentication helper for SquidTrustIII ## Scott Owen June/25/2012 ## sowen-at-edzone.net ## ## ## ## ## ## ## ## ## ## Squid authentication helper for use with the SquidtrustIII agent. "ERR" or "OK" codes will be given depending on group membership In this example FULLACCESS membership = "OK user=username[FULLACCESS]" LIMITEDaccess membership = "OK user=username[LIMITEDaccess]" group4 membership = "OK user=username[group4]" ## ## ## ## ## ## ## ## ## ## Any other group memberships, or no matching group memberships will cause an "ERR" to be returned. "ERR" and "OK user=" are the two states that squid expects from an auth. helper. The users login name will be changed to a format of: username[group] This is the name that will show in access logs. This will show the users name and the group membership that allowed the user access to the proxy/cache. use IO::Socket; $|=1; ## Main loop (START), sets the loop to wait for an input <STDIN> and sets the ## input to $host (clients IP address) START: while ($host = <STDIN>) { ## Sets up the socket connection to the client computer $port = 2199; $sock = new IO::Socket::INET(PeerAddr => $host, PeerPort => $port, Proto => 'tcp', Timeout => '1',); ## "if - else" section to either print OK or ERR based on weather a successful ## connection was made, and then sort for group ## membership. # set error code to zero $errorcode = 0; if ($sock =~ /IO::Socket/) { #send a command to the workstation $cmd = "7"; print $sock $cmd; # print workstation response $adusername = <$sock>; # Check and make sure we got a response, # if the response wasn't blank, split it apart if ( length $adusername > 0 ) { ## print "$adusername\n"; @array = split (',', $adusername); foreach my $array (@array) { # start parsing the response for group memberships. # This part is pretty simple, just search the returned #string for group names. if ( $array =~ "FULLaccess"){ $errorcode = 1; print "OK user=$array[0]\[FULLaccess\]\n"; close $sock; next START; } else{ if ( $array =~ "LIMITEDaccess"){ $errorcode = 1; print "OK user=$array[0]\[LIMITEDaccess\]\n"; close $sock; next START; } else{ if ( $array =~ "group4"){ $errorcode = 1; print "OK user=$array[0]\[group4\]\n"; close $sock; next START; } ## closing brackets for if/else statements } } } ## if no group memberships matched, error out if ($errorcode < 1 ){ print "ERR\n"; close $sock; next START; } } ## if the socket response was blank, error out. } print "ERR\n"; close $sock; $errorcode = 0; next START; } [\code] NDS response AD response Jumping between AD and NDS The helper has basically changed the users name from “SOWEN” to “SOWEN[FULLaccess]” and from “mringle” to “mringle[FULLaccess]”. At this point the members of the FULLaccess group have a common string as part of their Squid username, so it becomes very simple to apply Squid ACL’s based on weather their username contains the string “FULLaccess”…..just avoid making any users with the same string in their name. I add the authentication helper to my Squid.conf something like this: [code] external_acl_type IPUser ttl=60 children=10 %SRC/usr/local/squid/SquidTrustIII.pl acl AuthNDS external IPUser http_access allow AuthNDS auth_param basic program /usr/local/libexec/squid/squid_ldap_auth -v 2 -b T=MYTREE -D cn=adminusername -w adminpassword -f "(&(|(groupMembership=cn=LIMITEDaccess,o=INTERNET)(groupMembership=cn=FULLacces s,o=INTERNET))(objectclass=User)(cn=%s))" -u uid -P 10.1.1.7 auth_param basic children 70 auth_param basic realm Welcome to my Internet Proxy, please enter your user name and password to continue: [\code] I run the helper before the default LDAP (squid_ldap_auth), that way if the user gets denied access via the auth helper, they have a chance to login with the standard LDAP authentication mechanism. As an example ACL using the group membership “FULLaccess”, I’ll send users that are members of the “FULLaccess” group out the WAN IP address 9.11.15.11 [code] acl Namecheck ext_user_regex [-i] .*FULLaccess*.* tcp_outgoing_address 9.11.15.11 Namecheck [\code] Using the “ext_user_regex” acl should allow you to use almost any standard acl directive(s).