How to setup certificate renewal using FreeBSD, crontab, uacme and mini_httpd with Let’s Encrypt CA

If you are hosting your own services (like smtpd, httpd or any other) – there is a high chance you’ll need TLS certificate 🙂

If this post, we’ll setup very simple flow, to acquire and renew certificate for your server – using FreeBSD.

  1. I assume you have basic knowledge about FreeBSD and your domain has IN A record setup already 🙂
  2. Those commands needs to be run as root user 🙂
  3. Update packages – pkg update
  4. Install needed software – pkg install uacme mini_httpd
  5. Setup mini_httpd
    1. mkdir -p /usr/local/www/.well-known/acme-challenge – directory for our www root
    2. chown -R www:www /usr/local/www/ – make it owned by www user/group only
    3. sysrc mini_httpd_enable=”YES” – enable mini_httpd on system boot
    4. sysrc mini_httpd_flags=”-d /usr/local/www -u www -r” – serve files from our www root, chroot and run as www user
    5. service mini_httpd start – after this you should be able to access your machine using non-secure http://
  6. Now uacme:
    1. mkdir /usr/local/etc/uacme – here we will store our secrets
    2. uacme -v -c /usr/local/etc/uacme new – setup new account
    3. cp /usr/local/share/examples/uacme/uacme.sh /usr/local/etc/uacme/ – copy web challenge hook script that we will use
    4. edit this file and change one of the first lines to be like CHALLENGE_PATH=”/usr/local/www/.well-known/acme-challenge” – this need to match path from where mini_httpd is serving content
    5. crontab -e – lets add entry to crontab, that will issue/renew our certificate to keep it valid, change hour/minute to something else not to stress CA servers 🙂
    6. 3 42 * * * /usr/local/bin/uacme -c /usr/local/etc/uacme -h /usr/local/etc/uacme/uacme.sh issue your.domain
    7. save it and either wait one day or run the command directly (you can add -v to have more verbose output)
    8. your PEM file should be it /usr/local/etc/uacme/your.domain/cert.pem

More to read:

That’s it, now you can setup secure httpd/smtpd/other services that require valid TLS certificate.

Recover “lost” CRM encryption key

Have you ever had “Data encryption can’t be activated because the encryption key doesn’t match the source encryption key used to encrypt the data” error when trying to activate/change encryption key on organization that was imported or upgraded from previous CRM version?
If you’re on on-prem and you have MSCRM_CONFIG database of source organization, you can recover your key – that told if you don’t have backed it up 🙂

First, let’s retrieve it from database:

SELECT ColumnName, VarBinaryColumn FROM OrganizationProperties
WHERE Id IN (SELECT Id FROM Organization WHERE UniqueName = '<OrgUniqName>')
AND (ColumnName = 'SymmetricKeySource')

It will look like “0xABCDEF”, looks like hexstring, let’s decode:

var sb = new StringBuilder();
var str = "0x37323A303A3130313A303A3130383A303A3130383A303A3131313A303A33323A303A38343A303A3130343A303A3130353A303A3131353A303A33323A303A37333A303A3131353A303A33323A303A3131323A303A39373A303A3131353A303A3131353A303A36343A303A3131393A303A3131313A303A3131343A303A3130303A303A34393A303A33323A303A3130323A303A3131343A303A3131313A303A3130393A303A33323A303A36373A303A38323A303A37373A30";
for (int i = 2; i < str.Length; i += 2)
{
var b1 = byte.Parse(str.Substring(i, 2), NumberStyles.HexNumber);

var part = ASCIIEncoding.ASCII.GetString(new byte[] { b1 });

sb.Append(part);
}
Console.WriteLine(sb);

Now it should look like this:

72:0:101:0:108:0:108:0:111:0:32:0:84:0:104:0:105:0:115:0:32:0:73:0:115:0:32:0:112:0:97:0:115:0:115:0:64:0:119:0:111:0:114:0:100:0:49:0:32:0:102:0:114:0:111:0:109:0:32:0:67:0:82:0:77:0

As you know, password can be Unicode, so here we go again:

var parts = sb.ToString().Split(':');
sb.Clear();
for (int i = 0; i < parts.Length; i += 2)
{
var b1 = byte.Parse(parts[i]);
var b2 = byte.Parse(parts[i + 1]);
var part = UnicodeEncoding.Unicode.GetString(new byte[] { b1, b2 });
sb.Append(part);
}
Console.WriteLine(sb);

And we have our password: Hello This Is pass@word1 from CRM.

