Thursday, December 13, 2018

Vagrant and Wordpress - Creating a Self Signed Certificate that Doesn't Make Chrome Crabby

Maybe I'm slow, but I recently discovered http://vccw.cc/, which is a great, easy way to get a Vagrant machine up and running with Wordpress.

My problem was that the site I'm working on uses SSL/HTTPS (as pretty much all sites do these days, and FYI they can do so freely thanks to Let's Encrypt).

Vagrant, Apache2, MySQL, Wordpress - everything was working fine, but I would get a dreaded Chrome error complaining about an invalid secure certificate. VCCW does install a self-signed certificate for you, but it's for vccw.test, which of course is not the domain of my site!

I was able to create a simple self-signed certificate easily by going into Vagrant (vagrant ssh) and using openssl, but Chrome still didn't like the fact that the certificate (a) was not signed by a trusted root authority, and (b) did not contain any subject alternative name information.

It took me a little while to piece together the steps for creating the certificate that contained these necessary features, and allowing Chrome to accept the certificate.

Here are my steps:

1. Log into Vagrant (vagrant ssh)

2. Navigate to the folder where apache will look for certificates:
cd /etc/apache2/ssl

3. Create a text file with the subject alternative name information:
sudo vi example.com.san

and in that file enter your SAN info:
subjectAltName=DNS:example.com,DNS:www.example.com

4. Create a certificate authority ca.key key and ca.crt certificate, if you don’t have one already (see note below about adding this ca.crt to Chrome):
sudo openssl genrsa -out ca.key 2048
sudo openssl req -new -x509 -days 365 -key ca.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=Acme Root CA" -out ca.crt

5. Create a certificate signing request for the domain you want to secure:
sudo openssl req -newkey rsa:2048 -nodes -keyout example.com.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=*.example.com" -out example.com.csr

6. Sign the certificate with your certificate authority:
sudo openssl x509 -req -extfile example.com.san -days 365 -in example.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out example.com.crt

Now you can update the apache config to use this new certificate and key.
sudo vi /etc/apache2/sites-enabled/000-default.conf

<IfModule mod_ssl.c>
  <VirtualHost example.com:443>
    ServerName example.com
    ServerAlias *.example.com

    DocumentRoot /var/www/html

    EnableSendfile off

    <Directory /var/www/html>
      Options FollowSymLinks
      AllowOverride FileInfo Options Limit
      Order allow,deny
      Allow from all
    </Directory>

    <Directory />
      Options FollowSymLinks
      AllowOverride None
    </Directory>

    LogLevel info
    ErrorLog /var/log/apache2/vccw.test-error.log
    CustomLog /var/log/apache2/vccw.test-access.log combined

    RewriteEngine On
    SSLEngine On
    SSLCertificateFile /etc/apache2/ssl/example.com.crt
    SSLCertificateKeyFile /etc/apache2/ssl/example.com.key
</VirtualHost>
</IfModule>


Finally, restart apache2:
sudo service apache2 restart

Now open up your development site in Chrome (you may need to completely close and re-open Chrome) and enjoy purportedly-secure browsing!


NOTE: If you just created a new certificate authority in step 4 above, you will need Chrome to trust your new certificate authority. Save the ca.crt file to your local machine (wherever you are running Chrome). Then, in Chrome, click the three dots in the upper left, go to Settings, scroll down and click to show Advanced Settings, then click Manage Certificates. In the box, click the tab for Trusted Root Certificate Authorities. Click Import, and select your ca.crt from your machine. Accept all the scary warnings. Then you should see your new certificate in the list:



Again, you may need to restart Chrome to get this to take effect.

Tuesday, September 22, 2015

Remote Desktop - password expired, but you can't change it? Solved. Well, for us, anyway...

If you're like me and you manage several Windows machines, you use Remote Desktop (RDP) frequently. In one environment, we run Windows Server 2012. Since this environment has multiple dedicated web servers and databases, we utilize Active Directory manage our credentials. Our passwords expire regularly, and we need to reset them.

If you are using these machines often, you would see a notification in the task tray saying that your password is about to expire in X days (usually I notice the warnings start at 5 days). You can then do the good ol' Ctrl+Alt+End to access the Change Password feature.

Unfortunately for me, in this particular environment, I may go a week or more without logging on. If I miss my password expiration, and then try to log in using Remote Desktop, I'm stuck: instead of having the chance to change my password, I get a message saying that my password has expired, and that I need to contact my "administrator". Well, I'm the administrator... Darn those administrators!

