SSL Certificates for Jabber

This week I’ve ventured out of my comfort zone while helping out with the Microsoft side of things on a Cisco Jabber project. First of all I’d like to point you to this document: Jabber Complete How-To Guide for Certificate Validation. While not the clearest of all it does contain everything you need to know. I had to read it a couple of times to completely understand what needs to be done so here is my own summary.

You can take three approaches with certificates but whichever method you go for to have any chance of the certificate being verified by the client device you need to make sure you have A records created for each server and then using the FQDN rather than IP addresses in a fair few places as listed in the Cisco article. Otherwise you’d end up with a mismatch between the server address and the certificate.jabber1

Source: http://www.cisco.com/c/en/us/support/docs/unified-communications/unified-presence/116917-technote-certificate-00.html

  1.  Use the default self signed certificates from each server (Cisco Unified Communications Manager IM and Presence, Cisco Unified Communications Manager,Cisco Unity Connection).
    This is quite simple as you don’t need to generate any new certificates at all. You just need to find a way of making your devices trust these.
  2. Use private CA to sign the certificates.
    This is the route we went down. The main advantage is that your domain devices will already trust your enterprise CA so there isn’t much work required there and in all fairness it doesn’t take long to request and upload the new certs. You’re still going to run into issues on devices that aren’t a part of  your domain and will have to find another way of making them trust the CA but this wasn’t an issue in this case.
  3. Use public CA.
    Most devices should already trust certificates issued by public CA so regardless of weather your devices are domain members or not you shouldn’t need to do anything special. The only downside here is the cost as you’ll need a minimum of 4 certificates and possibly more if you’re going for cluster configuration as each server will need a signed certificate.

Cisco recommend options 2 and 3. If you decide to go down the self signed route there are 2 methods to get your clients to trust these certificates:

  1. Get your users to accept the certificate warnings when they sign into the Jabber client for the first time. This imports the server certificates to the Enterprise Trust Store on the device.
  2. Run a scrip (perhaps as part of your logon script) to import these. You’ll need to download all four server certificates and place them in a network share accessible by the users. The script should look something like this:certutil -f -addstore “trust” “\\server\certs\cert1.cer”
    certutil -f -addstore “trust” “\\server\certs\cert2.cer”
    certutil -f -addstore “trust” “\\server\certs\cert3.cer”
    certutil -f -addstore “trust” “\\server\certs\cert4.cer”If you’re unsure which certificates you need just sing in to the Jabber client and accept all warnings. Then look at the Enterprise Trust Store on your computer.

Using Enterprise CA to sign certificates

As I said before the method I have experience with is using a private CA and that’s the scenario I’m going to focus on. Assuming all the DNS configuration is in place you need to get a CSR generated for each required certificate and then submit these to your Enterprise CA.

Server Certificate
Cisco Unified Communications Manager IM and Presence TomcatXMPP
Cisco Unified Communications Manager Tomcat
Cisco Unity Connection Tomcat

 

If you’re running the servers above in a cluster set up you need to sign certificates for all of them.

Before the XMPP CSR is generated the following needs to be done on the server:

  1. Open the administration interface for your presence server, either the Cisco Unified CM IM and Presence Administrationinterface or the Cisco Unified Presence Administration interface.
  2. Navigate to System > Security > Settings.
  3. Locate the XMPP Certificate Settings section.
  4. Specify the presence server domain  in the Domain name for XMPP Server-to-Server Certificate Subject Alternative Name field. The part of users’ logon name after the @ sign (user@yourdomain.com)
  5. Check the Use Domain Name for XMPP Certificate Subject Alternative Name check box.
  6. Click Save.
  7. Restart XCP Router in order for the change to take effect.

I’m not the person to go to on how to generate the CSRs so just borrowing from the Cisco article.

Generate a CSR

Note: This example is for CUCM Version 8.x. The process might vary between servers.

  1. Navigate to Cisco Unified OS Administration.
  2. Choose Security > Certificate Management.
  3. Click Generate CSR, and choose Tomcat from the drop-down list.
  4. Click Generate CSR, and click Close.
  5. Click Download CSR, and choose Tomcat from the drop-down list.
  6. Click Download CSR, and save the file.
  7. Send the .csr file to be signed by your Private CA Server or a Public CA.

Request a certificate

  1. Browse to https://<yourinternalCA>/certsrv
  2. Click on Request a certificate, then Submit an advance certificate request.
  3. Create and submit a request to this CA
  4. Select Web Server template and paste in the contents of the CSR file.
  5. Submit the request and then download the certificate chain.

