Using OpenSSL on Windows to create a pfx certificate from a private key and cert file

Creating an PFX from a private key file and crt file on Windows.

Every year the task comes around to renew the SSL certificates for various services, depending on the certificate provider you can’t always download it as a PFX file.

Now for some services that’s fine, but for others – in this case Azure, we need to upload a PFX file.

Now, in this example it was a cert generated by GoDaddy. We get the private key in a file, along with the .crt file. What we need to do is use the 2 and generate the pfx.

We can use the OpenSSL executable, but where to find this on Windows, well if you have Git Desktop installed you can usually find it in the following folder.

C:\Program Files\Git\usr\bin

Now one note with the private key file, it is usually saved in the wrong encoding, so open it up in notepad (yes it will work for this), or your editor of choosing, you need to make sure the encoding type is UTF-8, my originally key file for example was saved as UTF-8 with BOM – it just doesn’t work.

I usually add this folder to my environment PATH, but that’s your choice.

If you have added it to your PATH, then enter the following at the command prompt in the folder you have your cert file (.crt) and private key file (.key)

openssl pkcs12 -export -in yourcert.crt -inkey yourprivatekey.key -out yournewpfx.pfx

If you didn’t add it to the PATH, then you will need to run the above command from the OpenSSL.exe folder.

Either way, replace the bold files with the appropriate ones for you, it should ask you for a password, then create your PFX file for you.

Easy 🙂

ASPNET Core – asp-append-version for remote images

Solving the asp-append-version problem with remote files in aspnet core with a custom TagHelper

I recently came across an issue where the site wasn’t refreshing images that the customer has updated even though they had changed them. Obviously browser caching was the original thought – which it was.

Some background, the is hosted on Azure and provided a back end portal for customers (B2B) to be able to order products via the website, these in turn are then pushed to the customers Microsoft Dynamics NAV instance (also known now as Microsoft Dynamics 365 Business Central). This has been developed my my Consultancy company in the UK – TAIG Solutions

In this instance the product images are actually stored seperately to the Azure site – they are hosted on the customers own on-prem server this makes it easier for the designers to update the images, they can just overwrite the image with a new one…. and here lies the problem…

One of the tools we have available is the asp-append-version tag which, when applied to the img tag basically adds a hash value of the file onto the end of the url, so for example

<img src="yourdomain.com/image.png?v=1234567890" />

The ?v=1234567890 being key, normally each time the file is served a hash is generated based on the file, so if the image changes, so does the hash and the browser will force a refresh of the image and not use the cached image.

However, this doesn’t work with files that are stored remotely, as we found out. There are a couple of solutions to this problem, but the easier we chose was to use the same versioning, but generate our own hash value – but not based on the file, we’d use the date (in this case they change the images so often we decided to do it on a day-by-day basis, but you could do something not as regular).

So how do we do this, we create our own TagHelper of course.

In your project, create a new class with the following code:

using Microsoft.AspNetCore.Razor.TagHelpers;
using System;

namespace TAIG.Solutions.WebPortal.TagHelpers
{
    [HtmlTargetElement("static-image-file", TagStructure = TagStructure.WithoutEndTag)]
    public class StaticImageTagHelper : TagHelper
    {
        // Can be passed via <static-image-file image-src="..." />. 
        // PascalCase gets translated into kebab-case.
        public string ImageSrc { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "img";    // Replaces <static-image-file> with <a> tag

            // create a version
            string version = DateTime.Now.ToString("yyyyMMdd"); // caching for a day - could use a setting in future?

            // generate url
            string url = $"{ImageSrc}?v={version}";

            output.Attributes.SetAttribute("src", url);
        }
    }
}

Now, in your _ViewImports.cshtml file we need to add the following

@addTagHelper TAIG.Solutions.WebPortal.TagHelpers.StaticImageTagHelper, TAIG.Solutions.WebPortal

Obviously if you changes the class name you need to adjust it, and make sure you change the namespace to the one you are using.

The result now, is we can now use our own tag instead of image, so instead of

<img src="yourdomain.com/image.png?v=1234567890" />

We can now use

<static-image-file image-src="yourdomain.com/image.png" />

Now code code will add a ?v= along with a date value which changes each day.

Problem solved. Yes, if they change an image during the day then, if you have viewed the page already you would have to wait until the following day for it to change, but that is good enough for us.

Use Python and Django to control your GPIO pins, hosted on a Raspberry Pi using Nginx and Gunicorn – Part 2 – Setting up the Raspberry Pi

In Part 2 we go through the initial setup of the Pi and its OS

