#
#
# This is a sample authentication and authorization module for nnrpd hook
#
# For details, see the file README.python_auth_hook that came with INN.
#

#
# This file is loaded when nnrpd starts up. An instance of AUTH class
# is passed to nnrpd via set_auth_hook() function imported from nnrpd. The
# following methods of that class are known to nnrpd:
#
#   __init__()                  - Called on nnrpd startup. Use this method
#                                 to initilalize your variables or open
#                                 a database connection.
#   close()                     - Called on nnrpd termination. Save your state
#                                 variables or close a database connection.
#   authenticate()              - Called whenever a reader connects or uses
#                                 AUTHINFO command. A "type" entry of 
#                                 "attributes" dictionary is passed to this
#                                 method to figure out the type of
#                                 authentication happening.
#   authorize()                 - Called whenever a reader requests either
#                                 read or post access to a newsgroup.
#
# Attributes about the connection are passed to the program in the
# "attributes" global dictinary variable.
#
# The authenticate() method should return a tuple of four elements:
#
# 1) NNTP response code.  Should be one of the codes from
#    NNRPD_AUTH.connectcodes{} or NNRPD_AUTH.authcodes{}
# 2) Reading Allowed. Should be a boolean value.
# 3) Posting Allowed. Should be a boolean value.
# 4) Wildmat expression that says what groups to provide access to.
#
# All four of these are required.
#
# The authorize() method should return None to grant requested
# priveleges or a non-empty string (which will be reported back to reader)
# otherwise.
#
# If there is a problem with return codes from any of these methods then nnrpd
# will die and syslog the exact reason.
#
# There are also a few Python functions defined in nnrpd:
#
# set_auth_hook()               - Called by nnrpd as this module is loaded.
#                                 It is used to pass a reference to an 
#                                 instance of authentication class to nnrpd.
# syslog()                      - An equivalent replacement for regular syslog.
#                                 One consideration for using it is to
#                                 uniform nnrpd logging.

#
# Sample authentication and authorization class. It defines all methods known
# to nnrpd.
#
class AUTH:
    """Provide authentication and authorization callbacks to nnrpd."""
    def __init__(self):
        """This runs on nnrpd startup. It is a good place to initialize
           variables or open a database connection.
        """
        # Create a list of NNTP codes to respond on connect
        self.connectcodes = {   'READPOST':200,
                                'READ':201,
                                'AUTHNEEDED':480,
                                'PERMDENIED':502
        }

        # Create a list of NNTP codes to respond on authentication
        self.authcodes = {  'ALLOWED':281,
                            'DENIED':502
        }

        syslog('notice', 'nnrpd authentication class instance created')

    def close(self):
        """Runs when nnrpd exits. You can use this method to save state
           information to be restored by the __init__() method or close
           a database connection.
        """
        syslog('notice', "close method running, bye!")

    def authenticate(self, attributes):
        """Called when a reader connects or authenticates"""

	# just for debugging purposes
	syslog('debug', 'authenticate() invoked against type %s, hostname %s, ipaddress %s, interface %s, user %s' % (\
		attributes['type'], \
		attributes['hostname'], \
		attributes['ipaddress'], \
		attributes['interface'], \
		attributes['user']))

	# allow newsreading from specific host only
        if attributes['type'] == buffer('connect'):
            if attributes['ipaddress'] == buffer('127.0.0.1'):
                syslog('notice', 'authentication by IP address succeeded')
                return ( self.connectcodes['READPOST'], 1, 1, '*' )
            else:
                syslog('notice', 'authentication by IP address failed')
                return ( self.connectcodes['PERMDENIED'], 0, 0, '!*' )
                
	# do not do any username authentication
        elif attributes['type'] == buffer('authinfo'):
            syslog('notice', 'authentication by username succeeded')
            return ( self.authcodes['ALLOWED'], 1, 1, '*')
        else:
            syslog('notice', 'authentication type is not known: %s' % attributes['type'])
            return ( self.authcodes['DENIED'], 0, 0, '!*')

    def authorize(self, attributes):
        """Called when a reader requests either read or post permission
           for particular newsgroup.
        """
	# just for debugging purposes
	syslog('debug', 'authorize() invoked against type %s, hostname %s, ipaddress %s, interface %s, user %s, newsgroup %s' % (\
		attributes['type'], \
		attributes['hostname'], \
		attributes['ipaddress'], \
		attributes['interface'], \
		attributes['user'], \
		attributes['newsgroup']))

	# Allow reading of any newsgroup
        if attributes['type'] == buffer('read'):
            syslog('notice', 'authorization for read access succeeded')
            return None
	# ..but disallow postings
        elif attributes['type'] == buffer('post'):
            syslog('notice', 'authorization for post access failed')
            return "Posting disallowed"
        else:
            syslog('notice', 'authorization type is not known: %s' % attributes['type'])
            return "Internal error"


#
# The rest is used to hook up the auth module on nnrpd. It is unlikely
# you will ever need to modify this.
#

# Import functions exposed by nnrpd. This import must succeed, or nothing
# will work!
from nnrpd import *

# Create a class instance
myauth = AUTH()

# ...and try to hook up on nnrpd. This would make auth object methods visible
# to nnrpd.
try:
    set_auth_hook(myauth)
    syslog('notice', "authentication module successfully hooked into nnrpd")
except Exception, errmsg:
    syslog('error', "Cannot obtain nnrpd hook for authentication method: %s" % errmsg[0])

