How to Get All User Claims at Claims Augmentation Time in SharePoint 2010


A fairly constant hurdle when doing claims augmentation in SharePoint 2010 has been trying to figure out what claims a user has when your custom claims provider is invoked to do claims augmentation.  For example, the claims you want to augment for a person may depend on the value of other claims the user has, e.g. if the person belongs to the role “Domain Admins” then add the role claim “Uber User”, otherwise add the claim “Standard User”.  After being frustrated by this for a long time, my good friend Israel V. and Matt Long finally came up with the solution to this sticky problem (and deserves 100% of the credit for this solution, so thank you guys!).
 
One of the underlying problems in trying to get to this information outside of the parameters provided when your claim provider is invoked for augmentation is that you don’t have any access to an HttpContext to look at the collection of claims.  Israel and Matt correctly figured this out and figured out the alternative, which is the OperationContext.  So what is that?
 
Well, OperationContext has a good overview here:  http://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontext(v=VS.90).aspx.  In a nutshell, the thing we care about, is it allows you to access incoming message headers and properties (for SAML users) and the security context (for Windows users).  So how does this help us?  Well, when your custom claims provider is invoked for augmentation, you can get to this incoming message info for SAML users which looks like this:
 
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
   <s:Header>
       <a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
       <a:MessageID>urn:uuid:85a0daaa-2288-4d0a-bda8-5fac05ea61cf</a:MessageID>
       <a:ReplyTo>
          <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
       </a:ReplyTo>
       <a:To s:mustUnderstand="1">http://localhost:32843/SecurityTokenServiceApplication/securitytoken.svc</a:To>
   </s:Header>
   <s:Body>
       <trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
          <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
              <a:EndpointReference>
                 <a:Address>https://fc1/</a:Address>
              </a:EndpointReference>
          </wsp:AppliesTo>
          <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
          <trust:OnBehalfOf>
              <saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="_8f1d7b46-2b71-4263-859b-c3e358d7ea84" Issuer="http://myadfsserver/adfs/services/trust" IssueInstant="2011-03-26T18:51:54.671Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
                 <saml:Conditions NotBefore="2011-03-26T18:51:33.198Z" NotOnOrAfter="2011-03-26T19:51:33.198Z">
                     <saml:AudienceRestrictionCondition>
                        <saml:Audience>urn:sharepoint:fc1</saml:Audience>
                     </saml:AudienceRestrictionCondition>
                 </saml:Conditions>
                 <saml:AttributeStatement>
                     <saml:Subject>
                        <saml:SubjectConfirmation>
                           <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
                        </saml:SubjectConfirmation>
                     </saml:Subject>
                     <saml:Attribute AttributeName="emailaddress" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
                        <saml:AttributeValue>testuser@vbtoys.com</saml:AttributeValue>
                     </saml:Attribute>
                     <saml:Attribute AttributeName="role" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
                        <saml:AttributeValue>pOregon Marketing</saml:AttributeValue>
                        <saml:AttributeValue>Domain Users</saml:AttributeValue>
                        <saml:AttributeValue>pSales</saml:AttributeValue>
                        <saml:AttributeValue>Portal People</saml:AttributeValue>
                     </saml:Attribute>
                     <saml:Attribute AttributeName="windowsaccountname" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
                        <saml:AttributeValue>testuser</saml:AttributeValue>
                     </saml:Attribute>
                     <saml:Attribute AttributeName="primarysid" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
                        <saml:AttributeValue>testuser@vbtoys.com</saml:AttributeValue>
                     </saml:Attribute>
                 </saml:AttributeStatement>
                 <saml:AuthenticationStatement AuthenticationMethod="urn:federation:authentication:windows" AuthenticationInstant="2011-03-26T18:51:33.069Z">
                     <saml:Subject>
                        <saml:SubjectConfirmation>
                           <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
                        </saml:SubjectConfirmation>
                     </saml:Subject>
                 </saml:AuthenticationStatement>
                 <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                     <ds:SignedInfo>
                        <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                        </ds:CanonicalizationMethod>
                        <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256">
                        </ds:SignatureMethod>
                        <ds:Reference URI="#_8f1d7b46-2b71-4263-859b-c3e358d7ea84">
                           <ds:Transforms>
                               <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature">
                               </ds:Transform>
                               <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                               </ds:Transform>
                           </ds:Transforms>
                           <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256">
                           </ds:DigestMethod>
                           <ds:DigestValue>5Qvu+blahblah=</ds:DigestValue>
                        </ds:Reference>
                     </ds:SignedInfo>
                     <ds:SignatureValue>VUSrynYjN8NOcUexqJOCblahblah</ds:SignatureValue>
                     <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                        <X509Data>
                           <X509Certificate>MIIFlzCCBH+gAwIBAgIKHmblahblahblah</X509Certificate>
                        </X509Data>
                     </KeyInfo>
                 </ds:Signature>
              </saml:Assertion>
          </trust:OnBehalfOf>
          <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
       </trust:RequestSecurityToken>
   </s:Body>
