SharePoint maintains an internal Certificate Authority (CA) which just happens to be managed by the SPTrustedRootAuthorityManager. Microsoft graciously provided us with a form in Central Admin and Power Shell commands to work with the list of certificates (see get-command -noun SPTrustedRootAuthority), but the only way to work one is through then PS command scripts. This is OK, but it seems like SharePoint team took the easy way out and didn't finish the GUI in Central Admin.
So what's a boy (or girl for that matter) to do? I went and found all of the PS Cmdlets that parallel the steps in the Claims Walkthrough, just so I wouldn't have to write a Forms app just to setup the SPTrustedLoginProvider. That was great for me, but I'm a consultant these days and I need to get my clients up and running on this stuff. If I can barely remember the sequence of command, how could they. Especially when you want to add new Known Claim Values when a new set of secureables comes out.
Well I took it upon myself to create my own user interface to manage CBA trust providers and developed it into a set of 14 hive application pages, in the ADMIN folder (/_admin/TrustConfig, etc.) so that they would only be available through Central Admin and not through a normal site. Configuring Trust is an administrative task after all...
So everybody knows when you setup a new CBA Trust you do the following:
- Get an X.509 certificate w/o the private key attached in a DER file.
- Load the certificate into SharePoint's Trusted Authority Manager (CA or PS usually works)
- Create new SPTrustedLoginProvider that references the certificate.
Anyway, that was only one problem, when you first setup the Login Provider. You need to come back to one and update the Known Claim Values, maybe add a new Claim Type now and again too. But try describing that over the phone (you may be better at than I am).
Solution, add those application pages to Central Admin. But you'll need to use some reflection magic to get a hold of that data. Now if you review my code I'm about to post, you may notice that there may have been more direct ways to get to the data, like accessing the TRA manager directly, or calling the "Certificate" property on the TRA. I'm not saying my code is perfect, but it got me there.
What, you're about to see, is what the GOF would call Adapter Classes. The first TrustedRootAuthority wraps the SPTrustedRootAuthority to provide access to the X509Certificate2 and the second, RootAuthority, wraps the SPCmdletGetTrustedRootAuthority Power Shell Cmdlet to get the set of all installed certificates.
These additions don't let you install new certificates, but that wouldn't be too hard once you've gotten this far. They do allow you to get a hold of all of the installed certs so that you can pick and choose the certificate you want to add to your newly minted SPTrustedLoginProvider.
class TrustedRootAuthority
{
static
Type traType;
static
TrustedRootAuthority() {
Assembly
a = Assembly.Load("Microsoft.SharePoint,
Version=14.0.0.0, "
+"Culture=neutral, PublicKeyToken=71e9bce111e9429c");
traType = a.GetType("Microsoft.SharePoint.Administration.SPTrustedRootAuthority",
true, true);
}
object
tra;
public
TrustedRootAuthority(object tra) {
this.tra
= tra;
}
public
X509Certificate2 Certificate {
get
{
return traType.InvokeMember("m_Certificate",
BindingFlags.NonPublic |
BindingFlags.GetField | BindingFlags.Instance,
null,
tra, null)
as X509Certificate2;
}
}
}
class RootAuthority
{
static
ConstructorInfo ctor;
static
MethodInfo rdo;
static
RootAuthority() {
Assembly
a = Assembly.Load("Microsoft.SharePoint.PowerShell,
Version=14.0.0.0, "+
"Culture=neutral, PublicKeyToken=71e9bce111e9429c");
Type
t = a.GetType("Microsoft.SharePoint.PowerShell.SPCmdletGetTrustedRootAuthority",
true, true);
ctor = t.GetConstructor(new Type[0]);
rdo = t.GetMethod("RetrieveDataObjects",
BindingFlags.NonPublic
| BindingFlags.Instance);
}
private
object tra;
public
RootAuthority() {
tra = ctor.Invoke(null);
}
public
IEnumerable<TrustedRootAuthority>
RetrieveDataObjects() {
IEnumerable
src = rdo.Invoke(tra, null) as IEnumerable;
List<TrustedRootAuthority> ret = new List<TrustedRootAuthority>();
foreach
(object o in
src) {
ret.Add(new TrustedRootAuthority(o));
}
return
ret;
}
}