Completed
Push — master ( bab30e...5d9c47 )
by Stefan
18s queued 14s
created

WebAuthn::setAuthState()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
nc 1
nop 1
cc 1
1
<?php
2
3
namespace SimpleSAML\Module\webauthn\Controller;
4
5
use SimpleSAML\Auth;
6
use SimpleSAML\Configuration;
7
use SimpleSAML\Error;
8
use SimpleSAML\Logger;
9
use SimpleSAML\Module;
10
use SimpleSAML\Session;
11
use SimpleSAML\Utils;
12
use SimpleSAML\XHTML\Template;
13
use Symfony\Component\HttpFoundation\Request;
14
15
/**
16
 * Controller class for the webauthn module.
17
 *
18
 * This class serves the different views available in the module.
19
 *
20
 * @package SimpleSAML\Module\webauthn
21
 */
22
class WebAuthn
23
{
24
    /** @var \SimpleSAML\Configuration */
25
    protected $config;
26
27
    /** @var \SimpleSAML\Session */
28
    protected $session;
29
30
    /**
31
     * @var \SimpleSAML\Auth\State|string
32
     * @psalm-var \SimpleSAML\Auth\State|class-string
33
     */
34
    protected $authState = Auth\State::class;
35
36
    /**
37
     * @var \SimpleSAML\Logger|string
38
     * @psalm-var \SimpleSAML\Logger|class-string
39
     */
40
    protected $logger = Logger::class;
41
42
43
    /**
44
     * Controller constructor.
45
     *
46
     * It initializes the global configuration and session for the controllers implemented here.
47
     *
48
     * @param \SimpleSAML\Configuration              $config The configuration to use by the controllers.
49
     * @param \SimpleSAML\Session                    $session The session to use by the controllers.
50
     *
51
     * @throws \Exception
52
     */
53
    public function __construct(
54
        Configuration $config,
55
        Session $session
56
    ) {
57
        $this->config = $config;
58
        $this->session = $session;
59
    }
60
61
62
    /**
63
     * Inject the \SimpleSAML\Auth\State dependency.
64
     *
65
     * @param \SimpleSAML\Auth\State $authState
66
     */
67
    public function setAuthState(Auth\State $authState): void
68
    {
69
        $this->authState = $authState;
70
    }
71
72
73
    /**
74
     * Inject the \SimpleSAML\Logger dependency.
75
     *
76
     * @param \SimpleSAML\Logger $logger
77
     */
78
    public function setLogger(Logger $logger): void
79
    {
80
        $this->logger = $logger;
81
    }
82
83
84
    /**
85
     * @param \Symfony\Component\HttpFoundation\Request $request
86
     * @return \SimpleSAML\XHTML\Template  A Symfony Response-object.
87
     */
88
    public function main(Request $request): Template
89
    {
90
        $this->logger::info('FIDO2 - Accessing WebAuthn interface');
91
92
        $stateId = $request->request->get('StateId');
93
        if ($stateId === null) {
94
            throw new Error\BadRequest('Missing required StateId query parameter.');
95
        }
96
97
        /** @var array $state */
98
        $state = $this->authState::loadState($stateId, 'webauthn:request');
99
100
        // Make, populate and layout consent form
101
        $t = new Template($this->config, 'webauthn:authentication.twig');
102
        $t->data['UserID'] = $state['FIDO2Username'];
103
        $t->data['FIDO2Tokens'] = $state['FIDO2Tokens'];
104
105
        $challenge = str_split($state['FIDO2SignupChallenge'], 2);
106
        $username = str_split(
107
            hash('sha512', $state['FIDO2Username'] . '|' . Utils\Config::getSecretSalt() . '|' . $state['Source']['entityid']),
108
            2
109
        );
110
111
        $challengeEncoded = [];
112
        foreach ($challenge as $oneChar) {
113
            $challengeEncoded[] = hexdec($oneChar);
114
        }
115
116
        $credentialIdEncoded = [];
117
        foreach ($state['FIDO2Tokens'] as $number => $token) {
118
            $idSplit = str_split($token[0], 2);
119
            $credentialIdEncoded[$number] = [];
120
            foreach ($idSplit as $credIdBlock) {
121
                $credentialIdEncoded[$number][] = hexdec($credIdBlock);
122
            }
123
        }
124
125
        $usernameEncoded = [];
126
        foreach ($username as $oneChar) {
127
            $usernameEncoded[] = hexdec($oneChar);
128
        }
129
130
        $frontendData = [];
131
        $frontendData['challengeEncoded'] = $challengeEncoded;
132
        $frontendData['state'] = [];
133
        foreach (['Source', 'FIDO2Scope','FIDO2Username','FIDO2Displayname','requestTokenModel'] as $stateItem) {
134
            $frontendData['state'][$stateItem] = $state[$stateItem];
135
        }
136
137
        $t->data['showExitButton'] = !array_key_exists('Registration', $state);
138
        $frontendData['usernameEncoded'] = $usernameEncoded;
139
        $frontendData['attestation'] = $state['requestTokenModel'] ? "indirect" : "none";
140
        $frontendData['credentialIdEncoded'] = $credentialIdEncoded;
141
        $t->data['frontendData'] = json_encode($frontendData);
142
143
        $t->data['FIDO2AuthSuccessful'] = $state['FIDO2AuthSuccessful'];
144
        if (
145
            count($state['FIDO2Tokens']) == 0 ||
146
            ($state['FIDO2WantsRegister'] === true && $state['FIDO2AuthSuccessful'] !== false)
147
        ) {
148
            $t->data['regURL'] = Module::getModuleURL('webauthn/regprocess.php?StateId=' . urlencode($stateId));
149
            $t->data['delURL'] = Module::getModuleURL('webauthn/managetoken.php?StateId=' . urlencode($stateId));
150
        }
151
152
        $t->data['authForm'] = "";
153
        if (
154
            count($state['FIDO2Tokens']) > 0 &&
155
            ($state['FIDO2WantsRegister'] !== true || $state['FIDO2AuthSuccessful'] === false)
156
        ) {
157
            $t->data['authURL'] = Module::getModuleURL('webauthn/authprocess.php?StateId=' . urlencode($stateId));
158
        }
159
160
        // dynamically generate the JS code needed for token registration
161
        return $t;
162
    }
163
}
164