We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 26334
    • 77 Posts
    OK I am trying to get a single sign on working with Facebook / Google etc for front end membership.

    I have read through the OpenGeek version here:
    https://github.com/opengeek/engaged

    I am trying to get my head around a few things.

    JanRain simply return (in the simplest form):
    - username
    - email address
    - unique identifier

    Now I understand that at that point we have to:
    1) Check if that email address or unique identifier exist on our system. If so then log them in.

    2) If not create their account and log them in.

    Looking through the login snippet I can’t work out what the actual login command is. It appears to be:
    $authenticated = $modx->user->isAuthenticated($loginContext);

    In that by that point that returns authenticated = 1 so they seem to be logged in. I can’t work out where the username and password are passed, where they are checked and sessions set. I have spent the last day and a half reading doco but can’t get any closer.

    Can someone point me towards the process of taking a username / password and logging the person in. Obviously in this instance it will be a different combination as we wont be getting their modx password but rather a unique identifier and email address or username (or both).

    I am guessing it is part of the modUser section but can’t fathom how to do the check and complete the login.

    ---
    Secondly

    With the registering of the user from OpenGeeks work I see that he does this:
                    if (!$user) {
                        /* create a new rpxUser */
                        $user = $modx->newObject('rpxUser');
                        $user->fromArray(array(
                            'username' => $rpxProfile['preferredUsername']
                            ,'active' => true
                            ,'remote_key' => $rpxIdentifier
                            ,'remote_data' => $rpxProfile
                        ));
                        $profile = $modx->newObject('modUserProfile');
                        $profile->fromArray(array(
                            'email' => isset($rpxProfile['email']) ? $rpxProfile['email'] : ''
                            ,'fullname' => isset($rpxProfile['displayName']) ? $rpxProfile['displayName'] : (isset($rpxProfile['preferredUsername']) ? $rpxProfile['preferredUsername'] : $rpxIdentifier)
                        ));
                        $user->addOne($profile, 'Profile');
                        $saved = $user->save();
                    }


    Is that just inserting into the modx_users table with a class_key off ’rpxUser’ instead of ’modUser’ and if so why do that? Is that just to identify them as not having registered locally rather by Janrain? Does it have any other implications or am I reading that totally wrong? Or is it inserting into a separate database table of rpxUser and if so how does he complete the login as per (1) above?

    Thanks.
      • 26334
      • 77 Posts
      OK seems heaps of people are asking about this on heaps of different threads and there is nothing but silence.

      Can someone point me towards the process of taking a username / password and logging the person in.

      From reading the code of the login snippet it seems to be encapsulated in this:
      $authenticated = $modx->user->isAuthenticated($loginContext);

      now $loginContext is just the domain of interest. Where/how is the username/password passed to what module where and how to log the person in. Clearly at some stage the username and password have to be checked against the DB and if they match then something is done to trigger that the person is logged in, some sessions setup or something. Is there any doco on that anywhere? Can someone point me to the code that does it so I can reverse engineer it please because I have searched and searched and can’t find it.

      If it is in isAuthenticated - where do I find that, and how does it get the username/password - I am assuming that would be clear enough in there.

      I am quite capable at php so that isn’t an issue but tracking down where to look is the challenge at this stage.

      Thanks.
        • 28215
        • 4,149 Posts
        I cant explain in detail, but a bulk of the auth method in Revo is done by extending modUser, and utilizing the OnUserNotFound and OnWebAuthentication (or OnMgrAuthentication) events.

        You might want to look into the modActiveDirectory Extra I made, which does kind of what you’re doing. You can find the code here:

        https://github.com/splittingred/modActiveDirectory

        Sorry I can’t provide more at the moment. We’ll definitely try and get more documentation on this as we finish some other priorities. Thanks.
          shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
        • Lines 71 through 76 of the rpx snippet do the logging in...
          <?php
                      if ($user && ($user instanceof rpxUser) && $saved) {
                          $modx->log(modX::LOG_LEVEL_INFO, 'RPXNow logging in remote user into contexts: ' . print_r($contexts, true));
                          foreach ($contexts as $context) {
                              $user->addSessionContext($context);
                          }
                      }
          ?>
            • 26334
            • 77 Posts
            Thanks. Got called away on another job for a few days and back on it now.

            So if I look in the doco:
            http://rtfm.modx.com/display/revolution20/modX

            $modx->log is not defined.

            What I understand from your quoted extract of the snippet is:

            if $user passes your test (is a user, and part of the rpxuser group and $saved (not sure what that is checking))

            Then do this undefined log function which I am guessing has something to do with identifying what contexts they have access to, so similar to modUser::getSessionContexts ??

            Then for each of those contexts you addSessionContext to the user.

            The addSessionContext does that then actually then "log them in" so that if you then do a user logged in check they will now be seen as logged in whereas before the addSessionContext they aren’t?

            Thanks for your help on this, just trying to get my head around what is actually happening here.

            So if I check their unique id from Janrain which I have stored and their username and that checks against my user list in my modx_users table then I can simply define a user of that username and addSessionContext of the appropriate context for them and they will then be "logged in"?
              • 26334
              • 77 Posts
              As an addon to that - the login package that is standard with modx has this process:

              $corePath = $modx->getOption('login.core_path',$scriptProperties,$modx->getOption('core_path',null,MODX_CORE_PATH).'components/login/');
              $login = $modx->getService('login','Login',$corePath.'model/login/',$scriptProperties);
              
              if (!is_object($login) || !($login instanceof Login)) return '';
              
              $output = '';
              $modx->lexicon->load('login:default');
              
              /* setup default properties */
              $preHooks = $modx->getOption('preHooks',$scriptProperties,'');
              $loginTpl = $modx->getOption('loginTpl',$scriptProperties,'lgnLoginTpl');
              $logoutTpl = $modx->getOption('logoutTpl',$scriptProperties,'lgnLogoutTpl');
              $loginMsg = $modx->getOption('loginMsg',$scriptProperties,'');
              $logoutMsg = $modx->getOption('logoutMsg',$scriptProperties,'');
              $tplType = $modx->getOption('tplType',$scriptProperties,'modChunk');
              $actionKey = $modx->getOption('actionKey',$scriptProperties,'service');
              $loginKey = $modx->getOption('loginKey',$scriptProperties,'login');
              $logoutKey = $modx->getOption('logoutKey',$scriptProperties,'logout');
              $errorPrefix = $modx->getOption('errorPrefix',$scriptProperties,'error');
              $errTpl = $modx->getOption('errTpl',$scriptProperties,'lgnErrTpl');
              $errTplType = $modx->getOption('errTplType',$scriptProperties,'modChunk');
              $rememberMeKey = $modx->getOption('rememberMeKey',$scriptProperties,'rememberme');
              $loginContext = isset($_REQUEST['login_context']) && !empty($_REQUEST['login_context']) ? $_REQUEST['login_context'] : $modx->context->get('key');
              $contexts = !empty($scriptProperties['contexts']) ? $scriptProperties['contexts'] : '';
              $contexts = !empty($_REQUEST['add_contexts']) ? $_REQUEST['add_contexts'] : $contexts;
              
              //echo '<h4>here, authenticated =  '.$authenticated.'</h4>';
              $authenticated = $modx->user->isAuthenticated($loginContext);
              //echo '<h4>here, authenticated =  '.$authenticated.' context = '.$loginContext.'</h4>';


              The first bits are all obvious and getting information passed as hooks, then we get to $loginContext which presumably gets the context from the db from modx_context table. Not sure how it knows which one to get here.

              Can’t work out what the next 2 lines are doing - the $contexts

              Then the 2 echos - the first one they are not logged in, the 2nd they are and $loginContext is set to the current context correctly.

              But where is the username and password checked? It must be in there somewhere but stuffed if I can work out where!

              So is my other option to check the username and unique id as returned by JanRain and if they match then simply :
              $authenticated = $modx->user->isAuthenticated($loginContext);

              where the loginContext is the one I want them logged into?

              Am I missing something crucial here that will open up a security hole for me?
              • Quote from: scarfy96 at Nov 17, 2010, 04:31 AM

                So if I look in the doco:
                http://rtfm.modx.com/display/revolution20/modX

                $modx->log is not defined.
                It’s not undefefined; it’s inherited from the xPDO class, which modX extends.

                Quote from: scarfy96 at Nov 17, 2010, 04:31 AM

                What I understand from your quoted extract of the snippet is:

                if $user passes your test (is a user, and part of the rpxuser group and $saved (not sure what that is checking))

                Then do this undefined log function which I am guessing has something to do with identifying what contexts they have access to, so similar to modUser::getSessionContexts ??

                Then for each of those contexts you addSessionContext to the user.

                The addSessionContext does that then actually then "log them in" so that if you then do a user logged in check they will now be seen as logged in whereas before the addSessionContext they aren’t?

                Thanks for your help on this, just trying to get my head around what is actually happening here.

                So if I check their unique id from Janrain which I have stored and their username and that checks against my user list in my modx_users table then I can simply define a user of that username and addSessionContext of the appropriate context for them and they will then be "logged in"?
                No, JanRain is different from the Login snippet. You are not passing username/password ever. JanRain handles that and returns either a successful or unsuccessful result. All you have to do is add the user data (minus the password, since you never need the password locally), capture any external data you want to, and simple addSessionContext for whatever contexts you want the user to be logged into when JanRain returns a successful result.
                  • 26334
                  • 77 Posts
                  Quote from: OpenGeek at Nov 17, 2010, 05:55 AM
                  No, JanRain is different from the Login snippet. You are not passing username/password ever. JanRain handles that and returns either a successful or unsuccessful result. All you have to do is add the user data (minus the password, since you never need the password locally), capture any external data you want to, and simple addSessionContext for whatever contexts you want the user to be logged into when JanRain returns a successful result.

                  Yes I realise this - if JanRain returns success it returns the username and a unique id (google id or facebook id etc) along with some other data if requested.

                  Now if that username exists in my database I then need to check if the unique id matches otherwise it is another user with that username and I have to deal with that separately - creating another user for example. So I can do that check. If it matches OK then all I need to do is addSessionContext for that user?

                  That is then effectively "logging them in" so to speak so that modx recognises that user as logged in if I then want to pull other info from their profile (ie I use JanRain to log them in but they also have the option to update their profile with other information that I can then use to personalise some of the pages for them depending on the preferences they set there - so on other pages I would then be able to use $modx->user type commands if needed?).

                  Thanks.
                  • Quote from: scarfy96 at Nov 17, 2010, 06:09 AM

                    Now if that username exists in my database I then need to check if the unique id matches otherwise it is another user with that username and I have to deal with that separately - creating another user for example. So I can do that check. If it matches OK then all I need to do is addSessionContext for that user?

                    That is then effectively "logging them in" so to speak so that modx recognises that user as logged in if I then want to pull other info from their profile (ie I use JanRain to log them in but they also have the option to update their profile with other information that I can then use to personalise some of the pages for them depending on the preferences they set there - so on other pages I would then be able to use $modx->user type commands if needed?).
                    Yep, just addSessionContext() for each context you want them authenticated in.

                    Figuring out how to handle duplicate usernames and/or email addresses is what I had left to accomplish in the engaged code I published on GitHub. Once that is solved, it should be ready for general use.

                    So, once you get a successful JanRain login and add the user to the table, you can act on that User object like any other in the system, minus password reset handling at least (since you would not be storing/managing their password).
                      • 26334
                      • 77 Posts
                      Excellent. Thanks for that. Should be able to get that all up and running now with no major issue from here.

                      Much appreciated.