Migrando contas de usuário das Declarações do Windows para as Declarações SAML
Migrando contas de usuário das Declarações do Windows para as Declarações SAML
No trabalho que estou fazendo no momento, tenho visto muita gente interessada em começar a usar declarações do Windows e mais adiante passar para declarações SAML. Parece razoável, mas o problema é que não tenho uma forma automática de migrar contas das declarações do Windows para declarações SAML. A boa notícia é que o grupo de produtos do SharePoint fez uma atualização na CU de agosto de 2010 para permitir que você execute seu próprio código personalizado no método MigrateUsers. Temos um documento completo sobre a API que será lançado brevemente, junto com um exemplo de código que foi resultado de um ótimo trabalho de Bryan P. e Raju S., e meu exemplo é baseado nisso. Eles fizeram um excelente trabalho na documentação da nova API (na verdade, uma interface,IMigrateUserCallback), portanto não entrarei em muitos detalhes aqui. Assim que eu tiver um link para as informações recém-publicadas sobre isso, atualizarei esta postagem com ele.
Portanto, como sempre, vou começar apenas colando o código da minha classe de migração personalizada e percorrerei as partes que acho interessantes.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Security;
using System.Security.Principal;
//add references to Microsoft.SharePoint and Microsoft.IdentityModel for these
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.IdentityModel.Claims;
namespace MigrateUserSample
{
public class MigrateTest : IMigrateUserCallback
{
public string SPTrustedIdentityTokenIssuerName { get; set; }
public MigrateTest(string TrustedIdentityTokenIssuerName)
{
SPTrustedIdentityTokenIssuerName = TrustedIdentityTokenIssuerName;
}
public string ConvertFromOldUser(string oldUser,
SPWebApplication.AuthenticationMethod authType, bool isGroup)
{
string value = string.Empty;
try
{
switch (authType)
{
case SPWebApplication.AuthenticationMethod.Windows:
//code for converting from classic Windows would be here
Debug.WriteLine(oldUser);
break;
case SPWebApplication.AuthenticationMethod.Claims:
//this is the only scenario this sample will cover
//migrating from Windows claims to SAML claims
Debug.WriteLine(oldUser);
//get the claim provider manager
SPClaimProviderManager cpm = SPClaimProviderManager.Local;
//create a claim from the identifier so we can see if the
//original issuer came from Windows
SPClaim idClaim = cpm.ConvertIdentifierToClaim(oldUser,
SPIdentifierTypes.EncodedClaim);
//this is a Windows claims user, and we are going to
//convert to a SAML claims user
if (idClaim.OriginalIssuer == "Windows")
{
//windows claims users will be in the format domain\user;
//windows claims groups will be in the SID format
if (idClaim.Value.Contains("\\"))
{
//migrating a user
//you will want to check the identity of the user here
//there may be some Windows claims accounts you don't want to
//convert yet, and there will also be service accounts that
//are passed in that you may not want to convert either;
//ideally you would just read from a data source to determine
//which users you should convert, and then check the identity
//here to see if it's one of the users that should be
//converted
//in this case, I'm only converting one user - darrins
if (idClaim.Value == "contoso\\darrins")
{
//I’m getting an identity claim here, grabbing the
//part after the "domain\", and appending the email
//suffix to it, so it becomes darrins@contoso.com
SPClaim migratedUserClaim =
SPClaimProviderManager.CreateUserClaim(
idClaim.Value.Split('\\')[1] + "@contoso.com",
SPOriginalIssuerType.TrustedProvider,
SPTrustedIdentityTokenIssuerName);
//get the encoded value of what the new identity
//claim will be
value = migratedUserClaim.ToEncodedString();
}
}
else
{
//migrating a group
//get the plain name of the group
SecurityIdentifier sid =
new SecurityIdentifier(idClaim.Value);
NTAccount groupAccount =
(NTAccount)sid.Translate(typeof(NTAccount));
string groupName = groupAccount.ToString();
//only interested in migrating the Portal People group
if (groupName.ToLower() == "contoso\\portal people")
{
//create a new role claim
SPClaim migratedGroupClaim =
new SPClaim("https://schemas.microsoft.com/ws/2008/06/identity/claims/role",
groupName.Split('\\')[1],
Microsoft.IdentityModel.Claims.ClaimValueTypes.String,
SPOriginalIssuers.Format(
SPOriginalIssuerType.TrustedProvider,
SPTrustedIdentityTokenIssuerName));
//get the encoded value of what the new role claim will be
value = migratedGroupClaim.ToEncodedString();
}
}
}
break;
case SPWebApplication.AuthenticationMethod.Forms:
//code for converting from Forms would be here
Debug.WriteLine(oldUser);
break;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return value;
}
}
}
A primeira coisa que estou fazendo é verificar o valor do parâmetro SPWebApplication.AuthenticationMethod que foi passado. Como estou apenas interessado em converter usuários de declarações (Windows para SAML), esta é a única situação em que tenho um código para executar. Quando o usuário atual é um usuário de declarações, começo obtendo uma referência ao SPClaimProviderManager local para obter uma representação de declaração do usuário. Faço isso para determinar se o usuário é um usuário de declaração do Windows, de declarações FBA ou de declarações SAML. Em meu caso, apenas quero converter usuários de declarações do Windows.
Depois que eu determinar que tenho um usuário de declarações do Windows, a próxima coisa a fazer é descobrir se a declaração é de um usuário ou grupo. Aqui estão algumas coisas estranhas que você pode perceber. Mesmo quando o usuário atual é um grupo de declarações do Windows, o parâmetro isGroup que é passado para o método retorna falso. Isso significa que preciso verificar eu mesmo se a “entidade” atual é um usuário ou grupo. Portanto, apenas observo o valor da declaração. Se for um usuário, ela estará no formato domínio\usuário; caso contrário, trata-se de um grupo, que estará em um formato SID.
Agora que sei qual é o tipo de entidade, posso determinar que tipo de declaração é necessária. Para um usuário, preciso criar uma declaração de identidade. Uma das coisas que preciso saber é o nome do SPTrustedIdentityTokenIssuer que está sendo usado no aplicativo Web. Eu poderia ter escrito um código para descobrir isso, mas em vez disso, “parti do princípio de que era um exemplo, me processe por ser preguiçoso” e forçá-lo a fornecer o nome correto no construtor da minha classe. Portanto, pego o nome de logon do usuário (depois da parte do domínio) e para mim o endereço de email dele será sempre loginname@contoso.com. Se a sua organização não for essa, você precisará descobrir por si mesmo para determinar o endereço de email correto. Eu uso esse endereço com o código acima para criar uma declaração de identidade para esse usuário, e esse é o valor que retorno, neste caso, aquele para o qual a conta vbtoys\darrins será convertida. (regra de gramática: não me perturbe por terminar a minha frase em uma preposição)
Para grupos, pego o SID que recebe e uso a classe NTAccount para obter o nome amigável do grupo. Uso isso para criar uma nova declaração de função e retiro o valor codificado como o valor para o qual o grupo deve ser migrado. (regra de gramática: feliz agora, sim?!?)
Uma outra coisa a se notar, para os usuários e grupos, é que não tento migrar tudo automaticamente. Há algumas coisas que talvez eu não queira migrar, como contas de serviço, contas internas, etc.; se você vai querer migrar ou não depende das suas necessidades. O que é bom nesse método de migração é que você pode fazê-lo quantas vezes quiser. Se você quiser migrar apenas um subconjunto de usuários, ou fazer isso em lotes, ou durante um tempo, ou o que quiser; é possível fazê-lo. Por exemplo, você pode ter um banco de dados com os usuários que deseja migrar. Você poderia consultá-lo para obter a lista e quando cada usuário fosse chamado no código de migração, você poderia ver se ele está na lista de usuários do seu banco de dados. Isso é apenas um exemplo.
OK, não quero entrar muito em detalhes sobre a documentação de SDK que Bryan e Raju fizeram, mas me sinto tentado a pelo menos informá-lo como a sua classe é chamada, portanto, não vou deixar você perdido por aqui. O que fiz foi apenas escrever um aplicativo winforms e adicionar uma referência de projeto ao meu assembly personalizado descrito acima. Isso tornou extremamente fácil compilar e depilar ao mesmo tempo. O código que uso para invocar a minha classe e fazer a migração se parece com o seguinte:
//get a reference to my web application
SPWebApplication wa = SPWebApplication.Lookup(new Uri("https://foo"));
//this is the name of my trusted identity token issuer
string SPTrustedIdentityTokenIssuerName = "ADFSProvider";
//create an instance of the custom migrate user callback class
MigrateUserSample.MigrateTest mt =
new MigrateUserSample.MigrateTest(SPTrustedIdentityTokenIssuerName);
//create an interface reference to it
IMigrateUserCallback muc = mt as IMigrateUserCallback;
//migrate the users with it
wa.MigrateUsers(muc);
É isso aí. Haverá muitas outras variações disso necessárias para cobrir todos os cenários, mas este é um bom começo, e Bryan e Raju farão acréscimos significativos nesse trabalho.
Esta é uma postagem de blog localizada. O artigo original está em Migrating User Accounts from Windows Claims to SAML Claims