Is there a setting for this? Had a quick look but I can't see one. What to secure the join and sign up process. Cheers.
Anyone? I really need to get this up and running in the next few hours. I have the cert. Typing https works a treat... anyway to make the EntryController change the connection to https?
Do you only want to secure the sign in process or the entire forum activity?
Hey Minisweeper,
Preferably just the sign in and register processes. Any ideas?
Derek.
It gets tricky because we ajax the sign in form into pages where you don't want to have ssl. Because of that, the easiest thing to do is ssl the entire application. We don't have anything set up to just ssl the sign-in pages at the moment.
Hey Mark,
Thanks for your speedy response and for letting me know. Is it possible to create a plugin for this purpose? Or is there no way this will work right now? Doesn't the class.dispatcher.php handle these requests?
Derek.
If I enable SSL for the entire site the with something like this in my htaccess file...
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]
an unspecified error is returned when focusing out of the username form field during a new registration? when removed there's no more error but no SSL! Any idea?
If I manually enter https://www.example.com/entry/register with the previous rewrite rules in the .htacess file removed, I still get the error when I attempt to focus out of the Name/Username field...
A fatal error occurred while processing the request. The server returned the following response: error
think the problem is in the entry.js file!
Okay I got this working...
Please note that this is using SSL for the entire app for the moment... and without these steps you'll have errors in your ajax forms when then check if the username already exists etc.
My .htaccess file looks like this but it may be possible to simplify (no htaccess expert)
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,NC,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,L]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]
In your conf/config.php...
$Configuration['Garden']['WebRoot'] = ''; // Mine is blank
$Configuration['Garden']['RewriteUrls'] = TRUE; // Mine is TRUE
$Configuration['Garden']['Domain'] = 'www.example.com/'; // Remove http:// reference
$Configuration['Garden']['SSL'] = TRUE; // And add this line under the above
In library/core/class.url.php update the Domain function to look like this...
public static function Domain() {
// Attempt to get the domain from the configuration array
$Domain = Gdn::Config('Garden.Domain', '');
$SSL = Gdn::Config('Garden.SSL', FALSE);
if ($Domain === FALSE || $Domain == '')
$Domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
if ($Domain != '' && $Domain !== FALSE) {
if (substr($Domain, 0, 7) != 'http://')
{
(!$SSL) ? $Domain = 'http://'.$Domain : 'https://'.$Domain;
}
if (substr($Domain, -1, 1) != '/')
$Domain = $Domain . '/';
}
return $Domain;
}
Now when you access your site you should be kicked into SSL and the forms should work as expected.
Cheers.
Great work thanks for the tutorial. Looks like this might still need a bit of work in the back end then.
No problem... Yeah I think this can be tackled though with a plugin... might look at putting something together. Like to know if those .htaccess rules are as simple as they should be.
I actually don't think having the SSL enabled for the entire application is a good idea from an SEO and performance perspective. Don't think a lot of spiders will crawl and index the site correctly if at all. @Mark now that I have the above working, and the ajax forms error free with SSL on, is there no way at all I could wire it up to just use SSL when the sign in and register are in use? Is it possibly for a controller "EntryController" to change the protocol to https? Or for the signin.php or registerbasic.php views to trigger this? Thanks.
It's not possible right now, but it should be a part of the core product to do so. All it really takes is:
1. We need some slick way of NOT popping the the sign-in form up in pages if SSL authentication is enabled.
2. We need to use absolute urls (with https) when ssl auth is enabled.
3. We need the entry controller to detect if it is on https and redirect back to itself on https if it is not (when ssl auth is enabled).
Those are the steps necessary, and it really shouldn't be difficult to do. Does anyone want to take a stab at this?
@Mark
Thanks Mark. I'm actually almost there with this. I've tried different methods of doing it all with mixed results. My latest attempt is long the lines of what you mentioned. I've had to modify the core a bit to make it work, but I've had enough success to know that it will work. I've done nothing that breaks the way things currently work, mainly just added an extra attribute or two to some of the functions in the following files.
class.controller.php, functions.general.php, class.url.php
May need some guidance on what you guys prefer and if and how I can bundle my changes into a plugin that overrides the core functions in question or if it's okay to edit them directly as I am. Once I finish I may look at how I can move them.
In my version anyone can add an https link in a view by adding a sixth param that equals TRUE. Example:
Anchor('Sign In', Gdn::Authenticator()->SignInUrl($this->_Sender->SelfUrl), 'Button', NULL, NULL, TRUE); // Had to remove the extra popup css class while testing
Extra argument placement in functions.general...
Anchor($Text, $Destination = '', $CssClass = '', $Attributes = '', $ForceAnchor = FALSE, $Secure = FALSE)
This $Secure arg gets passed around until it reaches the class.url Domain method.
public static function WebRoot($WithDomain = FALSE, $Secure = FALSE) {
....condensed....
if (is_string($WebRoot) && $WebRoot != '') {
// Strip forward slashes from the beginning of webroot
return ($WithDomain ? Gdn_Url::Domain($Secure) : '') . preg_replace('/(^\/+)/', '', $WebRoot);
} else {
return $WithDomain ? Gdn_Url::Domain($Secure) : '';
}
}
public static function Domain($Secure = FALSE) {
// Attempt to get the domain from the configuration array
$Domain = Gdn::Config('Garden.Domain', '');
$SSLAvailable = Gdn::Config('Garden.SSL', FALSE);
if ($Domain === FALSE || $Domain == '')
$Domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
if ($Domain != '' && $Domain !== FALSE) {
if ((substr($Domain, 0, 7) != 'http://') || (substr($Domain, 0, 8) != 'https://'))
{
$Domain = ($SSLAvailable && $Secure) ? 'https://'.$Domain : 'http://'.$Domain;
}
if (substr($Domain, -1, 1) != '/')
$Domain = $Domain . '/';
}
return $Domain;
}
This is still available but I was thinking that the controller should be told to use SSL explicitly if available. I've added a...
/**
* A flag to use https if available.
*
* @var boolen
*/
protected $_SecureController;
to the base class.controller file.
In the EntryController's initialize method I've...
public function Initialize() {
....condensed....
$this->AddCssFile('style.css');
$this->MetaRobots('noindex,nofollow');
$this->SecureController = TRUE;
parent::Initialize();
}
then for in the same file...
private function RegisterBasic() {
if ($this->Form->IsPostBack() === TRUE) {
....condensed....
}
else
{
if(($this->SecureController) && (!$this->SentSSLRedirect)) // What can I check here?
{
$this->SentSSLRedirect = TRUE; // Remove this! Check other way, also needs reset
Redirect($this->SelfUrl, TRUE); // Not right yet...
}
}
$this->Render(); // Maybe I can hook before render later...
}
One thing that you may be able to help me with now is the redirection stuff... the rest I think I'll manage. Not the https aspect of it! Just what to check after a redirect back to the same controller method? count headers array?
I'll have more questions soon...
Work in progress...
@Mark
I've started a plugin version of this. Having a problem calling the functions.general Redirect function from within the plugin. The Redirect doesn't exist in the controller, but in the controller file it looks like its called just as Redirect($URL). Do I need to import something in the plugin?
public function Base_Render_Before(&$Sender)
{
....condensed....
$Sender->Redirect($Sender->SelfUrl, TRUE);
....condensed....
}
tried $this->Redirect($Sender->SelfUrl, TRUE);
also fails... I know I'm missing something obvious!
Please ignore the last comment! Stupid!
Redirect($Sender->SelfUrl, TRUE); // works thanks to the bootstrap file
Might it be easier to actually edit the core files rather than making a plugin? Then all your hard work can be integrated into the application release :)
Indeed, that's definitely something that should work right out of the box, hence in the core.
@Minisweeper
I'm going to keep it as a plugin I think as it's a lot cleaner then rewriting core methods. The core developers can then review the changes the plugin contains and intergrate them if they like. The approach I'm currently using doesn't really make core changes and is clean and simple enough.
@Mark
Most of the stuff I mentioned before, core changes etc have been removed.
My plugin defines a secure controllers array
$Configuration['Garden']['WebRoot'] = '';
$Configuration['Garden']['RewriteUrls'] = TRUE;
$Configuration['Garden']['Domain'] = 'www.example.com/'; // Protocols here will be automatically removed
$Configuration['Garden']['SSL'] = TRUE; // Override a system check
$Configuration['Garden']['SecureControllers'] = 'arr:["entrycontroller"]'; // Specify the controllers you wish to secure
This approach feels a lot cleaner.
I can now move in an out of secure and unsecure controllers in my application regardless of the hrefs protocol. This works fine but when I log out I get "Failed to sign out of the application because of failed postback authentication" but I'm trying to sort that now.
From the plugin can I override methods of the core? Or is this allowed? ie. methods in Gdn_Url. Can I override methods in functions.general just by defining them in the plugin?
Cheers.
@Mark
I assume its not possible to override a static function from a plugin?
ie
class Gdn_Url
{
public static function WebRoot($WithDomain = FALSE)
...with
class SSLControllers implements Gdn_IPlugin
{
public function Gdn_Url_WebRoot_Override($WithDomain) // Written correctly?
{
return "test";
}
Cheers
From docs...
So, the plugin author has the ability to override any core function simply by defining it before the framework does.
Is this possible do to inside a plugin? If I put
function Redirect($Destination) {}
...above my plugin class delaration I get
Fatal error: Cannot redeclare redirect() (previously declared in ... functions.general.php.
Would this need to be done in the bootstrap file?
In : bootstrap.before.php in conf dir
@bean
thought so, cheers!
Having a problem overriding a method in the base Gdn_Controller...
Can anyone tell me is it... (within your plugin class)
public function Gdn_Controller_MethodXYZ_Override(&$Sender) ??
Doesn't seem to working... probably missing something stupid.
Well I'd say, it doesn't work as the underscore is used to automatically find what to do, so here, as the controller has an underscore in its name, it is lost.
Maybe done on purpose or not, as the Gdn_ was added later on. I'd say you will have to wait for @Mark for an answer on this.
Only Controller::xMethod() can be overriden.
Now only two contrroller has these methods DiscussionController::xGetNew() and Gdn_Controller::xRender()
Okay I have this working but I need to sort out the ajax part of it... may need a bit of help. I want to try a avoid editing the existing files.
First off...
garden/js/entry.js uses definition('WebRoot', '') to get the webroot which it uses to check for an existing username etc. This is always http as the base class.controller's DefinitionList method writes a string of definitions which I can't override.
It uses Gdn_Url::WebRoot(TRUE) as a value for a hidden WebRoot field.
I also can't override Gdn_Url's methonds.
I have tried a number of things.
I've added my own,
$Sender->AddDefinition('WebRoot', $this->_WebRoot()); // Returns webroot with correct protocol
which gets added to the end of the class.controller's DefinitionList when rendered. But this just means there is two definitions for WebRoot, and the original is still the one that gets used. When the original is removed. The one with the correct protocol gets used by entry.js
I have also been experimenting with an sslcontrollerhelper.js which is added to the controllers
$Sender->AddJsFile('plugins/SSLControllers/sslcontrollerhelper.js');
It's file contents is short,
var WebRoot = '';
// Get the protocol and WebRoot for the current controller via an ajax call
// "/plugin/getwebroot" maps to magic method "PluginController_GetWebRoot_Create"
$.getJSON("/plugin/getwebroot", function (json)
{
WebRoot = json.WebRoot;
});
I can get values from the plugin with this but I'm not sure if it helps yet so I'm not using it. I don't use Ajax much.
I also have a bootstrap.before.php file which re-defines a few of functions.general's methods. Nothing major.
Any ideas on the best way to get definition('WebRoot', '') in the js files to return my protocol webroot when the plugin is enabled instead of the default?
@derekdon - I'm going to change the controller class so that those "hard-coded" values are no longer hard-coded. They should be override-able.
@Mark
That's great news! Going a bit mad trying to work around it... :-)
Okay - pushed the change to master at GitHub. Now you'll be able to just go $Sender->AddDefinition('WebRoot', 'whatever you want');
@Mark
I don't suppose it's possible to override the Gdn_HandshakeAuthenticator's and the Gdn_PasswordAuthenticator's SignInUrl methods from a plugin? Or perhaps the Gdn_MenuModule AddLink method?
@Mark
Cheers mate that great!
I think that the authenticators should probably define the protocol. Gimme a minute to dig around.
If you have a test site I can email you the plugin as it stands so you can get an idea of what's going on? It should work for you.
Maybe you could change line 174 of the class.menumodule to also account for https if you're in the mood. :-)
@derekdon - Okay, check this out: http://github.com/lussumo/Garden/commit/0c6b68652c733a582dee658ef3cd0ee18a33c09e
I've made it so that your plugin can go:
Gdn::Authenticator->Protocol('https');
Also fixed the menu module here: http://github.com/lussumo/Garden/commit/b63e9f7fc50e8eec0035621e09f7a66d7a88489c
@Mark
That's cool! I've also just emailed you a couple of minor updates in relation to the whole http/https issue. Might be useful.
@Mark
The Base_Render_Before method in my plugin sets the Authenticator protocol. This works fine and switches the top menu sign in link to http or https. The problem is it has no effect on the links in the garden/views/modules/guest.php file. I've changed the SignInUrl method in the class.passwordauthenticator.php to return $this->_Protocol... and low and behold it's http for the module, and https for the top menu sign in link. The Base_Render_Before does some stuff and sets it. I imagine the problem is that I need to hook on to the module somehow to do the same. I would of thought they would be the same. Isn't it a Singleton?
The only other different I can see is the top menu link is set from the master template like so;
$this->Menu->AddLink('Entry', Gdn::Translate('Sign In'), $Authenticator->SignInUrl($this->SelfUrl), FALSE, array('class' => 'NonTab'), array('class' => 'SignInPopup'));
and the one if the module is set like so;
Anchor('Sign In', Gdn::Authenticator()->SignInUrl($this->_Sender->SelfUrl), 'Button');
It's not a major issue as the plugin automatically kicks the controller into https if it's in the SecureControllers array. But I want to resolve it.
Any ideas? Something in the Menu perhaps? I'll keep looking in the mean time.
Cheers.
Update to my last comment...
I've put almost the exact same line of trace code in both files to check the results... results on the root homepage
guest.php
<?php echo Gdn::Authenticator()->SignInUrl($this->_Sender->SelfUrl); ?> // traces 'http'
<?php echo $this->_Sender->SelfUrl; ?> // traces 'discussions'
default.master.php
<?php echo Gdn::Authenticator()->SignInUrl($this->SelfUrl); ?> // traces 'https'
<?php echo $this->SelfUrl; ?> // traces 'discussions'
As I said I have the SignInUrl currently returning the protocol.
The module isn't getting the correct sign in url because it is added to the controller before your Base_Render_Before is fired. We need to do something sooner than that so that your change affects all modules.
I was thinking about this issue this afternoon. I think that https should be a core option, anyway. What do you think of just having an https configuration option to set this to either:
a: straight http
b: https on entry pages
c: https on entire forum
?
@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.
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...
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.
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?
@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;
"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.
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?
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!
@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.
@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.
@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.
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".
@Mark
Thanks for clearing this up for me. I've dealt with cross domain policy quite a bit in Flash, but like I said I don't use Ajax a great deal so this is news to me. Any idea what the best way to tackle this might be?
I came across a post, http://abhinavsingh.com/blog/2009/11/making-cross-sub-domain-ajax-xhr-requests-using-mod_proxy-and-iframes/
which discusses the use of mod_proxy as a possible solution. I know iframes may do the trick but I'm not mad on the idea.
I think any content under /home/(Index, FileNotFound, TermsOfService, PrivacyPolicy, RegistrationUnderApproval, Permission), should be delivered/viewable under http. The TermsOfService, and PrivacyPolicy should be viewable (popup if possible) from the register page under https. I know I could copy these under /entry/ but I don't want to duplicate content. Could a TermsOfService() and PrivacyPolicy() function if added to the EntryController render these views without calling the HomeController?
mod_proxy being apache specific (at least, I think so, with the name), that definitely shouldn't be the complete solution.
@bean
It sounded like you were going to say mod_proxy shouldn't be used because it's apache specific... is that what you meant or are you saying that it IS probably the right approach? Sorry just want to be clear. Have you tried SSLControllers yet? Interested to hear if anyone has any problems with it, but as I said it does need a couple of core file updates to work. The files are listed in the plugin's comment.
Missing a "n't" :). It's edited now.
It should not be the solution as it's specific a single webserver.
I haven't tried it yet, no. As it's only running on a couple of website (for css test and for plugins/applications tests), I don't really need it, as the password are specific for those 2 sites. But that's definitely something that should be there in the released v2.
Using a proxy, the password would be sent using http. You don't want that. To login using https from the http domain, you need to drop the ajax validation.
I'm wondering if your plugin could add js that overrides the default js and pop the terms of service into an actual popup window?
Obviously you could also just https the TOS. There's really no harm in it.
@Mark
Yeah I guess I could add some js that overrides the default...
Would it make any sense to add a TermsOfService() and PrivacyPolicy() method to the EntryController that could load those views without calling the HomeController or duplicating any content?
@Mark
Would it be possible to read a variable from the config.php within my custom js file for this plugin? I was thinking I could use the existing popup class hooks to trigger a custom popup/link function in the custom js, that checked if a "use popup" variable was set to true before rendering a standard popup, or if false simply re-directed the window to the requested url. This would remove the need for plugin users to remove the popup class refs from the links in their default.master and module templates that contain popup links. I'm just not sure if I can read the a value from config.php from the js?
You can add the variable to the definition list using $Controller->AddDefinition() and then use js to grab it from the page.
@Mark
Sweet! Thanks!
@Mark, @Dinoboff
The plugin now has a protected $_UsePopups = TRUE; this is added to the config.php file, and the $Sender->AddDefinition('UsePopups', $UsePopups); is set, along with a custom js file, $Sender->AddJsFile('plugins/SSLControllers/sslcontrollerhelper.js');.
All this is working fine, but I need a little help overriding the default popup behaviour in javascript. Not up on jquery/ajax...
The contents of sslcontrollerhelper.js look like this:
jQuery(document).ready(function($)
{
// The following getJSON snippet is based on the AnonymizeURLs Plugin js snippet.
var WebRoot = '';
// Get the protocol and WebRoot for the current controller via an ajax call
// "/plugin/getwebroot" maps to magic method "PluginController_GetWebRoot_Create"
$.getJSON("/plugin/getwebroot", function (json)
{
WebRoot = json.WebRoot;
});
// Override Ajax popups or open popup links directly
var UsePopups = definition('UsePopups', 1);
// Override default?
$.popup = function(options, data)
{
var UsePopups = definition('UsePopups', 1);
//alert('UsePopups = ' + UsePopups);
var href = $(this).attr('href');
(UsePopups) ? window.open(href, 'popup', 'height=500,width=400,toolbar=no') : window.location = href;
return false;
}
/*
$(function() {
$('a.SignInPopup').click(function() {
var href = $(this).attr('href');
window.open(href, 'popup', 'height=500,width=400,toolbar=no');
return false;
});
});
*/
});
It's just not working as I'd expect. Redefining the $.popup = function() has stopped the ajax popup from happening, but it's now just redirecting to the href. I tried to do this:
$('a.SignInPopup').popup = null;
and
delete $('a.SignInPopup').popup;
then add my own click function but with this the ajax popup still tries to open, so I'm doing something wrong.
Anyone know what the js code should look like?
@Mark, @Dinoboff
Okay, I got this working in the end with the following js in sslcontrollerhelper.js.
jQuery(document).ready(function($)
{
// The following getJSON snippet is based on the AnonymizeURLs Plugin js snippet.
var WebRoot = '';
// Get the protocol and WebRoot for the current controller via an ajax call
// "/plugin/getwebroot" maps to magic method "PluginController_GetWebRoot_Create"
$.getJSON("/plugin/getwebroot", function (json)
{
WebRoot = json.WebRoot;
});
// Open href in a normal popup window or the current window
SSLPopup = function()
{
var UsePopups = definition('UsePopups', 0);
var href = $(this).attr('href');
if(UsePopups)
{
// TODO: Window sizing/positioning etc
window.open(href, 'popup', 'height=500,width=400,toolbar=0,scrollbars=1,resizable=1').focus();
}
else
window.location = href;
return false;
}
// Override Ajax popups
$('a.Popup').click(SSLPopup);
$('a.Popdown').click(SSLPopup);
$('a.SignInPopup').click(SSLPopup);
});
At the moment I don't have a nice way to resize the popup depending on page content etc, and the sign up page does not have a liquid width so it won't fit inside a thinner popup window. As a result I have set the default for UsePopups to be FALSE. This means if you enable this plugin all your popup links (class Popup, Popdown & SignInPopup) will open their links in the current window by default. Current setups will work without any html/css class adjustments. Also opening in the current window actually looks better then having a non-ajax popup in my opinion.
Should be a viable plugin now to add to the add ons? What do you think? Only thing is users will still need some of the latest core files as stated in the plugin comment.
I'm going to commit the latest changes to github shortly.
http://github.com/derekdon/GardenPlugins
Changes committed!
Plugin added: http://vanillaforums.org/addon/514/sslcontrollers
Once people start using it and providing feedback we may learn of a better way to handle the popup problem.
I only have acces to SSL by using another domain:
I have to use https://www.ssl-id.de/forum.xxxxx.de/ instead of http://forum.xxxxx.de/
Can I just enter the https://www.ssl-id.de/ -part somewhere in the default.php of the plugin to make it work?
thanks!
Or maybe this could work by a mixture of the plugin and .htaccess?
@basb - What is the value of $Configuration['Garden']['Domain'] in your /conf/config.php file?
@derekdon - $Configuration['Garden']['Domain'] = 'forum.xxxxxt.de/';
@basb -Does your forum work as expected for an entire session by accessing
https://www.ssl-id.de/forum.xxxxx.de/? Can you browse the forum and does the url stay at https://www.ssl-id.de/forum.xxxxx.de or does it redirect to your sub url? I could add a https suffix url variable to the code base that would be appended around line 170 of the default.php file if the protocol is https. Not 100% sure how it would work in your case. Let me know.
@derekdon - If I go to https://www.ssl-id.de/forum.xxxxx.de/ (SSL-Plugin disabled) the CSS is broken and all the links go to https://www.ssl-id.de/index.php/...
Thanks!
@basb - As a quick and dirty test...
change line 168 of the plugin's default.php to read...
if(substr($URL, 0, 8) == $this->_HTTPS_PROTOCOL) $URL = www.ssl-id.de/ . substr($URL, 8);
and enable the plugin.
Let me know if that works for you.
If so I may add an SSL suffix variable to the code for you and other users to set...
It looks like you're new here. If you want to take part in the discussions, click one of these buttons!