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

Implementing SSO with Vanilla forums

Good Afternoon.

I am building a community site that comprises of various third party technologies and custom code. We want the user experience to be seamless across these technologies and are looking to implement SSO. I have done this already with Magento and it was pretty straight forward however I'm struggling to understand how this is best achieved with Vanilla.

My requirements:

  • The solution is not dependent on JavaScript.
  • We extend Vanilla in a way that allows us to maintain and patch the software.
  • The login functionality of Vanilla is disabled so the only way to log in would be through the single sign on service.
    • Users would never log directly into Vanilla.
    • Links to login would re-direct back to the SSO page

I've managed to achieve this in Magento as follows:

  • Create an observer for the controller_front_init_before event in Magento (this happens sufficiently early enough in the code flow that Magento is initialised however no controller has yet been loaded to facilitate the request)
  • Check the shared $_SESSION for a 'Logged-in User' object

    • If one exists then the user has authenticated themselves.
    • We then use the details in $_SESSION to log the user in automatically
  • If a user exists in the shared $_SESSION but no Magento user is found then we create a new user in Magento and log that user in.

Ideally I'd need to be able to so something similar to this in Vanilla (ie load / create accounts and automatically log a user in)

After some research, I'm not confident this is something that can be easily achieved with Vanilla and wondered if anyone else had been able to achieve this or if anyone is able to point me in the right direction?

Also, apologies if this is in the wrong place, I attempted to post to the developer list but I do not have the correct permission.

Cheers
Rob.

Tagged:
«1

