diff --git a/certidude/auth.py b/certidude/auth.py index 5b5d15e..40f88b5 100644 --- a/certidude/auth.py +++ b/certidude/auth.py @@ -1,5 +1,6 @@ import click +import falcon import logging import os import re @@ -133,7 +134,8 @@ def authenticate(optional=False): import simplepam if not simplepam.authenticate(user, passwd, "sshd"): - logger.critical(u"Basic authentication failed for user %s from %s", + logger.critical(u"Basic authentication failed for user %s from %s, " + "are you sure server process has read access to /etc/shadow?", repr(user), req.context.get("remote_addr")) raise falcon.HTTPUnauthorized("Forbidden", "Invalid password", ("Basic",)) diff --git a/certidude/user.py b/certidude/user.py index e33f2da..6232a4c 100644 --- a/certidude/user.py +++ b/certidude/user.py @@ -60,6 +60,13 @@ class PosixUserManager(object): _, _, gid, members = grp.getgrnam(config.ADMIN_GROUP) return user.name in members + def all(self): + _, _, gid, members = grp.getgrnam(config.USERS_GROUP) + for username in members: + yield self.get(username) + for user in self.filter_admins(): # TODO: dedup + yield user + class DirectoryConnection(object): def __enter__(self): diff --git a/tests/test_cli.py b/tests/test_cli.py index e7f7548..50bce54 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,5 +1,7 @@ import os import requests +import subprocess +import pwd from falcon import testing from click.testing import CliRunner from certidude.cli import entry_point as cli @@ -43,6 +45,39 @@ def test_cli_setup_authority(): assert authority.ca_cert.not_valid_before < datetime.now() assert authority.ca_cert.not_valid_after > datetime.now() + timedelta(days=7000) + try: + pwd.getpwnam("userbot") + except KeyError: + # useradd userbot -G users -p '$1$PBkf5waA$n9EV6WJ7PS6lyGWkgeTPf1' + cmd = "useradd", "userbot", "-G", "users", "-p", "$1$PBkf5waA$n9EV6WJ7PS6lyGWkgeTPf1" # bot + subprocess.call(cmd) + + try: + pwd.getpwnam("adminbot") + except KeyError: + # Note: on Fedora use group 'wheel' instead of 'sudo' + # useradd adminbot -G sudo -p '$1$PBkf5waA$n9EV6WJ7PS6lyGWkgeTPf1' + cmd = "useradd", "adminbot", "-G", "sudo", "-p", "$1$PBkf5waA$n9EV6WJ7PS6lyGWkgeTPf1" # bot + subprocess.call(cmd) + + usertoken = "Basic dXNlcmJvdDpib3Q=" + admintoken = "Basic YWRtaW5ib3Q6Ym90" + + result = runner.invoke(cli, ['users']) + assert not result.exception + + + # Test session API call + r = client().simulate_get("/api/", headers={"Authorization":usertoken}) + assert r.status_code == 200 + + r = client().simulate_get("/api/", headers={"Authorization":admintoken}) + assert r.status_code == 200 + + r = client().simulate_get("/api/") + assert r.status_code == 401 + + # Try starting up forked server result = runner.invoke(cli, ['serve', '-f', '-p', '8080']) assert not result.exception @@ -172,6 +207,13 @@ def test_cli_setup_authority(): r = client().simulate_get("/api/signed/test2/tag/") assert r.status_code == 401 + r = client().simulate_get("/api/signed/test2/tag/", headers={"Authorization":usertoken}) + assert r.status_code == 403 + + r = client().simulate_get("/api/signed/test2/tag/", headers={"Authorization":admintoken}) + assert r.status_code == 200 + + # Revoke all valid ones result = runner.invoke(cli, ['revoke', 'test2']) assert not result.exception