Como validar credenciais em cache do usuário em um domínio?
Quando você faz logon no Windows, suas credenciais sãoem cache. Isso permite que você uselogon único. Se você deveria procurar outro computador, por exemplo:
\\hydrogen
você poderianão ser solicitadas credenciais.
O Windows levará seu:
nome de usuário atual(hash) senhae tente autenticar você automaticamente. O interessante é que isso funciona mesmo se sua estação de trabalho não estiver no domínio. Windows iráautomaticamente use seu nome de usuário e senha ao se conectar ao servidor. E se o seu:
local nome de usuário / senha corresponde adomínio usuário senhavocê é deixado automaticamente entrar.
Bonita foto:
Isso é chamadoLogon único. Você entra no Windows uma vez e suas credenciais em cache são usadas para validá-lo conforme você usa outras coisas na rede.
Os navegadores também fazem issoChrome, Internet Explorer e Firefox também fazem uma variação disso. Se você precisar fazer login em um site, e o servidor suportarNegociação autorização, o servidor enviará de volta uma indicação de que você deve tentar as credenciais do Windows / Domínio / Kerberos do usuário:
HTTP/1.1 401 Unauthorized
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
Date: Thu, 09 Jul 2015 14:35:58 GMT
Content-Length: 0
O Chrome levará seuem cache credenciais e (após alguma mágica intermediária) encaminhe-as para o servidor da web:
GET http://hr.woodglue.com HTTP/1.1
Host: hr.woodglue.com
Authorization: Negotiate YIIFzwYGKwYBBQUCoIIFwzCCBb....
A Microsoft fala sobre esse mecanismo no Internet Explorer no artigo antigo:
Autenticação de plataforma cruzada baseada em HTTP usando o protocolo de negociaçãoO cliente chamaAcquireCredentialsHandle()
eInitializeSecurityContext()
com o SPN para criar o Contexto de Segurança que solicita o ticket de sessão do TGS / KDC.Você valida em um domínio, não em servidoresUm ponto final que quero mencionar é que servidores, servidores Web, estações de trabalho, servidores de arquivos não validam credenciais em relação a umservidor, eles validam em um domíniocontrolador. Você tem um nebulosofloresta de muitos servidores de domínio e um deles lida com sua solicitação.
Em outras palavras, você não valida credenciais contra:
\\uranium
(um controlador de domínio nowoodglue.com
domínio)você valida credenciais contra:
awoodglue.com
domínioTemos o conceito importante de que alguém pode:
valide suaem cache credenciaiscontra um domíniosem precisar digitar um nome de usuário ou senhaComo posso fazer isso?Como posso validar as credenciais em cache de alguém? Como podeI:
validar o usuárioem cache credenciaiscontra umdomíniosem o usuário precisa digitar um nome de usuário ou senha(ou seja, usando as credenciais em cache do Windows)O ponto importante é que não se sabe (ou se importa):
se a máquina do usuário estiver associada a um domíniose a máquina do usuário estiver associada a um grupo de trabalhose a máquina do usuário estiver associada aowoodglue.com
ou algum outro domínio (por exemplo,superglue.com
)os nomes dos servidores que alimentam osuperglue.com
domínioEu não sei como fazer isso.
Não sei quais tecnologias de API estão envolvidas.
Eu sei que existe uma API chamadaInterface do provedor de suporte de segurança (SSPI). É isso que poderesWWW-Authenticate: Negotiate
(embora eu não saiba se é isso que habilita o SMB a partir de um PC sem domínio).
O código-fonte aberto do Chromium pode começar com um trecho de códigohttp_auth_sspi_win.cc
. Eles usam a função SSPIAcquireCredentialsHandle
:
int AcquireDefaultCredentials(CredHandle* cred)
{
TimeStamp expiry;
// Pass the username/password to get the credentials handle.
// Note: Since the 5th argument is NULL, it uses the default
// cached credentials for the logged in user, which can be used
// for a single sign-on.
SECURITY_STATUS status = library->AcquireCredentialsHandle(
NULL, // pszPrincipal
const_cast<SEC_WCHAR*>(package), // pszPackage
SECPKG_CRED_OUTBOUND, // fCredentialUse
NULL, // pvLogonID
NULL, // pAuthData
NULL, // pGetKeyFn (not used)
NULL, // pvGetKeyArgument (not used)
cred, // phCredential
&expiry); // ptsExpiry
}
Passe o nome de usuário / senha para obter o identificador de credenciais.
Nota: Como o quinto argumento é NULL, ele usa as credenciais em cache padrão para o usuário conectado, que pode ser usado para uma conexão única.
este"saída" ligar paraAcquireCredentialsHandle
é seguido por uma chamada paraInitializeSecurityContext
. A ideia é queInitializeSecurityContext
gera um blob opaco que representa o cliente.
Você pode executar um conjunto paralelo de chamadas:
"entrada" ligar paraAcquireCredentialsHandle
ligarAcceptSecurityContext
, passando o blob retornado anteriormente deInitializeSecurityContext
Pararoubar re-hospedarA excelente imagem de Daniel Doubrovkine:
Nota: Nesse caso"cliente" e"servidor" são usados para se referir ao contexto de produtor e consumidor. No meu caso, o"cliente" e"servidor" estão na mesma máquina.
Mas essa linha de"mostra esforço de pesquisa" desmorona porque eu não vejo em nenhum lugarInitializeSecurityContext
onde eu posso especificarwoodglue.com
como o domínio para validar.
Eu sei dissoInitializeSecurityContext
entra em contato com um servidor kerberos e obtém um"bilhete" blob. Esse blob de ticket é passado para o "servidor" por meio deAcceptSecurityContext
. Às vezes, o blob pode ser passado por uma rede; no meu caso, é passado na memória na mesma máquina.
Mas não vejo como especificar o servidor de domínio que ele deve entrar em contatopara esse bilhete.
Não implica que o SSPI seja útil para resolver meu problema. É apenas"esforço de pesquisa".
Esforço de pesquisa mais antigoQual TargetName usar ao chamar InitializeSecurityContext (Negotiate)?Como validar credenciais de domínio (do código nativo)?Validar a senha de um usuário usando o hash?Win32: Como validar credenciais no Active Directory?Como executar a autenticação do Windows?Obviamente, durante tudo isso, se as credenciais em cache não forem válidas no domínio especificado, eu teria que solicitar ao usuário um nome de usuário e senha. Mas nomes de usuário e senhas são maus, a ruína da computação, e eu quero evitá-los.
eu estou usando código nativo; não c#.