WordPress.org

Ready to get started?Download WordPress

Forums

Google Authenticator
[resolved] Feature Request - Ask for code on second page (27 posts)

  1. eatingrules
    Member
    Posted 1 year ago #

    Is there any way you can have the plugin ask for the code only after a successful login? When you log into Google, you enter your username and password, and then once you're successful with that, it asks for your authenticator code on a new page. This would increase usability, particularly in two scenarios:

    First, for sites where only some users are required to enter their authenticator code. (Otherwise they see a field and may not be sure it's okay to leave it blank.)

    Second, if you're able to remember specific devices, you could then skip the nag screen when someone successfully logs in on a remembered devices.

    Thanks Henrik!

    http://wordpress.org/extend/plugins/google-authenticator/

  2. Henrik Schack
    Member
    Plugin Author

    Posted 1 year ago #

    Hi
    I don't think it's possible to break up the loginflow in WordPress, but I may be wrong, I'll do some reading on the subject.

    I don't think remembering devices is a good idea, I think it's safe to say most WordPress installations run non-SSL, so any cookies giving special rights to one computer could easily become special rights on other computers.

    Best regards
    Henrik Schack

  3. eatingrules
    Member
    Posted 1 year ago #

    Funny, I've actually been thinking about doing SSL on my admin pages.. But I agree, the vast majority of WP installs will be non-SSL.

    Maybe it can be a combination of cookie & IP address? And perhaps it could be a global plugin option to enable/disable that functionality?

    As for breaking up the login flow, you'd probably have to get some redirection functionality in place, to intercept successful logons and then either ask for an authenticator code (or let them automatically bypass if they're on a remembered device).

    If you're able to crack both of these, it'll take the plugin to a whole new level of usability! :)

    Thanks again,
    Andrew

  4. icc97
    Member
    Posted 1 year ago #

    This is how WordPress.com does it. So you might be able to get some ideas from there, although I don't know how customised WordPress.com is vs WordPress.org

  5. Henrik Schack
    Member
    Plugin Author

    Posted 1 year ago #

    WordPress.com can modify the core files, I can't
    But if you have any ideas on how to make it work with a plugin, please let me know.

    Best regards
    Henrik Schack

  6. theApe
    Member
    Posted 11 months ago #

    I second, asking for the code on a second page if one is needed for the user.

  7. eatingrules
    Member
    Posted 11 months ago #

    @Henrik - Perhaps there's some logic or code you could utilize from this plugin?

    http://wordpress.org/extend/plugins/peters-login-redirect/

    Or maybe there's something useful in here?

    http://itswordpress.com/tips-tricks/redirecting-wordpress-users-after-login/

    Thanks!

    - Andrew

  8. Rouven Hurling
    Member
    Posted 11 months ago #

    what about something like this:

    in check_otp see if user has google authenticator activated
    if so check if user POSTed token and verify if he did
    and log in with the username from session and unset the saved username from session
    else remove the default wordpress login action,
    replace the login fields with token field
    and store username (or whatever is needed to log the user in later) in a session

    i'll try to get together an at least halfway working example as soon as possible

  9. Rouven Hurling
    Member
    Posted 11 months ago #

    okay, here are some actions and filters that should really help implementing something like this

    filter login_redirect
    check if global $user is valid and if he has activated google authenticator return url to wp-login.php?action=go (whicht triggers login_form_go action; also log the user back out and save info for later)

    action login_form_go
    verify post if exists and redirect or echo form (see wp-login.php for code example) and exit at the end to prevent duplicate due to switch statement after do_action in wp-login.php

    and this is what i got so far

    function loginredirect($url) {
        global $user;
        if ( !is_wp_error($user) && isset($_POST['log'], $_POST['pwd']) && trim(get_user_option( 'googleauthenticator_enabled', $user->ID ) ) == 'enabled' ) {
            wp_logout();
            session_start();
            $_SESSION['cred'] = array(
                'log' => $_POST['log'],
                'pwd' => $_POST['pwd'],
                'rememberme' => $_POST['rememberme']
            );
            wp_safe_redirect( wp_login_url() . '?action=go' );
            exit();
        }
        return $url;
    }
    
    function loginform_go() {
        session_start();
        var_dump($_SESSION['cred']);
        exit();
    }

    and this in init

    add_filter('login_redirect', array( $this, 'loginredirect' ) );
        add_action('login_form_go', array( $this, 'loginform_go' ) );
    
        #add_action( 'login_form', array( $this, 'loginform' ) );
        #add_action( 'login_footer', array( $this, 'loginfooter' ) );
        #add_filter( 'authenticate', array( $this, 'check_otp' ), 50, 3 );

    it disables google authenticator for now, but now almost the only thing left is copying the 'login' case statement and changing the fields (either write the credentials to hidden fields or leave them in session and pass to wp_signon

  10. Tunghsiao Liu
    Member
    Posted 11 months ago #

    +1 for a second page for authentication.

    I'm running a multisite so everyone has its own blog. I activate this plugin site widely to make sure my users know it has two-factor authentication support.

    But only some of them will use it, so I think the auth form should be disabled from the login page by default, and then show up for users who enable it in a second auth page is good idea.

    I also see some other plugins uses this way: http://wordpress.org/extend/plugins/im-login-dongle/screenshots/

    Thanks.

  11. James Collins
    Member
    Posted 11 months ago #

    I would love to see this implemented too.

    It is what is preventing us from using this plugin on our WordPress multisite installations.

    We'd like to have some user accounts using Multi Factor authentication, and all other users shouldn't see the third field on the login screen.

    The way WordPress.com implements this is great.

  12. Rouven Hurling
    Member
    Posted 11 months ago #

    okay,
    i don't really know if it's the best solution, but it works and i wouldn't know any other way to achieve this

    google-authenticator.zip

    i didn't test if it passes through users who don't have google authenticator enabled, but in theory that's what should happen^^

    it would be awesome if Hendrik could merge it into the plugin,
    until then you could use the version above

  13. Rouven Hurling
    Member
    Posted 11 months ago #

    i just fixed the bug that showed an empty error field, so here it is:

    google-authenticator.zip

  14. SlammedDime
    Member
    Posted 11 months ago #

    Rather than a second page, I would like to see something in the form of AJAX - when the username field is 'blured', run an AJAX call to see if that username requires OTP and if so, show the OTP box.

  15. icc97
    Member
    Posted 11 months ago #

    @SlammedDime, a big reason for the second page is to duplicate the functionality of WordPress.com on the basis that they've done some usability studies on the best way to implement it.

  16. Henrik Schack
    Member
    Plugin Author

    Posted 11 months ago #

    I like the AJAX solution, since it doesn't mess with the loginflow I supposed it would be much more likely not to break because of WordPress updates.

  17. Rouven Hurling
    Member
    Posted 11 months ago #

    okay,
    i guess it wouldn't mess with the loginflow in the way it happens now, which would be more future-proof, but i wouldn't really like it.

    furthermore:
    any plans of implementing something like a force mechanism (for example for different user levels or based on capabilities; example: users who have edit_them_options need to have google authenticator enabled)

  18. icc97
    Member
    Posted 11 months ago #

    If the login flow is going to be a problem, I imagine at some point the WordPress.org core will be updated to allow Google Authentication. Thinking about it - the AJAX solution would probably also suit the only request I wanted which was to be able to use the autologin from my password manager :)

  19. Rouven Hurling
    Member
    Posted 11 months ago #

    well, google authenticator and autologin would never work, since you can't store dynamically generated codes in your password manager (or can yours do that?).
    and if you have an extension for your browser it could happen that it breaks the AJAX solution, because it loads before the javascript for the ajax would load.
    then the 2nd page would be the only option

  20. icc97
    Member
    Posted 11 months ago #

    Ah, in WordPress.com - autologin takes me to the second page with the Google authenticator text box. But using this plugin it fails because the extra Google authenticator input needs to be filled.

    I'm guessing that with the AJAX solution the Google Authenticator input would be similarly hidden until after the login submit.

  21. hlwinkler
    Member
    Posted 10 months ago #

    Just wanted to put in another vote for this. This plugin is great and works exactly as advertised -- no complaints whatsoever, thank you Henrik. But I occasionally worry about whether some users signing up to my site in order to get support get confused by the authenticator field that doesn't apply to their account and don't log in and ask questions when they need to. It's also occurred to me that a second page is perhaps the only 100% reliable way to know who it should be shown to or not.

    However, a couple of other possibilities come to mind that might address the issue via easy UI changes instead of difficult refactoring:

    1. Address it with a UI textual hint. Instead of "Google Authenticator code" it could say "If you have enabled the optional Google Authenticator code, enter it below" or something along those lines.

    2. Instead of showing the field, show a button that says "I have turned on Google Auth for this account" and clicking or tapping it exposes the field inline, along with a button that says "I don't have a Google Auth code" that will hide it again. Just make sure that a user who needs auth but who hasn't pressed the button gets a prompt that they need to press the button and enter their auth or it will lead to a lot of support requests from people who forgot they turned auth on.

    Both of those approaches demonstrate to the casual user that it isn't a requirement for their login unless they have turned it on themselves.

  22. SlammedDime
    Member
    Posted 10 months ago #

    Here's a diff of the changes I made for AJAX support. Even supports lack of javascript support. I think this works really well and suits the purpose well of only showing to those who need it.

    --- google-authenticator (copy).php	2013-06-10 13:06:42.000000000 -0700
    +++ google-authenticator.php	2013-06-10 13:54:21.000000000 -0700
    @@ -61,8 +61,10 @@
         add_action( 'login_footer', array( $this, 'loginfooter' ) );
         add_filter( 'authenticate', array( $this, 'check_otp' ), 50, 3 );
    
    -    if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
    +    if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
             add_action( 'wp_ajax_GoogleAuthenticator_action', array( $this, 'ajax_callback' ) );
    +        add_action( 'wp_ajax_nopriv_check_otp_action', array( $this, 'ajax_check_otp' ) );
    +    }
    
         add_action( 'personal_options_update', array( $this, 'personal_options_update' ) );
         add_action( 'profile_personal_options', array( $this, 'profile_personal_options' ) );
    @@ -139,7 +141,7 @@
      * Add verification code field to login form.
      */
     function loginform() {
    -    echo "\t<p>\n";
    +    echo "\t<p id=\"google-auth\">\n";
         echo "\t\t<label title=\"".__('If you don\'t have Google Authenticator enabled for your WordPress account, leave this field empty.','google-authenticator')."\">".__('Google Authenticator code','google-authenticator')."<span id=\"google-auth-info\"></span><br />\n";
         echo "\t\t<input type=\"text\" name=\"googleotp\" id=\"user_email\" class=\"input\" value=\"\" size=\"20\" /></label>\n";
         echo "\t</p>\n";
    @@ -153,6 +155,29 @@
         echo "\ttry{\n";
         echo "\t\tdocument.getElementById('user_email').setAttribute('autocomplete','off');\n";
         echo "\t} catch(e){}\n";
    +    echo "jQuery(function($) {
    +            $('#google-auth').hide();
    +            $('#user_login').on('blur', function() {
    +                if ($(this).val() != '') {
    +                    var data = {
    +                        action: 'check_otp_action',
    +                        user: $(this).val()
    +                    };
    +                    $.post(
    +                        '", admin_url('admin-ajax.php'), "',
    +                        data,
    +                        function(response) {
    +                            if (response == true) {
    +                                $('#google-auth').slideDown();
    +                            } else {
    +                                $('#google-auth').slideUp();
    +                            }
    +                        },
    +                        'json'
    +                    );
    +                }
    +            });
    +        });";
         echo "</script>\n";
     }
    
    @@ -492,6 +517,17 @@
     	die();
     }
    
    +/**
    + * AJAX Callback to determine if user should have OTP
    + */
    +function ajax_check_otp() {
    +	$user = get_user_by( 'login', $_POST['user'] );
    +
    +	// Does the user have the Google Authenticator enabled ?
    +	echo json_encode(trim(get_user_option( 'googleauthenticator_enabled', $user->ID ) ) == 'enabled');
    +    die();
    +}
    +
     } // end class
    
     $google_authenticator = new GoogleAuthenticator;
  23. Ian Dunn
    Member
    Posted 5 months ago #

    +1 for this, showing the input field to users who don't have it enabled is confusing and prevents me from using the plugin on multi-user sites. We're also considering using this on WordPress.org itself, but it will have to be on the second page or we'd get an insane amount of support requests because of it.

    I think the AJAX approach is a bad idea because it leaks whether or not the user has 2FA enabled, which will help an attacker. Imagine if an attacker knows that a site has 3 administrator and know their usernames. He can simulate the AJAX call for each of them and then target the one that doesn't have 2FA enabled.

    I don't think we should really worry about the feature breaking because of WordPress updates. WP is very good at maintaining backwards compatibility; usually the only times a plugin breaks is if the plugin is doing something the wrong way.

    Using the actions in wp-login.php to inject an extra step into the login process isn't exactly a supported use case, but it's not that crazy either. I've built plugins for clients in the past that did similar things to this, and I can't foresee any changes to Core that would break it.

    In fact, that's how we do it on WordPress.com; it's just a plugin that hooks into wp_login, login_form_{action}, etc.

    Henrik, I'd be happy to refresh Rouven's code and turn it into a patch for this, if you're open to it. What do you think?

  24. Rouven Hurling
    Member
    Posted 5 months ago #

    @iandunn: I would love to help with that (if i can).
    maybe that would be a start for me to contribute to WordPress (which i wanted to do for quite some time, but didn't really know where to start^^)

  25. Ian Dunn
    Member
    Posted 5 months ago #

    Yeah, that'd be awesome :) A good place to start would be to do an SVN checkout of the plugin's trunk, apply your existing code to it, then create a patch that can easily be applied by others who want to test it out and contribute. Upload the patch somewhere and add a link to it here.

    There's also lots of resources available for contributing to WordPress itself. If you're interested in Core, the Core Contributor Handbook is a great place to start. There are tons of other ways to get involved too, from working on the community websites (WordPress.org, WordCamp.org, WordPress.tv, etc), documentation, reviewing plugins and themes, translation, etc. Check out make.wordpress.org for more details.

    There's also the #wordpress-getinvolved channel on Freenode IRC if you'd like to chat with people about getting involved.

  26. Rouven Hurling
    Member
    Posted 5 months ago #

    okay, did that and uploaded my patch
    I'm pretty sure it doesn't go with the WordPress Coding Standards and I'm using the php Session, but that was mostly was just a quick'n'dirty solution which I wrote months ago.

  27. Ian Dunn
    Member
    Posted 4 months ago #

    Henrik hasn't responded to this lately, so I went ahead and made a new plugin to do this instead of trying to get a patch in. It runs alongside Google Authenticator and modifies the login workflow so that only users with 2FA enabled are prompted.

    It's available at http://wordpress.org/plugins/google-authenticator-per-user-prompt/

    I'm also offering a security reward if anyone can find a vulnerability in it.

    If you have any questions or feedback, or run into any problems, please post them in the support forums for the new plugin.

Topic Closed

This topic has been closed to new replies.

About this Plugin

About this Topic