<?php

/**
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is protected by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @version    $Id:$
 * @link       http://www.life-style.de
 */

namespace LifeStyle\Tools\WebserviceBundle\EventListener;

use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use LifeStyle\Tools\WebserviceBundle\Event\FilterCredentialsEvent;
use LifeStyle\Tools\WebserviceBundle\Event\Credentials;

/**
 * Class WsSecurityListener
 * @package LifeStyle\Tools\WebserviceBundle\EventListener
 */
class WsSecurityListener implements EventSubscriberInterface
{

    /**
     * Event dispatcher
     *
     * @var EventDispatcherInterface
     */
    protected $eventDispatchter;

    /**
     * Constructor
     *
     * @param EventDispatcherInterface $eventDispatcher
     */
    public function __construct(EventDispatcherInterface $eventDispatcher)
    {
        $this->eventDispatchter = $eventDispatcher;
    }

    /**
     * Handle event
     *
     * @param FilterControllerEvent $event
     */
    public function onKernelController(FilterControllerEvent $event)
    {
        $request = $event->getRequest();
        if (!$configuration = $request->attributes->get('_wsSecurity')) {
            return;
        }

        $eventFilter = new FilterCredentialsEvent($request->headers->get('sso-api-controller'),
            $request->headers->get('sso-api-action'), $this->getCredentials($request), $this->getRemoteIp($request));
        $configuredEvents = $configuration->getTests();
        foreach (Credentials::getEventList() as $eventName => $eventRequired) {
            if ($eventRequired || in_array($eventName, $configuredEvents)) {
                $this->eventDispatchter->dispatch($eventName, $eventFilter);
            }
        }
    }

    /**
     * Get credentials from xml if exists
     *
     * @return \SimpleXMLElement|null
     */
    protected function getCredentials(Request $request)
    {
        $xmlRequest = $request->attributes->get('XmlRequest');
        return false !== $xmlRequest && isset($xmlRequest->Credentials) ? $xmlRequest->Credentials : null;
    }

    /**
     * @param Request $request
     * @return string
     */
    private function getRemoteIp(Request $request)
    {

        // Search for ip behind elastic load balancer (ELB)
        if ($request->headers->has('x-forwarded-for')) {
            $parts = array_map('trim', explode(',', $request->headers->get('x-forwarded-for')));
            $ipAddress = filter_var($parts[0], FILTER_VALIDATE_IP);
        }

        // Not behind a ELB
        if (empty($ipAddress)) {
            $ipAddress = $request->getClientIp();
        }

        return $ipAddress;
    }

    /**
     * Returns list of subscribed events
     *
     * @return array
     */
    public static function getSubscribedEvents()
    {
        return array(KernelEvents::CONTROLLER => 'onKernelController');
    }
}
