# -*- coding: utf-8 -*- ----------------------------------------------------===#
#
#  Copyright 2016-2026 Trovares Inc. dba Rocketgraph.  All rights reserved.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#
#===------------------------------------------------------------------------===#

"""Authentication credential classes.

Kept in a separate module so both connection.py and oidc.py can import from
here without creating a circular dependency.
"""

from __future__ import annotations

import os

from typing import Optional


class BasicAuth:
  """
  Basic authentication mechanism with user id and password.

  Parameters
  ----------
  username : str
    The username to authenticate as.
  password : str
    Password used to authenticate.
  """
  def __init__(self, username : str = 'MajorTom', password : str = ''):
    """Constructor for BasicAuth.  Called when BasicAuth is created."""
    self._username = username
    self._password = password

  @property
  def username(self) -> str:
    """The username used for authentication."""
    return self._username

  @property
  def password(self) -> str:
    """The password used for authentication."""
    return self._password

class KerberosAuth:
  """
  Kerberos-based single-sign on authentication.

  Parameters
  ----------
    principal : str
      Value to use for the Kerberos principal name of the xGT service to
      connect to.  Only needed when the Kerberos principal cannot be derived
      from the host name.
  """
  def __init__(self, principal : str = ''):
    """Constructor for KerberosAuth.  Called when KerberosAuth is created."""
    self._principal = principal

  @property
  def principal(self) -> str:
    """The Kerberos principal."""
    return self._principal

class PKIAuth:
  """
  PKI-based authentication.  Will derive user ID from information in the
  required x509 client certificate.  Automatically enables mutual TLS for
  connecting to the server.

  .. versionadded:: 1.15.0

  Parameters
  ----------
    ssl_root_dir : str | None
      Path to the root folder for ssl certificates and private keys.  Defaults
      to the user's home directory.
    ssl_server_cert : str | None
      File containing the certificate chain that validates the server's
      certificate.  Defaults to ssl_root_dir + '/certs/ca-chain.cert.pem'.
    ssl_client_cert : str | None
      File containing the client's certificate.  Defaults to ssl_root_dir +
      '/certs/client.cert.pem'
    ssl_client_key : str | None
      File containing the client's key.  Defaults to ssl_root_dir +
      '/private/client.key.pem'

      .. versionadded:: 1.16.0
  """
  def __init__(self, ssl_root_dir : Optional[str] = None,
               ssl_server_cert : Optional[str] = None,
               ssl_client_cert : Optional[str] = None,
               ssl_client_key : Optional[str] = None):
    """Constructor for PKIAuth.  Called when PKIAuth is created."""
    if ssl_root_dir is None:
      self._ssl_root_dir = os.path.expanduser("~") + '/.ssl/'
    else:
      self._ssl_root_dir = ssl_root_dir
    if ssl_server_cert is None:
      self._ssl_server_cert = self._ssl_root_dir + '/certs/ca-chain.cert.pem'
    else:
      self._ssl_server_cert = ssl_server_cert
    if ssl_client_cert is None:
      self._ssl_client_cert = self._ssl_root_dir + '/certs/client.cert.pem'
    else:
      self._ssl_client_cert = ssl_client_cert
    if ssl_client_key is None:
      self._ssl_client_key = self._ssl_root_dir + '/private/client.key.pem'
    else:
      self._ssl_client_key = ssl_client_key

  @property
  def ssl_root_dir(self) -> str:
    """The SSL certificate directory."""
    return self._ssl_root_dir

  @property
  def ssl_server_cert(self) -> str:
    """
    The location of the file with the certificate chain validating the server
    certificate.
    """
    return self._ssl_server_cert

  @property
  def ssl_client_cert(self) -> str:
    """The location of the file with the client's certificate."""
    return self._ssl_client_cert

  @property
  def ssl_client_key(self) -> str:
    """The location of the file with the client's key."""
    return self._ssl_client_key