You’ll be selecting the web server template for each certificate even the XMPP one.

Now upload each newly signed certificate chain under Security > Certificate Management. You’ll need to restart the tomcat service and the XCP router after the upload for the servers to start using their new certificates.

If you’ve previously accepted the certificate warnings on your test PC you’ll need to delete them manually from the Enterprise Trust Store in order to properly test your certificate verification. When you sign in on a new PC now you shouldn’t get any warning at all.

I intended a more concise and clear variation on the original Cisco article but I’m not too sure I’ve completely succeeded – feel free to leave me a comment.

Creating AD users from a CSV file

I must be in scripting mood lately. Here we have a belated Christmas present in the form of a powershell script to create users from a csv file.

Again I have butchered somebody else’s script so if you’d like the unobliterated version head over to http://gallery.technet.microsoft.com/office/AD-and-mailbox-from-CSV-96a4713f – thanks Rahmat!

My own addition is the little waiting and checking section in the middle as I sometimes had the mailbox creation fail as it couldn’t see the user yet.

I’ve also added a section for creating home drives as for some reason when you assign the home folder location during the AD user creation it only adds the AD property but doesn’t actually create the folder.

For my purposes the CSV has the folowing headers:

LastName,FirstName,Username,Title,Password,OU,Database

But you could add more as needed and use in the script:

#############################################################################
# New-UserAD and Email + Home Folder
# Create email and AD Account for new Users in Contoso.com
#
# ============================================================================

$date = Get-Date
#Set up Log files for output
$ErrorLog = “C:\PS\Errorlog.txt”
$SuccessLog = “C:\PS\Successlog.txt”
Add-Content $SuccessLog “————————————————————————————————-”
Add-Content $SuccessLog $date
Add-Content $SuccessLog “————————————————————————————————-”
Add-Content $ErrorLog “—————————————————————————————————-”
Add-Content $ErrorLog $date
Add-Content $ErrorLog “—————————————————————————————————-”

## Create Session with Exchange 2010 change your URI address
$s=New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://EXCHANGESERVER/powershell -Authentication Kerberos

## Add AD Cmdlets
Import-Module ActiveDirectory
#Import CSV

$csv = @()
$csv = Import-Csv -Delimiter “,” -Path “C:\PS\newADuserList.csv”
#Get Domain Base
$searchbase = Get-ADDomain | ForEach { $_.DistinguishedName }

