Forum OpenACS Q&A: optionally using unix passwords for OpenACS auth

We like to expire passwords after X days for our various network services. We would also like to use ACS for more intranet development.

Because cookies encourage people to forget their passwords, I would like to avoid using cookies for ACS authentication, for community members who have Unix accounts on that server (i.e., staff here at the museum). Instead, I'd like to force them to type in their Unix user names (or email addresses) and matching unix passwords to login.

Since our Unix passwords are also synched with Windows 2000 AD passwords, this would serve the further purpose of minimizing the number of different passwords that our staff need to remember and change, which makes password expiration lots more palatable to them (they'll still complain).

For members who don't have Unix accounts, i.e., the public, we could continue to use cookies. So actually I want a dual system, that is able to check first for the existence of the unix account (if that's possible).

Has anybody tried something similar? I see some entries in these forums about using "basic authentication," but as far as I can tell, that's not linked to Unix passwords. Any thought on how you would proceed?

Collapse
Posted by Jun Yamog on
Hi Matt,

I think OpenACS for 4 will support for LDAP authentication.  Not sure
though check it out.  Although I think using LDAP is the best way to
go, especially if you are using W2k AD since AD is just LDAP, DNS,
Kerberos and MS lock-in tech.

Jun

If anyone is interested in LDAP, I have compiled openldap into a AOLserver module. Not all the functions are ready to go, but everything is stubbed in.

The code is at http://zmbh.com/discussion/ldap/.

There is an acs-ldap-authentication package in the OpenACS4 CVS.

But, I don't think it has been ported, the status page shows it lacks a person to do the porting work.  Also, it seems to use some Java functions...

Overall, it looks like something Matt could use, if it was ported and working for OpenACS.  Matt... did you just volunteer to port that package for us? 😊

Worst case, at least reading its documentation looks like it would be worth your while.

I like Tom's approach, because this would be useful for non-ACS AOLserver users as well as useful for us.

Tom - how much would be involved in finishing your ns_ldap module?

With that complete rewriting the OACS 4 package to use it would be simple.

Jonathan's right in that no one stepped forward to offer to port the OACS 4 LDAP package.  Any offers to help out will be accepted.

The LDAP module in ACS, relies on LDAP inside Oracle. I don't think it will port to PG unless PG has that built in as well. From looking through the small amount of code, I don't believe the author had much of an understanding of LDAP.

LDAP has a well defined API in C. All the client libraries support this API. The result is that it is relatively easy to write an AOLserver C module and then switch out the actual library you use. I chose OpenLDAP.

One problem I ran into is that there is relatively no information on how to use LDAP. The authors of the software wrote a huge fat book _Understanding and Deploying Directory Services_ that is great for managers, but otherwise is a bookshelf hog. They also wrote _LDAP Programming Directory-Enabled Applications with Lightweight Directory Access Protocol_. I own that one as well and it is useful for working with the client library. I initially found most of this book online at the publisher website. (MacMillan Technical Publishing).

Again the problem is in the use. There is no simple logical method of translation from what most of us do with databases and permissions to LDAP. It isn't easy to draw up a schema, and permissions is just wacky.

I was able to get OpenLDAP setup so that I could use the server to store my Netscape Roaming Profile. Even that was a pain, because the original doc at Netscape was written in an outdated Schema format. I did find a howto (linuxdoc.org?), but I still had to deal with permissions on my own.

What we need is some real LDAP guru who can guide us through an example of how to use this beast.

My module compiles and doesn't eat memory. It can bind, authenticate and query, at least a little.

Yes, we do need an LDAP guru, I think you've got that right.  I know LDAP authentication is something commercial clients are interested in, so we do need to figure out a way to address it at some point.
At LAUSD we set up our mail servers using LDAP (openLDAP) and I know that there were some issues (as you said, intellectual, not technical).
If someone gives me specific examples I will ping the LDAP guru. They know nothing of OpenACS nor Oracle/PG so this needs to be kept in mind.

If I didn't already have to much on my plate I would like to help. In any case let me know if I can help as this would be a huge win for PR and OpenACS

The good news about using LDAP for authentication is that you don't need to pull a result set over and cycle through it. You can get a yes/no answer. But I don't think it will be any easy task to substitute general ACS permissions using this. Authentication should be a much simpler task, you simply pass the username/password to the server and see if it accepts it or not, I guess. I believe my module will already serve the purpose of doing this. (Still need to figure out how to get the data into the LDAP server, not too hard)

Tom,

If I understand correctly you can create a tcl command
"ldap_authenticate username password" and then patch
ad_check_password to use this new command then modifying ACS to
interact with your module should be relatively painless.

Here is what I was using to test my module. All you need it to provide some kind of translation of the username into the namespace used on the LDAP server. Changing the namespace also allows one server to authenticate multiple domains.

