############################################################################
##
## Copyright (c) 2000-2015 BalaBit IT Ltd, Budapest, Hungary
## Copyright (c) 2015-2018 BalaSys IT Ltd, Budapest, Hungary
##
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
##
############################################################################
"""
<module maturity="stable">
  <summary>
    Module defining interface to the authentication databases.
  </summary>
  <description>
    <para>
      This module contains classes related to authentication databases. Together
      with the <link linkend="python.Auth">Auth</link> module it implements the
      Authentication and Authorization framework of Zorp. See
      <xref linkend="authentication_overview"/> and <xref linkend="zorp_authentication"/>
       for details.
    </para>
  </description>
</module>

"""
import Zorp
from Zorp import *

Z_AUTH_UNKNOWN    = 0
Z_AUTH_GETMETHODS = 1
Z_AUTH_METHODS    = 2
Z_AUTH_SETMETHOD  = 3
Z_AUTH_REQUEST    = 4
Z_AUTH_RESPONSE   = 5
Z_AUTH_ACCEPT     = 6
Z_AUTH_ABORT      = 7
Z_AUTH_REJECT     = 8



class AuthenticationProvider(object):
    """
    <class type="authprov">
      <summary>A database-independent class used by Zorp to connect to an
      authentication backend.
      </summary>
      <description>
      <para>
      The authentication provider is an intermediate layer that mediates
      between Zorp and the <emphasis>authentication backend</emphasis> (e.g., a user database)
      during connection authentication
       - Zorp itself does not directly communicate with the database.
      </para>
       <example>
        <title>A sample authentication provider</title>
        <para>The following example defines an authentication provider that
        uses the <link linkend="python.AuthDB.ZAS2AuthenticationBackend">ZAS2AuthenticationBackend</link> backend.</para>
        <synopsis>AuthenticationProvider(name="demo_authentication_provider", backend=ZAS2AuthenticationBackend(serveraddr=SockAddrInet('192.168.10.10', 1317), use_ssl=TRUE, ssl_verify_depth=3, pki_cert=("/etc/key.d/ZAS_certificate/cert.pem", "/etc/key.d/ZAS_certificate/key.pem"), pki_ca=("/etc/ca.d/groups/demo_trusted_group/certs/", "/etc/ca.d/groups/demo_trusted_group/crls/")))</synopsis>
        </example>
      </description>
      <metainfo>
        <attributes/>
      </metainfo>
    </class>
    """
    def __init__(self, name, backend):
        """
        <method maturity="stable">
          <summary>
            Constructor to initialize an AbstractAuthorizationBackend instance.
          </summary>
          <description>
            <para>
              This constructor initializes an AbstractAuthorizationBackend instance.
            </para>
          </description>
          <metainfo>
            <arguments>
              <argument maturity="stable">
                <name>name</name>
                <type>
                  <string/>
                </type>
                <description>Name of the ZAS instance.</description>
              </argument>
              <argument maturity="stable">
                <name>backend</name>
                <type>
                  <class filter="authdb" instance="yes"/>
                </type>
                <description>Type of the database backend used by the ZAS instance.</description>
              </argument>
            </arguments>
          </metainfo>
        </method>
        """
        if Globals.authentication_providers.has_key(name):
            raise ValueError, "Duplicate authorization provider: %s" % name
        Globals.authentication_providers[name] = self
        self.name = name
        self.backend = backend

def getAuthenticationProviderBackend(name):
    """
    <function internal="yes">
    </function>
    """
    if name:
        if Globals.authentication_providers.has_key(name):
            return Globals.authentication_providers[name].backend
        else:
            log(None, CORE_POLICY, 3, "No such authentication provider; provider='%s'", (name))
    return None

