Apache-based authentication for Seaside
I recently posted about a completely Smalltalk-based solution for LDAP authentication for Seaside applications. After I got that working for my application, I realized that once I submitted my application to our security group here on campus for review, it would never pass inspection due to the fact that user passwords are accessible to my code. I can imagine many scenarios where programmer access to user credentials is unacceptable.
Fortunately, our university provides its own kerberos-based authentication solution for applications called Bluestem. It provides the user first with a screen to enter their username, then a second screen to enter their university kerberos password. Upon successful authentication, the user is given access to the proper resources on the server. Bluestem is written in Perl and there exists an Apache module to integrate it with web applications. I previously set up the server I plan to deploy my Seaside application on for Bluestem authentication for other web applications that I host on it, but I did not know of a way that I could use this type of authentication with Seaside since I was planning on using mod_proxy to proxy requests from my external-facing Apache server to my headless Pharo VM.
While I was researching how to do this, I came across an Apache module that someone has posted on Github at https://github.com/aimxhaisse/mod-proxy-add-user which takes the authenticated user name set by Apache and forwards it on to servers being proxied. I was able to compile it (manually, the Makefile appeared to be broken) and get it up and running on my CentOS server within a few minutes. I configured my Apache configuration file with:
<Proxy *> Order deny,allow Allow from all ProxyAddUser On ProxyAddUserKey "HTTP_X_FORWARDED_USER" </Proxy>
And low and behold, I was able to access the authenticated user name in my proxied Seaside application with:
username := self class decodeUserIdFrom: (self requestContext request headerAt: 'http_x_forwarded_user' ifAbsent: [username := 'cemeyer2']).
Let me explain a little bit. In most cases, just self requestContext request headerAt: ‘http_x_forwarded_user’ will give you the authenticated user name, but our university’s kerberos solution sets this variable to ‘email@example.com/kerberos’, so the decodeUserIdFrom message strips off everything but the user name. The above line also is useful for when accessing the application when not being proxied behind university authentication (such as during development), as it will default to return my user name if the header is not found.