MediaWiki  1.34.0
TOTPEnableForm.php
Go to the documentation of this file.
1 <?php
2 
4 
7 use Html;
8 use Status;
9 
15  public function getHTML( $submitResult ) {
16  $this->getOutput()->addModules( 'ext.oath.totp.showqrcode' );
17  $this->getOutput()->addModuleStyles( 'ext.oath.totp.showqrcode.styles' );
18 
19  return parent::getHTML( $submitResult );
20  }
21 
25  public function onSuccess() {
26  $this->getOutput()->addWikiMsg( 'oathauth-validatedoath' );
27  }
28 
29  protected function getDescriptors() {
30  $keyData = $this->getRequest()->getSessionData( 'oathauth_totp_key' ) ?? [];
31  $key = TOTPKey::newFromArray( $keyData );
32  if ( !$key instanceof TOTPKey ) {
33  $key = TOTPKey::newFromRandom();
34  $this->getRequest()->setSessionData(
35  'oathauth_totp_key',
36  $key->jsonSerialize()
37  );
38  }
39 
40  $secret = $key->getSecret();
41  $label = "{$this->oathUser->getIssuer()}:{$this->oathUser->getAccount()}";
42  $qrcodeUrl = "otpauth://totp/"
43  . rawurlencode( $label )
44  . "?secret="
45  . rawurlencode( $secret )
46  . "&issuer="
47  . rawurlencode( $this->oathUser->getIssuer() );
48 
49  $qrcodeElement = Html::element( 'div', [
50  'data-mw-qrcode-url' => $qrcodeUrl,
51  'class' => 'mw-display-qrcode',
52  // Include width/height, so js won't re-arrange layout
53  // And non-js users will have this hidden with CSS
54  'style' => 'width: 256px; height: 256px;'
55  ] );
56 
57  return [
58  'app' => [
59  'type' => 'info',
60  'default' => $this->msg( 'oathauth-step1-test' )->escaped(),
61  'raw' => true,
62  'section' => 'step1',
63  ],
64  'qrcode' => [
65  'type' => 'info',
66  'default' => $qrcodeElement,
67  'raw' => true,
68  'section' => 'step2',
69  ],
70  'manual' => [
71  'type' => 'info',
72  'label-message' => 'oathauth-step2alt',
73  'default' =>
74  '<strong>' . $this->msg( 'oathauth-account' )->escaped() . '</strong><br/>'
75  . htmlspecialchars( $this->oathUser->getAccount() ) . '<br/><br/>'
76  . '<strong>' . $this->msg( 'oathauth-secret' )->escaped() . '</strong><br/>'
77  . '<kbd>' . $this->getSecretForDisplay( $key ) . '</kbd><br/>',
78  'raw' => true,
79  'section' => 'step2',
80  ],
81  'scratchtokens' => [
82  'type' => 'info',
83  'default' =>
84  $this->msg( 'oathauth-scratchtokens' )
85  . $this->createResourceList( $this->getScratchTokensForDisplay( $key ) ),
86  'raw' => true,
87  'section' => 'step3',
88  ],
89  'token' => [
90  'type' => 'text',
91  'default' => '',
92  'label-message' => 'oathauth-entertoken',
93  'name' => 'token',
94  'section' => 'step4',
95  'dir' => 'ltr',
96  'autocomplete' => false,
97  'spellcheck' => false,
98  ]
99  ];
100  }
101 
106  private function createResourceList( $resources ) {
107  $resourceList = '';
108  foreach ( $resources as $resource ) {
109  $resourceList .= Html::rawElement( 'li', [], Html::rawElement( 'kbd', [], $resource ) );
110  }
111  return Html::rawElement( 'ul', [], $resourceList );
112  }
113 
122  protected function getSecretForDisplay( TOTPKey $key ) {
123  return $this->tokenFormatterFunction( $key->getSecret() );
124  }
125 
134  protected function getScratchTokensForDisplay( TOTPKey $key ) {
135  return array_map( [ $this, 'tokenFormatterFunction' ], $key->getScratchTokens() );
136  }
137 
144  private function tokenFormatterFunction( $token ) {
145  return implode( ' ', str_split( $token, 4 ) );
146  }
147 
154  public function onSubmit( array $formData ) {
155  $keyData = $this->getRequest()->getSessionData( 'oathauth_totp_key' ) ?? [];
156  $key = TOTPKey::newFromArray( $keyData );
157  if ( !$key instanceof TOTPKey ) {
158  return [ 'oathauth-invalidrequest' ];
159  }
160 
161  if ( $key->isScratchToken( $formData['token'] ) ) {
162  // A scratch token is not allowed for enrollment
163  LoggerFactory::getInstance( 'authentication' )->info(
164  'OATHAuth {user} attempted to enable 2FA using a scratch token from {clientip}', [
165  'user' => $this->getUser()->getName(),
166  'clientip' => $this->getRequest()->getIP(),
167  ]
168  );
169  return [ 'oathauth-noscratchforvalidation' ];
170  }
171  if ( !$key->verify( [ 'token' => $formData['token'] ], $this->oathUser ) ) {
172  LoggerFactory::getInstance( 'authentication' )->info(
173  'OATHAuth {user} failed to provide a correct token while enabling 2FA from {clientip}', [
174  'user' => $this->getUser()->getName(),
175  'clientip' => $this->getRequest()->getIP(),
176  ]
177  );
178  return [ 'oathauth-failedtovalidateoath' ];
179  }
180 
181  $this->getRequest()->setSessionData( 'oathauth_totp_key', null );
182  $this->oathUser->setKeys( [ $key ] );
183  $this->oathUser->setModule( $this->module );
184  $this->oathRepo->persist( $this->oathUser, $this->getRequest()->getIP() );
185 
186  return true;
187  }
188 }
MediaWiki\Extension\OATHAuth\Key\TOTPKey\getScratchTokens
getScratchTokens()
Definition: TOTPKey.php:125
MediaWiki\Extension\OATHAuth\Key\TOTPKey\getSecret
getSecret()
Definition: TOTPKey.php:118
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm\getHTML
getHTML( $submitResult)
Definition: TOTPEnableForm.php:15
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm\onSubmit
onSubmit(array $formData)
Definition: TOTPEnableForm.php:154
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm\getDescriptors
getDescriptors()
Definition: TOTPEnableForm.php:29
MediaWiki\Logger\LoggerFactory\getInstance
static getInstance( $channel)
Get a named logger instance from the currently configured logger factory.
Definition: LoggerFactory.php:92
MediaWiki\Extension\OATHAuth\Key\TOTPKey
Class representing a two-factor key.
Definition: TOTPKey.php:41
MediaWiki\Extension\OATHAuth\HTMLForm\OATHAuthOOUIHTMLForm
Definition: OATHAuthOOUIHTMLForm.php:17
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:71
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm\createResourceList
createResourceList( $resources)
Definition: TOTPEnableForm.php:106
ContextSource\getUser
getUser()
Definition: ContextSource.php:120
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm\tokenFormatterFunction
tokenFormatterFunction( $token)
Formats a key or scratch token by creating groups of 4 separated by space characters.
Definition: TOTPEnableForm.php:144
Status
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:40
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
ContextSource\getOutput
getOutput()
Definition: ContextSource.php:112
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm\onSuccess
onSuccess()
Add content to output when operation was successful.
Definition: TOTPEnableForm.php:25
MediaWiki\Extension\OATHAuth\HTMLForm
Definition: IManageForm.php:3
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:168
MediaWiki\Extension\OATHAuth\Key\TOTPKey\newFromRandom
static newFromRandom()
Definition: TOTPKey.php:64
MediaWiki\Extension\OATHAuth\Key\TOTPKey\newFromArray
static newFromArray(array $data)
Definition: TOTPKey.php:93
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm
Definition: TOTPEnableForm.php:10
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm\getScratchTokensForDisplay
getScratchTokensForDisplay(TOTPKey $key)
Retrieve current scratch tokens for display purposes.
Definition: TOTPEnableForm.php:134
MediaWiki\Extension\OATHAuth\HTMLForm\IManageForm
Definition: IManageForm.php:10
MediaWiki\Extension\OATHAuth\HTMLForm\TOTPEnableForm\getSecretForDisplay
getSecretForDisplay(TOTPKey $key)
Retrieve the current secret for display purposes.
Definition: TOTPEnableForm.php:122