Thursday, February 25, 2010

SSL and Certificate security with WCF

Set up WCF to use certificates for security. There are a number of examples and tutorials, but there is still a number of gotchas in doing this, the keys we found being:

- For TRANSPORT security using Certificate authentication
  • make sure you have a ROOT CA, and trust it on both the server and the client. This means the ROOT CA public key needs to be imported into the trusted certificates of both. Transport security will not work (even in dev) without a trusted CA on both the client and server.
  • make sure the server SSL certificate is issued to the server name you will be using in the URL - i.e if you are using http://my.server.wcf/MyService, then issue the SSL server certificate to my.server.wcf
  • make sure your client certificate has a private key and it is imported to the personal cert store on the client. Ensure the client's public key is in the trusted people on the server.
  • Ensure the web site n IIS has SSL required checked on, and require client certificate checked on.
  • We setup up a vanilla web site with a simple "Hello World" web page to check the SSL and client certificates are working (Require SSL and Require Client Certificate turned on). If you use IE to connect to the basic web site on the server, it should prompt you to select a certificate. If you can select your certificate and connect to a basic web site, then the same certificates will work in WCF. If not, then it wont work in WCF either!
  • you can use certificate mapping to map to a windows account, and then use .net security demands in your application is normal. Make sure you set windows account mapping on in the wcf server configuration (mapClientCertificateToWindowsAccount="true") AND in IIS.
  • you can achieve this with self signed certificates or CA assigned certificates
  • you can achieve this in IIS 6 and IIS 7
- For MESSAGE security using certificates
  • basic Message security with certificates is simpler
  • use PeerTrust, and trust the client public key on the server, and the server public key on the client (Trusted People).
  • No need for a trusted CA (or any CA) in this configuration
  • use the identity/dns settings in the wcf configuration to match the certificate names issued to the server and client.
  • certificate mapping to windows accounts does not work using message security
  • you can achieve this with self signed certificates or CA assigned certificates
  • you can achieve this in IIS 6 and IIS 7
Thats a simple checklist of things to look out for. Hope it helps someone.


Monday, February 1, 2010

Create ADAM accounts in VB.NET SSIS script

Had to write an SSIS script to Load accounts in to ADAM and had trouble trying to get it working. In the end it looks pretty simple but the gotcha's are in what you can and can not set against the user class, and also setting the password encoding and port.

Here is my method that met my requirements for creating the ADAM accounts with a password, ready to use. I searched all over for how to do this and borrowed bits and pieces from other posts and samples, but in the end did not find a sample that was as simple as this with only one commit.

NOTE this is for a NON-SSL installation, where the ADAM accounts are used by an ASP.NET application via the Membership Provider.

Also note that in this installation the user name and email are required to be the same - hence the search on the mail property being equal to the user account to ensure duplicates are not created.
---------------------------------------------------------------------------------------------
Public Function CreateADAMAccount(ByVal LdapDomain As String, ByVal AUser As String, ByVal APwd As String, ByVal userAccountToCreate As String) As Boolean

Dim resList As List(Of String) = New List(Of String)()
Dim distinguishedName As String = String.Empty
Dim connectionPrefix As String = LdapDomain
Dim entry As DirectoryEntry = New DirectoryEntry(connectionPrefix, AUser, APwd, AuthenticationTypes.ServerBind)

Dim mySearcher As DirectorySearcher = New DirectorySearcher(entry)

' do the search just to be sure that there is no other account with that email address
mySearcher.Filter = "(&(objectClass=user)(mail=" & userAccountToCreate & "))"
mySearcher.PropertiesToLoad.Add("distinguishedName")
mySearcher.PropertiesToLoad.Add("cn")
mySearcher.PropertiesToLoad.Add("name")

Dim results As SearchResultCollection = mySearcher.FindAll()

Dim res As Boolean = False
If results.Count > 0 Then
res = False
Else
Dim usr1 As DirectoryEntry = entry.Children.Add("CN=" & userAccountToCreate, "user")
usr1.Properties("userPrincipalName").Value = userAccountToCreate
usr1.Properties("mail").Value = userAccountToCreate
usr1.Properties("userPassword").Value = "XXXXXXXXX"
usr1.Properties("msDS-UserAccountDisabled").Value = False

usr1.Properties("passwordQuestion").Value = "XXXXXXXX"
usr1.Properties("passwordAnswer").Value = "XXXXXXXX"

usr1.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingClear
usr1.Options.PasswordPort = 389

usr1.CommitChanges()

res = True
End If

entry.Close()
entry.Dispose()
mySearcher.Dispose()

Return res

End Function
--------------------------------------------------------------------------------------------

In coming to this solution I tried to use the Membership Provider within SSIS - dynamically setting the configuration settings etc. However I came to the conclusion while testing that it was not going to work as the non-ssl install required the machine key to be available (for encryption) in the system.web section of the configuration - not likely in an SSIS setup. This was getting to be too much of a hack so I reverted to the directory services solution and ended up with the above.