set ci [ns_queryget i "1"]
set cj [ns_queryget j "1"]
set start [clock clicks -milliseconds]
set count 0
set entries "no"
for {set i 0} {$i < $ci} {incr i} {

        set ldaphandle [ns_ldap init "zmbh.com:389" "cn=Manager,dc=zmbh,dc=com" "mypassword"]
        ns_ldap simple_bind_s $ldaphandle
        for {set j 0} {$j < $cj} {incr j} {
                ns_ldap search_s $ldaphandle "dc=zmbh,dc=com"  "(objectclass=*)"
                incr count
                set entries [ns_ldap count_entries $ldaphandle]
        }
        ns_ldap unbind $ldaphandle
}

set total [expr [clock clicks -milliseconds] - $start ]
ns_return 200 text/plain "
time for $count cycles: $total milliseconds
found $entries entries
$ci bind-unbind cycles
$cj searches per cycle" 

Btw, the bind/unbind cycle is very fast. I don't think there is any need to maintain a connection or use a pool of connections.

Hi all,

I work with Matt and am following up on his original post.

LDAP or not, I think what we're really asking about is a two-tiered authentication hierarchy because of concerns about password and cookie security.

I envision something like this: we have a group called, for instance, "staff". Everyone in staff is forced to log in every time, i.e. they never get a cookie except perhaps for a very short-term so it acts as a timeout. Everyone else (non-employee community members) gets cookies so they rarely have to enter a password.

Has anyone done anything similar, any kind of user or group level security policy? What about granting access based on IP address?

Secondly, what about password security. If you set EncryptPasswordsInDBP, how does security on the database itself compare to security on /etc/shadow, and how does it compare to LDAP? We would like to sync our staff's passwords systemwide, so cracking the DB would be pretty serious.

Thanks

Access based on IP is simple - just set up a filter that compares the URL with a set of pages restricted to your LAN subnet (I assume that's the level of restriction you have in mind).

Passwords in cookies are encrypted.  If you ask passwords to be encrypted in the DB, they're encrypted using ns_crypt, which uses the same crypt function in glibc as has been traditionally used in Unix-land for a very long time.  The linux world is switching over to stronger encryption for system password encryption, but I wouldn't worry much about people cracking db's encrypted in the database.

Most cracks come about because of poor passwords.  I suspect you'd be hard pressed to find a case of a crack succeeding based on unencrypting
crypt'd passwords.

A very simple patch to packages/acs-subsite/www/register/indext.tcl could prevent your staff from getting the persistent login cookie. Just replace
set persistent_login_p [ad_parameter AllowPersistentLoginP security 1]
with
if [db_string is_staff_member {
    select count(1) 
      from group_member_map m, groups g
     where m.group_id = g.group_id
       and g.group_name = 'Staff'
}] {
    set persistent_login_p 0
} else {
    set persistent_login_p 1
}
The effect will be that staff members will have to log in again each time they visit the site from a new browser window. Combine that with the SessionTimeout parameter (which you set on the acs-kernel package), and you've made it pretty hard for someone to sneak into your office and get admin access to your website.

You've still got to solve the problem of synchronizing the passwords in the ACS users table with the unix passwords chosen by your employees. Is it possible to run a setuid perl or shell script that can decrypt the passwords in /etc/shadow? If so, then you could execute that script from an AOLServer scheduled procedure, notice any passwords that have changed since the last time you ran, and call ad_change_password. I don't know how to write that hypothetical script though (maybe it's intentionally not possible), or how to let AOLServer run it without also making it available to any other hacker on the system.

Luke's suggestion is very good. In an older ACS version, admins could not login forever. Very annoying, but hey. With session timeouts, if they leave their desk for 10 minutes or so, they have to log back in. This is really what you want. It is as safe as you can get.

Some other points about ACS4 security. The user password is never stored in the cookie! What is stored there is a token that is used to prove to the system that you knew the password at one time. This token could still be stolen and used on another machine. There are actually two login cookies that could be sent: ad_user_login and ad_user_login_secure. The second is sent when logging in using https. Both are blank if persistent login is not allowed. The session id cookie is called ad_session_id, which is alway sent to everyone on every connection to the server. This cookie is not persistent, so at most this one lives for as long as the browser is open. Setting the session timeout causes the life of this cookie to be more predictable.

If you choose to encrypt the password in the db, the encryption is really an SHA hash. A hash cannot be unencrypted. Along with the hash is stored the 'salt' used to create the hash. What the ACS code does it to combine the user supplied password with the salt and to then hash the combination. Unless the algorithm used to create the hash is identical for /etc/shadow you cannot syncronize the passwords. I doubt that they will be identical, so that isn't going to work.

The reason for using LDAP is not to create syncronization problems, but to eliminate them. LDAP would replace the database lookup of the hash. Each time a user is required to login, from windows, or to ACS, they would provide the username and password. The application would create a query to send to the LDAP server. The response received would determine if the user had the right to access the resource. The LDAP server might have one or more records, but only one username/password. OpenLDAP can also be configured to use /etc/passwd, or /etc/shadow, but if you are going to install LDAP you might as well use it.