Partager via


Share Point 2010에서 클레임 확대 시에 모든 사용자 클레임을 가져오는 방법

최초 문서 게시일: 2011년 3월 30일 수요일

SharePoint 2010에서 클레임 확대를 수행할 때 까다로운 작업 중 하나는, 클레임 확대를 수행하기 위해 사용자 지정 클레임 공급자를 호출할 때 사용자가 보유한 클레임을 확인하는 것입니다. 예를 들어 특정 사용자에 대해 확대할 클레임은 해당 사용자가 보유한 다른 클레임의 값에 따라 달라질 수 있습니다. 즉, 사용자가 "Domain Admins" 역할에 속하는 경우에는 "Uber User" 역할 클레임을 추가하고, 그렇지 않은 경우에는 "Standard User" 클레임을 추가합니다. 저와 절친한 Israel V.와 Matt Long도 이 까다로운 문제 때문에 오랜 고민을 거듭하다가 드디어 해결 방법을 찾아냈습니다. 완벽하게 신뢰할 만한 해결 방법이라고 하니, 여러분도 사용해 보시기 바랍니다.

 

확대를 위해 클레임 공급자를 호출할 때 제공되는 매개 변수에서 이 정보를 가져올 때 기본적으로 발생하는 문제 중 하나는, 클레임 컬렉션에서 HttpContext를 확인하기 위한 액세스 권한이 없다는 것입니다. Israel과 Matt는 이 문제를 정확히 간파하여 대체 항목인 OperationContext를 개발했습니다. 그러면 OperationContext란 무엇일까요?

 

OperationContext에 대한 설명은 https://msdn.microsoft.com/ko-kr/library/system.servicemodel.operationcontext(vs.90).aspx에 잘 나와 있습니다. 간단하게 말하자면, OperationContext를 통해 들어오는 메시지 헤더 및 속성(SAML 사용자의 경우)과 보안 컨텍스트(Windows 사용자의 경우)에 액세스할 수 있습니다. 그러면 OperationContext는 어떻게 활용할 수 있을까요? 확대를 위해 사용자 지정 클레임 공급자를 호출할 때는 SAML 사용자에 대해 다음과 같은 들어오는 메시지를 받게 됩니다.

 

<s:Envelope xmlns:s="https://www.w3.org/2003/05/soap-envelope" xmlns:a="https://www.w3.org/2005/08/addressing">

   <s:Header>

       <a:Action s:mustUnderstand="1">https://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>https://www.w3.org/2005/08/addressing/anonymous</a:Address>

       </a:ReplyTo>

       <a:To s:mustUnderstand="1">https://localhost:32843/SecurityTokenServiceApplication/securitytoken.svc</a:To>

   </s:Header>

   <s:Body>

       <trust:RequestSecurityToken xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">

          <wsp:AppliesTo xmlns:wsp="https://schemas.xmlsoap.org/ws/2004/09/policy">

              <a:EndpointReference>

                 <a:Address>https://fc1/</a:Address>

              </a:EndpointReference>

          </wsp:AppliesTo>

          <trust:KeyType>https://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="https://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="https://schemas.xmlsoap.org/ws/2005/05/identity/claims">

                        <saml:AttributeValue>testuser@vbtoys.com</saml:AttributeValue>

                     </saml:Attribute>

                     <saml:Attribute AttributeName="role" AttributeNamespace="https://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="https://schemas.microsoft.com/ws/2008/06/identity/claims">

                        <saml:AttributeValue>testuser</saml:AttributeValue>

                     </saml:Attribute>

                     <saml:Attribute AttributeName="primarysid" AttributeNamespace="https://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="https://www.w3.org/2000/09/xmldsig#">

                     <ds:SignedInfo>

                        <ds:CanonicalizationMethod Algorithm="https://www.w3.org/2001/10/xml-exc-c14n#">

                        </ds:CanonicalizationMethod>

                        <ds:SignatureMethod Algorithm="https://www.w3.org/2001/04/xmldsig-more#rsa-sha256">

                        </ds:SignatureMethod>

                        <ds:Reference URI="#_8f1d7b46-2b71-4263-859b-c3e358d7ea84">

                           <ds:Transforms>

                               <ds:Transform Algorithm="https://www.w3.org/2000/09/xmldsig#enveloped-signature">

                               </ds:Transform>

                               <ds:Transform Algorithm="https://www.w3.org/2001/10/xml-exc-c14n#">

                               </ds:Transform>

                           </ds:Transforms>

                           <ds:DigestMethod Algorithm="https://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="https://www.w3.org/2000/09/xmldsig#">

                        <X509Data>

                           <X509Certificate>MIIFlzCCBH+gAwIBAgIKHmblahblahblah</X509Certificate>

                        </X509Data>

                     </KeyInfo>

                 </ds:Signature>

              </saml:Assertion>

          </trust:OnBehalfOf>

          <trust:RequestType>https://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>>

 

위의 코드에는 클레임이 포함된 XML 청크가 있으므로 쉽게 래핑을 해제하여 확대 중에 사용할 수 있습니다. 이를 위해 간단한 예제를 작성해 보았습니다.

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", "https://www.w3.org/2003/05/soap-envelope");

       xNS.AddNamespace("trust", "https://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

}

 

대략 이와 같은 코드를 사용할 수 있습니다. 이 코드는 매우 간단하며 주석이 아주 상세하게 달려 있기 때문에, 여러분도 훑어 보시고 Visual Studio .NET에서 제공되는 것과 같은 XML 편집기에 XML을 붙여 넣으면 작동 방법을 명확하게 파악하실 수 있을 것입니다. 전문적인 기술 없이 XML만 사용되었기 때문입니다.

 

블로그 독자인 Luis A.님이 이 패턴을 기반으로 구현할 수 있는 또 다른 기능을 지적해 주셨습니다. RequestMessage를 통해 가져오는 클레임 집합에는 IP-STS에서 전송되는 모든 항목이 포함됩니다. 여기에는 해당하는 클레임이 매핑되어 있지 않은 경우 SharePoint STS에서 삭제하는 클레임도 포함됩니다. 따라서 SharePoint에서 삭제할 클레임을 보관하려는 경우에는 역시 사용자 지정 클레임 공급자를 통해 직접 해당 클레임을 확대할 수 있습니다. RequestMessage에서 클레임 값과 유형을 가져와서 다시 추가하면 됩니다.

 

Windows 클레임 사용자에게는 요청과 관련하여 이 메시지가 표시되지 않지만, OperationContext의 SecurityContext를 사용하면 Windows 사용자용으로 WindowsIdentity를 가져올 수 있습니다. 그러면 사용자가 속한 그룹 목록 가져오기 등 WindowsIdentity를 통해 가능한 모든 작업을 수행할 수 있습니다. 아래에 그 예가 나와 있습니다.

 

//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("https://schemas.microsoft.com/ws/2008/06/identity/claims/role",

              groupName));

}

 

가져오는 WindowsIdentity, IdentityReference, NTAccount 등이 올바르게 확인되도록 하려면 System.Security.Principal에 대해 using 문을 추가해야 합니다. 그렇지 않은 경우의 코드는 매우 단순해집니다. 여기서는 사용자에 대해 그룹 목록을 가져와서 사용자 지정 클레임 컬렉션에 표준 Role 클레임으로 추가하는 작업만 수행했습니다.

 

이와 같은 매우 유용한 정보를 공유해 준 Israel과 Matt에게 다시 한 번 감사의 인사를 전합니다.

이 문서는 번역된 블로그 게시물입니다. 원본 문서는 How to Get All User Claims at Claims Augmentation Time in SharePoint 2010을 참조하십시오.