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.

Enabling SSL in Vanilla 2?

1356

Comments

  • @Mark
    I just added a Singleton type test...

    In Gdn_PasswordAuthenticator I added...

    private $_SingleTestName = "Derek";
    public function SingleTest($Value)
    {
    $this->_SingleTestName = $Value;
    }

    public function GetSingleTest()
    {
    return $this->_SingleTestName;
    }

    In the plugin I just set this once with a flag option to "Sandra"

    ie. if(!$this->_SwitchedSingleName) Gdn::Authenticator()->SingleTest('Sandra');

    So it's only switched once I think, unless the plugin class is created new each time...

    and the default master traces the update, Sandra.
    yet the guest module traces, Derek.

    So the module is definitely getting it's own version...

    It might be understandable if the plugin code is defined repeatedly on each page call? Any insight...

    Before you go down the core route, let me just try and sort this last bit... Like I said, the links don't really need to be https anyway, as the controller will automatically take care of the protocol... just wondered what was going on.
  • derekdonderekdon New
    edited January 2010
    The plugin's Setup method checks for an SSL config option already, and sets one.

    // Do setup
    public function Setup()
    {
    // Check if the server can support SSL
    $Domain = Gdn::Config('Garden.Domain', '');
    $SSLSpecified = Gdn::Config('Garden.SSL', FALSE);
    if($SSLSpecified) $this->SSLSupport = TRUE;

    if(($Domain != '') && ($Domain !== FALSE))
    {
    // Remove any http prefixes
    if(substr($Domain, 0, 7) == $this->_HTTP_PROTOCOL)
    $Domain = substr($Domain, 7);
    else if(substr($Domain, 0, 8) == $this->_HTTPS_PROTOCOL)
    $Domain = substr($Domain, 8);

    // Do the actual check
    if(!$this->SSLSupport)
    {
    $SSLCheck = @fsockopen('ssl://' . $Domain, 443, $errno, $errstr, 30); // Not working for me at the moment? Might be my staging server. Error: Name or service not known?
    $this->SSLSupport = ($SSLCheck) ? TRUE : FALSE;
    fclose($SSLCheck);
    }

    // Add the SSL param
    $Config = Gdn::Factory(Gdn::AliasConfig);
    $Config->Load(PATH_CONF.DS.'config.php', 'Save');
    $Config->Set('Garden.SSL', $this->SSLSupport, TRUE); // Override what the user specified if we know it to be different
    $Config->Set('Garden.SecureControllers', $this->SecureControllers, FALSE); // Keep whatever controllers the user wants to secure
    $Config->Set('Garden.Domain',$Domain, TRUE); // Override the current domain as we will need it protocol free
    $Config->Save();
    }
    }

    Then every time the Base_Render_Before it sets the Authenticator's Protocol. Probably happens to late as you said... Any way in the plugin to do it earlier that's global?

    public function Base_Render_Before(&$Sender)
    {
    ...
    $this->_SetAuthenticatorProtocol(($this->SSLSupport) ? $this->_HTTPS_PROTOCOL : $this->_HTTP_PROTOCOL);
    ...
    }

    // Set Authenticator Protocol
    protected function _SetAuthenticatorProtocol($Protocol = '')
    {
    $Protocol = $this->_GetValidProtocol($Protocol);
    Gdn::Authenticator()->Protocol(rtrim($Protocol, '://'));
    }

    The plugin currently works and makes the app go in and out of SSL. Just need to sort that out for the links and double check why the ajax existing username check returns an error... the urls match. Might be because the protocol isn't staying...
  • MarkMark Vanilla Staff
    The module is added before your render event fires. That's why the value is different.
  • @Mark
    Re
    a: straight http
    b: https on entry pages
    c: https on entire forum

    I think allowing users to specify which controllers to secure is the right way to go. The behaviour of the plugin allows that. Perhaps it's functionality could be integrated into the core after it's complete and hopefully gets the thumbs up.
  • @Mark
    Okay! Thanks.
  • MarkMark Vanilla Staff
    I see your point about selecting controllers for https.
  • SSL on the login page only protects the password but not the session cookie later when the user is back on a plain http connection.

    You should let a forum use both http or https and check on each request which protocol is used (for links and redirects). Anonymous users (and bots) should use http, authenticated users should use https.

    When ssl is enable on the server, the login page should always be secure; the session cookie should be secure, and the login page after authentication should redirect to a secure page. That should be quite easy except for the ajax login feature (it could show the login form with an iframe to a secure page)
  • I think IE has some issues with HTTPS iframes in HTTP pages...
  • @Mark
    The plugin now secures validated sessions if SecureSession is TRUE in the config, and SSL is available of course. Thanks @Dinoboff.

    I’m just trying to sort out a couple of ajax errors. Think they are parse errors, but I don’t have to much experience with ajax.

    The Sign In popup link on the main menu when clicked opens the ajax popup but it’s just processing [][][][] endlessly. I imagine this has something to do with the fact that the connection is not currently https as it’s the default controller with is unsecured. The same link when click from under /entry opens the popup successfully, but clicking Sign In doesn’t cause a visible state change of any kind and the popup remains open. Of course when under /entry there is already a Sign In page displayed which works perfectly, but then this is already https due to the entry controller being a secured controller.

    When I login the plugin will secure the entire session if specified or just the specific secure controllers, switching in and out of https when accessing the controllers that are secure. At this point you can Sign Out and that works as expected, happens under https, and returns you to the /entry page still under https as /entry is a secure controller. If I visit /entry/register, which is https, I can register a new user as normal and the above applies. But when I focus out of the Name (Username) field, the ajax returns “A fatal error occurred while processing the request. The server returned the following response: error”, even though submitting the form is successful. I’ve traced the checkUrl in entry.js to appear instead of the one word error response, and the url is the full secure url, https://www.example.com/index.php/garden/utility/usernameavailable/blabla
    Maybe the utility controller needs to be added to the SecureControllers array? I’ll check that… Ah bingo! That was it… I took me to type all that to get to figure that out!!! Okay that’s the Username checking sorted… The other problems still remain. Any ideas?
  • derekdonderekdon New
    edited January 2010
    @Mark
    Just wondering what you think the cleanest way for a user to say secure all controllers in the config? Should I put a * in the array or something? I know you could use the .htaccess file to secure every page, but let's say it's mixed in with a blog or another app... better if they could do it here.
    $Configuration['Garden']['SSL'] = TRUE;
    $Configuration['Garden']['SecureControllers'] = 'arr:["entrycontroller", "utilitycontroller"]'; // What's the perfered way to indicate all controllers?
    $Configuration['Garden']['SecureSession'] = TRUE;
  • derekdonderekdon New
    edited January 2010
    "Maybe the utility controller needs to be added to the SecureControllers array? I’ll check that… Ah bingo! That was it…"
    Actually that has stopped any errors from popping up during registration alright, but no matter what you enter the it's says Username Unavailable so the ajax calls still aren't right... the password checker is fine. Any insight into the ajax part of this problem would be greatly appreciated! This is happening directly on https://www.example.com/entry/register page (not in a popup), with $Configuration['Garden']['SecureControllers'] = 'arr:["entrycontroller", "utilitycontroller"]'; in the config.
  • derekdonderekdon New
    edited January 2010
    I did some digging and it looks like the parsererror is coming from the httpData() method. I found these refs on the following lines in the jquery library files.

    Line 250, jquery.form.js: data = $.httpData(xhr, opts.dataType);
    Line scrambled (compressed js), jquery.js: V=o.httpData(J,M.dataType,M)

    I've re-formatted some of the compressed js in jquery.js so that I could see the build up to the call properly.

    var N=function(X)
    {
    if(J.readyState==0)
    {
    if(P)
    {
    clearInterval(P);
    P=null;
    if(M.global&&!--o.active)
    {
    o.event.trigger("ajaxStop")
    }
    }
    }
    else
    {
    if(!K&&J&&(J.readyState==4||X=="timeout"))
    {
    K=true;
    if(P)
    {
    clearInterval(P);
    P=null
    }

    R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";

    if(R=="success")
    {
    try
    {
    V=o.httpData(J,M.dataType,M)
    }
    catch(Z)
    {
    R="parsererror" // <-- this is the string that is shown in the onscreen error. I've changed it's value to double check.
    }
    }

    if(R=="success")
    {
    var Y;
    try
    {
    Y=J.getResponseHeader("Last-Modified")
    }
    catch(Z){ }

    if(M.ifModified&&Y)
    {
    o.lastModified[M.url]=Y
    }

    if(!W)
    {
    I()
    }
    }
    else
    {
    o.handleError(M,J,R)
    }

    L();

    if(X)
    {
    J.abort()
    }

    if(M.async)
    {
    J=null
    }
    }
    }
    };

    I think something is wrong with the format when it's encrypted by https. Any thoughts?
  • derekdonderekdon New
    edited January 2010
    Sorry for the length of my posts...

    Just to check everything again I disabled my plugin's main logic by doing this...

    public function Base_Render_Before(&$Sender)
    {
    // Add protocol webroot definition
    $Sender->AddDefinition('WebRoot', $this->_WebRoot()); // Still needs to be set with correct protocol
    return; // Stop for the moment, tracking bugs...
    ...

    Then in the root .htaccess file I set it to always render the site as ssl.
    ...
    RewriteCond %{SERVER_PORT} 80
    RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]
    ...

    With this setup everything works... ie. the site is entirely in SSL and the ajax stuff is doing it's thing correctly for post previews, page refreshes, username checking etc.

    Without the $Sender->AddDefinition('WebRoot', $this->_WebRoot()); the username checking and probably some other stuff doesn't work.

    So my question is, are these rewrite rules helping potentially inaccurate ajax calls or validation checks? Are they changing something in the headers that I should be also doing? Or is it more likely that sending a controller back to itself under a secure https connection is the cause of my problems with ajax?

    This is driving me nuts!

  • derekdonderekdon New
    edited January 2010
    @Mark

    Can you tell me if....

    Base_Render_Before(&$Sender)
    {
    // Add protocol webroot definition
    $Sender->AddDefinition('WebRoot', $this->_WebRoot());
    ...

    will set the definition in time for the /js/global.js file's and some of the other jquery file's references to WebRoot? This is probably a stupid question, I imagine it does.

    The plugin doesn't do anything strange other then some detection and redirection, so I think the problem might be a reference to an incorrect WebRoot within the js files that I'm not in time for...
    Although it's likely that the class.url WebRoot & Domain functions may be causing the issue as they only return http WebRoots as far as I can tell (can't override). I know the Authenticator will swap these protocols out, but that's probably not the case elsewhere...

    I think the reason it works when the plugin is off and the whole app is in ssl, is thanks to those rewrite calls,
    RewriteCond %{SERVER_PORT} 80
    RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]

    They probably convert any incorrect protocol WebRoot paths into the correct (in this case) https version when calls are made...

    Any idea if this could be the case?
  • @Mark

    Before you spend time answering these questions, I think I may have figured out the problem... give me a little while to cross check.
  • MarkMark Vanilla Staff
    @derekdon - I guess we're on different working schedules - sorry I haven't been around. Needed sleep!
  • @Mark - Don't worry about it! I'm based in Dublin, Ireland, on GMT. But I start early...

    Finally! To anyone who might be interested is this functionality, @Mark @Minisweeper @bean @Dinoboff @fredwufredwu

    The plugin is now available here - http://github.com/derekdon/GardenPlugins

    Ironically the bulk of problems I was having above re ajax errors were caused by the fact I was echo/ing out debug statements in the plugin trying to track errors in the first place... Ajax calls to controllers that expected a return value or TRUE or FALSE were also getting my statements which caused them to fail!!! Needless to say I feel good when I realised this was the cause of hours of debugging pain! :-)

    Anyway give it a go and let me know what you think or how it could be improved. Some core file updates may be required but these are listed in a comment inside the plugin. If you guys are happy with its implementation I will add it as an addon plugin on vanillaforums.

    Remaining Issues:
    The remaining issue/s is that the sign in popup can't go to SSL so it won't render. You can't use it from the DefaultController / the home page, but it does work when you're already in /entry under https. Remove the 'SignInPopup' class from it in the default master if you like or do a fancy check...
    Also I can't set the Authenticator's protocol in advance of it's usage in any 'modules' as they are added and ran before the Base_Render_Before triggers. This isn't really a problem, as the controllers will go to SSL if they should anyway, just means that the link rendering functions that check the authenticator's protocol will see http as it's the default and will render the link as such.

    Derek.
  • latest class.controller.php is also needed... sorry forgot.
  • derekdonderekdon New
    edited January 2010
    @Mark
    Did you get a chance to try this yet?
    Just noticed that if you are in the process of joining (under https) and click to read the terms of service ( exists under home/) which would be a http page, the popup just keeps showing the spinner. This is a similar problem to that of the homepage sign up popup I imagine, expect in reverse, https -> http problem. If you add the "homecontroller" to the SecureControllers (not that it would make sense), the popup does open, I imagine because they are now both https. But the strange thing is, with the "homecontroller" in your SecureControllers array, after you close the popup and click sign up you are signed up but redirected back to the register form (which doesn't normally happen) in https but without the browser bar colour change indication of the ssl cert... It states some items were encrypted and some were not. The only other time I noticed this behaviour is when you are not logged in and viewing discussion, you click sign in, and are redirected back to that discussion. Again it says https which you would expect now as the session is secure, but without the browser bar colour change indication of the ssl cert, for the same reason probably. Strange, but probably fixable. Let me know what you think.
  • MarkMark Vanilla Staff
    edited January 2010
    I haven't had a chance to give it a shot yet.

    The popup and eternal spinner is a browser security-related issue. Your browser considers https://domain.com and http://domain.com to be two completely different domains, so when you try to make an ajax request to a different domain, your browser will kill the request - which leaves you eternally "loading".
Sign In or Register to comment.