from app import app, OVERRIDE_CONFIG_DIRECTORY
from data.users.externaljwt import ExternalJWTAuthN
from util.config.validators import BaseValidator, ConfigValidationException

class JWTAuthValidator(BaseValidator):
  name = "jwt"

  @classmethod
  def validate(cls, config, user, user_password, public_key_path=None):
    """ Validates the JWT authentication system. """
    if config.get('AUTHENTICATION_TYPE', 'Database') != 'JWT':
      return

    verify_endpoint = config.get('JWT_VERIFY_ENDPOINT')
    query_endpoint = config.get('JWT_QUERY_ENDPOINT', None)
    getuser_endpoint = config.get('JWT_GETUSER_ENDPOINT', None)

    issuer = config.get('JWT_AUTH_ISSUER')

    if not verify_endpoint:
      raise ConfigValidationException('Missing JWT Verification endpoint')

    if not issuer:
      raise ConfigValidationException('Missing JWT Issuer ID')

    # Try to instatiate the JWT authentication mechanism. This will raise an exception if
    # the key cannot be found.
    users = ExternalJWTAuthN(verify_endpoint, query_endpoint, getuser_endpoint, issuer,
                             OVERRIDE_CONFIG_DIRECTORY,
                             app.config['HTTPCLIENT'],
                             app.config.get('JWT_AUTH_MAX_FRESH_S', 300),
                             public_key_path=public_key_path,
                             requires_email=config.get('FEATURE_MAILING', True))

    # Verify that the superuser exists. If not, raise an exception.
    username = user.username
    (result, err_msg) = users.verify_credentials(username, user_password)
    if not result:
      msg = ('Verification of superuser %s failed: %s. \n\nThe user either does not ' +
             'exist in the remote authentication system ' +
             'OR JWT auth is misconfigured') % (username, err_msg)
      raise ConfigValidationException(msg)

    # If the query endpoint exists, ensure we can query to find the current user and that we can
    # look up users directly.
    if query_endpoint:
      (results, _, err_msg) = users.query_users(username)
      if not results:
        err_msg = err_msg or ('Could not find users matching query: %s' % username)
        raise ConfigValidationException('Query endpoint is misconfigured or not returning ' +
                                        'proper users: %s' % err_msg)

      # Make sure the get user endpoint is also configured.
      if not getuser_endpoint:
        raise ConfigValidationException('The lookup user endpoint must be configured if the ' +
                                        'query endpoint is set')

      (result, err_msg) = users.get_user(username)
      if not result:
        err_msg = err_msg or ('Could not find user %s' % username)
        raise ConfigValidationException('Lookup endpoint is misconfigured or not returning ' +
                                        'properly: %s' % err_msg)