Completed
Push — master ( 81d457...c620f4 )
by Garion
12s queued 11s
created

VerifyHandlerTest::testGetLeadInLabel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace SilverStripe\WebAuthn\Tests;
4
5
use Exception;
6
use PHPUnit_Framework_MockObject_MockObject;
7
use Psr\Log\LoggerInterface;
8
use SilverStripe\Control\HTTPRequest;
9
use SilverStripe\Core\Injector\Injector;
10
use SilverStripe\Dev\SapphireTest;
11
use SilverStripe\MFA\Model\RegisteredMethod;
12
use SilverStripe\MFA\State\Result;
13
use SilverStripe\MFA\Store\SessionStore;
14
use SilverStripe\Security\Member;
15
use SilverStripe\WebAuthn\VerifyHandler;
16
use Webauthn\AuthenticatorAssertionResponse;
17
use Webauthn\AuthenticatorAssertionResponseValidator;
18
use Webauthn\AuthenticatorAttestationResponse;
19
use Webauthn\AuthenticatorResponse;
20
use Webauthn\PublicKeyCredential;
21
use Webauthn\PublicKeyCredentialLoader;
22
23
class VerifyHandlerTest extends SapphireTest
24
{
25
    protected $usesDatabase = true;
26
27
    /**
28
     * @var VerifyHandler
29
     */
30
    protected $handler;
31
32
    /**
33
     * @var Member
34
     */
35
    protected $member;
36
37
    /**
38
     * @var HTTPRequest
39
     */
40
    protected $request;
41
42
    /**
43
     * @var SessionStore
44
     */
45
    protected $store;
46
47
    /**
48
     * @var RegisteredMethod
49
     */
50
    protected $registeredMethod;
51
52
    /**
53
     * @var array
54
     */
55
    protected $mockData = [];
56
57
    protected function setUp()
58
    {
59
        parent::setUp();
60
61
        $this->request = new HTTPRequest('GET', '/');
62
        $this->handler = Injector::inst()->create(VerifyHandler::class);
63
64
        $memberID = $this->logInWithPermission();
65
        /** @var Member $member */
66
        $this->member = Member::get()->byID($memberID);
67
68
        $this->store = new SessionStore($this->member);
69
70
        $this->registeredMethod = new RegisteredMethod();
71
        $this->registeredMethod->Data = json_encode([
72
            'descriptor' => [
73
                'type' => 'public-key',
74
                'id' => '7lE6zdHESCF3/qSijHVuTwlTNi/yZSD/XP6Nm6HBI8YLA0uzPqyU4U4RxyZyuKXEPiIENEr509TekP2mDKrFoQ=='
75
            ],
76
            'data' => [
77
                'aaguid' => 'AAAAAAAAAAAAAAAAAAAAAA==',
78
                'credentialId' => '7lE6zdHESCF3/qSijHVuTwlTNi/yZSD/XP6Nm6HBI8YLPiIENEr509TekP2mDKrFoQ==',
79
                'credentialPublicKey' => 'pU4vyn6OmHbdDyx7nWsJD+/2CycZkGzJ1u3TVj+c='
80
            ],
81
            'counter' => null,
82
        ]);
83
    }
84
85
    /**
86
     * @expectedException \Assert\InvalidArgumentException
87
     */
88
    public function testStartThrowsExceptionWithMissingData()
89
    {
90
        $this->registeredMethod->Data = null;
91
        $this->handler->start($this->store, $this->registeredMethod);
92
    }
93
94
    public function testStart()
95
    {
96
        $result = $this->handler->start($this->store, $this->registeredMethod);
97
        $this->assertArrayHasKey('publicKey', $result);
98
    }
99
100
    public function testVerifyReturnsErrorWhenRequiredInformationIsMissing()
101
    {
102
        $this->registeredMethod->Data = null;
103
        $result = $this->handler->verify($this->request, $this->store, $this->registeredMethod);
104
105
        $this->assertFalse($result->isSuccessful());
106
        $this->assertContains('Incomplete data', $result->getMessage());
107
    }
108
109
    /**
110
     * @param AuthenticatorResponse $mockResponse
111
     * @param Result $expectedResult
112
     * @param callable $responseValidatorMockCallback
113
     * @dataProvider verifyProvider
114
     */
115
    public function testVerify(
116
        $mockResponse,
117
        $expectedResult,
118
        callable $responseValidatorMockCallback = null
119
    ) {
120
        /** @var VerifyHandler&PHPUnit_Framework_MockObject_MockObject $handlerMock */
121
        $handlerMock = $this->getMockBuilder(VerifyHandler::class)
122
            ->setMethods(['getPublicKeyCredentialLoader', 'getAuthenticatorAssertionResponseValidator'])
123
            ->getMock();
124
125
        $responseValidatorMock = $this->createMock(AuthenticatorAssertionResponseValidator::class);
126
        // Allow the data provider to customise the validation check handling
127
        if ($responseValidatorMockCallback) {
128
            $responseValidatorMockCallback($responseValidatorMock);
129
        }
130
        $handlerMock->expects($this->any())->method('getAuthenticatorAssertionResponseValidator')
131
            ->willReturn($responseValidatorMock);
132
133
        $loggerMock = $this->createMock(LoggerInterface::class);
134
        $handlerMock->setLogger($loggerMock);
135
136
        $loaderMock = $this->createMock(PublicKeyCredentialLoader::class);
137
        $handlerMock->expects($this->once())->method('getPublicKeyCredentialLoader')->willReturn($loaderMock);
138
139
        $publicKeyCredentialMock = $this->createMock(PublicKeyCredential::class);
140
        $loaderMock->expects($this->once())->method('load')->with('example')->willReturn(
141
            $publicKeyCredentialMock
142
        );
143
144
        $publicKeyCredentialMock->expects($this->once())->method('getResponse')->willReturn($mockResponse);
145
146
        $this->request->setBody(json_encode([
147
            'credentials' => base64_encode('example'),
148
        ]));
149
        $result = $handlerMock->verify($this->request, $this->store, $this->registeredMethod);
0 ignored issues
show
Bug introduced by
The method verify() does not exist on PHPUnit_Framework_MockObject_MockObject. Did you maybe mean __phpunit_verify()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

149
        /** @scrutinizer ignore-call */ 
150
        $result = $handlerMock->verify($this->request, $this->store, $this->registeredMethod);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
150
151
        $this->assertSame($expectedResult->isSuccessful(), $result->isSuccessful());
152
        if ($expectedResult->getMessage()) {
153
            $this->assertContains($expectedResult->getMessage(), $result->getMessage());
154
        }
155
    }
156
157
    /**
158
     * Some centralised or reusable logic for testVerify. Note that some of the mocks are only used in some of the
159
     * provided data scenarios, but any expected call numbers are based on all scenarios being run.
160
     *
161
     * @return array[]
162
     */
163
    public function verifyProvider()
164
    {
165
        return [
166
            'wrong response return type' => [
167
                // Deliberately the wrong child implementation of \Webauthn\AuthenticatorResponse
168
                $this->createMock(AuthenticatorAttestationResponse::class),
169
                new Result(false, 'Unexpected response type found'),
170
            ],
171
            'valid response' => [
172
                $this->createMock(AuthenticatorAssertionResponse::class),
173
                new Result(true),
174
                function (PHPUnit_Framework_MockObject_MockObject $responseValidatorMock) {
175
                    // Specifically setting expectations for the result of the response validator's "check" call
176
                    $responseValidatorMock->expects($this->once())->method('check')->willReturn(true);
177
                },
178
            ],
179
            'invalid response' => [
180
                $this->createMock(AuthenticatorAssertionResponse::class),
181
                new Result(false, 'I am a test'),
182
                function (PHPUnit_Framework_MockObject_MockObject $responseValidatorMock) {
183
                    // Specifically setting expectations for the result of the response validator's "check" call
184
                    $responseValidatorMock->expects($this->once())->method('check')
185
                        ->willThrowException(new Exception('I am a test'));
186
                },
187
            ],
188
        ];
189
    }
190
191
    public function testGetLeadInLabel()
192
    {
193
        $this->assertContains('security key', $this->handler->getLeadInLabel());
194
    }
195
196
    public function testGetComponent()
197
    {
198
        $this->assertSame('WebAuthnVerify', $this->handler->getComponent());
199
    }
200
}
201