Compare this with CRM to be sure:
CRM Encryption Key

Hope this will help someone.

Installing Microsoft Dynamics CRM 2016 on Windows Server 2016

Running Out-of-the-box Windows 2016 Technical Preview 4, when trying to install Microsoft Dynamics 2016, I’ve run into this error (Action Microsoft.Crm.Setup.Common.InstallWindowsSearchAction failed):

CRM 2016 Installation Error

Checking for Windows Search Service, it looks like it’s installed:

Windows Search

Checking under “services.msc” – it was disabled. Simple changeing to “Manual”,  hitting “Retry” and installation continued without any further problems.

CRM Online Security roles strange issue

I’ve seen some strange issue lately (similar to this one), with one of our CRM Online deployment. We had 2 users, in the same BU, with the same security roles.
Problem was:

  1. First user was able to access CRM records based on priviliges
  2. Second one was “blind” – couldn’t see any records

After looking at all possible settings, the solution was:

  1. Add System Administrator role to second user
  2. Remove System Administrator role from second user

After that, second user could “see” again. Don’t know if removing all roles or any other than System Administrator would do the trick.

CRM Security Roles Summary

To quickly view which role have what rights, You can use this SQL query:

SELECT  DISTINCT
        r.Name
        ,COALESCE(e.OriginalLocalizedName, e.Name) AS EntityName
        ,CASE p.AccessRight
             WHEN 32     THEN 'Create' 
             WHEN 1      THEN 'Read'
             WHEN 2      THEN 'Write'
             WHEN 65536  THEN 'Delete' 
             WHEN 4      THEN 'Append'
             WHEN 16     THEN 'AppendTo'
             WHEN 524288 THEN 'Assign' 
             WHEN 262144 THEN 'Share' 
             ELSE 'None'
        END AS [Privilege]
        ,CASE (rp.PrivilegeDepthMask % 0x0F)
             WHEN 1 THEN 'User (Basic)'
             WHEN 2 THEN 'Business Unit (Local)'
             WHEN 4 THEN 'Parental (Deep)'
             WHEN 8 THEN 'Organization (Global)'
             ELSE 'Unknown'
        END AS [PrivilegeLevel]
        ,(rp.PrivilegeDepthMask % 0x0F) as PrivilegeDepthMask
        ,CASE WHEN e.IsCustomEntity = 1 THEN 'Yes' ELSE 'No' END AS IsCustomEntity
FROM    Role AS r
INNER JOIN RolePrivileges AS rp ON r.RoleId = rp.RoleId
INNER JOIN Privilege AS p ON rp.PrivilegeId = p.PrivilegeId
INNER JOIN PrivilegeObjectTypeCodes AS potc ON potc.PrivilegeId = p.PrivilegeId
INNER JOIN MetadataSchema.Entity AS e ON e.ObjectTypeCode = potc.ObjectTypeCode
ORDER BY r.Name, EntityName

Get strongly typed attribute logical name for CRM Entity

When using early bound entities, there’s a easy way to get CRM entity logical attribute name thanks to AttributeLogicalNameAttribute attribute in generated code. You can use this simple extension method:

        public static string GetEntityPropertyLogicalName<E, P>(this E src, Expression<Func<E, P>> expression)
        {
            var member = expression.Body as MemberExpression;
            if (member != null && member.Member is PropertyInfo)
            {
                var pi = member.Member as PropertyInfo;
                var pn = pi.Name;

                var epi = typeof(E).GetProperty(pn);
                var attr = (AttributeLogicalNameAttribute) epi.GetCustomAttribute(typeof(AttributeLogicalNameAttribute));

                if (attr == null)
                {
                    throw new System.ArgumentNullException(pn, "AttributeLogicalNameAttribute not found on property");
                }

                return attr.LogicalName;
            }

            throw new ArgumentException("Expression is not a Property");
        }

And usage is very simple:

            var account = new Account();
            var line1 = account.GetEntityPropertyLogicalName(p => p.Address1_Line1);

Now line1 should contain address1_line1 string.

Lookup Dialog in CRM 2013 with custom FetchXML filtering

Dynamics 2013 introduced some new cool functions to filter lookup during “run-time”, so we can do something like this:

var ctrl = Xrm.Page.getControl('some_lookup_control');
ctrl.addPreSearch(function() {
 var someFetchXml = '<filter type="and"><condition attribute="some_field" operator="eq" value="some_value" /></filter>';
 ctrl.addCustomFilter(someFetchXml);
});

Continue reading