-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add 2-factor authentication support for phpMyAdmin. #13495
Conversation
7677411
to
c62bcbc
Compare
I described the procedure for setting it up 2-factor authentication in my blog post. As I mentioned there, I need advice on where to place the link to access |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've quickly gone through your code, some general remarks:
- Please include documentation, having it in the blog is great, but it really should be part of our documentation.
- Any reason for not integrating 2FA into existing Settings tab?
js/get_scripts.js.php
Outdated
@@ -7,6 +7,8 @@ | |||
* @package PhpMyAdmin | |||
*/ | |||
|
|||
/* var_dump($_GET['scripts']); */ | |||
/* exit; */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is not intentional...
libraries/phpqrcode.php
Outdated
* PHP QR Code encoder | ||
* | ||
* This file contains MERGED version of PHP QR Code library. | ||
* It was auto-generated from full version for your convenience. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not include third party libraries, can't this be loaded using composer? Also including generated code without source doesn't really play well with GPL, so we would have to distribute the source code as well.
libraries/session.inc.php
Outdated
@@ -138,18 +138,19 @@ function PMA_sessionFailed($errors) | |||
|
|||
// on first start of session we check for errors | |||
// f.e. session dir cannot be accessed - session file not created | |||
$orig_error_count = $GLOBALS['error_handler']->countErrors(false); | |||
if (!isset($_SESSION)){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is purpose of this change? If really needed, please do that in separate commit explaining why it is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nijel are you satisfied with this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to have the documentation in the code as well, not only in the commit message, but thanks for documenting this.
PMA_secureSession(); | ||
$this->auth(); | ||
} | ||
$check_2FA_db_query = 'SELECT `pma_user`, `secret` FROM `pma__2fa_secrets` WHERE `pma_user` LIKE \'' . $GLOBALS['PHP_AUTH_USER'] . '\';'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Please do not hardcode table name, see how others are handled.
- Why using LIKE when doing exact match?
} | ||
$controllink = $GLOBALS['dbi']->connect( | ||
DatabaseInterface::CONNECT_CONTROL | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can fail, so you should handle false return value here.
$conn_error = $GLOBALS['dbi']->getError($controllink); | ||
return false; | ||
} | ||
$check_2FA_db_query = 'SELECT `pma_user` FROM `pma__2fa_secrets` WHERE `pma_user` LIKE \'' . $GLOBALS['PHP_AUTH_USER'] . '\';'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as with auth2FA. Also these seem to share quite some amount of code, so you might want to factor that out.
setup2FA.php
Outdated
if (isset($_REQUEST['logincheck']) && $_REQUEST['logincheck'] == 'true') { | ||
$_SESSION['2FAVerified'] = true; | ||
} | ||
echo 'true'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really?
setup2FA.php
Outdated
} | ||
echo 'true'; | ||
} else { | ||
echo 'Sorry. The key does not match. Please ensure that server time and your app\'s time are in sync.' . $_SESSION['secret']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be localized, also there is probably no point in showing the secret here. Especially not unescaped as it seems to be user input.
setup2FA.php
Outdated
$response = PhpMyAdmin\Response::getInstance(); | ||
if (!$GLOBALS['dbi']->selectDb('phpmyadmin', $GLOBALS['controllink'])) { | ||
$response->disable(); | ||
echo $GLOBALS['dbi']->getError($GLOBALS['controllink']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case you want to pass the error details to client, please use JSON. Definitely do not output unescaped error messages.
474825f
to
6238513
Compare
@nijel, I addressed most of the issues you raised. I left comments for the rest. Please verify. |
$_SESSION['2FAVerified'] = true; | ||
echo 'true'; | ||
} else { | ||
echo htmlspecialchars('Sorry. The key does not match. Please ensure that server time and your app\'s time are in sync.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By this time, translations may not be possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a comment to the code as well stating that translations may not be possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, maybe this should be part of the setup script in the end (which we indeed do not localize)?
Edit: I think there is no reason why the localization wound not work here, why it doesn't work here? You should just include common.inc.php (what you should do anyway for authentication and CSRF protection) and localization will work.
Also it should probably display proper error message, not just plain text...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By this time, the user would not have been completely authenticated i.e., he/she is in the middle of authentication. Including common.inc.php is not possible because it will circularly check for 2-factor authentication again.
This part is accessed only by ajax request and the error message is displayed in standard PMA error dialog once received.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be better to closer integrate this to the authentication so that it can use the authentication API to show the form
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Authentication form is shown by auth2FA
function in AuthenticationCookie.php
. This is for verification. Do you mean I should move verification to a different file.
setup2FA.php
Outdated
echo htmlspecialchars($GLOBALS['dbi']->getError($GLOBALS['controllink'])); | ||
exit; | ||
} | ||
$add_secret_query = 'INSERT INTO ' . $cfg_2fa_table . ' VALUES (\'' . $GLOBALS['PHP_AUTH_USER'] . '\' ,\'' . $_SESSION['secret'] . '\');'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgive me if I missed you doing it earlier, but I think you need to escape PHP_AUTH_USER and secret here; you could use the Dbi function escapeString
for that.
I tried opening my main phpMyAdmin after pulling your branch (without configuring any user for 2FA or setting up config.inc.php) and got a number of errors. We should be more graceful about failing if the user hasn't configured their system for this.
|
We'll have to deal gracefully with situations where the user either hasn't configured it or the table doesn't exist. You can also see for instance libraries/classes/Bookmark.php:114 for an example of how we might deal with this. We have to test the array to make sure $cfgRelation['2fa_secret'] (or whatever configuration directive you use) isn't empty first, before trying to use it. We initialize it as part of the default configuration to an empty value, so before using we'll test if the user has configured it. Also, you should add the new directive to libraries/config.default.php with a blank assignment such as $cfg['Servers'][$i]['2fa_secret'] = '';. You can add it right after the export_template area around line 503. We should also add this new directive to libraries/relation.lib.php around line 353; this file is used by chk_rel.php which warns the user if their table structure is outdated. Can you add the structure for the 2fa_secrets table to Instead of manually running the SQL, it might be more efficient to use PMA_queryAsControlUser such as
|
use RobThree\Auth\Providers\Qr\IQRCodeProvider; | ||
use PHPQRCode; | ||
|
||
class PMAQRProvider implements IQRCodeProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please place the class to separate file and include tests for it?
3ae9916
to
d9934cc
Compare
Could you rebase this against current master to reflect the changes Maurício has done? |
d9934cc
to
0c0648f
Compare
This is required because we start in setup2FA.php while checking for 2-factor authentication. session variable for accessing secret. We also need that libraries/common.inc.php should not be loaded by this time. Signed-off-by: Raghuram <raghuram.4350@gmail.com>
0c0648f
to
d9d7bbe
Compare
Codecov Report
@@ Coverage Diff @@
## master #13495 +/- ##
==========================================
- Coverage 53.17% 52.96% -0.21%
==========================================
Files 468 470 +2
Lines 81619 81953 +334
==========================================
+ Hits 43404 43410 +6
- Misses 38215 38543 +328 |
c3b5a95
to
6087fe4
Compare
Signed-off-by: Raghuram <raghuram.4350@gmail.com>
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Signed-off-by: Raghuram raghuram.4350@gmail.com
Before submitting pull request, please check that every commit: