MediaWiki REL1_33
OATHAuthKey.php
Go to the documentation of this file.
1<?php
21
34 const MAIN_TOKEN = 1;
35
40 const SCRATCH_TOKEN = -1;
41
43 private $secret;
44
47
53 public static function newFromRandom() {
54 $object = new self(
56 []
57 );
58
59 $object->regenerateScratchTokens();
60
61 return $object;
62 }
63
69 // Currently harcoded values; might be used in future
70 $this->secret = [
71 'mode' => 'hotp',
72 'secret' => $secret,
73 'period' => 30,
74 'algorithm' => 'SHA1',
75 ];
76 $this->scratchTokens = $scratchTokens;
77 }
78
82 public function getSecret() {
83 return $this->secret['secret'];
84 }
85
89 public function getScratchTokens() {
91 }
92
102 public function verifyToken( $token, OATHUser $user ) {
104
105 if ( $this->secret['mode'] !== 'hotp' ) {
106 throw new \DomainException( 'OATHAuth extension does not support non-HOTP tokens' );
107 }
108
109 // Prevent replay attacks
110 $memc = ObjectCache::newAnything( [] );
111 $uid = CentralIdLookup::factory()->centralIdFromLocalUser( $user->getUser() );
112 $memcKey = wfMemcKey( 'oathauth', 'usedtokens', $uid );
113 $lastWindow = (int)$memc->get( $memcKey );
114
115 $retval = false;
117 Base32::decode( $this->secret['secret'] ),
118 $this->secret['period'], -$wgOATHAuthWindowRadius, $wgOATHAuthWindowRadius
119 );
120
121 // Remove any whitespace from the received token, which can be an intended group seperator
122 // or trimmeable whitespace
123 $token = preg_replace( '/\s+/', '', $token );
124
125 $clientIP = $user->getUser()->getRequest()->getIP();
126
127 $logger = $this->getLogger();
128
129 // Check to see if the user's given token is in the list of tokens generated
130 // for the time window.
131 foreach ( $results as $window => $result ) {
132 if ( $window > $lastWindow && $result->toHOTP( 6 ) === $token ) {
133 $lastWindow = $window;
134 $retval = self::MAIN_TOKEN;
135
136 $logger->info( 'OATHAuth user {user} entered a valid OTP from {clientip}', [
137 'user' => $user->getAccount(),
138 'clientip' => $clientIP,
139 ] );
140 break;
141 }
142 }
143
144 // See if the user is using a scratch token
145 if ( !$retval ) {
146 $length = count( $this->scratchTokens );
147 // Detect condition where all scratch tokens have been used
148 if ( $length === 1 && $this->scratchTokens[0] === "" ) {
149 $retval = false;
150 } else {
151 for ( $i = 0; $i < $length; $i++ ) {
152 if ( $token === $this->scratchTokens[$i] ) {
153 // If there is a scratch token, remove it from the scratch token list
154 unset( $this->scratchTokens[$i] );
155
156 $logger->info( 'OATHAuth user {user} used a scratch token from {clientip}', [
157 'user' => $user->getAccount(),
158 'clientip' => $clientIP,
159 ] );
160
162 $user->setKey( $this );
163 $oathrepo->persist( $user, $clientIP );
164 // Only return true if we removed it from the database
165 $retval = self::SCRATCH_TOKEN;
166 break;
167 }
168 }
169 }
170 }
171
172 if ( $retval ) {
173 $memc->set(
174 $memcKey,
175 $lastWindow,
176 $this->secret['period'] * ( 1 + 2 * $wgOATHAuthWindowRadius )
177 );
178 } else {
179
180 $logger->info( 'OATHAuth user {user} failed OTP/scratch token from {clientip}', [
181 'user' => $user->getAccount(),
182 'clientip' => $clientIP,
183 ] );
184
185 // Increase rate limit counter for failed request
186 $user->getUser()->pingLimiter( 'badoath' );
187 }
188
189 return $retval;
190 }
191
192 public function regenerateScratchTokens() {
193 $scratchTokens = [];
194 for ( $i = 0; $i < 10; $i++ ) {
196 }
197 $this->scratchTokens = $scratchTokens;
198 }
199
207 public function isScratchToken( $token ) {
208 $token = preg_replace( '/\s+/', '', $token );
209 return in_array( $token, $this->scratchTokens, true );
210 }
211
215 private function getLogger() {
216 return LoggerFactory::getInstance( 'authentication' );
217 }
218}
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two and(2) offer you this license which gives you legal permission to copy
wfMemcKey(... $args)
Make a cache key for the local wiki.
static decode($b32)
Decodes a base32 string into a binary string according to RFC 4648.
Definition base32.php:48
static encode($string)
Encodes a binary string into a base32 string according to RFC 4648 (no padding).
Definition base32.php:80
static generateByTimeWindow( $key, $window, $min=-1, $max=1, $timestamp=false)
Generate a HOTP key collection based on a timestamp and window size all keys that could exist between...
Definition hotp.php:72
static getOATHUserRepository()
Get the singleton OATH user repository.
Class representing a two-factor key.
static newFromRandom()
Make a new key from random values.
regenerateScratchTokens()
isScratchToken( $token)
Check if a token is one of the scratch tokens for this two factor key.
const SCRATCH_TOKEN
Represents that a token corresponds to a scratch token.
__construct( $secret, array $scratchTokens)
array $secret
Two factor binary secret.
const MAIN_TOKEN
Represents that a token corresponds to the main secret.
string[] $scratchTokens
List of scratch tokens.
verifyToken( $token, OATHUser $user)
Verify a token against the secret or scratch tokens.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
Definition OATHUser.php:24
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))