Comments

  • Options
    hgtonighthgtonight ∞ · New Moderator

    If I can't do this via JS, and I want it to be completely seamless, I would create a new authenticator that uses the $_SESSION super global. Copy the /library/core/authenticators/class.passwordauthenticator.php file and start hacking away.

    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

    Garden Sessions do not use $_SESSION

    grep is your friend.

  • Options

    Hi thanks for your replies.

    @‌hgtonight - Thanks - I'm looking at this class now - so far I have written a plugin that hooks into the AppStartup event. This is able to load my Authentication Service which checks to see if a user is logged in - (a user object exists in the current user's $_SESSION) - so from here are you suggesting I overwrite the Gdn_PasswordAuthenticator::authenticate() method and then call that from my plugin? - If so is there a 'correct' way to do this - I am reluctant to 'start hacking away.' - I started looking at Vanilla yesterday and wondered if I'm missing some obvious resources - for example, I can't find much information about the Garden framework apart from a series of blog articles from the creator - which while interesting are not particularly insightful...

    • It is not clear how you programmatically create a new User - this would ideally be using Vanilla/Garden and not writing a user to the database manually.

    @x00‌ Thanks for the heads up - so assuming that session data is stored in the database and not on the webserver itself - I don;t suppose it's possible to move the session over to something like Memcache??

    Cheers for the help guys I'm really keen to use Vanilla - but am struggling with the lack of proper documentation - am I missing something or is this everything: http://docs.vanillaforums.com/developers/

    Thanks for your time,
    Rob.

  • Options
    x00x00 MVP
    edited September 2014

    First the data passed between request is linked to a special cookie which has nothing to do with the authentication related cookie. That data is only stored when needed in the GDN_Session table. This is used quite sparingly however. Don't confuse it with validating sessions.

    The main authentication uses HMAC, which is means it doesn't need to be "stored" on the server at all. Storing authentication sessions on the server make it vulnerable to certain attacks.

    HTTP is stateless the session status is purely abstract construct. There is no "Logged On".

    What you need to check the session is valid is the hmac algo, which is now native to PHP, plugging in the data the comes with the cookie, plus the cookie salt to create a hash which you compare with the hash that comes with the cookie. You also need to a timing attack proof comparison as if you use the normal equals operator you will be vulnerable to timing attack (think similar to listening for clicks on a dial safe)

    grep is your friend.

  • Options

    But anyway, you don't actually need to check vanilla sessions it does that for you, what you want is to initiate the session. There is a standalone gist for creating the cookie.

    But what you really need to cover is the user creation.

    grep is your friend.

  • Options

    @x00 - thanks for the reply struggling with some of this:

    While I appreciate HTTP is a stateless protocol - I'm not quite following what you are describing.

    • Is there a way to programmatically log a user in to Vanilla for the duration of the request (I have the user stored in the PHP global session so can re-authenticate on each page request to Vanilla no issue)

    • Is there a way to programmatically create a new user in Vanilla?

  • Options

    There is no logged in. If the cookie can be validated then the session is valid. This is per request.

    grep is your friend.

  • Options

    Basically if the cookie is not there create it.

    grep is your friend.

  • Options

    Interesting - thanks for your time.

  • Options

    Is there a way to programmatically create a new user in Vanilla?

    You can force load vanilla, to create a user. Just don't force load all the time, just when needed.

    You can also implement a connect method like jsConnect works but server to server.

    There is and API application that would also work, but as I understand it is for 2.2 which is not stable.

    grep is your friend.

  • Options
    hgtonighthgtonight ∞ · New Moderator

    Creating your own authenticator solves this issue. Parse the $_SESSION variable. Look for a vanilla user with the same id, if it doesn't exist insert a new user via the user model. If it does, pass that id back to the system and let it handle the session normally (via the HMAC cookie).

    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

    What hgtonight said except wrap that in a very basic cookie detection, so you only do this when there is no cookie present.

    grep is your friend.

  • Options

    Once again, thanks for your help - plenty to be looking into! Cheers, Rob.

  • Options
    slRobertSslRobertS New
    edited September 2014

    Right - I've come back to this today - in principle I understand what you have said and have also found an article someone had posted attempting to do something similar with Vanilla and Code Igniter.

    https://ellislab.com/forums/viewthread/134946/

    I've been playing about with this but have a few questions about the $Configuration settings in conf\config.php - The article suggest you can do the following:

     $Configuration['AUTHENTICATION_MODULE'] = 'People/People.Class.CI_Authenticator.php';
     $Configuration['AUTHENTICATION_CLASS'] = 'Authenticator';
     $Configuration['SAFE_REDIRECT'] = '/uri/to/CI-app/login';
    
    // Path Settings
    $Configuration['SIGNIN_URL'] = '/uri/to/CI-app/login'; # uri as in $_SERVER['REQUEST_URI'] not the url.
    $Configuration['SIGNOUT_URL'] = '/uri/to/CI-app/logout/';
    
    // Vanilla Settings
    $Configuration['ALLOW_NAME_CHANGE'] = '0';
    $Configuration['ALLOW_EMAIL_CHANGE'] = '0';
    $Configuration['ALLOW_PASSWORD_CHANGE'] = '0';
    $Configuration['USE_REAL_NAMES'] = '0'; 
    

    But in Vanilla 2.1 these don't seem to change anything - also, all of the configuration for Vanilla 2.1 looks different - instead of being uppercase keys - there are multidimensional keys and these are lowercase.

    I'm starting to feel a bit of frustration - It's not the lack of support I've received here - more like the lack of documentation and the number of broken links you encounter trying to piece together bits of the puzzle. Telling users that Vanilla is built on top of a powerful framework is one thing - but trying to work with it is something else.

    What am I missing..?

    I found this page: http://docs.vanillaforums.com/developers/configuration/using/

    But is there a list of all the possible configuration settings and what they do?

    (I'm aware of the config-defaults.php file - have some config options been removed in later versions of Vanilla - if so, how do you safely replace classes?)

    Rob.

  • Options

    These are not garden or vanilla config values, atleast not since 2.0

    The configuration will not help you much here.

    I would suggest you take a look how the jsconnect plugin implements SSO:
    https://github.com/vanilla/addons/blob/master/plugins/jsconnect/class.jsconnect.plugin.php

    There is a "Connect" function in the entrycontroller
    https://github.com/vanilla/vanilla/blob/master/applications/dashboard/controllers/class.entrycontroller.php#L391

    On line 409 the Event "ConnectData" is fired

    Plugins can hook into that event to connect a user with vanilla.

    Take a look at how the facebook, openid or twitter sign in plugin does it. They should be a good start.

  • Options

    @slRobertS the example you seeing is to do with Vanilla 1 a completely different software.

    grep is your friend.

  • Options

    Yes - I had my suspicions it wasn't the version I'm using. It's just a shame there is an absence of solid and concise development resources for the latest version of Vanilla - I've done some more reading around - is it true the Community version is several versions behind the SaaS version?

  • Options
    x00x00 MVP
    edited September 2014

    The OS version is 1 version release (not update) behind the SaaS, as odd numbers are for OS, and even for the SaaS. I think that is fair, becuase it will only be stable on that platform.

    Here is a hacky way you can do it.

    <?php 
    // no cookie?
    if(!array_key_exists('Vanilla', $_COOKIE)){// Or whatever the cookie is called
        define('APPLICATION', 'Vanilla');
        define('APPLICATION_VERSION', '2.1.1');
        define('DS', '/');
        define('PATH_ROOT', '/path/to/forum');
        ob_start();
        require_once(PATH_ROOT.DS.'bootstrap.php');
        ob_end_clean(); // clear ouput
    
        // if has vanilla user id stored with user
        if($VanillaUserID){
            //if no valid session or wrong user
            if(!Gdn::Session()->IsValid() || Gdn::Session()->User->UserID!=$VanillaUserID){
                Gdn::Authenticator()->SetIdentity($VanillaUserID, TRUE, TRUE);
            }
            //var_dump(Gdn::Session()->User);
        }else{
            //create vanilla user 
            //store vanilla user id with site user
        }
    
    }
    

    Alternatively to you could recreate the cookie creation, and only force load when you need to create a user.

    You will still need to tie up loose ends such as the entry hardening on vanilla side.

    grep is your friend.

  • Options
    slRobertSslRobertS New
    edited September 2014

    I worry about the word 'hack' id much prefer to do this by extending Vanilla and hooking into the plugin system.

    I've written a plugin that hooks into the AppStartup event. I believe this is fired after Vanilla has bootstrapped itself but before any controller action is called. This is called every time a user access the forum. So, all good so far.

    After here - I'm not quite sure what I should be doing. I've looked at the various SSO plugins but they all depend on the user initiaiting the login event and then responding to that. In my application - the login has already happened.

    I'm not sure if I'm thinking in Vanilla terms - but im expecting to do the following:

    • Check for a logged in user
      • If one is found, check if that user exists with Vanilla
      • If the user does exist with Vanilla call (something?) which triggers the login cookie to be created - allowing Vanilla to recognise a user has authenticated.
      • If the user DOES NOT exist then we create a user (ideally using Vanilla to do so rather than writing data into tables) and then log that user in.

    @‌ If I can retrieve the internal id Vanilla uses to identify users then I can authenticate a user using this line

    Gdn::Authenticator()->SetIdentity($VanillaUserID, TRUE, TRUE);
    

    Great! - similarly I would also be able to create a user - I'd expect to use the UserModel here but there is no method for creating a user - so again, I appear to be looking in the wrong place.

    You will still need to tie up loose ends such as the entry hardening on vanilla side.

    I was planning on doing this by removing links in the template and then overriding the handlers for the login event. Is it possible in Vanilla 2.1 to extend classes (like it appears to be in the example from version 1)

    In all honesty - I've spent quite a bit of my week getting nowhere with Vanilla. I'm disappointed. No reflection on the community - you've all been great - but I'm asking rudimentary questions about things because there is very little documentation - for someone without any previous exposure to the development of Vanillla, from version 1 to version 2.1 some of the things you talk about are not obvious or particularly developer friendly.

    I'm quite comfortable looking at code and solving problems, but I find the structure and composition of the Garden framework unintuitive especially compared to other PHP frameworks.

    Are the docs here: http://vanillaforums.org/docs relevant for version 2.1.1?

    Edit

    I see that page was last edited in 2012? - so assuming this is the latest: http://docs.vanillaforums.com/

    Depending on which page you are on the Documentation link goes to two separate places...

  • Options
    hgtonighthgtonight ∞ · New Moderator

    http://docs.vanillaforums.com/ is the most up to date official documentation.

    The source code is the best documentation.

    There is also a community wiki at http://vanillawiki.homebrewforums.net/index.php/Main_Page

    I still think creating a new authenticator is the best approach for you.

    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.

Sign In or Register to comment.