</s:Envelope>
 
<<apologies for what I realize is a long chunk of ugly Xml, but I wanted you to see it>>
 
Now, since we have a chunk of Xml with our claims embedded inside, it’s no big deal to unwrap them and be able to use them during augmentation.  Here’s a quick little sample that I wrote to do just that:
using System.Xml;
 
private class IncomingClaim
{
   public string claimType { get; set; }
   public string claimValue { get; set; }
 
   public IncomingClaim(string claimType, string claimValue)
   {
      this.claimType = claimType;
       this.claimValue = claimValue;
   }
}
 
protected override void FillClaimsForEntity(Uri context, SPClaim entity,
            List<SPClaim> claims)
{
//get the request envelope with the claims information
       string rqst =
System.ServiceModel.OperationContext.Current.RequestContext.RequestMessage.ToString();
 
       //create a list to store the results
       List<IncomingClaim> incomingClaims = new List<IncomingClaim>();
                          
       //create an Xml document for parsing the results and load the data
       XmlDocument xDoc = new XmlDocument();
       xDoc.LoadXml(rqst);
 
       //create a new namespace table so we can query
       XmlNamespaceManager xNS = new XmlNamespaceManager(xDoc.NameTable);
 
       //add the namespaces we'll be using
       xNS.AddNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
       xNS.AddNamespace("trust", "http://docs.oasis-open.org/ws-sx/ws-trust/200512");
       xNS.AddNamespace("saml", "urn:oasis:names:tc:SAML:1.0:assertion");
                    
       //get the list of claim nodes
       XmlNodeList xList =
xDoc.SelectNodes("s:Envelope/s:Body/trust:RequestSecurityToken/trust:OnBehalfOf/saml:Assertion/saml:AttributeStatement/saml:Attribute", xNS);
 
       //get the matches
       if ((xList != null) && (xList.Count > 0))
       {
              //enumerate through the matches to get the claim list
              foreach (XmlNode xNode in xList)
              {
                     //get the claim type first
                     string currentClaimType =
                           xNode.Attributes["AttributeNamespace"].Value +
                           "/" + xNode.Attributes["AttributeName"].Value;
 
                     //each claim type will have one to many child nodes with the values
                     foreach (XmlNode claimNode in xNode.ChildNodes)
                     {
                           incomingClaims.Add(new IncomingClaim(currentClaimType,
                                  claimNode.InnerText));                                
                     }
              }
       }
 
//now you can do whatever you want with the list of claims and finish
//your augmentation
}
 
That’s pretty much it.  The code is simple enough and commented out so verbosely that I believe if you look at it, and paste the Xml into a nice Xml editor (like the one that comes with Visual Studio .NET) that it should be pretty clear how it works.  No rocket science at this point, just Xml.
 
There is also an interesting side effect you can implement based on this pattern that blog reader Luis A. points out.  The set of claims you will get in the RequestMessage includes everything that came from your IP-STS, including any claims that the SharePoint STS will be dropping if there isn’t a corresponding claim mapped.  So, if you know which claims SharePoint is going to be dropping and you want to keep them anyways, you can just augment them yourself again with your custom claims provider.  Just pull the claim values and types out of the RequestMessage and add them back in.
 
Windows claims users won’t have this message associated with their request, but you can get a WindowsIdentity for them by using the SecurityContext of the OperationContext.  From that you can do all the things available with a WindowsIdentity, like getting the list of groups the user belongs to, etc.  Here’s an example of that:
 
//do windows
WindowsIdentity wid =
System.ServiceModel.OperationContext.Current.ServiceSecurityContext.WindowsIdentity;
 
//get a reference to the groups to which the user belongs
IdentityReferenceCollection grps = wid.Groups;
 
