Version Description
- Initial release
Download this release
Release Info
Developer | Henrik.Schack |
Plugin | Google Authenticator |
Version | 0.20 |
Comparing to | |
See all releases |
Version 0.20
- base32.php +82 -0
- google-authenticator.php +340 -0
- lang/google-authenticator.pot +87 -0
- readme.txt +61 -0
- screenshot-1.jpg +0 -0
- screenshot-2.jpg +0 -0
- screenshot-3.jpg +0 -0
- screenshot-4.jpg +0 -0
base32.php
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Encode in Base32 based on RFC 4648.
|
5 |
+
* Requires 20% more space than base64
|
6 |
+
* Great for case-insensitive filesystems like Windows and URL's (except for = char which can be excluded using the pad option for urls)
|
7 |
+
*
|
8 |
+
* @package default
|
9 |
+
* @author Bryan Ruiz
|
10 |
+
**/
|
11 |
+
class Base32 {
|
12 |
+
|
13 |
+
private static $map = array(
|
14 |
+
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
|
15 |
+
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
|
16 |
+
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
|
17 |
+
'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
|
18 |
+
'=' // padding char
|
19 |
+
);
|
20 |
+
|
21 |
+
private static $flippedMap = array(
|
22 |
+
'A'=>'0', 'B'=>'1', 'C'=>'2', 'D'=>'3', 'E'=>'4', 'F'=>'5', 'G'=>'6', 'H'=>'7',
|
23 |
+
'I'=>'8', 'J'=>'9', 'K'=>'10', 'L'=>'11', 'M'=>'12', 'N'=>'13', 'O'=>'14', 'P'=>'15',
|
24 |
+
'Q'=>'16', 'R'=>'17', 'S'=>'18', 'T'=>'19', 'U'=>'20', 'V'=>'21', 'W'=>'22', 'X'=>'23',
|
25 |
+
'Y'=>'24', 'Z'=>'25', '2'=>'26', '3'=>'27', '4'=>'28', '5'=>'29', '6'=>'30', '7'=>'31'
|
26 |
+
);
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Use padding false when encoding for urls
|
30 |
+
*
|
31 |
+
* @return base32 encoded string
|
32 |
+
* @author Bryan Ruiz
|
33 |
+
**/
|
34 |
+
public static function encode($input, $padding = true) {
|
35 |
+
if(empty($input)) return "";
|
36 |
+
$input = str_split($input);
|
37 |
+
$binaryString = "";
|
38 |
+
for($i = 0; $i < count($input); $i++) {
|
39 |
+
$binaryString .= str_pad(base_convert(ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT);
|
40 |
+
}
|
41 |
+
$fiveBitBinaryArray = str_split($binaryString, 5);
|
42 |
+
$base32 = "";
|
43 |
+
$i=0;
|
44 |
+
while($i < count($fiveBitBinaryArray)) {
|
45 |
+
$base32 .= self::$map[base_convert(str_pad($fiveBitBinaryArray[$i], 5,'0'), 2, 10)];
|
46 |
+
$i++;
|
47 |
+
}
|
48 |
+
if($padding && ($x = strlen($binaryString) % 40) != 0) {
|
49 |
+
if($x == 8) $base32 .= str_repeat(self::$map[32], 6);
|
50 |
+
else if($x == 16) $base32 .= str_repeat(self::$map[32], 4);
|
51 |
+
else if($x == 24) $base32 .= str_repeat(self::$map[32], 3);
|
52 |
+
else if($x == 32) $base32 .= self::$map[32];
|
53 |
+
}
|
54 |
+
return $base32;
|
55 |
+
}
|
56 |
+
|
57 |
+
public static function decode($input) {
|
58 |
+
if(empty($input)) return;
|
59 |
+
$paddingCharCount = substr_count($input, self::$map[32]);
|
60 |
+
$allowedValues = array(6,4,3,1,0);
|
61 |
+
if(!in_array($paddingCharCount, $allowedValues)) return false;
|
62 |
+
for($i=0; $i<4; $i++){
|
63 |
+
if($paddingCharCount == $allowedValues[$i] &&
|
64 |
+
substr($input, -($allowedValues[$i])) != str_repeat(self::$map[32], $allowedValues[$i])) return false;
|
65 |
+
}
|
66 |
+
$input = str_replace('=','', $input);
|
67 |
+
$input = str_split($input);
|
68 |
+
$binaryString = "";
|
69 |
+
for($i=0; $i < count($input); $i = $i+8) {
|
70 |
+
$x = "";
|
71 |
+
if(!in_array($input[$i], self::$map)) return false;
|
72 |
+
for($j=0; $j < 8; $j++) {
|
73 |
+
$x .= str_pad(base_convert(@self::$flippedMap[@$input[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
|
74 |
+
}
|
75 |
+
$eightBits = str_split($x, 8);
|
76 |
+
for($z = 0; $z < count($eightBits); $z++) {
|
77 |
+
$binaryString .= ( ($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48 ) ? $y:"";
|
78 |
+
}
|
79 |
+
}
|
80 |
+
return $binaryString;
|
81 |
+
}
|
82 |
+
}
|
google-authenticator.php
ADDED
@@ -0,0 +1,340 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: Google Authenticator
|
4 |
+
Plugin URI: http://henrik.schack.dk/google-authenticator-for-wordpress
|
5 |
+
Description: Multi-Factor Authentication for Wordpress using the Android/Iphone/Blackberry app as One Time Password generator.
|
6 |
+
Author: Henrik Schack
|
7 |
+
Version: 0.20
|
8 |
+
Author URI: http://henrik.schack.dk/
|
9 |
+
Compatibility : WordPress 3.1.2
|
10 |
+
Text Domain: google-auth
|
11 |
+
Domain Path: /lang
|
12 |
+
|
13 |
+
----------------------------------------------------------------------------
|
14 |
+
|
15 |
+
Thanks to Bryan Ruiz for his Base32 encode/decode class, found at php.net
|
16 |
+
|
17 |
+
----------------------------------------------------------------------------
|
18 |
+
|
19 |
+
Copyright 2011 Henrik Schack (email : henrik@schack.dk)
|
20 |
+
|
21 |
+
This program is free software; you can redistribute it and/or modify
|
22 |
+
it under the terms of the GNU General Public License as published by
|
23 |
+
the Free Software Foundation; either version 2 of the License, or
|
24 |
+
(at your option) any later version.
|
25 |
+
|
26 |
+
This program is distributed in the hope that it will be useful,
|
27 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
28 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
29 |
+
GNU General Public License for more details.
|
30 |
+
|
31 |
+
You should have received a copy of the GNU General Public License
|
32 |
+
along with this program; if not, write to the Free Software
|
33 |
+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
34 |
+
*/
|
35 |
+
|
36 |
+
require_once('base32.php');
|
37 |
+
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Check the verification code entered by the user.
|
41 |
+
*/
|
42 |
+
function GoogleAuthenticate($secretkey,$thistry) {
|
43 |
+
|
44 |
+
$tm=intval(time()/30);
|
45 |
+
|
46 |
+
$secretkey=Base32::decode($secretkey);
|
47 |
+
// Keys from 30 seconds before and after are valid aswell.
|
48 |
+
for ($i=-1; $i<2; $i++) {
|
49 |
+
// Pack time into binary string
|
50 |
+
$time=chr(0).chr(0).chr(0).chr(0).pack('N*',$tm+$i);
|
51 |
+
// Hash it with users secret key
|
52 |
+
$hm=hash_hmac ('SHA1' ,$time, $secretkey,true);
|
53 |
+
// Use last nipple of result as index/offset
|
54 |
+
$offset = ord(substr($hm,-1)) & 0x0F;
|
55 |
+
// grab 4 bytes of the result
|
56 |
+
$hashpart=substr($hm,$offset,4);
|
57 |
+
// Unpak binary value
|
58 |
+
$value=unpack("N",$hashpart);
|
59 |
+
$value=$value[1];
|
60 |
+
// Only 32 bits
|
61 |
+
$value = $value & 0x7FFFFFFF;
|
62 |
+
$value = bcmod($value,1000000) ;
|
63 |
+
if ($value == $thistry) {
|
64 |
+
return true;
|
65 |
+
}
|
66 |
+
}
|
67 |
+
return false;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Create a new secret for the Google Authenticator app.
|
72 |
+
* Hash the current time, with the hash of the users password
|
73 |
+
* then grap 10 bytes of the result using lower nipple as offset
|
74 |
+
* into the datastring.
|
75 |
+
*/
|
76 |
+
function GoogleAuthenticator_create_secret($inputvalue) {
|
77 |
+
$rawsecret = hash_hmac('SHA256',microtime(),$inputvalue,true);
|
78 |
+
$offset = ord(substr($rawsecret,-1)) & 0x0F;
|
79 |
+
$secret = substr($rawsecret,$offset,10);
|
80 |
+
return Base32::encode($secret);
|
81 |
+
}
|
82 |
+
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Add verification code field to login form.
|
86 |
+
*/
|
87 |
+
function GoogleAuthenticator_loginform() {
|
88 |
+
echo "\t<p>\n";
|
89 |
+
echo "\t\t<label><a href=\"http://code.google.com/p/google-authenticator/\" target=\"_blank\" title=\"".__('If You don\'t have Google Authenticator enabled for Your Wordpress account, leave this field empty.','google-auth')."\">".__('Google Authenticator code','google-auth')."</a><span id=\"google-auth-info\"></span><br />\n";
|
90 |
+
echo "\t\t<input type=\"password\" name=\"otp\" id=\"user_email\" class=\"input\" value=\"\" size=\"20\" tabindex=\"25\" /></label>\n";
|
91 |
+
echo "\t</p>\n";
|
92 |
+
}
|
93 |
+
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Login form handling.
|
97 |
+
* Check Google Authenticator verification code, if user has been setup to do so.
|
98 |
+
* @param wordpressuser
|
99 |
+
* @return user/loginstatus
|
100 |
+
*/
|
101 |
+
function GoogleAuthenticator_check_otp( $user ) {
|
102 |
+
|
103 |
+
// Does the user have the Google Authenticator enabled ?
|
104 |
+
if ( trim(get_user_option('googleauthenticator_enabled',$user->ID)) == 'enabled' ) {
|
105 |
+
|
106 |
+
// Get the users secret
|
107 |
+
$GA_secret = trim( get_user_option( 'googleauthenticator_secret', $user->ID ) );
|
108 |
+
|
109 |
+
// Get the verification code entered by the user trying to login
|
110 |
+
$otp = intval( trim( $_POST[ 'otp' ] ) );
|
111 |
+
|
112 |
+
// Valid code ?
|
113 |
+
if (! GoogleAuthenticate( $GA_secret, $otp ) ) {
|
114 |
+
return false;
|
115 |
+
}
|
116 |
+
}
|
117 |
+
return $user;
|
118 |
+
}
|
119 |
+
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Extend personal profile page with Google Authenticator settings.
|
123 |
+
*/
|
124 |
+
function GoogleAuthenticator_profile_personal_options() {
|
125 |
+
global $user_id, $is_profile_page;
|
126 |
+
|
127 |
+
$GA_secret =trim( get_user_option( 'googleauthenticator_secret', $user_id ) );
|
128 |
+
$GA_enabled =trim( get_user_option( 'googleauthenticator_enabled', $user_id ) );
|
129 |
+
$GA_description =trim( get_user_option( 'googleauthenticator_description', $user_id ) );
|
130 |
+
|
131 |
+
// In case the user has no secret ready (new install), we create one.
|
132 |
+
if ($GA_secret == "") {
|
133 |
+
$GA_secret=GoogleAuthenticator_create_secret( get_user_option( 'user_pass', $user_id ) );
|
134 |
+
}
|
135 |
+
|
136 |
+
// Use "Wordpress blog" as default description
|
137 |
+
if ($GA_description == "") {
|
138 |
+
$GA_description=__("Wordpress blog",'google-auth');
|
139 |
+
}
|
140 |
+
|
141 |
+
echo "<h3>".__( 'Google Authenticator settings', 'google-auth' )."</h3>\n";
|
142 |
+
|
143 |
+
echo "<table class=\"form-table\">\n";
|
144 |
+
echo "<tbody>\n";
|
145 |
+
echo "<tr>\n";
|
146 |
+
echo "<th scope=\"row\">".__( 'Active', 'google-auth' )."</th>\n";
|
147 |
+
echo "<td>\n";
|
148 |
+
|
149 |
+
echo "<div><input name=\"GA_enabled\" id=\"GA_enabled\" class=\"tog\" type=\"checkbox\"";
|
150 |
+
if ( $GA_enabled == 'enabled' ) {
|
151 |
+
echo ' checked="checked"';
|
152 |
+
}
|
153 |
+
echo "/>";
|
154 |
+
echo "</div>\n";
|
155 |
+
|
156 |
+
echo "</td>\n";
|
157 |
+
echo "</tr>\n";
|
158 |
+
|
159 |
+
// Create URL for the Google charts QR code generator.
|
160 |
+
$chl=urlencode("otpauth://totp/".$GA_description."?secret=".$GA_secret);
|
161 |
+
$qrcodeurl="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chld=H|0&chl=".$chl;
|
162 |
+
|
163 |
+
if ( $is_profile_page || IS_PROFILE_PAGE ) {
|
164 |
+
echo "<tr>\n";
|
165 |
+
echo "<th><label for=\"GA_description\">".__('Description','google-auth')."</label></th>\n";
|
166 |
+
echo "<td><input name=\"GA_description\" id=\"GA_description\" value=\"".$GA_description."\" type=\"text\" /><span class=\"description\">".__(' Description you\'ll see on your phone.','google-auth')."</span><br /></td>\n";
|
167 |
+
echo "</tr>\n";
|
168 |
+
|
169 |
+
echo "<tr>\n";
|
170 |
+
echo "<th><label for=\"GA_secret\">".__('Secret','google-auth')."</label></th>\n";
|
171 |
+
echo "<td>\n";
|
172 |
+
echo "<input name=\"GA_secret\" id=\"GA_secret\" value=\"".$GA_secret."\" readonly=\"true\" type=\"text\" />";
|
173 |
+
echo "<input name=\"GA_newsecret\" id=\"GA_newsecret\" value=\"".__("Create new secret",'google-auth')."\" type=\"button\" class=\"button\" />";
|
174 |
+
echo "<input name=\"show_qr\" id=\"show_qr\" value=\"".__("Show/Hide QR code",'google-auth')."\" type=\"button\" class=\"button\" onclick=\"jQuery('#GA_QR_INFO').toggle('slow');\" />";
|
175 |
+
echo "</td>\n";
|
176 |
+
echo "</tr>\n";
|
177 |
+
|
178 |
+
echo "<tr>\n";
|
179 |
+
echo "<th></th>\n";
|
180 |
+
echo "<td><div id=\"GA_QR_INFO\" style=\"display: none\" >";
|
181 |
+
echo "<img id=\"GA_QRCODE\" src=\"".$qrcodeurl."\" alt=\"QR Code\"/>";
|
182 |
+
echo "<span class=\"description\">".__('<br/> Scan this with the Google Authenticator app.','google-auth')."</span>";
|
183 |
+
echo "</div></td>\n";
|
184 |
+
echo "</tr>\n";
|
185 |
+
|
186 |
+
}
|
187 |
+
|
188 |
+
|
189 |
+
echo "</tbody></table>\n";
|
190 |
+
echo "<script type=\"text/javascript\">\n";
|
191 |
+
echo "var ajaxurl='".admin_url( 'admin-ajax.php' )."'\n";
|
192 |
+
echo "var GAnonce='".wp_create_nonce('GoogleAuthenticatoraction')."';\n";
|
193 |
+
echo <<<ENDOFJS
|
194 |
+
jQuery('#GA_newsecret').bind('click', function() {
|
195 |
+
var data=new Object();
|
196 |
+
data['action'] = 'GoogleAuthenticator_action';
|
197 |
+
data['nonce'] = GAnonce;
|
198 |
+
jQuery.post(ajaxurl, data, function(response) {
|
199 |
+
jQuery('#GA_secret').val(response['new-secret']);
|
200 |
+
chl=escape("otpauth://totp/"+jQuery('#GA_description').val()+"?secret="+jQuery('#GA_secret').val());
|
201 |
+
qrcodeurl="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chld=H|0&chl="+chl;
|
202 |
+
jQuery('#GA_QRCODE').attr('src',qrcodeurl);
|
203 |
+
jQuery('#GA_QR_INFO').show('slow');
|
204 |
+
});
|
205 |
+
});
|
206 |
+
|
207 |
+
jQuery('#GA_description').bind('focus blur change keyup', function() {
|
208 |
+
chl=escape("otpauth://totp/"+jQuery('#GA_description').val()+"?secret="+jQuery('#GA_secret').val());
|
209 |
+
qrcodeurl="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chld=H|0&chl="+chl;
|
210 |
+
jQuery('#GA_QRCODE').attr('src',qrcodeurl);
|
211 |
+
});
|
212 |
+
|
213 |
+
</script>
|
214 |
+
ENDOFJS;
|
215 |
+
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Form handling of Google Authenticator options added to personal profile page (user editing his own profile)
|
220 |
+
*/
|
221 |
+
function GoogleAuthenticator_personal_options_update() {
|
222 |
+
global $user_id;
|
223 |
+
|
224 |
+
$GA_enabled = trim( $_POST['GA_enabled'] );
|
225 |
+
$GA_secret = trim( $_POST['GA_secret'] );
|
226 |
+
$GA_description = trim( $_POST['GA_description'] );
|
227 |
+
|
228 |
+
if ($GA_enabled !="") {
|
229 |
+
$GA_enabled="enabled";
|
230 |
+
} else {
|
231 |
+
$GA_enabled="disabled";
|
232 |
+
}
|
233 |
+
|
234 |
+
update_user_option( $user_id, 'googleauthenticator_enabled', $GA_enabled, true );
|
235 |
+
update_user_option( $user_id, 'googleauthenticator_secret', $GA_secret, true );
|
236 |
+
update_user_option( $user_id, 'googleauthenticator_description', $GA_description, true );
|
237 |
+
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Extend profile page with ability to enable/disable Google Authenticator authentication requirement.
|
242 |
+
* Used by an administrator when editing other users.
|
243 |
+
*/
|
244 |
+
function GoogleAuthenticator_edit_user_profile() {
|
245 |
+
global $user_id;
|
246 |
+
$GA_enabled = trim( get_user_option( 'googleauthenticator_enabled', $user_id ) );
|
247 |
+
echo "<h3>".__('Google Authenticator settings','google-auth')."</h3>\n";
|
248 |
+
echo "<table class=\"form-table\">\n";
|
249 |
+
echo "<tbody>\n";
|
250 |
+
echo "<tr>\n";
|
251 |
+
echo "<th scope=\"row\">".__('Active','google-auth')."</th>\n";
|
252 |
+
echo "<td>\n";
|
253 |
+
echo "<div><input name=\"GA_enabled\" id=\"GA_enabled\" class=\"tog\" type=\"checkbox\"";
|
254 |
+
if ( $GA_enabled == 'enabled' ) {
|
255 |
+
echo ' checked ';
|
256 |
+
}
|
257 |
+
echo "/>\n";
|
258 |
+
echo "</td>\n";
|
259 |
+
echo "</tr>\n";
|
260 |
+
echo "</tbody>\n";
|
261 |
+
echo "</table>\n";
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Form handling of Google Authenticator options on edit profile page (admin user editing other user)
|
266 |
+
*/
|
267 |
+
function GoogleAuthenticator_edit_user_profile_update() {
|
268 |
+
global $user_id;
|
269 |
+
|
270 |
+
$GA_enabled = trim( $_POST['GA_enabled'] );
|
271 |
+
if ( $GA_enabled != '' ) {
|
272 |
+
update_user_option( $user_id, 'googleauthenticator_enabled', 'enabled', true );
|
273 |
+
} else {
|
274 |
+
update_user_option( $user_id, 'googleauthenticator_enabled', 'disabled', true );
|
275 |
+
}
|
276 |
+
}
|
277 |
+
|
278 |
+
|
279 |
+
/**
|
280 |
+
* AJAX callback function used to generate new secret
|
281 |
+
*/
|
282 |
+
function GoogleAuthenticator_callback() {
|
283 |
+
global $user_id;
|
284 |
+
|
285 |
+
// Some AJAX security
|
286 |
+
check_ajax_referer('GoogleAuthenticatoraction', 'nonce');
|
287 |
+
|
288 |
+
// Create new secret, using the users password hash as input for further hashing
|
289 |
+
$secret=GoogleAuthenticator_create_secret( get_user_option( 'user_pass', $user_id ) );
|
290 |
+
|
291 |
+
$result=array('new-secret'=>$secret);
|
292 |
+
header( "Content-Type: application/json" );
|
293 |
+
echo json_encode( $result );
|
294 |
+
|
295 |
+
// die() is required to return a proper result
|
296 |
+
die();
|
297 |
+
}
|
298 |
+
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Does the PHP installation have what it takes to use this plugin ?
|
302 |
+
*/
|
303 |
+
function GoogleAuthenticator_check_requirements() {
|
304 |
+
|
305 |
+
// is the SHA-1 hashing available ?
|
306 |
+
$GoogleAuthenticatorAlgos = hash_algos();
|
307 |
+
if ( ! in_array( "sha1", $GoogleAuthenticatorAlgos ) ) {
|
308 |
+
return false;
|
309 |
+
}
|
310 |
+
// is the SHA-256 hashing available ?
|
311 |
+
$GoogleAuthenticatorAlgos = hash_algos();
|
312 |
+
if ( ! in_array( "sha256", $GoogleAuthenticatorAlgos ) ) {
|
313 |
+
return false;
|
314 |
+
}
|
315 |
+
return true;
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Prevent activation of the plugin if the PHP installation doesn't meet the requirements.
|
320 |
+
*/
|
321 |
+
function GoogleAuthenticator_activate() {
|
322 |
+
if ( ! GoogleAuthenticator_check_requirements()) {
|
323 |
+
die( __('Google Authenticator: Something is missing, this plugin requires the SHA1 & SHA256 Hashing algorithms to be present in your PHP installation.', 'google-auth') );
|
324 |
+
}
|
325 |
+
}
|
326 |
+
|
327 |
+
// Initialization and Hooks
|
328 |
+
add_action('personal_options_update','GoogleAuthenticator_personal_options_update');
|
329 |
+
add_action('profile_personal_options','GoogleAuthenticator_profile_personal_options');
|
330 |
+
add_action('edit_user_profile','GoogleAuthenticator_edit_user_profile');
|
331 |
+
add_action('edit_user_profile_update','GoogleAuthenticator_edit_user_profile_update');
|
332 |
+
add_action('login_form', 'GoogleAuthenticator_loginform');
|
333 |
+
add_action('wp_ajax_GoogleAuthenticator_action', 'GoogleAuthenticator_callback');
|
334 |
+
|
335 |
+
add_filter('wp_authenticate_user','GoogleAuthenticator_check_otp');
|
336 |
+
|
337 |
+
register_activation_hook( __FILE__, 'GoogleAuthenticator_activate' );
|
338 |
+
|
339 |
+
load_plugin_textdomain('google-auth', false , dirname( plugin_basename(__FILE__)).'/lang' );
|
340 |
+
?>
|
lang/google-authenticator.pot
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (C) 2010 Google Authenticator
|
2 |
+
# This file is distributed under the same license as the Google Authenticator package.
|
3 |
+
msgid ""
|
4 |
+
msgstr ""
|
5 |
+
"Project-Id-Version: Google Authenticator 0.20\n"
|
6 |
+
"Report-Msgid-Bugs-To: http://wordpress.org/tag/google-authenticator\n"
|
7 |
+
"POT-Creation-Date: 2011-05-17 19:38:36+00:00\n"
|
8 |
+
"MIME-Version: 1.0\n"
|
9 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
+
"Content-Transfer-Encoding: 8bit\n"
|
11 |
+
"PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
|
12 |
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
+
|
15 |
+
#: google-authenticator.php:89
|
16 |
+
msgid ""
|
17 |
+
"If You don't have Google Authenticator enabled for Your Wordpress account, "
|
18 |
+
"leave this field empty."
|
19 |
+
msgstr ""
|
20 |
+
|
21 |
+
#: google-authenticator.php:89
|
22 |
+
msgid "Google Authenticator code"
|
23 |
+
msgstr ""
|
24 |
+
|
25 |
+
#: google-authenticator.php:138
|
26 |
+
msgid "Wordpress blog"
|
27 |
+
msgstr ""
|
28 |
+
|
29 |
+
#: google-authenticator.php:141 google-authenticator.php:247
|
30 |
+
msgid "Google Authenticator settings"
|
31 |
+
msgstr ""
|
32 |
+
|
33 |
+
#: google-authenticator.php:146 google-authenticator.php:251
|
34 |
+
msgid "Active"
|
35 |
+
msgstr ""
|
36 |
+
|
37 |
+
#: google-authenticator.php:165
|
38 |
+
msgid "Description"
|
39 |
+
msgstr ""
|
40 |
+
|
41 |
+
#: google-authenticator.php:166
|
42 |
+
msgid " Description you'll see on your phone."
|
43 |
+
msgstr ""
|
44 |
+
|
45 |
+
#: google-authenticator.php:170
|
46 |
+
msgid "Secret"
|
47 |
+
msgstr ""
|
48 |
+
|
49 |
+
#: google-authenticator.php:173
|
50 |
+
msgid "Create new secret"
|
51 |
+
msgstr ""
|
52 |
+
|
53 |
+
#: google-authenticator.php:174
|
54 |
+
msgid "Show/Hide QR code"
|
55 |
+
msgstr ""
|
56 |
+
|
57 |
+
#: google-authenticator.php:182
|
58 |
+
msgid "<br/> Scan this with the Google Authenticator app."
|
59 |
+
msgstr ""
|
60 |
+
|
61 |
+
#: google-authenticator.php:323
|
62 |
+
msgid ""
|
63 |
+
"Google Authenticator: Something is missing, this plugin requires the SHA1 & "
|
64 |
+
"SHA256 Hashing algorithms to be present in your PHP installation."
|
65 |
+
msgstr ""
|
66 |
+
|
67 |
+
#. Plugin Name of the plugin/theme
|
68 |
+
msgid "Google Authenticator"
|
69 |
+
msgstr ""
|
70 |
+
|
71 |
+
#. Plugin URI of the plugin/theme
|
72 |
+
msgid "http://henrik.schack.dk/google-authenticator-for-wordpress"
|
73 |
+
msgstr ""
|
74 |
+
|
75 |
+
#. Description of the plugin/theme
|
76 |
+
msgid ""
|
77 |
+
"Multi-Factor Authentication for Wordpress using the Android/Iphone/"
|
78 |
+
"Blackberry app as One Time Password generator."
|
79 |
+
msgstr ""
|
80 |
+
|
81 |
+
#. Author of the plugin/theme
|
82 |
+
msgid "Henrik Schack"
|
83 |
+
msgstr ""
|
84 |
+
|
85 |
+
#. Author URI of the plugin/theme
|
86 |
+
msgid "http://henrik.schack.dk/"
|
87 |
+
msgstr ""
|
readme.txt
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Google Authenticator ===
|
2 |
+
Contributors: Henrik.Schack
|
3 |
+
Donate Link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=CA36JVKMLE9EA&lc=DK&item_number=Google%20Authenticator¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted
|
4 |
+
Tags: authentication,otp,password,security,login,android,iphone,blackberry
|
5 |
+
Requires at least: 3.1.2
|
6 |
+
Tested up to: 3.1.2
|
7 |
+
Stable tag: 0.20
|
8 |
+
|
9 |
+
Google Authenticator for your Wordpress blog.
|
10 |
+
|
11 |
+
== Description ==
|
12 |
+
|
13 |
+
The Google Authenticator plugin for WordPress gives you multifactor authentication using the Google Authenticator app for Android/iPhone/Blackberry.
|
14 |
+
|
15 |
+
If you're security aware you may allready have the Google Authenticator app installed, using it for multifactor authentication on your Gmail or Google Apps account.
|
16 |
+
|
17 |
+
The multifactor authentication requirement can be enabled on a per user basis, You could enable it for your administrator account, but login as usual with less privileged accounts.
|
18 |
+
|
19 |
+
|
20 |
+
** Notice: This plugin requires the SHA1 & SHA256 hashing algorithms to be available in your PHP installation, it's not possible to activate the plugin without **
|
21 |
+
|
22 |
+
== Installation ==
|
23 |
+
|
24 |
+
1. Install and activate the plugin.
|
25 |
+
2. Enter a description on the Users -> Profile and Personal options page, in the Google Authenticator section.
|
26 |
+
3. Scan the generated QR code with your phone, or enter the secret manually (remember to pick the time based one)
|
27 |
+
4. Remember to hit the **Update profile** button at the bottom of the page before leaving the Personal options page.
|
28 |
+
4. That's it, your Wordpress blog is now a little more secure.
|
29 |
+
|
30 |
+
== Frequently Asked Questions ==
|
31 |
+
|
32 |
+
= Are there any special requirements for my Wordpress/PHP installation ? =
|
33 |
+
|
34 |
+
Yes, your PHP installation needs the SHA1 & SHA256 hashing algorithms.
|
35 |
+
|
36 |
+
= Can I use Google Authenticator for Wordpress with the Android/iPhone apps for Wordpress ? =
|
37 |
+
|
38 |
+
No, that wont work, but you could create a special account for mobile usage and choose not to enable
|
39 |
+
the Google Authenticator this account.
|
40 |
+
|
41 |
+
= I want to update the secret, should I just scan the new QR code after creating a new secret ? =
|
42 |
+
|
43 |
+
No you'll have to delete the existing account from your Google Authenticator app before you scan the new QR code, that is unless you
|
44 |
+
change the description as well.
|
45 |
+
|
46 |
+
= Sometimes I am unable to login using this plugin, the first code never works, what's wrong ? =
|
47 |
+
|
48 |
+
The Google Authenticator verification codes are time based, so it's crucial the clock in your phone is accurate.
|
49 |
+
|
50 |
+
|
51 |
+
== Screenshots ==
|
52 |
+
|
53 |
+
1. The enhanced loginbox.
|
54 |
+
2. Google Authenticator section on the Profile and Personal options page.
|
55 |
+
3. QR code on the Profile and Personal options page.
|
56 |
+
4. Google Authenticator app on Android
|
57 |
+
|
58 |
+
== Changelog ==
|
59 |
+
|
60 |
+
= 0.20 =
|
61 |
+
* Initial release
|
screenshot-1.jpg
ADDED
Binary file
|
screenshot-2.jpg
ADDED
Binary file
|
screenshot-3.jpg
ADDED
Binary file
|
screenshot-4.jpg
ADDED
Binary file
|