Project overview

In this series of posts, I will go through all the steps required to use a Raspberry Pi along with Python and Django to control the GPIO pins for an automation project.

Part 1 – The introduction, what I hope to achieve and what you will need.

Part 2 (this one) – I will start right at the beginning with getting Raspbian installed and running, then moving onto the basic configuration of the Raspberry Pi.

Part 3 – Then we’ll move onto making sure we have Python and the required modules installed and do some basic tests to make sure we are happy Python is running and we can use the GPIO pins.

Part 4 – Now it will get interesting, we’ll install the Django module for Python, and then create our project and our app (it will make sense later), we’ll also have a quick look at our database options. Once we have this, we’ll create our backend objects so we can easily add/remove our GPIO pins as we please, all managed through the admin side of Django!

Part 5 – So we have our backend, now we’ll create our front end (warning – I’m not a front end master – design/graphics will be at a minimum!). This will allow us to turn our pins on and off – we’ll test it locally.

Part 6 – So we have everything sorted, all done, we can navigate to it on our internal network… well yes, but we shouldn’t be using the development server to run it full time. In this part we’ll look at using Gunicorn as our webserver.#

Part 7 – Great, we have Gunicorn serving our site, but we still shouldn’t expose this to the word, in step Nginx, this will sit between the outside and our Gunicorn server.

So all in all quite a few steps, this is all based on what I have learnt while trying to get everything working.  I hope you enjoy reading.

My disclaimer!

Before I go any further I should state that I am by no means a Linux, Python or Django expert, nor am I used to Nginx and Gunicorn for serving it up. There will no doubt be errors along the way, along with ways of doing things that aren’t best practice. This is very much intended as an internal network project so security will be minimal. I will also point out that my project will be switching mains power, you do this as your own risk, if you are not comfortable wiring mains just don’t do it, get an electrician.

Getting the Raspberry Pi ready

So this is where our fun really starts. First we need to download Raspbain, extract it onto the Micro SD Card and do a little configuration. I want it headless, which basically means for this series of posts I won’t need to connect and keyboard, mouse or monitor – everything will be done via SSH.

So firstly to download Raspbian, head over to https://www.raspberrypi.org/downloads/, we need to get the appropiate imager for the OS we’ll be using to do the setup, in my case I am going to download the Imager for macOS.

Once downloaded open it, firstly we choose the OS, which you choose is ultimately your choice, for this we are going to choose Raspbain (Other), then the Lite option – we don’t need the Desktop for this, plus its the smallest download size. Now select your SD Card, then click Write. Sit back while it does the work for you 🙂

Ok, so once that has done, reinsert the SD Card and it should mount/show a drive called boot. This is what we want.

So we need to setup the following before we even boot.

  1. SSH Connectivity
  2. Wi-Fi Connection
  3. Static IP address
  4. Pi Password

By default, since 2016 I think, SSH has been disabled by default on Raspbian. As we need this enabled to connect, that will be our first change.

With your SD card plugged into your computed, navigate to the boot partition or volume. On Windows this should show up as a drive, I’m using a Mac, so I need to go to /Volumes/boot.

In here, to enable SSH at boot, we simply need to create a file called SSH, that’s it! So on my Mac, in the boot directory I simply run:

touch SSH

That’s SSH enabled.

Next, Wi-Fi. Now I’m assuming you are using Wi-Fi, if you are using a cabled connection you can skip this part.

Again, this has been made easy, we need to create another file in the boot folder, this time called wpa_supplicant.conf.

Unlike last time we now need to edit this file and put the following content in it, replacing the placeholders with your Wi-Fi details:

network={
 ssid="<Name of your wireless LAN>"
 psk="<Password for your wireless LAN>"
}

Okay, so thats our Wi-Fi setup, now I like to use a static IP address on my network.

Now there are 2 ways you can do this, if you have linux/mac it is possible to mount and see the entire Raspbain system, edit the file you need and it’s done. However, its a little more involved and beyond what I want to cover here, so we are going to do it the easy way.

Remove the SD card, place it in your Raspberry Pi – make sure the monitor and keyboard are plugged in, turn it on 🙂

Once booted, enter the default user pi and the password raspberry. You should now be logged in.

From the prompt type:

sudo nano /etc/dhcpd.conf

Go to the bottom, for a Wi-Fi connection type:

wlan0 interface 
static ip_address = 192.168.1.100 / 24 
static routers = 192.168.1.1 
static domain_name_servers = 192.168.1.1

If you are using a cabled connection, type:

