/pam-http

A Linux pam-module using https and ssl client certificates for authentication

Primary LanguageCMIT LicenseMIT

Description

Linux-pam (Pluggable Authentication Modules) is responsible for handling authentication requests in a flexible way from linux applications, such as login. This is a minimal pam-module implementation written in C which performs authentication through HTTP.

The purpose for developing this pam-module is to dispatch the authentication procedure to a remote party, and keep options open of how authentication actually is performed. Compare with options like kerberos, ldap, pam_*sql, which is both higly coupled to a specific implemetation and complicated to install & configure.

By using a simple HTTP POST request the authentication api is standardized and independent of the underlying implementation and scheme. A mutual trust between server and pam-client is establish using ssl server & client certificates. The remote party (authentication server) could use ldap, password-database or enables usage of other authentication schemes such as OpenID and Webauthn only intended for web services.

This pam-plugin is built for usage with a webauth server using OpenID (from Google or others) for authentication instead of promting for passwords.

See more @ https://github.com/1nfiniteloop/webauth.

Build

  1. Create build-environment with docker build --tag=pam-http-builder:1.0.0 .devcontainer/.
  2. Build pam_http
docker run \
    --rm \
    --workdir=/home/build \
    --volume=$(pwd):/home/build \
    --name=pam-http-builder \
    --user=$(id -u):$(id -g) \
    pam-http-builder:1.0.0 \
    /bin/bash -c 'mkdir build && cd build && cmake .. && make package'

Install

Install pam_http from the debian package: sudo dpkg -i build/pam-http-1.0.0-Linux.deb

Configuration

Each Linux utility which need authentication and uses pam have a configuration file in /etc/pam.d. Example su has its own configuration file named accordingly, same as for login, sudo, passwd etc. A pam-module consists of four different services; auth, session, account, password which always is present in each configuration file. See more @ http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html

This module implements only the auth service, this is the only service you need to reconfigure. Below is an example for /etc/pam.d/login. You might place the pam-http configuration just above the common-auth include or optionally inside /etc/pam.d/common-auth, at the top.

...
# Custom http authentication
auth     [success=done perm_denied=die new_authtok_reqd=done default=ignore]     pam_http.so url=https://auth-server.com:443/api/auth cert-path=/etc/pam-http.d/ssl key=client.key.pem cert=client.cert.pem cacert=ca-chain.cert.pem

# Standard Un*x authentication.
@include common-auth

...

The options within the brackets above means:

  • success=done a successfull auth request will return success to the application, without calling any further modules in the stack.
  • default=ignore errors such as connectivity issues, outdated certificate falls back to unix passwd authentication.
  • perm_denied=die stops evaluation of further modules in the pam-stack when "401 - Permission Denied" is returned from the auth-server. Except for this item it's equivalent to replace the entire bracket with the keyword sufficient.

Available command-line options in format "key=value" are:

  • timeout= optional, default 30s - Max timeout for a http request.
  • url= required - Url endpoint used for authentication.
  • cert-path= optional - Prefix path for certificate files below.
  • cacert= optional - Bundled certificate chain used to validate the server certificate, containing intermediate and root certificates.
  • key=, cert= optional - Client certificate.

API

The authentication is performed by sending a http POST request to a server with parameters for username and service-name (e.g. login, sudo, su). Password is not part of the http post request since my intention with this project is to avoid the need for local user password promting.

The server can choose to send a 200 status code for grant authentication or 401 for deny. Other status codes are treated as errors. The pam-http module make sure that user exists locally before sending a request.

Develop

The project is built using a docker-container as development environment, see further in .devcontainer/Dockerfile. Tests is written in C++ for conveniece and have further dependencies located as git submodules under folder third_party/.

If you want to build unittests you need to first build the libraries gtest and httpmockserver under third_party/.

  1. Initialize git submodules with git submodule update --init.
  2. Build gtest/gmock and httpmockserver.
  3. Build pam_http with unittests using cd build && cmake -DWITH_UNITTEST=ON .. followed by make test_all.

Reference

Some sources of inspiration used within this project: