VerificationService::verify()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 9.472
c 0
b 0
f 0
cc 4
nc 4
nop 1
1
<?php
2
3
/**
4
 * Copyright 2014 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\YubikeyApiClient\Service;
20
21
use Surfnet\YubikeyApiClient\Crypto\NonceGenerator;
22
use Surfnet\YubikeyApiClient\Crypto\Signer;
23
use Surfnet\YubikeyApiClient\Exception\InvalidArgumentException;
24
use Surfnet\YubikeyApiClient\Exception\RequestResponseMismatchException;
25
use Surfnet\YubikeyApiClient\Exception\UntrustedSignatureException;
26
use Surfnet\YubikeyApiClient\Http\ServerPoolClient;
27
use Surfnet\YubikeyApiClient\Otp;
28
29
class VerificationService
30
{
31
    /**
32
     * @var ServerPoolClient
33
     */
34
    private $httpClient;
35
36
    /**
37
     * @var Signer
38
     */
39
    private $signer;
40
41
    /**
42
     * @var string Yubico client ID
43
     */
44
    private $clientId;
45
46
    /**
47
     * @var NonceGenerator
48
     */
49
    private $nonceGenerator;
50
51
    /**
52
     * @param ServerPoolClient $httpClient
53
     * @param NonceGenerator $nonceGenerator
54
     * @param Signer $signer
55
     * @param string $clientId
56
     */
57
    public function __construct(ServerPoolClient $httpClient, NonceGenerator $nonceGenerator, Signer $signer, $clientId)
58
    {
59
        if (!is_string($clientId)) {
60
            throw new InvalidArgumentException('Client ID must be string.');
61
        }
62
63
        $this->httpClient = $httpClient;
64
        $this->signer = $signer;
65
        $this->clientId = $clientId;
66
        $this->nonceGenerator = $nonceGenerator;
67
    }
68
69
    /**
70
     * @param Otp $otp
71
     * @return OtpVerificationResult
72
     * @throws UntrustedSignatureException When the signature doesn't match the expected signature.
73
     * @throws RequestResponseMismatchException When the response data doesn't match the requested data (otp, nonce).
74
     */
75
    public function verify(Otp $otp)
76
    {
77
        $nonce = $this->nonceGenerator->generateNonce();
78
79
        $query = [
80
            'id'    => $this->clientId,
81
            'otp'   => $otp->otp,
82
            'nonce' => $nonce,
83
        ];
84
        $query = $this->signer->sign($query);
85
86
        $httpResponse = $this->httpClient->get(['query' => $query]);
87
        $response = $this->parseYubicoResponse((string) $httpResponse->getBody());
88
89
        if (!$this->signer->verifySignature($response)) {
90
            throw new UntrustedSignatureException('The response data signature doesn\'t match the expected signature.');
91
        }
92
93
        if ($response['otp'] !== $otp->otp) {
94
            throw new RequestResponseMismatchException('The response OTP doesn\'t match the requested OTP.');
95
        }
96
97
        if ($response['nonce'] !== $nonce) {
98
            throw new RequestResponseMismatchException('The response nonce doesn\'t match the requested nonce.');
99
        }
100
101
        return new OtpVerificationResult($response['status']);
102
    }
103
104
    /**
105
     * Parses the response.
106
     *
107
     * @param string $response
108
     * @return array
109
     */
110
    private function parseYubicoResponse($response)
111
    {
112
        $lines = array_filter(explode("\r\n", $response));
113
        $responseArray = array();
114
115
        foreach ($lines as $line) {
116
            list($key, $value) = explode('=', $line, 2);
117
118
            $responseArray[$key] = $value;
119
        }
120
121
        return $responseArray;
122
    }
123
}
124