#Loop through all items in the CSV
ForEach ($user In $csv)
{

## change your OU with your own OU
$OU = $User.’OU’
$Password = $User.Password
$title= $user.’Title’
$lastname= ($user.’LastName’.Substring(0,1).toupper() + $User.’LastName’.Substring(1).tolower())
$Detailedname = $User.’FirstName’ + ” ” + $lastname
$UserFirstname = $User.’FirstName’
$SAM = $User.’Username’
$UPN= $SAM + “@YOURDOMAIN.COM”
$Displayname= $User.’Username’
$Dis= $User.’title’ + ” ” + “$Detailedname”
$group= “ADGROUPS TO INCLUDE USER IN”
$homedrive= $User.HomeDrive
$logonscript= “LOGON SCRIPT PATH”
$database= $User.’Database’

#Check if the User exists
$NameID = $user.’Username’
$User = Get-ADUser -LDAPFilter “(SamAccountName=$NameID)”
If ($User -eq $Null)

{
#Create the User if it doesn’t exist

$create = New-ADUser -Name $SAM -SamAccountName $SAM -UserPrincipalName $UPN -DisplayName $Displayname -Path $OU -GivenName $UserFirstname -Surname $lastname -AccountPassword (ConvertTo-SecureString $Password -AsPlainText -Force) -Enabled $true -Description $Dis -HomeDrive Z: -HomeDirectory $homedrive -ChangePasswordAtLogon $true;

do
{
#Wait for bit as sometimes the user creation takes a little while to take effect
sleep -seconds 3
$accountExists = get-ADUser -LDAPFilter “(SamAccountName=$SAM)”
Write-Host “.” -nonewline
} while ($accountExists -eq !$Null)

Write-Host “AD Account $Detailedname created!”

add-content $SuccessLog “User $SAM created Sucessfully.”

## Adding User to Group
Add-ADPrincipalGroupMembership -Identity $SAM -MemberOf $group

Write-Host ” Added to Groups Needed”

add-content $SuccessLog “AD User $SAM Added to groups Sucessfully.”
Write-Host -ForegroundColor Green $SAM

### Create Homedrive

# Assign the Drive letter and Home Drive for the user in Active Directory
$HomeDrive=’Z:’
$UserRoot=’\FILESERVER\USERSHARE\’
$HomeDirectory=$UserRoot+$SAM
SET-ADUSER $SAM –HomeDrive $HomeDrive –HomeDirectory $HomeDirectory

# Create the folder on the root of the common Users Share
NEW-ITEM –path $HomeDirectory -type directory -force
$Domain=’YOURDOMAIN’
$IdentityReference=$Domain+’\’+$SAM

# Set parameters for Access rule
$FileSystemAccessRights=[System.Security.AccessControl.FileSystemRights]”FullControl”
$InheritanceFlags=[System.Security.AccessControl.InheritanceFlags]”ContainerInherit, ObjectInherit”
$PropagationFlags=[System.Security.AccessControl.PropagationFlags]”None”
$AccessControl=[System.Security.AccessControl.AccessControlType]”Allow”

# Build Access Rule from parameters
$AccessRule=NEW-OBJECT System.Security.AccessControl.FileSystemAccessRule -argumentlist($IdentityReference,”FullControl”,”ObjectInherit, ContainerInherit”,”None”,”Allow”)

# Get current Access Rule from Home Folder for User
$HomeFolderACL=Get-ACL $HomeDirectory
$HomeFolderACL.AddAccessRule($AccessRule)
SET-ACL –path $HomeDirectory -AclObject $HomeFolderACL

## Creating Mailbox on EX2010
Enable-Mailbox -Identity $SAM -Alias $SAM -Database $database

## Set Dial in Properties
set-aduser $SAM -replace @{msnpallowdialin=$true}
## Set Dial in Properties
set-aduser $SAM -replace @{msnpallowdialin=$true}

Add-Content $SuccessLog “—————————————————————————————————-”

}
Else

{
## If user already exists unlock and enable user account and log message in error log.
Unlock-ADAccount -Identity $SAM
Enable-ADAccount -Identity $SAM
Write-Host -ForegroundColor Red “AD User $SAM already exists. Account unlocked.”
add-content $ErrorLog ” User Already exist : $Detailedname. Account unlocked”

Add-Content $ErrorLog “—————————————————————————————————-”

}

}

My favourite inventory script

UPDATE: New script download link here.

Last week I received one of the most dreaded emails ever. It began with “can you please fill out an inventory spread sheet for this customer?”. I’ve been through a fair few IT jobs and whether I worked for a small or large company documentation was never their strong side so I pretty much knew I’d have to do it from scratch. Luckily I came across Jesse Hamrick’s script on the powershellpro site. You can download my edited version here.

I’ve only made a couple of modifications to the original script:

1. Replaced 1024 / 1024 with 1GB to get RAM etc. in GB instead of MB and updated the spreadsheet headers accordingly.

2. Excel 2013 only creates one worksheet rather than three when you open a new workbook so you’ll end up missing two sheets (networking and disks). To create the two additional sheets I’ve inserted  two more lines of $Sheet = $Excel.Worksheets.Add().

And that’s it. You can obviously tweak this as much as you want but Jesse’s original script pretty much does everything I need it t do.

Below is an example of the spread sheet it produces:

This slideshow requires JavaScript.

Attachments not visible in Outlook 2010

Even though multipart messages have been around for ages and generally the features and interoperability across all sorts of email clients are pretty good I often come across issues where in particular Outlook can’t quite handle certain content types.

On this occasion the problem was such that emails with attachments from a particular sender were getting delivered fine but the recipient couldn’t see the attachments anywhere even though the message size clearly suggested there should be some. After some quick investigation it became apparent that while Outlook 2010 didn’t display the attachments OWA did albeit without showing the usual paperclip icon next to the message. Users were also able to see the attachments on their blackberries. This suggested that the issue lies within outlook (2010 in my case but it later transpired that Outlook 2007 would do the same).