class AbstractAuthenticationBackend(object):
    """
    <class maturity="stable" abstract="yes" type="authdb">
      <summary>
        Class encapsulating the abstract authentication backend like ZAS.
      </summary>
      <description>
        <para>
          This is an abstract class to encapsulate an authentication
          backend, which is responsible for checking authentication
          credentials against a backend database. In actual configurations, use one of the derived classes like <link
          linkend="python.AuthDB.ZAS2AuthenticationBackend">ZAS2AuthenticationBackend</link>.
        </para>
        <para>
          The interface defined here is used by various authentication
          methods like <link
          linkend="python.Auth.ZAAuthentication">ZAAuthentication</link> and <link
          linkend="python.Auth.InbandAuthentication">InbandAuthentication</link>.
        </para>
      </description>
      <metainfo>
        <attributes/>
      </metainfo>
    </class>
    """
    def __init__(self):
        """
        <method internal="yes">
          <summary>
            Constructor to initialize an AbstractAuthorizationBackend instance.
          </summary>
          <description>
            <para>
              This constructor initializes an AbstractAuthorizationBackend instance.
            </para>
          </description>
          <metainfo>
            <arguments/>
          </metainfo>
        </method>
        """
        pass

    def startSession(self, session_id, session):
        """
        <method internal="yes">
          <summary>
            Method to be called when an authentication session starts.
          </summary>
          <description>
            <para>
              This method is called when an authentication session
              identified by 'session_id' starts. 'session_id' can be used
              to associate data with this session, as each subsequent
              calls to AbstractAuthorization methods will get this value.
            </para>
          </description>
          <metainfo>
            <arguments>
              <argument maturity="stable">
                <name>session_id</name>
                <type></type>
                <description>session identifier represented as a string</description>
              </argument>
            </arguments>
          </metainfo>
        </method>
        """
        pass

    def stopSession(self, session_id):
        """
        <method internal="yes">
          <summary>
            Method to be called when an authentication session ends.
          </summary>
          <description>
            <para>
              This method is called when an authentication session is ended.
              It's a placeholder for freeing up any resources associated to
              a given session.
            </para>
          </description>
          <metainfo/>
        </method>
        """
        pass

    def getMethods(self, session_id, entity):
        """
        <method internal="yes">
          <summary>
            Function returning the allowed set of methods.
          </summary>
          <description>
            <para>
              This function calculates and returns the set of allowed methods
              a user is allowed to authenticate with. We return an empty
              set here, overridden methods should return something more
              interesting.
              Returns return a tuple. First value is Z_AUTH_*, the second is a array of applicable methods. (if any)
            </para>
          </description>
          <metainfo>
            <arguments>
              <argument maturity="stable">
                <name>session_id</name>
                <type></type>
                <description>authentication session id </description>
              </argument>
              <argument maturity="stable">
                <name>entity</name>
                <type></type>
                <description>username</description>
              </argument>
            </arguments>
          </metainfo>
        </method>
        """
        return None

    def setMethod(self, session_id, method):
        """
        <method internal="yes">
          <summary>
            Function to set the authentication Method.
          </summary>
          <description>
            This function should return a challenge for a given entity
            using the given method, or None if challenge is not
            applicable for the given method.
            Returns return a tuple. First value is one of Z_AUTH*, second value is a string containing the challenge, or None if not applicable
          </description>
          <metainfo>
            <arguments>
              <argument maturity="stable">
                <name>session_id</name>
                <type></type>
                <description>authentication session id</description>
              </argument>
              <argument maturity="stable">
                <name>entity</name>
                <type></type>
                <description>username</description>
              </argument>
              <argument maturity="stable">
                <name>method</name>
                <type></type>
                <description>authentication method</description>
              </argument>
            </arguments>
          </metainfo>
        </method>
        """
        raise NotImplementedError

    def converse(self, session_id, credentials):
        """
        <method internal="yes">
          <summary>
            Function checking the presented credentials of an entity.
          </summary>
          <description>
            <para>
              This function is called to check the credentials presented
              by the client for validity. It should return either TRUE, if
              the credentials for the given challenge  method  username
              are valid.
              Returns return a tuple. First value is one of Z_AUTH_*, second is depending on the first.
            </para>
          </description>
          <metainfo>
            <arguments>
              <argument maturity="stable">
                <name>session_id</name>
                <type></type>
                <description>authentication session id</description>
              </argument>
              <argument maturity="stable">
                <name>entity</name>
                <type></type>
                <description>username</description>
              </argument>
              <argument maturity="stable">
                <name>challenge</name>
                <type></type>
                <description>a previously issued challenge (might be None or an empty string)</description>
              </argument>
              <argument maturity="stable">
                <name>credentials</name>
                <type></type>
                <description>response for the given challenge</description>
              </argument>
            </arguments>
          </metainfo>
        </method>
        """
        raise NotImplementedError



