<?php
/**
 * Saml Request
 *
 * 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  2015 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace LifeStyle\Tools\SamlBundle\Saml;

use Symfony\Bridge\Monolog\Logger;

/**
 * Saml Request
 */
class Request
{

    /**
     * Symfony logger
     *
     * @var Logger
     */
    protected $logger;

    /**
     * Saml config
     *
     * @var Configuration
     */
    protected $samlConfig;

    /**
     * Constructor
     *
     * @param Logger $logger
     * @param Configuration $samlConfig SAML configuration
     */
    public function __construct(Logger $logger, Configuration $samlConfig)
    {
        $this->logger = $logger;
        $this->samlConfig = $samlConfig;
    }

    /**
     * Generate the request.
     *
     * @return string A fully qualified URL that can be redirected to in order to process the authorization request.
     */
    public function getRedirectUrl()
    {
        $id = $this->generateUniqueID();
        $issueInstant = $this->getTimestamp();

        $request = <<<AUTHNREQUEST
<samlp:AuthnRequest
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="$id"
    Version="2.0"
    IssueInstant="$issueInstant"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    AssertionConsumerServiceURL="{$this->samlConfig->getSpReturnUrl()}">
    <saml:Issuer>{$this->samlConfig->getSpIssuer()}</saml:Issuer>
    <samlp:NameIDPolicy
        Format="{$this->getNameIdFormat()}"
        AllowCreate="true"></samlp:NameIDPolicy>
    <samlp:RequestedAuthnContext Comparison="exact">
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
    </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>
AUTHNREQUEST;

        $deflatedRequest = gzdeflate($request);
        $base64Request = base64_encode($deflatedRequest);
        $encodedRequest = urlencode($base64Request);

        return $this->samlConfig->getIdpSingleSignOnUrl() . "?SAMLRequest=" . $encodedRequest;
    }

    /**
     * Generate a logout request.
     *
     * @param Response $samlResponse
     * @return string A fully qualified URL that can be redirected to in order to process the authorization request.
     */
    public function getLogoutUrl(Response $samlResponse)
    {
        $id = $this->generateUniqueID();
        $issueInstant = $this->getTimestamp();
        $request = <<<AUTHNREQUEST
<samlp:LogoutRequest
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="$id"
    Version="2.0"
    IssueInstant="$issueInstant"
    Destination="{$this->samlConfig->getIdpLogoutUrl()}">
    <saml:Issuer>{$this->samlConfig->getSpIssuer()}</saml:Issuer>
    <saml:NameID SPNameQualifier="{$this->samlConfig->getSpIssuer()}" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">{$samlResponse->getNameId()}</saml:NameID>
</samlp:LogoutRequest>
AUTHNREQUEST;

        $deflatedRequest = gzdeflate($request);
        $base64Request = base64_encode($deflatedRequest);
        $encodedRequest = urlencode($base64Request);

        return $this->samlConfig->getIdpLogoutUrl() . "?SAMLRequest=" . $encodedRequest;
    }

    /**
     * Generate a unique request id
     *
     * @return string
     */
    protected function generateUniqueID()
    {
        return $this->samlConfig->getIdpRequestPrefix() . sha1(uniqid(mt_rand(), true));
    }

    /**
     * Get current timestamp as string
     *
     * @return string
     */
    protected function getTimestamp()
    {
        $defaultTimezone = date_default_timezone_get();
        date_default_timezone_set('UTC');
        $timestamp = strftime('%Y-%m-%dT%H:%M:%SZ');
        date_default_timezone_set($defaultTimezone);
        return $timestamp;
    }

    /**
     * Get name-id-format from saml config
     *
     * @return string
     */
    protected function getNameIdFormat()
    {
        switch ($this->samlConfig->getRequestedNameIdFormat()) {
            case 'NAMEID_EMAIL_ADDRESS':
                return 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress';
            case 'NAMEID_X509_SUBJECT_NAME':
                return 'urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName';
            case 'NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME':
                return 'urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName';
            case 'NAMEID_KERBEROS':
                return 'urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos';
            case 'NAMEID_ENTITY':
                return 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity';
            case 'NAMEID_TRANSIENT':
                return 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
            case 'NAMEID_PERSISTENT':
                return 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent';
        }
        return $this->samlConfig->getRequestedNameIdFormat();
    }
}