Quick google revealed a KB article which pretty nicely matched my problem. The problem is with Exchange not validating reference to an inline attachment and hiding the attachment. I have followed the resolution steps:

  1. Stop the Exchange Transport service.
  2. Locate the EdgeTransport.exe.config file. This file is located in the following path:  <drive> :\Program Files\Microsoft\Exchange Server\Bin\
  3. In the EdgeTransport.exe.config file, add the following entry between the <appSettings> element and the </appSettings> element: <add key=”TreatInlineDispositionAsAttachment” value=”true” />
  4.  Restart the Transport service.

After getting the affected sender to resend the message the attachments were displayed but no paperclip in the navigation pane. I was a little bit intrigued as to why would Exchange regard the attachments as inline in the first place when I knew these were individual attachments. To get to the bottom of this problem I have compared the headers of two messages – one that was displayed correctly and one without the paperclip. Messages from the affected senders had the Content-Type header value as multipart/related while a normally displayed message would be multipart/mixed. You can find all the details on RFC2387 here but to get to my point the use of multipart/related isn’t correct in this scenario where the recipient is expected to view individual attachments.

Exchange considers all attachment parts inside multipart/related as inline attachments which should be accessible from inside the body and therefore hides them from the attachments list which explains why the first solution worked but suggests a nicer solution.

Since the MIME is malformed we really should be fixing the original message format. In most cases you will have no control over the sender’s infrastructure so the only option left is creating a hub transport rule on your Exchange server to change the content-type value from multipart/related to multipart/mixed:

  1. Launch Exchange Management Console
  2. Expand Organization Configuration, and select Hub Transport
  3. Select New Transport Rule … in the action pane
  4. Give the rule a name (ex. Change Content-Type)
  5. Select When the message header contains text patterns
  6. Under message header enter Content-Type and multipart/related under text patterns. Click Next.
  7. Select Set header with value and enter Content-Type as header.
  8.  Enter multipart/mixed as value and click Next.
  9. You don’t need to create any exceptions (unless you want to).
  10. Click finish to complete the rule creation.

With this solution you should have the message display nicely including the paperclip in Outlook navigation pane.

The joys of SCCM or How difficult is it to get an inventory report

It all started with the simple thought of getting a list of all PCs at my work with some pretty basic info like the computer name, model number, OS….I didn’t think I was being too demanding especially knowing I can put SCCM to work. I was in for a major surprise or disappointment when I found that no such report comes with SCCM and you have to build a custom report.

In the spirit of not reinventing the wheel and with the hope of not being the only person on the planet that ever wanted to do this (not to mention my less than impressive skills when it comes to SQL) I have enlisted the help of the online community. Fortunately I have found enough information to get me started and in the end came up with the following query:

SELECT  distinct
CS.name0 as ‘Computer Name’,
CS.domain0 as ‘Domain’,
v_R_System.Last_Logon_Timestamp0 as ‘Last logon’,
v_R_System.User_Name0 as ’ Username’,
BIOS.SerialNumber0 as ‘Bios serial’,
SE.SerialNumber0 as ‘System Enclosure serial’,
CS.Manufacturer0 as ‘Manufacturer’,
CS.Model0 as ‘model’,
OS.Caption0 as ‘OS’,
RAM.TotalPhysicalMemory0 as ‘Total Memory’,
sum(isnull(LDisk.Size0,’0’)) as ‘Hardrive Size’
from
v_GS_COMPUTER_SYSTEM CS right join v_GS_PC_BIOS BIOS on BIOS.ResourceID = CS.ResourceID
right join v_GS_SYSTEM SYS on SYS.ResourceID = CS.ResourceID
right join v_GS_OPERATING_SYSTEM OS on OS.ResourceID = CS.ResourceID
right join V_GS_X86_PC_MEMORY RAM on RAM.ResourceID = CS.ResourceID
right join v_GS_Logical_Disk LDisk on LDisk.ResourceID = CS.ResourceID
right join v_GS_SYSTEM_ENCLOSURE SE on SE.ResourceID = CS.ResourceID
right join v_R_System on v_R_System.ResourceID = CS.ResourceID
where
LDisk.DriveType0 =3
group by
CS.Name0,
CS.domain0,
v_R_System.User_Name0,
v_R_System.Last_Logon_Timestamp0,
BIOS.SerialNumber0,
SE.SerialNumber0,
CS.Manufacturer0,
CS.Model0,
OS.Caption0,
RAM.TotalPhysicalMemory0

The resulting report looks something like this:

Capture

Bear in mind that this report doesn’t provide real-time information and based on your SCCM inventory settings can be out by quite some time. For example my Heartbeat discovery only runs once a day so data like last logon can be outdated.