eth0 
static ip_address = 192.168.1.100 / 24 
static routers = 192.168.1.1 
static domain_name_servers = 192.168.1.1

You’ll notice the only difference if the first line, this defines the cable connection or Wi-Fi connection. Adjust the IP address and subnet to suit what your network needs.

Reboot the Raspberry Pi… Once restarted and logged in type:

ifconfig

This will show your current IP address, it should match what you had in your above file now.

Excellent, good progress. Lastly for this part we need to change our user password, to do this simply type the below and follow the prompts:

passwd

Okay, you’ve now changed your default password for the pi user. Shutdown the Raspberry Pi. You can now disconnect the monitor and keyboard if you want, we can do the rest remotely – or you can leave it connected and do it on the Raspberry Pi if you prefer.

Well that’s if for part 2, in the next part things start to get interesting..

Bye.

Dynamics NAV 2018 and VS Code – Debugging Error, sorry that didn’t work

So you have downloaded and installed the shiny new version of Microsoft Dynamics NAV, fired up VS Code to create your first extension, run it, but then when the WebClient opens you are greeted with the blue screen and a ‘Sorry that didn’t work’ message…

Fortunately there is a quick fix, navigate to the C:\Program Files\Microsoft Dynamics NAV\110\Service folder, and edit the Microsoft.Dynamics.Nav.Server.exe.config file (you need to edit it with Administrator rights), find and remove the following line;

<NetFx40_LegacySecurityPolicy enabled=”true”/>

Restart the NST and viola 🙂

 

Dynamics N.A.V and Homogenous AppDomain Error

Homogenous AppDomain Error within Microsoft Dynamics N.A.V.

What an earth I hear you ask.. well that’s what I thought too.

Background

So I have doing some development, basically I have an incoming Json feed from a Shopify Web-hook, my initial thought was to create a C# Object which I could reference as a DotNet variable in Dynamics N.A.V. the using Newtonsoft deserialize into this object.. easy.. and to be honest it was…

Until that is I got sent a request from Shopify that had an unexpected reference. Originally when I built the object class I used the samples provided by Shopify, turns out though that the sample doesn’t contain everything, so the first time a shipment notification came through that contained an order with a refund…. bam! It broke.

My original object didn’t have a Refunds section, so when I tried to deserialize it, well it didn’t know what to do.

So… I thought I would simply use a dynamic object, then just map info I actually needed, ignoring what I didn’t, then pass this back into Dynamics N.A.V.

I added an overloaded constructor to my c# class which now looked like;

///
<summary>
/// Ctor +1
/// </summary>
/// <param name="jsonText"></param>
public FulfillmentNotice (string jsonText)
{
    dynamic t = JsonConvert.DeserializeObject<dynamic>(jsonText);

    id = t.id;
    order_number = t.order_number;
    billing_address = t.billing_address.ToObject<Address>();
    shipping_address = t.shipping_address.ToObject<Address>();

    payment_gateway_names = new List<string>();
    foreach (string s in t.payment_gateway_names)
        payment_gateway_names.Add(s);

    // init list
    shipping_lines = new List<Shipping_Lines>();
    foreach (dynamic shipline in t.shipping_lines)
        shipping_lines.Add(shipline.ToObject<Shipping_Lines>());

    // init list
    fulfillments = new List<Fulfillment>();
    foreach (dynamic fulLine in t.fulfillments)
        fulfillments.Add(fulLine.ToObject<Fulfillment>());

    // init list
    discount_codes = new List<Discount_Codes>();
    foreach (dynamic disLine in t.discount_codes)
        discount_codes.Add(disLine.ToObject<Discount_Codes>());

}

So now I call the new constructor passing in the Json text, worked nicely, now it completely ignores anything unexpected, great!

Next I altered my codeunit within Dynamics N.A.V. to use the new code, complied then ran the function, unfortunately I got..

A call to ShopifyFulfillmentReceiver.Library.FulfillmentNotice failed with this message: Dynamic operations can only be performed in homogenous AppDomain.

Well I wasn’t really expecting that, though I thought I had seen it before.

The Solution

So what do you need to do? You need to remove/change the following file in the Microsoft.Dynamics.Nav.Server.exe.config file. Find the section <runtime> and you should see a line <NetFx40_LegacySecurityPolicy enabled=”false”/> and change it to false, restart the NST and it should work –  if the section exist, put the below withing the <configuration> section

<runtime>
<NetFx40_LegacySecurityPolicy enabled="false"/>
</runtime>

As always, you should check it on a dev instance before rolling out to a live instance, making sure it doesn’t affect anything!