Please upgrade here. These earlier versions are no longer being updated and have security issues.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.
Options

$100 - Helper Class for External Authentication Integration

2

Comments

  • Options

    Thanks for the reply @hbf,

    you really dont need vanilla

    Agree, wish I had just written my own basic forum given the time spent bug fixing/trawling Vanilla's code. That said I'm using the entire themed vanilla forum (views etc), I just want it to login when I login with the other app and think requiring two logins for one site is bad-practise.

    Perhaps feasible to intercept the ReadUser function and make it point to AppSite User Database? Instead of having the GDN_User table just intercept all read/write's and return custom.

  • Options

    I think I go back to the original point, which is you need to pay someone to do the SSO for you. You might streamline the SSO somewhat. What you want is secure sessions, with user management, there are a number of ways of achieving this. ProxyConnect is a methodology, implementations may vary.

    I applaud you for making the effort, and giving it a go, but you need some expertise to debug it for you, and possibly make it streamline.

    You don't actually want to replicate all the forum functionality, this would be expensive and unnecessary.

    I tried my best not to mock you I was just trying to steer you in the right direction, and first find out what you real wanted to do.

    grep is your friend.

  • Options

    Done. Set the provider key from proxy connect and it automagically creates a new user and logs them in.

    Provider key comes from GDN_UserAuthentication table.

    http://pastebin.com/rf4gz6Gu

    <?php
    /*
       Vanilla Forum Helper Functions
    */
        class appForum {
    
            function __construct(){
                define('APPLICATION', 'Vanilla');
                define('APPLICATION_VERSION', '2.0.18.4');
                define('DS', '/');
                define('PATH_ROOT', 'forum');
            }
    
            /*
            *   Set the vanilla session as logged in with this user object.
            */
            public static function setLoggedIn($bLoggedIn, $cUser, $iVanillaUserID = -1) {
                
                ob_start();
                require_once(PATH_ROOT.DS.'bootstrap.php');
                ob_end_clean();
                
                $cAuthenticator = new Gdn_PasswordAuthenticator();
                
                //Get the vanilla ID:
                if ($iVanillaUserID == -1) {
                    $cUserAuth = mysql_query("SELECT * FROM GDN_UserAuthentication WHERE ForeignUserKey = ? LIMIT 1", array($cUser['id']));
                    $iVanillaUserID = $cUserAuth['userid']; //UserID
                }
                
                //Set cookie: persist login for a month
                $cAuthenticator->SetIdentity($iVanillaUserID, true);
                Gdn::Authenticator()->Trigger(Gdn_Authenticator::AUTH_SUCCESS);
            }
                    
            /*
            *   Check if user is logged in, if so return user model.
            */
            public static function loggedIn() {
                
                ob_start();
                require_once(PATH_ROOT.DS.'bootstrap.php');
                ob_end_clean();
                
                $Session = Gdn::Session();
                $Authenticator = Gdn::Authenticator();
                if ($Session->IsValid()) {
                    return true;
                } else {
                    return false;
                }
            }
                    
            /*
            *   Log out of the user's account:
            */
            public static function logout($sCookiePath = '/', $sCookieDomain = '.mydomain.com') {
                $iPastTime = time() - 24 * 60 * 60;
                setcookie('Vanilla', ' ', $iPastTime, $sCookiePath, $sCookieDomain);
                setcookie('VanillaSessionID', ' ', $iPastTime, $sCookiePath, $sCookieDomain);
                setcookie('Vanilla-Volatile', ' ', $iPastTime, $sCookiePath, $sCookieDomain);
                unset($_COOKIE['Vanilla']);
                unset($_COOKIE['Vanilla-Volatile']);
                unset($_COOKIE['VanillaSessionID']);
                session_destroy();
                $_COOKIE = null;
            }
    
            /*
            *   Manually insert a user into the vanilla tables:
            */
            public static function createUser($iUserID, $sName, $sEmail, $sPassword, $sProviderKey = "my provider key here") {
                ob_start();
                require_once(PATH_ROOT.DS.'bootstrap.php');
                ob_end_clean(); // clear any header output from vanila
    
                $User = new UserModel();
    
                $iVanillaUserID = $User->InsertForBasic(
                    array('Email'=>$sEmail, 'Name'=>$sName, 'ShowEmail'=>'0', 'Gender'=>'m', 'Password'=>$sPassword, 'Preferences'=>'a:1:{s:13:"Authenticator";s:5:"proxy";}'),
                    FALSE,
                    array('ValidateEmail' => FALSE, 'NoConfirmEmail' => TRUE)
                );
    
                if ($iVanillaUserID) {
                    // Save the authentication - different array keys to the database...igits.
                    $User->SaveAuthentication(array(
                        'UniqueID' => $iUserID,
                        'Provider' => $sProviderKey,
                        'UserID' => $iVanillaUserID
                    ));
                    
                    //Set user logged in:
                    appForum::setLoggedIn(true, null, $iVanillaUserID);
                }
    
                //Save the vanilla ID to your own user database to call for setLogin later.
                return $iVanillaUserID;
            }
    
            /*
            *   Vanilla User Is logged iN
            */
            public static function VanillaAuth() {
                
                ob_start();
                require_once(PATH_ROOT.DS.'bootstrap.php');
                ob_end_clean(); // clear any header output from vanila
                
                $Session = Gdn::Session();
                $Authenticator = Gdn::Authenticator();
                if ($Session->IsValid()) {
                    return $Session->User;
                } else {
                    $Authenticator = Gdn::Authenticator()->GetAuthenticator('proxy');
                    $Authenticator->Authenticate();
                }
            }
    
        }
    ?>
    
  • Options

    glad you persevered.

    grep is your friend.

  • Options

    What for us, then, with no code expertise despite our envy having even close to that $100 amount at the same time? @jaredNZ, would you kindly show us some guidelines or modify and make up a full -and working- vanilla plugin?

  • Options
    EdelAliEdelAli New
    edited June 2013

    /me with that @jaredNZ . newb , now I feel even more

  • Options
    businessdadbusinessdad Stealth contributor MVP

    Well done @jaredNZ. I see that you reused existing Vanilla libraries, I think it's the best way.

    By the way, the Systems Hungarian notation brings back memories... :)

  • Options
    x00x00 MVP
    edited June 2013

    @businessdad said:
    Well done jaredNZ. I see that you reused existing Vanilla libraries, I think it's the best way.

    By the way, the Systems Hungarian notation brings back memories... :)

    true

    @jaredNZ

    I'd maybe change this

     $cUserAuth = mysql_query("SELECT * FROM GDN_UserAuthentication WHERE ForeignUserKey = ? LIMIT 1", array($cUser['id']));
    $iVanillaUserID = $cUserAuth['userid']; //UserID
    

    You could use Gdn::SQL() query builder with PDO, and mysql_query is depreciated. I'm not sure what you are trying to do here becuase the second parameter is supposed the connection identifier. You don't get the data from the query unless you fetch the row.

    grep is your friend.

  • Options
    hgtonighthgtonight ∞ · New Moderator

    @jaredNZ Thanks for sharing!

    Don't forget to pay out that bounty ;)

    @EdelAli said:
    What for us, then, with no code expertise despite our envy having even close to that $100 amount at the same time? jaredNZ, would you kindly show us some guidelines or modify and make up a full -and working- vanilla plugin?

    This would be a nesting situation of loading the framework inside the framework. the line require_once(PATH_ROOT.DS.'bootstrap.php'); is the key line that is in each function. If you were to take out the lines:

    ob_start();
    require_once(PATH_ROOT.DS.'bootstrap.php');
    ob_end_clean();
    

    from each function, you could call these functions from any Vanilla plugin.

    Search first

    Check out the Documentation! We are always looking for new content and pull requests.

    Click on insightful, awesome, and funny reactions to thank community volunteers for their valuable posts.

  • Options

    Thanks,

    @x00 -- mysql_query is just a placeholder, I have my own SQL sanitizer on the application I removed it from this copy-paste since it wouldn't make sense. Please do take this and replace parts to make it use Vanilla SQL.

    @EdelAli -- This is more like a plugin for an external application/website/blog etc. Its not a plugin for vanilla. You could embed this in Vanilla but it wouldn't make sense I don't think? Vanilla plugins work with events, so you can't have an event trigger a user login, or an event creating a new user?

    e.g. WordPress > inside the wordpress createUser function > insert line forum.createUser(...);

    @businessdad -- I like hungarian for PHP, JS - Languages without strong typing built in sort of need it. Especially PHP which is so "flexible".

  • Options
    businessdadbusinessdad Stealth contributor MVP

    @jaredNZ I haven't used Hungarian Notation in a long time, simply because I didn't find it useful, despite all the attempts of my Professors and some of my former bosses to enforce it. Application Hungarian made some sense, Systems Hungarian not so much (wparam and lparam of Windows API are examples of that). Personally, I don't really care what the type of a variable is, I care about what information it carries.

    Anyway, mine was not a criticism, just a "reminiscence". Everybody is free to use the notation and coding style he/she prefers. For example, I also develop for WordPress, but I can't stand "Yoda" comparisons, and I dislike spaces used within parentheses (as in if ( SomeFunc( SomeVar ) )), so I don't use them. :)

  • Options

    I don't really care what the type of a variable is, I care about what information it carries

    Its for other developers reading the code later, for example:

    function login(variable) {
     ... 
    }
    

    "variable" is an argument to a function -- without looking anywhere else, what information does "variable" carry? Code must be discrete and modular according to good OOP practises.

    vs.

    bVariable carries ? boolean.
    sVariable carries ? string.
    iVariable carries? integer.

    The only real debate about hungarian is whether the extra information about the information it carries is worth making the variable name slightly less readable.

  • Options
    businessdadbusinessdad Stealth contributor MVP
    edited June 2013

    @jaredNZ said:
    The only real debate about hungarian is whether the extra information about the information it carries is worth making the variable name slightly less readable.

    In my opinion, the type is still irrelevant, as it might change later. That's why I find Systems Hungarian pointless. Besides, if the function is documented properly, there is no need to carry type information within its name.

    /**
     * The function does something.
     * 
     * @param int UserID A User ID.
     * @return some_type The User ID of User's cousin.
     */
    function MyFunction($UserID) {
      // UserID contains a UserID, which will be passed to methods and classes who can handle it. If that 
      // is an integer, a string, a float or a class, I don't really care, as I need to know how to use it anyway.
      // Besides, just calling the variable $iUserID won't prevent anybody from passing another thing.
    }
    

    In case a variable has to be of a specific type, one can use Type Hinting:

    function MyFunction(array $SomeVar) {
    }
    
    function MyFunction(SomeClass $SomeVar) {
    }
    
  • Options

    @businessdad - it would've been lovely to see those comments in Vanilla =P... Perhaps you can go through and add them?

  • Options
    businessdadbusinessdad Stealth contributor MVP

    @jaredNZ said:
    businessdad - it would've been lovely to see those comments in Vanilla =P... Perhaps you can go through and add them?

    I add them in every piece of code I write. Actually, some of my pastime, when I sip coffee during breaks, is looking for method that I forgot to document and fix the issue. I'm afraid that documenting the whole Vanilla Core would take me more time than I have left to live. :D

  • Options
    LincLinc Detroit Admin

    You really want to use jsConnect for single sign on.

    ProxyConnect is deprecated and will be deleted one day.

    Hacking a new solution ain't a great plan. We integrate many, many SSO solutions on a weekly basis, and they are nearly all based on jsConnect.

  • Options
    LincLinc Detroit Admin

    @businessdad said:
    I'm afraid that documenting the whole Vanilla Core would take me more time than I have left to live. :D

    Possible. I've added hundreds of lines of documentation to core and it's still eons from done. I play a game where anytime I'm flying somewhere I write inline docs during the flight and tag it with what airports I was flying between.

  • Options

    @jaredNZ said:
    businessdad - it would've been lovely to see those comments in Vanilla =P... Perhaps you can go through and add them?

    That could be a community effort once everyone knows how github works and when there's a separate branch for documentation

    Besides : we know how the community Wiki is going so need a special someone to lead the documentation community. Also I wouldn't expect documentation with 2.1 until it goes really really beta or beyond

    There was an error rendering this rich post.

  • Options
    LincLinc Detroit Admin
    edited June 2013

    @UnderDog said:
    when there's a separate branch for documentation

    You can document directly on master or whatever branch you fancy, really. It's not like we'll turn it down because of performance concerns. :D Just match the format of the rest of it closely. Have a look around a lot of files so you get the patterns involved.

  • Options

    @Lincon Hacking a new solution ain't a great plan.

    This is something you don't have at the moment, not a hack of past methods. This is to integrate with outside websites.

    And sorry but jsConnect is just lazy and bad practise. I implemented it already as mentioned at the top of the discussion:

    1 - It requires action from the user to sign up when they already are a member on your site

    2 - Requires JS pings back and forth to server to do the auth using data on client side... insane?!
    These are just PHP files accessing a database. There's no reason you need to do this client-side.

    ProxyConnect is deprecated and will be deleted one day.

    If you actually read the code you'll see it doesn't use ProxyConnect at all. Just the key for provider table which can be anything.

This discussion has been closed.