Pergunta

Estou executando PHP, Apache e Windows.Como não tenho uma configuração de domínio, gostaria que a autenticação baseada em formulários do meu site usasse o banco de dados de contas de usuários locais integrado ao Windows (acho que se chama SAM).

Eu sei que se o Active Directory estiver configurado, você poderá usar o módulo PHP LDAP para conectar e autenticar em seu script, mas sem AD não há LDAP.Qual é o equivalente para máquinas autônomas?

Foi útil?

Solução

Também não encontrei uma solução simples.Há exemplos usando CreateObject e o provedor WinNT ADSI.Mas eventualmente todos eles esbarram Problemas de autenticação de usuário com o provedor WinNT de interfaces de serviço do Active Directory.Não tenho 100% de certeza, mas eu adivinhar a abordagem WSH/conexão de rede tem o mesmo problema.
De acordo com Como validar credenciais de usuário em sistemas operacionais Microsoft você deve usar LogonUser ou SSPI.
Também diz

LogonUser Win32 API does not require TCB privilege in Microsoft Windows Server 2003, however, for downlevel compatibility, this is still the best approach.

No Windows XP, não é mais necessário que um processo tenha o privilégio SE_TCB_NAME para chamar LogonUser.Portanto, o método mais simples para validar as credenciais de um usuário no Windows XP é chamar a API LogonUser.

Portanto, se eu tivesse certeza de que o suporte ao Win9x/2000 não é necessário, eu escreveria uma extensão que expõe o LogonUser ao php.
Você também pode estar interessado em Autenticação de usuário de contas NT.Ele usa a extensão w32api e precisa de uma dll de suporte ... Prefiro escrever aquela pequena extensão LogonUser ;-)
Se isso não for viável, provavelmente examinarei o módulo fastcgi para IIS e quão estável ele é e deixarei o IIS cuidar da autenticação.

editar:
Eu também tentei utilizar System.Security.Principal.WindowsIdentity e php extensão com/.net.Mas o construtor dotnet não parece permitir a passagem de parâmetros para o construtor de objetos e meu "experimento" para obter o assembly (e com ele CreateInstance()) de GetType() falhou com um erro "zval desconhecido".

Outras dicas

Boa pergunta!

Eu pensei um pouco sobre isso ...e não consigo pensar em uma boa solução.O que consigo pensar é um hack horrível e horrível que pode funcionar.Depois de ver que ninguém postou uma resposta para essa pergunta por quase um dia, achei uma resposta ruim, mas funcional, seria aceitável.

O arquivo SAM está fora dos limites enquanto o sistema está em execução.Existem alguns truques de injeção de DLL que você pode conseguir fazer funcionar, mas no final você acabará com hashes de senha e terá que fazer o hash das senhas fornecidas pelo usuário para combiná-las de qualquer maneira.

O que você realmente deseja é algo que tente autenticar o usuário no arquivo SAM.Acho que você pode fazer isso fazendo algo como o seguinte.

  1. Crie um compartilhamento de arquivos no servidor e faça com que apenas as contas nas quais você deseja fazer login tenham acesso a ele.
  2. Em PHP use o comando do sistema para invocar um script wsh que:monta o compartilhamento usando o nome de usuário e a senha fornecidos pelo usuário do site.registra se funcionar e, em seguida, desmonta a unidade, se funcionar.
  3. Colete o resultado de alguma forma.O resultado pode ser retornado ao php no stdout do script ou, esperançosamente, usando o código de retorno do script.

Eu sei que não é bonito, mas deve funcionar.

Eu me sinto sujo :|

Editar:A razão para invocar o script wsh externo é que o PHP não permite que você use caminhos UNC (até onde me lembro).

Construir uma extensão PHP requer um investimento bastante grande em termos de espaço no disco rígido.Como já tenho o ambiente GCC (MinGW) instalado, decidi aproveitar o impacto no desempenho ao iniciar um processo a partir do script PHP.O código fonte está abaixo.

// Usage: logonuser.exe /user username /password password [/domain domain]
// Exit code is 0 on logon success and 1 on failure.

#include <windows.h>

int main(int argc, char *argv[]) {
    HANDLE r = 0;
    char *user = 0;
    char *password = 0;
    char *domain = 0;
    int i;

    for(i = 1; i < argc; i++) {
        if(!strcmp(argv[i], "/user")) {
            if(i + 1 < argc) {
                user = argv[i + 1];
                i++;
            }
        } else if(!strcmp(argv[i], "/domain")) {
            if(i + 1 < argc) {
                domain = argv[i + 1];
                i++;
            }
        } else if(!strcmp(argv[i], "/password")) {
            if(i + 1 < argc) {
                password = argv[i + 1];
                i++;
            }
        }
    }

    if(user && password) {
        LogonUser(user, domain, password, LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &r);
    }
    return r ? 0 : 1;
}

A seguir está a fonte do PHP demonstrando seu uso.

if($_SERVER['REQUEST_METHOD'] == 'POST') {
    if(isset($_REQUEST['user'], $_REQUEST['password'], $_REQUEST['domain'])) {
        $failure = 1;
        $user = $_REQUEST['user'];
        $password = $_REQUEST['password'];
        $domain = $_REQUEST['domain'];

        if($user && $password) {
            $cmd = "logonuser.exe /user " . escapeshellarg($user) . " /password " . escapeshellarg($password);
            if($domain) $cmd .= " /domain " . escapeshellarg($domain);
            system($cmd, $failure);
        }

        if($failure) {
            echo("Incorrect credentials.");
        } else {
            echo("Correct credentials!");
        }
    }
}
?>
<form action="<?php echo(htmlentities($_SERVER['PHP_SELF'])); ?>" method="post">
    Username: <input type="text" name="user" value="<?php echo(htmlentities($user)); ?>" /><br />
    Password: <input type="password" name="password" value="" /><br />
    Domain: <input type="text" name="domain" value="<?php echo(htmlentities($domain)); ?>" /><br />
    <input type="submit" value="logon" />
</form>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top