apostrophe-proxy-auth
v0.5.5
Published
Log into Apostrophe via weblogin, cosign, shibboleth, basic auth, etc. with an Apache reverse proxy server
Downloads
11
Readme
apostrophe-proxy-auth
Sometimes you want users to log in via weblogin, cosign, Shibboleth, basic auth or other authentication methods that are not available natively in node. In these situations, you'll want to set up Apache as a reverse proxy, and pass the authenticated user's name to node and Apostrophe. This module allows Apostrophe to recognize such logins once they arrive.
This documentation also covers how to configure Apache for use with this module in a typical higher education environment with cosign (aka weblogin).
This module does not implement weblogin, cosign, basic auth or Shibboleth directly. Instead it relies on Apache to do that, and accepts Apache's word for it when a username is presented via an HTTP header. We'll demonstrate how to ensure that this information is authentic.
This module is not for CAS (Centralized Authentication Service). Use apostrophe-cas instead.
Installation
npm install --save apostrophe-proxy-auth
Configuration
Add the module to the modules
section of your app.js
file:
'apostrophe-proxy-auth': {
}
Next, make sure you shut off the regular authentication system. This is a top-level option in app.js
(that is, it's not inside "modules," it's at the same level as "modules"):
auth: false
Now the usual /login
form is replaced with code that simply recognizes when a username has been provided by Apache.
SECURE YOUR SITE CORRECTLY
On your server, as the non-root user with which you deploy Apostrophe, create /opt/stagecoach/apps/mysite/data/address
and populate it with:
127.0.0.1
Otherwise admin user accounts can be spoofed with this module by any moderately talented monkey. You have been warned.
What this does: we'll be trusting the reverse proxy server to provide the authenticated user's name. So we must only accept connections from the reverse proxy, never direct connections. We accomplish this by accepting connections only on the 127.0.0.1
interface (localhost). Here I assume your reverse proxy runs on the same server, which I recommend anyway for performance.
Never run Apostrophe on shared hosting. Always use a VPS or dedicated server. But you already knew that.
Configuring Apache for Cosign
I'll assume you're using Ubuntu Linux. Most of these steps would also apply to other distributions.
If your node site is already up and running behind some other proxy, like nginx, you need to shut it down and uninstall it: service nginx stop && apt-get remove nginx
Install Apache (all commands are as root):
apt-get install apache2
Enable the reverse proxy module and its HTTP protocol module:
a2enmod proxy
a2enmod proxy_http
Now install the apache2-dev
Ubuntu package on the server so cosign can compile:
apt-get install apache2-dev
Now go get the latest CoSign 3.x source code.
Untar the file in /usr/local/src.
cd
into the cosign-3.x.x
folder, then:
./configure --enable-apache2=/usr/bin/apxs2 && make install
This will take care of setting up the directives to load the cosign module on the next Apache restart.
Creating the Cache Folder
The Apache cosign module needs a cache folder. Be sure to create it. Give it to the non-root user and group that Apache is running as, typically www-data
:
mkdir -p /var/cache/cosign/filter
chown -R www-data.www-data /var/cache/cosign/filter
Configuration Files
Here I assume your site is secured with SSL. Clients who use cosign and similar systems will almost always require it. You will typically need to obtain a certificate for your site's subdomain through the client.
Create the /etc/apache2/cosign
folder:
mkdir /etc/apache2/cosign
Populate this folder with the certificate and key files provided by your customer. For PRE-PRODUCTION, you may use the certificate and key files for the SSL protection of the website, as well as for cosign. (Users will see browser warnings.) For PRODUCTION, you will need SEPARATE certificates and keys for cosign and for the actual website.
They may also provide a root CA (certificate authority) file which should be copied to /etc/ssl/certs
, under a name that does not conflict with other files there. After that, ask the system to rehash the root certificates:
cp cacert.pem /etc/ssl/certs/cosign-mysite-cacert.pem
c_rehash .
First create /etc/apache2/includes/weblogin.conf
and populate it with these directives needed for all sites using cosign. Here you'll need to replace myschool.edu
with your customer's domain name, and also change weblogin.myschool.edu
to your customer's weblogin host if it is different.
CosignProtected off
CosignHostname weblogin.myschool.edu
CosignRedirect https://weblogin.myschool.edu/login
CosignPostErrorRedirect https://weblogin.myschool.edu/post_error.html
CosignFilterDB /var/cache/cosign/filter
# Let's allow logins from a test domain we use for our company's projects,
# and also from the client's domain
CosignValidReference https:\/\/.*\.(mytestdomain\.net|myschool\.edu)/.*
CosignValidationErrorRedirect http://weblogin.myschool.edu/validation_error.html
# CoSign 3 requires a validation URL for each protected host.
# This location MUST be available without any restrictions at the registered
# URL (so don't CoSign-protect the entire host).
<Location /cosign/valid>
SetHandler cosign
CosignProtected off
Allow from all
Satisfy any
</Location>
Next, create /etc/sites-enabled/mysite
and configure it to protect the /login
URL with cosign and pass the REMOTE_USER
environment variable on to node via a new HTTP header. Note that this header is always overridden, even if REMOTE_USER
is empty. This prevents outsiders from "spoofing" accounts, as long as the node process only accepts connections from localhost.
Review this file carefully, you need to change several settings. This IS rocket science, be patient. You must ask your customer's cosign administrator for the CosignService
setting.
**First edit your /etc/apache2/ports file
and add Listen 443
if you are not already configured for https on this site.
# Non-secured site: just redirect to the secured site
<VirtualHost *:80>
ServerName mysite.myschool.edu
<Location />
RedirectMatch ^/(.*)$ https://mysite.myschool.edu/$1
</Location>
ErrorLog /var/log/apache2/mysite.error.log
CustomLog /var/log/apache2/mysite.access.log vhost_combined
</VirtualHost>
# Secured site: where the action is
<VirtualHost *:443>
RewriteEngine on
ServerName mysite.myschool.edu
SSLEngine On
# Might or might not be the same file as the cosign certificates, check
# with your customer's cosign administrator
SSLCertificateFile /etc/apache2/cosign/mysite-0.crt
SSLCertificateKeyFile /etc/apache2/cosign/mysite-0.key
Include /etc/apache2/cosign/weblogin.conf
# This setting will be provided by your customer's cosign administrator
CosignService mysite-0
# Your customer will usually provide a certificate and key for use by
# cosign which might or might not also be the certificate and key for
# the site's public SSL; in this example the files are the same.
# The third argument points to a folder of trusted root certificates,
# usually /etc/ssl/certs
CosignCrypto /etc/apache2/cosign/mysite-0.key /etc/apache2/cosign/mysite-0.crt /etc/ssl/certs
# Reverse proxy, only for URLs that are NOT part of cosign
# authentication, which must be handled as configured in
# weblogin.conf and the /login block below
<LocationMatch "^/(?!cosign)(.*)$">
RequestHeader set x-remote-user %{REMOTE_USER}s
ProxyPassMatch http://localhost:3000/$1
</LocationMatch>
# Force login for this URL, set REMOTE_USER once they log in
<Location /login>
# Cosign before proxy
CosignProtected on
AuthType Cosign
Require valid-user
# Check this setting with your customer's cosign administrator
CosignRequireFactor MYSCHOOL.EDU
</Location>
ErrorLog /var/log/apache2/mysite-ssl.error.log
CustomLog /var/log/apache2/mysite-ssl.access.log vhost_combined
</VirtualHost>
Now, assuming you configured Apache correctly and your node app is already listening on port 3000 with this module enabled, you're ready to go:
service apache2 restart
Creating Users On the Fly
In some cases, any person who can log into the reverse proxy should also be a valid account on your site.
Here's how to automatically create new people on the fly:
'apostrophe-proxy-auth': {
createPerson: true
}
Adding New Users to a Group
By default, users created on the fly are not added to any group. You can change that, and also set default permissions for the group if it does not already exist:
'apostrophe-proxy-auth': {
createPerson: {
group: {
name: 'guests',
permissions: [ 'guest' ]
}
}
}
Forcing an Admin User
You can use the admin
option to set a username that always receives full admin permissions upon logging in. This is convenient for bootstrapping a new site that uses weblogin, cosign, etc.
First use the admin
option to give your own account full privileges, then log in and add groups and permissions for other users.
`apostrophe-proxy-auth`: {
createPerson: true,
admin: 'jillrocks'
}
Setting First Names, Last Names and Other Metadata
Since basic auth only provides a username, Apostrophe sets the user's first and last name based on their username. If there is a system of record that can be contacted to learn more about the user, you can pass a before
callback that phones it up via LDAP or a database call:
'apostrophe-proxy-auth': {
createPerson: {
before: function(req, person, callback) {
// Try querying your LDAP or database server
// with person.username
// ...All done, invoke the callback
return callback(null);
}
}
}
There is also an after
option, which takes the same arguments and is invoked after the person exists in the database. This is handy if you need their _id
property.
Subclassing
If you prefer you can subclass the apostrophe-proxy-auth
module and override the beforeCreatePerson
and afterCreatePerson
methods in your index.js
file. You'll need to follow the same pattern used when subclassing apostrophe-snippets
. If this is all new to you, just use the options.
Logging Out
Logging out works out of the box. If you also want the user logged out of a larger campus "single sign on" environment, provide the afterLogout
option. The user is redirected to this URL after logout. Ask your customer's cosign administrator what URL to use.
'apostrophe-proxy-auth': {
// Optional: implement single-sign-out
afterLogout: 'https://weblogin.myschool.edu/logout'
}
Enabling the Module in Production Only
You may not wish to use this module in development environments where you don't have an authenticating reverse proxy. In such cases, just do your configuration on the production server in /opt/stagecoach/apps/mysite/data/local.js
instead of app.js
, like this:
module.exports = {
auth: false,
modules: {
'apostrophe-proxy-auth': { }
}
};
You will likely have other directives here as well, like minify: true
. Options here are merged with the options in app.js
.