""" ProxyProvider implementation for a per-user sub-proxy(PUSP) proxy generation using PUSP proxy server.
    More details about PUSP here: https://wiki.egi.eu/wiki/Usage_of_the_per_user_sub_proxy_in_EGI

    .. literalinclude:: /dirac.cfg
      :start-after: ## PUSP type:
      :end-before: ##
      :dedent: 2
      :caption: /Resources/ProxyProviders section
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from six.moves.urllib.request import urlopen

from DIRAC import S_OK, S_ERROR
from DIRAC.Core.Security.X509Chain import X509Chain  # pylint: disable=import-error
from DIRAC.Resources.ProxyProvider.ProxyProvider import ProxyProvider

__RCSID__ = "$Id$"


class PUSPProxyProvider(ProxyProvider):

  def __init__(self, parameters=None):

    super(PUSPProxyProvider, self).__init__(parameters)

  def checkStatus(self, userDN):
    """ Read ready to work status of proxy provider

        :param str userDN: user DN

        :return: S_OK()/S_ERROR()
    """
    # Search a unique identifier(username) to use as cn-label to generate PUSP
    if not userDN.split(":")[-1]:
      return S_ERROR('Can not found user label for DN: %s' % userDN)
    if not self.parameters.get('ServiceURL'):
      return S_ERROR('Can not determine PUSP service URL')

    return S_OK()

  def getProxy(self, userDN):
    """ Generate user proxy

        :param str userDN: user DN

        :return: S_OK(str)/S_ERROR() -- contain a proxy string
    """
    result = self.checkStatus(userDN)
    if not result['OK']:
      return result

    puspURL = self.parameters['ServiceURL']
    puspURL += "?proxy-renewal=false&disable-voms-proxy=true&rfc-proxy=true"
    puspURL += "&cn-label=user:%s" % userDN.split(":")[-1]

    try:
      proxy = urlopen(puspURL).read()
    except Exception:
      return S_ERROR('Failed to get proxy from the PUSP server')

    chain = X509Chain()
    chain.loadChainFromString(proxy)
    chain.loadKeyFromString(proxy)

    result = chain.getCredentials()
    if not result['OK']:
      return S_ERROR('Failed to get a valid PUSP proxy')
    credDict = result['Value']
    if credDict['identity'] != userDN:
      return S_ERROR('Requested DN does not match the obtained one in the PUSP proxy')

    return chain.generateProxyToString(lifeTime=credDict['secondsLeft'])
