New bug: SSL error from Mapped (non HTTPS) site to main blog (HTTPS)

Hello,

Since the latest update I discovered an SSL bug, unfortunately this isn't a one time thing.

Whenever I navigate from a mapped domain to the back-end I get an SSL error.

Prior to the latest update this wasn't the case.

What has changed? I will try to work around it.
...Or is this a known bug?

Either way, my settings are listed below.

Thanks and have a great day!

PS.

I went overboard with translating the plugin so I'll just list my settings in order with rough and short translation:

Allow more: no
Administrative: 1st
Login: Original <- causes the error
Cross-domain auto: Yes + async
Verify: no
Propagation check: no
Force admin: Yes <- helps cause the error
Force front: No
Forbidden: main blog
Allow sub: no (checked)
Allow exclude/force: none to all
Pro sites: all levels (checked)

EDIT: Oh I'd like to add that when the error occurs in the browser, I get the main blog (EV SSL) certificate sent. Not the wildcard domain cert.
https://verbijmontage.nl/wp-admin/post.php?post=174&action=edit will give you the error

  • Sybre Waaijer

    The bug has been pinpointed: The option "Force http/https (for original domain)" seemingly forces SSL also for the mapped domain.

    I solved it by changing one simple option and letting my .htaccess do the rest, this means the bug doesn't affect me but I think it should still be addressed for other users :slight_smile: Thus I'm leaving this topic open.

    Hope you're all doing well!
    Thanks @Michael Bissett for dropping by ^^

    For users whom wind up on this topic and want to solve this right away while still using HTTPS on the main blogs and wildcard domains (non-mapped), change example.com to your domain and add this to your .htaccess file above the WordPress stuff:

    #BEGIN all subdomains force SSL
    		RewriteCond %{HTTPS} off
    		RewriteCond %{HTTP_HOST} ^(.*)\.example\.com [NC]
    		RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    #END all subdomains force SSL
    
    #BEGIN main blog SSL
    		RewriteCond %{HTTPS} off
    		RewriteCond %{HTTP_HOST} ^example\.com [NC]
    		RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
    #END main blog SSL
  • Sybre Waaijer

    Alright, I'm releasing a hotfix here.
    This doesn't help the error stated on the topic starting though. But it does for the comment above.

    The thing that works is the script below, what you can clearly see here is that the url in the Javascript is HTTPS, thus being secure.

    <script type="text/javascript">
    			(function(window) {
    				var document = window.document;
    				var url = 'https://hostmijnpagina.nl/dm-sso-endpoint/1432292989/?dm_action=domainmap-check-login-status&domain=hsbnijenbergh.hostmijnpagina.nl';
    				var iframe = document.createElement('iframe');
    				(iframe.frameElement || iframe).style.cssText =
    					"width: 0; height: 0; border: 0";
    				iframe.src = "javascript:false";
    				var where = document.getElementsByTagName('script')[0];
    				where.parentNode.insertBefore(iframe, where);
    				var doc = iframe.contentWindow.document;
    				doc.open().write('<body onload="'+
    				'var js = document.createElement(\'script\');'+
    				'js.src = \''+ url +'\';'+
    				'document.body.appendChild(js);">');
    				doc.close();
    
    			}(parent.window));
    		</script>

    However, when we open that URL, you will see this. You can clearly see that HTTP is being outputted! D:

    // Starting Domain Mapping SSO
    					(function(window) {
    				var document = window.top.document;
    				var url = 'http://hsbnijenbergh.hostmijnpagina.nl/dm-sso-endpoint/1432293149/?dm_action=domainmap-authorize-user_async&auth=HASH_AND_ACCOUNT_HERE';
    				var iframe = document.createElement('iframe');
    				(iframe.frameElement || iframe).style.cssText =
    					"width: 0; height: 0; border: 0";
    				iframe.src = "javascript:false";
    				var where = document.getElementsByTagName('script')[0];
    				where.parentNode.insertBefore(iframe, where);
    				var doc = iframe.contentWindow.document;
    				doc.open().write('<body onload="'+
    				'var js = document.createElement(\'script\');'+
    				'js.src = \''+ url +'\';'+
    				'document.body.appendChild(js);">');
    				doc.close();
    
    			}(parent.top.window));

    @Sam
    I looked this up into Cdsso.php and I found out the following:
    Within function check_login_status(), $domain_name outputs: hsbnijenbergh.hostmijnpagina.nl

    So, I did a check if is_ssl works at this point, the output of the following code will be "yes".
    $is_ssl = is_ssl() ? 'yes' : 'no';

    Awesome!
    So is_ssl() works here.

    I'm not sure why the admin scheme is checked in the first place. The browser blocks the content independent of the admin scheme.

    If the front-end is SSL it doesn't mean it's back-end is SSL. The other way around also counts.
    I do however understand you need to look in different places regardless of the URL scheme. This is because of the obvious reason: The mapped URL != home URL.
    So you wrote _get_sso_endpoint_url(). Although this works well in many cases, I think it should go one step further.

    However, forcing this doesn't work. This is because the scheme is used in multiple layers.
    My suggestion? Rewrite the url_scheme to support the is_ssl check in two layers: one in the Javascript request and one in the JSON request.

    I'll dig deeper and report back with a rewrite.

  • Sybre Waaijer

    Alright, I fixed it :slight_smile:

    You can download the new Cdsso.php here:
    https://cyberwire.nl/share/bugfix/Cdsso.zip

    What I've changed:

    Changed:
    private function _get_sso_endpoint_url()
    (added is_ssl() check)
    
    New function:
    _get_sso_endpoint_url_auth()
    (uses old scheme)
    
    Changed function calls:
    _get_sso_endpoint_url
    to
    _get_sso_endpoint_url_auth
    in function
    _check_login_status() (twice)
    and in function
    _add_auth_script_sync() // but it should probably be the new scheme

    I disabled the force ssl schemes in Domain Mapping. No more problems :smiley:
    This should also work fine with the schemes enabled but it's untested.

    Enjoy and be sure to empty your cache =)

  • wp.network

    @Sybre Waaijer tested with all combos of scheme forcing configs at network>settings>dm

    In all cases I am still seeing issues with an insecure endpoint being blocked... lots symptoms all seem to lead back to some issue with the endpoint... don't have time (or insight) to really push further with testing or documenting at the moment...

    You can see some testing with Multi-Domains SSO issue at https://premium.wpmudev.org/forums/topic/domain-mapping-multi-domains-sso-insecure-endpoint-sso-fails-w-multi-domains#post-885374

    Unfortunately, though I did mess about the various DM configs, your file did not seem to solve endpoint issues, though in some configs it moved mapped domain login screens past a WSOD which is probably a good thing =)

    Thanks for bringing your skillz to bear on the issue... I've got confidence in your ability to provide some awesome inputs to speed @Sam's work =)

    Good days for all!

    Aloha, Max

  • Michael Bissett

    Hey @Sybre Waaijer,

    Odd, I'm not seeing that you're running 4.4.0.6 on the site you mentioned here, I'm seeing that it's running 4.4.0.5 at the moment. Did you revert back to an earlier version?

    Also, when you say this:

    Unfortunately, the update didn't prevent the load of mixed content on the front-end.
    This time without funny business, I just fill in what the settings ask.

    I trust that this ties in to what your original point was here in the thread? That being:

    Since the latest update (4.4.0.5) I discovered an SSL bug, unfortunately this isn't a one time thing.

    Whenever I navigate from a mapped domain to the back-end I get an SSL error.

    Just want to make sure we've got all of the facts clear here for Sam. :slight_smile:

    Kind Regards,
    Michael

  • wp.network

    @Michael Bissett thanks for being thorough in addressing this asap =)

    There is also this thread, experiencing similar SSO issues with insecure endpoint
    https://premium.wpmudev.org/forums/topic/my-subsites-can-no-longer-login-directly-to-their-websites?replies=8#post-886381
    and I am seeing similar issues at other member's networks as well, have already dealt with a few config updates and reversions.

    Cheers, Max

  • Michael Bissett

    Hey @Sybre Waaijer, thanks for clarifying that for me! :slight_smile:

    My "Bissett sense" tells me that Sam's going to want to have deeper access here, could you please send in the following for your site, just so we have that ready for him:

    - Mark to my attention, the subject line should contain only: ATTN: Michael Bissett
    - Do not include anything else in the subject line, doing so may delay our response due to how email filtering works.
    - Link back to this thread
    - Include WordPress network admin access details (login address, username & password)
    - Include FTP log-in details (hostname, username & password)
    - Include cPanel log-in details (for accessing the database, so phpMyAdmin or equivalent)
    - Include any relevant URLs for your site (e.g. a site on your network that we can visit to reproduce this)

    On the contact form, select "I have a different question", this ensures it comes through and gets assigned to me.

    https://premium.wpmudev.org/contact/

    Thanks a bunch! :slight_smile:

    @WPMS.CLUB, thanks for bringing that thread up, I see that you've been pretty busy over there. :slight_smile:

    Kind Regards,
    Michael

    • Sybre Waaijer

      Hi @Michael Bissett

      Although I do trust you guys, I'm not sure if I want my baby exposed :smiley:

      Either way, before we get to that, I think I've found the problem:

      Old _get_sso_endpoint_url:

      private function _get_sso_endpoint_url( $subsite = false, $domain = null ){
      
              global $wp_rewrite;
              if( $subsite ){
                  $admin_scheme = self::force_ssl_on_mapped_domain( $domain ) ? "https://" : "http://";
                  $url  = $admin_scheme . $domain . "/";
              }else{
                  $admin_scheme = $this->_plugin->get_option("map_force_admin_ssl") ? "https" : "http";
                  $url  = trailingslashit( network_home_url("/", $admin_scheme) );
              }
      
              return $wp_rewrite->using_permalinks() ? $url . self::SSO_ENDPOINT . "/" . time() . "/" : $url . "?" . self::SSO_ENDPOINT . "=" . time() ;
          }

      New _get_sso_endpoint_url:

      private function _get_sso_endpoint_url( $subsite = false, $domain = null){
              global $wp_rewrite;
      
              $admin_mapping = $this->_plugin->get_option("map_force_admin_ssl");
              if( $subsite ){
                  $admin_scheme = $admin_mapping ? "https://" : "http://";
                  $url  = $admin_scheme . $domain . "/";
              }else{
                  $admin_scheme = $admin_mapping ? "https" : "http";
                  $url  = trailingslashit( network_home_url("/", $admin_scheme) );
              }
      
              return $wp_rewrite->using_permalinks() ? $url . self::SSO_ENDPOINT . "/" . time() . "/" : $url . "?" . self::SSO_ENDPOINT . "=" . time() ;
          }

      The big difference:
      It doesn't check for the option 'force_ssl_on_mapped_domain' anymore.
      That function checks if the mapped domain is set to SSL or not.

      Instead, it uses the site-wide option 'map_force_admin_ssl'.
      That function checks if the super-admin has set "Would you like to force https in login and admin pages" to yes.

      Which is good! But I think they should work together in a XOR, AND or OR statement :wink: Be creative :smiley:

      I think that will solve it :smiley:

      To give you an idea of the new code:

      private function _get_sso_endpoint_url( $subsite = false, $domain = null){
          global $wp_rewrite;
      
          $blog_scheme = self::force_ssl_on_mapped_domain( $domain ); // blog option
          $admin_mapping = $this->_plugin->get_option("map_force_admin_ssl"); // sitewide option
      
          if( $subsite ){
              if ( $blog_scheme ) {
                  $url  = "https://" . $domain . "/";
              } else {
                  $admin_scheme = $admin_mapping ? "https://" : "http://";
                  $url  = $admin_scheme . $domain . "/";
              }
          }else{
              if ( $blog_scheme ) {
                  $url = trailingslashit( network_home_url("/", "https") );
              } else {
                  $admin_scheme = $admin_mapping ? "https" : "http";
                  $url  = trailingslashit( network_home_url("/", $admin_scheme) );
              }
          }
      
          return $wp_rewrite->using_permalinks() ? $url . self::SSO_ENDPOINT . "/" . time() . "/" : $url . "?" . self::SSO_ENDPOINT . "=" . time() ;
      }

      I haven't tested it though since I'm busy on other projects :slight_smile:

  • Michael Bissett

    Hey @Sybre Waaijer, glad to hear things are working now! :smiley:

    Not only object cache, but also page cache. I disabled both and the errors were gone. Re-enabled them and the errors are still gone

    When you say "both", what settings are you referring to here? Would they be:

    - Administration mapping -> domain entered by the user
    - Would you like to force https in login and admin pages: -> Yes

    Please advise,
    Michael

    • Sybre Waaijer

      Hi @Michael Bissett

      Thanks for dropping by.

      I'm referring to the w3tc settings "page cache and object cache". Last year the page cache was said to be the problem with object cache destroying everything lol.

      Now it's just the object cache. I had to do more research to come to this conclusion.

      Somehow object cache is caching the http/https outcome of the scripts. I have to clear them for the given page site to make the SSO work again.

      So the problem in one line:
      Object caching from W3TC somehow caches the HTTP/HTTPS output on any page, be it wp-login.php or the SSO script(s)

      My temporarily solution, (still testing):
      Set the object cache expiration date to 120 seconds, this is the same as the SSO process cookie time

      Unfortunately the "temporarily solution" increases the server load by quite a bit and lowers the page response time for logged in users.

  • Sybre Waaijer

    Marking this topic as unresolved, although I know how to temporarily fix it (clear object cache) or permanently (with object caching disabled), I still think a plugin shouldn't affect performance or other unrelated settings to a plugin.

    The object cache problem is also related to the reason why I opened this topic: Certificate errors. This issue has been fixed by disabling and enabling the object cache site wide, luckily a one time thing. :slight_smile:

    I want to thank you guys for all the effort, I really appreciate it ^^

    • Sybre Waaijer

      Hi there @Sam

      Thanks for dropping by :slight_smile: I see you went all the way with https/http now ^^ Awesome!

      Am testing this out right now, my findings (might be subject to cache invalidation, so I hope these will go away within 24 hours, 86400 seconds):

      The URL in the function '_add_iframe()' is the following:
      ?dm_action=domainmap-check-login-status&domain=example.com
      After a reload it is like this:
      https://maindomain.com/dm-sso-endpoint/1433192095/?dm_action=domainmap-check-login-status&domain=example.com

      The output in the 2nd link above shows this (stripped), the hash1 and hash2 are identical in the dupe, the duped does have HTTPS while the original has HTTP:

      // Starting Domain Mapping SSO
      				(function(window) {
      		var document = window.top.document;
      		var url = 'http://example.com/dm-sso-endpoint/1433192284/?dm_action=domainmap-authorize-user-async&auth=username|1433192344|hash1|hash2&refresh=0';
      		var iframe = document.createElement('iframe');
      		(iframe.frameElement || iframe).style.cssText =
      		"width: 0; height: 0; border: 0";
      		iframe.src = "javascript:false";
      		var where = document.getElementsByTagName('script')[0];
      		where.parentNode.insertBefore(iframe, where);
      		var doc = iframe.contentWindow.document;
      		doc.open().write('<body onload="'+
      					'var js = document.createElement(\'script\');'+
      					'js.src = \''+ url +'\';'+
      					'document.body.appendChild(js);">');
      	doc.close();
      
      	}(parent.top.window));
      				(function(window) {
      		var document = window.top.document;
      		var url = 'https://example.com/dm-sso-endpoint/1433192284/?dm_action=domainmap-authorize-user-async&auth=username|1433192344|hash1|hash2&refresh=1';
      		var iframe = document.createElement('iframe');
      		(iframe.frameElement || iframe).style.cssText =
      		"width: 0; height: 0; border: 0";
      		iframe.src = "javascript:false";
      		var where = document.getElementsByTagName('script')[0];
      		where.parentNode.insertBefore(iframe, where);
      		var doc = iframe.contentWindow.document;
      		doc.open().write('<body onload="'+
      					'var js = document.createElement(\'script\');'+
      					'js.src = \''+ url +'\';'+
      					'document.body.appendChild(js);">');
      	doc.close();
      
      	}(parent.top.window));

      I had this issue too when I edited your file in 4.4.0.5. But when I disable object caching... it's not duped. Weird....

      The only caching group you use is 'site-options', I disabled that from object caching, unfortunately it doesn't solve any issue :3

      The moment I disable object caching everything works perfectly! :smiley: Better than ever even, good job Sam ^^

      Might be a long shot, and I'll try this myself: cache the https:// thingies in objects themself :smiley:

      The objects will look something like this:
      wp_cache_set( $blog_id . $pagequery . $httpsorhttp, $something, 'site-options' );

      Will report back :slight_smile:

      • Sybre Waaijer

        Well, that was a lot of time wasted :smiley: now it caches the incorrect version and repeats that :stuck_out_tongue:

        Anyway, I found some bugs that could easily be fixed:

        In function render_health_column():
        'get_mapped_domain_scheme' should be replaced with an is_ssl check
        This will fix the insecure script in the health check on the user's domain mapping page

        In function check_login_status():
        $this->_add_inner_iframe( esc_url_raw( $url ) ); is called twice, this should be an ELSE statement, like so:

        if( $admin_mapping ){ // set user cookie for https as well and refresh
        	$args["refresh"] = 1;
        	$url = add_query_arg( $args, $this->_get_sso_endpoint_url( true, $domain_name ) );
        	$this->_add_inner_iframe( esc_url_raw( $url ) );
        } else {
        	$this->_add_inner_iframe( esc_url_raw( $url ) );
        }

        This will prevent the double calling of the script on HTTPS pages

        The second fix will probably fix the third issue automatically:
        ?dm_action=domainmap-check-login-status&domain=example.com
        instead of
        https://maindomain.com/dm-sso-endpoint/1433192095/?dm_action=domainmap-check-login-status&domain=example.com

        @Sam Thanks :slight_smile:

  • Sybre Waaijer

    FIXED FIXED FIXED :smiley: :smiley: :smiley:

    @Sam
    I spent a good 3 hours to rewrite the Cdsso.php file, please take it into consideration for the next update.

    What I did:
    Fully rewritten check_login_status()
    Fully rewritten _get_sso_endpoint_url()

    I commented out the old version, duped it and commented every change within.

    Download
    The download for the fix: https://hostmijnpagina.nl/share/bugfix/Cdsso.zip
    File location: wp-content/plugins/domain-mapping/classes/Domainmap/Module/

    Every site, being mapped (or not) as HTTPS or HTTP will work now :slight_smile: The refresh has been set to always on and Object Caching isn't a culprit anymore :smiley:

    -----

    @Sam
    As suggested above, I spent a good 2 minutes on Map.php :smiley:

    The other fix: invalid script when a mapped domain is http on a https domain. I simply commented out the set_url_scheme with the get_mapped_domain_scheme check and replaced it with an empty string.

    The reason I did this is because the script's protocol shouldn't be dependent on the mapped domain, but rather the current protocol of the page you're visiting, be it either http or https. This is automatically determined.

    Download
    The download for the fix: https://hostmijnpagina.nl/share/bugfix/Map.zip
    File location: wp-content/plugins/domain-mapping/classes/Domainmap/Render/Site/

    ----

    Still 1 bug remaining. This is considering map_admindomain (not working at all). However, I'm not bummed out about this, the whole thing is still functional as is but the result is not desired.
    I'll try to find a fix for this at fifteen to somewhere in the future :smiley:

    Thanks guys :smiley:

  • Sybre Waaijer

    Updated the Cdsso.zip file (download in previous post or below).

    1. I cheered too early. The object cache is still a culprit D:

    2. massively improved check_login_status()
    Reason: subsites with SSL didn't really like the previous idea, now they do.
    Reason 2: unclear variable names.

    : Uses wpdb now to check for mapped domain
    : if mapped, check for mapped domain ssl status
    : if not, check for is_ssl
    : uses object cache for var check, cdsso_theblogid_ $domain_name
       object group: domain_mapping

    3. Updated comments in check_login_status(), removed unused stuff.

    https://hostmijnpagina.nl/share/bugfix/Cdsso.zip

    Leaving object cache disabled will log everyone in at all times everywhere now :slight_smile: no more https mistakes.
    I'll check in later why object caching destroys this plugin. But it lies at the query after the inner iframe.

  • Sam

    @Sybre Waaijer

    I have released 4.4.0.7 due to the urgency to release some bug fixes coming with 4.4.07, but please upgrade and let me know how it behaves in relation to your issues and the valuable work you've done, and i'll be more than happy to release 4.4.0.8 with even more bug fixes, please note that i'm trying to perfect DM plugin and your efforts and inputs are tremendously welcomed and valued.

    Thanks,
    Sam

  • Sybre Waaijer

    Hello :slight_smile:

    I also noticed a bug with SSL on the Mapping table.

    1. Map domain
    2. See rendering "locker"
    3. Nothing happens

    Number 3 happens because admin ajax is being loaded from the mapped domain, not the admin domain. I'm not sure where this is caused.

    Example
    1. Working at https://subdomain.example.com/
    2. Map domain http://examplemap.org
    3. Admin-ajax.php is being loaded from http://examplemap.org/wp-includes/admin-ajax.php while the user is still on https://subdomain.example.com/

    I can't find where this happens but I expect this to be at map.php, somehow the admin_url() is fetching the URL from the mapped domain instead of the current domain.

    :3

  • Sybre Waaijer

    Hello :slight_smile:

    I created a little helper plugin that will disable Object caching for logged out users. Because when you use Page Cache, object cache is less useful than a snorkel device in outer space.

    The Problem, finally figured out:
    What exactly happens is that when the _add_inner_iframe function runs, your browser asks for a cookie, unfortunately because of object caching: no cookie is sent. This problem lies deep within the WP core functions using object cache and can't be fixed by adjusting the Domain Mapping plugin.

    The solution:
    Disable object caching for logged out users. This option can't be set within the W3 Total Cache interface, so let's just enforce it. Network activate the plugin below or add it as a mu-plugin :slight_smile:

    So this plugin will disable object caching, so far the results are good :smiley:
    This will help with the problem stated that object caching will mess up the cookie check.
    If you also use object caching, be sure to try it :slight_smile: let me know if it works :slight_smile:

    <?php
    /**
     * Plugin Name: Fix Domain Mapping Async Login
     * Plugin URI: https://hostmijnpagina.nl/
     * Description: Fixes the login cookie request by disabling object cache for when a user isn't logged in (yet).
     * Version: 1.0.0
     * Author: Sybre Waaijer
     * Author URI: https://cyberwire.nl/
     * License: GPLv2 or later
     */
    
    //* Make sure the user login is checked
    add_action( 'init', 'fix_dm_object_cache' );
    
    function fix_dm_object_cache() {
        if ( !is_user_logged_in() ) {
            if ( ! defined( 'DONOTCACHCEOBJECT' ) )
                define( 'DONOTCACHCEOBJECT', true );
        }
    }

    =================

    So what happened in this thread?
    1. We've solved a lot of HTTPS errors
    2. We've solved the async login feature with another plugin

    Marked as resolved :slight_smile:

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.