File: shadowauth.py

package info (click to toggle)
circuits 3.1.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 9,764 kB
  • sloc: python: 15,945; makefile: 131
file content (69 lines) | stat: -rwxr-xr-x 1,894 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Shadow Auth Demo

An example of a Circuits Component that requires users authenticate
against /etc/passwd or /etc/shadow before letting them into the web site.
"""

from os import path
from crypt import crypt
from socket import gethostname
from re import compile as compile_regex

from circuits import handler, Component
from circuits.web import _httpauth, Server, Controller
from circuits.web.errors import HTTPError, Unauthorized


def check_auth(user, password):
    salt_pattern = compile_regex(r"\$.*\$.*\$")
    passwd = "/etc/shadow" if path.exists("/etc/shadow") else "/etc/passwd"

    with open(passwd, "r") as f:
        rows = (line.strip().split(":") for line in f)
        records = [row for row in rows if row[0] == user]

    hash = records and records[0][1]
    salt = salt_pattern.match(hash).group()

    return crypt(password, salt) == hash


class PasswdAuth(Component):

    channel = "web"

    def init(self, realm=None):
        self.realm = realm or gethostname()

    @handler("request", priority=1.0)
    def _on_request(self, event, request, response):
        if "authorization" in request.headers:
            ah = _httpauth.parseAuthorization(request.headers["authorization"])
            if ah is None:
                event.stop()
                return HTTPError(request, response, 400)

            username, password = ah["username"], ah["password"]

            if check_auth(username, password):
                request.login = username
                return

        response.headers["WWW-Authenticate"] = _httpauth.basicAuth(self.realm)

        event.stop()
        return Unauthorized(request, response)


class Root(Controller):

    def index(self):
        return "Hello, {0:s}".format(self.request.login)

app = Server(("0.0.0.0", 8000))
PasswdAuth().register(app)
Root().register(app)
app.run()