class ProxyPKIAuth(PKIAuth):
  """
  PKI-based authentication through a proxy.  Will derive user ID from
  information in the passed-in x509 actual client certificate.  Automatically
  enables mutual TLS for connecting to the server.

  .. versionadded:: 2.0.6

  Parameters
  ----------
    ssl_root_dir : str | None
      Path to the root folder for ssl certificates and private keys.
      Defaults to the user's home directory.
    ssl_server_cert : str | None
      File containing the certificate chain that validates the server's
      certificate.
      Defaults to ssl_root_dir + '/certs/ca-chain.cert.pem'.
    ssl_proxy_cert : str | None
      File containing the proxy's certificate.
    ssl_proxy_key : str | None
      File containing the proxy's key.
    ssl_actual_cert : str | None
      Contents of the actual client certificate that should be validated.
      The gRPC connection will be done under the proxy's certificate identity,
      but the logical xGT connection will correspond to the actual certificate's
      identity.
  """
  def __init__(self, ssl_root_dir : Optional[str] = None,
               ssl_server_cert : Optional[str] = None,
               ssl_proxy_cert : Optional[str] = None,
               ssl_proxy_key : Optional[str] = None,
               ssl_actual_cert : Optional[str] = None):
    super().__init__(ssl_root_dir = ssl_root_dir,
                     ssl_server_cert = ssl_server_cert,
                     ssl_client_cert = ssl_proxy_cert,
                     ssl_client_key = ssl_proxy_key)
    self._ssl_actual_cert = ssl_actual_cert

  @property
  def ssl_proxy_cert(self) -> str:
    """The location of the file with the proxy's certificate."""
    return self.ssl_client_cert

  @property
  def ssl_proxy_key(self) -> str:
    """The location of the file with the proxy's key."""
    return self.ssl_client_key

  @property
  def ssl_actual_cert(self) -> str:
    """The contents of the actual client certificate."""
    return self._ssl_actual_cert

class TrustedProxyAuth(PKIAuth):
  """
  PKI-based authentication through a trusted proxy.  User ID is passed by
  the trusted proxy.  Automatically enables mutual TLS for connecting
  to the server.

  .. versionadded:: 2.3.0

  Parameters
  ----------
    userid : str
      User ID coming from the trusted proxy.  The gRPC connection will be done
      under the proxy's certificate identity, but the logical xGT connection
      will correspond to this user ID.
    ssl_root_dir : str | None
      Path to the root folder for ssl certificates and private keys.  Defaults
      to the user's home directory.
    ssl_server_cert : str | None
      File containing the certificate chain that validates the server's
      certificate.  Defaults to ssl_root_dir + '/certs/ca-chain.cert.pem'.
    ssl_proxy_cert : str | None
      File containing the proxy's certificate.
    ssl_proxy_key : str | None
      File containing the proxy's key.
  """
  def __init__(self, userid : str, ssl_root_dir : Optional[str] = None,
               ssl_server_cert : Optional[str] = None,
               ssl_proxy_cert : Optional[str] = None,
               ssl_proxy_key : Optional[str] = None):
    super().__init__(ssl_root_dir = ssl_root_dir,
                     ssl_server_cert = ssl_server_cert,
                     ssl_client_cert = ssl_proxy_cert,
                     ssl_client_key = ssl_proxy_key)
    self._userid = userid

  @property
  def ssl_proxy_cert(self) -> str:
    """The location of the file with the proxy's certificate."""
    return self.ssl_client_cert

  @property
  def ssl_proxy_key(self) -> str:
    """The location of the file with the proxy's key."""
    return self.ssl_client_key

  @property
  def userid(self) -> str:
    """The user ID provided by the proxy."""
    return self._userid

class BearerTokenAuth:
  """
  Bearer-token authentication for direct OIDC/JWT login.

  Parameters
  ----------
    access_token : str
      Access token to present to the server during session bootstrap.
  """
  def __init__(self, access_token : str):
    self._access_token = access_token

  @property
  def access_token(self) -> str:
    """The access token used for authentication."""
    return self._access_token