//enumerate each group (which will be represented as a SID)
//NOTE that this includes ALL groups – builtin, local, domain, etc.
foreach (IdentityReference grp in grps)
{
       //get the plain name of the group
       SecurityIdentifier sid = new SecurityIdentifier(grp.Value);
       NTAccount groupAccount = (NTAccount)sid.Translate(typeof(NTAccount));
       string groupName = groupAccount.ToString();
 
       //for domain groups remove the domain\ prefix from the group
       //name in order to have feature parity with SAML users
       if (groupName.Contains("\\"))
              groupName = groupName.Substring(groupName.IndexOf("\\") + 1);
 
       //add the claim
       incomingClaims.Add(new
IncomingClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
              groupName));
}
 
You’ll want to make sure you add a using statement for System.Security.Principal to get the WindowsIdentity, IdentityReference, NTAccount, etc. to resolve correctly.  Otherwise the code should again be fairly straightforward.  I’m just getting the list of groups for the user and putting them in my custom collection of claims as  a standard Role claim.
 
Thanks again Israel and Matt for sharing this super valuable information.

How to Get All User Claims at Claims Augmentation Time in SharePoint 2010.docx

Comments (11)

  1. Sorry, what I meant by my reply is that SharePoint is still going to drop those unmapped claims. You will see all claims that come from your IP-STS, so if you have some unmapped claims come through then you can capture them in this event and augment them yourself.  This is actually an interesting work-around (if you know which ones you need to grab that is) so I will update the blog post with that info too.  Thanks for the question.

  2. alexandrad9x says:

    Tao http://dichvuketoanlongbien.com/
    Rủa
    http://dichvuketoanlongbien.com/a2-96-dich-vu-ke-toan-tron-goi.html
    Thằng http://dichvuketoanlongbien.com/a2-98-dich-vu-ke-toan-thue.html
    Cờ
    http://dichvuketoanlongbien.com/a2-103-dich-vu-bao-cao-tai-chinh.html
    http://dichvuketoanlongbien.com/a2-97-dich-vu-quyet-toan-thue.html
    Nào
    http://dichvuketoanlongbien.com/a2-114-dich-vu-ke-toan-tai-29-quan-huyen.html
    Soi
    http://dichvuketoanlongbien.com/i780-dich-vu-ke-toan-thue-tron-goi-tai-bac-ninh.html
    Tài
    http://dichvuketoanlongbien.com/i779-dich-vu-ke-toan-thue-tron-goi-tai-bac-giang.html
    Khoản
    http://dichvuketoanlongbien.com/i778-dich-vu-ke-toan-thue-tron-goi-tai-phu-tho.html

    http://dichvuketoanlongbien.com/i781-dich-vu-ke-toan-thue-tron-goi-tai-hung-yen.html
    Link
    http://dichvuketoanlongbien.com/i782-dich-vu-ke-toan-thue-tron-goi-tai-vinh-phuc.html
    Của
    http://dichvuketoanlongbien.com/i783-dich-vu-ke-toan-thue-tron-goi-tai-hai-phong.html
    Tao. http://www.trungtamketoan.com.vn/
    Chúng
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-ha-noi.html
    Mày
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-tp-hcm.html
    Đủ
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-quang-ninh.html
    Trình
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-hai-duong.html
    Thì
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-bac-giang.html
    Tự
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-bac-ninh.html
    Đi
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-hai-phong.html

    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-nam-dinh.html
    Làm.
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-thai-binh.html
    Việc
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-thanh-hoa.html

    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-vinh-phuc.html
    Phải
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-hung-yen.html
    Rẻ
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-phu-tho.html
    Rách
    http://www.trungtamketoan.com.vn/p/trung-tam-dao-tao-ke-toan-tai-binh-duong.html
    Như http://www.tosvn.com
    Thế. http://iketoan247.blogspot.com
    Loại http://tailieuveketoan.blogspot.com
    Chó http://mauhinhnendep.blogspot.com
    Má. http://www.tosvn.com/search/label/Hack%20CF
    Tao http://www.tosvn.com/search/label/Hack%20AvatarStar
    Rủa http://www.tosvn.com/search/label/Hack%20Warcraft-Dota2
    Những http://hocketoan360.com/category/tai-lieu-ke-toan/
    Thằng http://iketoan247.blogspot.com/search/label/thong-tin-kinh-te
    Soi http://iketoan247.blogspot.com/search/label/tin-bai-ve-thue
    Tao http://hoclamketoan.edu.vn/
    Sẽ http://hoclamketoan.edu.vn/category/khoa-hoc-ke-toan
    Tan http://hoclamketoan.edu.vn/category/dich-vu-ke-toan
    Cửa http://hoclamketoan.edu.vn/category/hoc-lam-ke-toan
    Nát http://hoclamketoan.edu.vn/category/tai-lieu-ke-toan
    Nhà http://hocketoan360.com/
    Haha http://hocketoan360.com/category/khoa-hoc-ke-toan/
    http://hocketoan360.com/category/dich-vu-ke-toan/

  3. No, that is something different.  What is stated in that post still applies.

  4. Luis Azedo says:

    Hi Steve,

    if i understood correctly, this solution overcomes the problem you mention on your earlier post blogs.technet.com/…/figuring-out-what-claims-you-have-in-sharepoint-2010.aspx

    "If your STS sends back other claims besides what SharePoint is expecting, SharePoint will IGNORE all of those additional claims and it WILL NOT be added to the SPClaim".

    is this correct ?

    thanks

  5. Luis Azedo says:

    Hi, i thought that the message came from the sts provider. What would be the best aproach to overcome the problem mentioned?

    Thanks

  6. Janu says:

    how can i get custom groups (AD groups in the claims) is see only few groups . how can i get all groups

    associated to the token programticaly.

    thanks

  7. Prakash says:

    how to get the claims of a different user? Let say as a admin i want to see the claims of other user by passing userID

  8. SDF says:

    http://www.shopbestgoods.com/
    http://www.nike-jordanshoes.com/
    http://www.beatsbydreoutlet.net/
    http://www.michaelkorsus.com/
    http://www.polo-tshirts.com/
    http://www.northsclearance.com/
    http://www.ralph-laurensale.com/
    http://www.gucci-shoesuk2014.com/
    http://www.michael-korsusa.com/
    http://www.polo-outlets.com/
    http://www.ralphslauren.co.uk/
    http://www.marcjacobsonsale.com/
    http://www.mcmworldwides.com/
    http://www.salongchamppairs.com/
    http://www.canada-gooser.com/
    http://www.burberryoutlet2014.com/
    http://www.michaelkors.so/
    http://www.hermes-outletonline.com/
    http://www.oakley-sunglassoutlet.com/
    http://www.north-faceoutlets.net/
    http://www.moncler-clearance.com/
    http://www.woolrich-clearance.com/
    http://www.barbour-jacketsoutlet.com/
    http://www.moncler-jacketsoutletonline.com/
    http://www.monsterbeatsbydres.net/
    http://www.louis-vuittonblackfriday.com/
    http://www.lv-guccishoesfactory.com/
    http://www.mcmoutlet-jp.com/
    http://www.cheapdiscountoutlet.com/
    http://coachoutlet.iwopop.com/
    http://www.coachsfactoryoutlet.com/
    http://www.coach-blackfriday2014.com/
    http://www.coach-storeoutletonline.com/
    http://www.coach-factorysoutletonline.com/
    http://www.coachccoachoutlet.com/
    http://www.coach-factories.net/
    http://www.coach-pursesoutletonline.com/
    http://www.llouisvuitton-factory.net/
    http://www.coach-outletsusa.com/
    http://www.mksfactoryoutlet.com/
    http://www.zxcoachoutlet.com/
    http://www.mischristmas.com/
    http://www.misblackfriday.com/
    http://www.bestcustomsonline.com/
    http://www.newoutletonlinemall.com/
    http://www.clickmichaelkors.com/
    http://www.cmichaelkorsoutlet.com/
    http://www.ralphlaurenepolo.com/
    http://michaelkorsoutlet.mischristmas.com/
    http://mcmbackpack.mischristmas.com/
    http://monsterbeats.mischristmas.com/
    http://northfaceoutlet.mischristmas.com/
    http://mk.misblackfriday.com/
    http://coachoutlet.misblackfriday.com/
    http://coachfactory.misblackfriday.com/
    http://uggaustralia.misblackfriday.com/
    http://coachpurses.misblackfriday.com/
    http://coachusa.misblackfriday.com/
    http://coach.misblackfriday.com/
    http://michaelkorss.misblackfriday.com/
    http://michaelkors.misblackfriday.com/
    http://airmax.misblackfriday.com/
    http://michael-kors.misblackfriday.com/

    http://t.co/1PJuejI1ys
    http://t.co/FYm2MxWwLM
    https://twitter.com/CoachOutlet2014
    https://www.facebook.com/pages/Coach-Factory-Outlet-Online-Store-Michael-Kors-Outlet-Online-Sale-75-Off/712060898859091
    https://www.facebook.com/pages/Ralph-Lauren-Polo-Outlet-Online-Sale/1404100279810690

  9. Anonymous says:

    In Part 1 of this series, we went through how to configure SharePoint to use ACS and Azure Active Directory

  10. Anonymous says:

    Okay, I’m going to preface everything in this post by saying what I’m going to be describing