Completed
Push — feature/post-binding-without-c... ( c3fb1f )
by
unknown
02:20
created

RequestHelper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
3
/**
4
 * Copyright 2017 SURFnet bv
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupGateway\SecondFactorOnlyBundle\Adfs;
20
21
use InvalidArgumentException;
22
use Psr\Log\LoggerInterface;
23
use SAML2_DOMDocumentFactory;
24
use Symfony\Component\HttpFoundation\Request;
25
use Webmozart\Assert\Assert;
26
27
/**
28
 * The Adfs helper service is used to transform Adfs requests. Stripping the Adfs specific parameters.
29
 * @package Surfnet\StepupGateway\SecondFactorOnlyBundle\Service
30
 */
31
final class RequestHelper
32
{
33
34
    /** @var LoggerInterface */
35
    private $logger;
36
37
    /** @var StateHandler */
38
    private $stateHandler;
39
40
    const ADFS_PARAM_AUTH_METHOD = 'AuthMethod';
41
    const ADFS_PARAM_CONTEXT = 'Context';
42
    const ADFS_PARAM_AUTHNREQUEST = 'request';
43
44
    const SAML_AUTHNREQUST_PARAM_REQUEST = 'SAMLRequest';
45
46
    private static $requiredParams = [
47
        self::ADFS_PARAM_AUTH_METHOD,
48
        self::ADFS_PARAM_CONTEXT,
49
        self::ADFS_PARAM_AUTHNREQUEST
50
    ];
51
52
    public function __construct(StateHandler $stateHandler, LoggerInterface $logger)
53
    {
54
        $this->stateHandler = $stateHandler;
55
        $this->logger = $logger;
56
    }
57
58
    /**
59
     * @param Request $httpRequest
60
     * @return bool
61
     */
62
    public function isAdfsRequest(Request $httpRequest)
63
    {
64
        foreach (self::$requiredParams as $param) {
65
            if (!$httpRequest->request->has($param)) {
66
                return false;
67
            }
68
        }
69
        return true;
70
    }
71
72
    /**
73
     * Transforms the Adfs request to a valid Saml AuthnRequest
74
     *
75
     * @param Request $httpRequest
76
     * @return Request
77
     * @throws InvalidArgumentException
78
     */
79
    public function transformRequest(Request $httpRequest)
80
    {
81
        $this->logger->notice('Receiving and validating ADFS request parameters');
82
        $authMethod = $httpRequest->request->get(self::ADFS_PARAM_AUTH_METHOD);
83
        $context = $httpRequest->request->get(self::ADFS_PARAM_CONTEXT);
84
        $authnRequest = $httpRequest->request->get(self::ADFS_PARAM_AUTHNREQUEST);
85
86
        Assert::stringNotEmpty($authMethod);
87
        Assert::stringNotEmpty($context);
88
        Assert::stringNotEmpty($authnRequest);
89
        $requestId = $this->getRequestIdFrom($authnRequest);
90
91
        $this->logger->notice(sprintf('Store ADFS parameters for request id: "%s"', $requestId));
92
        $this->stateHandler
93
            ->setRequestId($requestId)
94
            ->setAuthMethod($authMethod)
95
            ->setContext($context);
96
97
        $this->logger->notice('Transforming ADFS Request to a valid AuthnRequest');
98
        $httpRequest->request->set(
99
            self::SAML_AUTHNREQUST_PARAM_REQUEST,
100
            $authnRequest
101
        );
102
103
        $httpRequest->request->remove(self::ADFS_PARAM_AUTH_METHOD);
104
        $httpRequest->request->remove(self::ADFS_PARAM_CONTEXT);
105
106
        return $httpRequest;
107
    }
108
109
    /**
110
     * @param string $samlRequest
111
     * @return string
112
     * @throws InvalidArgumentException
113
     */
114
    private function getRequestIdFrom($samlRequest)
115
    {
116
        // additional security against XXE Processing vulnerability
117
        $previous = libxml_disable_entity_loader(true);
118
        $document = SAML2_DOMDocumentFactory::fromString(base64_decode($samlRequest));
119
        libxml_disable_entity_loader($previous);
120
        $samlRequestNode = $document->firstChild;
121
122
        if (!$samlRequestNode->hasAttribute('ID')) {
123
            throw new InvalidArgumentException('The received AuthnRequest does not have a request id');
124
        }
125
        return $samlRequestNode->getAttribute('ID');
126
    }
127
}
128