Finally, after frustration grew, I dug and discovered the solution here: https://gist.github.com/pingec/7b391a04412a7034bfb6
If the remote machine does not enforce NLA (Network Level Authentication), it is still possible to start a remote desktop session by disabling NLA on the client. 
Add the following setting to your .rdp file ("C:\Users\\Documents\Default.rdp" if you aren't using a specific one). 
enablecredsspsupport:i:0
Phenomenal - simply opening my Default.rdp in a text editor and adding that one setting (enablecredsspsupport:i:0) to the end made all the difference. Now, I was able to enter my old password, and then prompted immediately to change. Hopefully this saves you undue frustration as well.

Friday, March 6, 2015

Automatically closing InfoWindows in Google Maps API v3 when using KML Layers

I had a client request related to the Google Maps API v3. The client is displaying a map that uses KML Layers to display additional markers and data. The map looks great. The issue was: each time you click on a marker, an InfoWindow opens. If you click on another marker, or on the map itself, the marker stays visible. You have to manually close each InfoWindow (using the little X in its upper left corner). The desired behavior was to have just one InfoWindow open at a time, and to automatically close that InfoWindow if the user clicked on the map (where there was no marker).

The solution that worked for the client was to have one single, global InfoWindow object. We could then make sure that only one InfoWindow was open, and we could close it whenever we wanted.

The challenge, though, was that the InfoWindows that appear for KML Layers seem to appear "by magic". It wasn't immediately obvious how to get a handle on the new InfoWindows when they appeared.

Fortunately, KMLLayer objects allow us to disable the default InfoWindows, and then listen to the "click" event so we can create them ourselves.

There's a great simple demo available that shows you all the pieces:
https://developers.google.com/maps/documentation/javascript/examples/layer-kml-features

In the above demo, you can see that, instead of opening an InfoWindow, the InfoWindow contents are displayed in a div to the right of the map.

Instead of displaying in a div, we can display in our own InfoWindow.

First, let's create a global variable for our InfoWindow object, and our map object.

// Using a global infowindow.  Each marker click simply changes this content
// and reopens it at a new location.
var _globalInfoWindow = new google.maps.InfoWindow();

// Global map object used as well.
var map;


Then, when adding your KML layer, you'll want to be sure to suppress the default InfoWindows using the suppressInfoWindows option:

    var kmlLayer = new google.maps.KmlLayer({
        url: 'http://kml-samples.googlecode.com/svn/trunk/kml/Placemark/placemark.kml',
        suppressInfoWindows: true,
        map: map
    });

Next, since we just suppressed the default InfoWindows, we'll need to add our own function to display InfoWindows. Note this function will receive a kmlEvent as a parameter:

// Function to create our own info windows.
// This is used simply to get a global handle on the info windows created
// using the KML data. We can use this handle to close the window later.
function handleInfoWindow(kmlEvent) {

    // Close any prior infowindow.
    _globalInfoWindow.close();

    // Set up the new info window based on the KML data.
    _globalInfoWindow = new google.maps.InfoWindow({
        content: kmlEvent.featureData.infoWindowHtml,
        position: kmlEvent.latLng
    });

    // Open (display) the info window within our global map.
    _globalInfoWindow.open(map);
}

Now the "magic" - we can add a listener to the KML Layer! This allows us to listen for the click event on all those magically-placed markers (defined within the KML data).

    
    google.maps.event.addListener(kmlLayer, 'click', handleInfoWindow);

With that all done, we can add a listener on the map itself to close info windows when the map is clicked:

   google.maps.event.addListener(map, "click", function(event) {  
        // If the map is clicked, close any potentially-open infowindow.
        _globalInfoWindow.close();
 });

Great! The InfoWindow appears when I click on the marker, and disappears when I click on the map.

Note that I can easily add more KML layers with the same functionality:

    var anotherKmlLayer = new google.maps.KmlLayer({
        url: 'http://somethingelse.com/whatever.kml',
        suppressInfoWindows: true,
        map: map
    });
    
    google.maps.event.addListener(anotherKmlLayer, 'click', handleInfoWindow);

Another interesting thing to note is that, although the InfoWindow disappears on click, it will linger if you drag the map.

Here's a demo:
http://jsfiddle.net/b02eoynv/1/





  
   - jsFiddle demo