Bom, este é o meu post de inauguração do blog. Vou começar com uma situação que passei a pouco tempo e que acho que outros que trabalham em empresas de médio porte também passaram ou passarão um dia. (rsrsr)
Eis o meu problema !!!
A universidade onde trabalho possui diversos prédios, cada prédio têm um servidor Microsoft Windows com AD (Active Diretor) armazenando o login e senha de todos os alunos. O aluno pode acessar qualquer máquinas de laboratórios em qualquer um dos prédios. Estes prédios não possuem, ainda, um link de comunicação entre si. Existe ainda, um site de serviços ao aluno, onde ele pode alterar a sua senha. Então você me pergunta: Qual o problema? Eu respondo: Sincronizar a senha de todos os alunos com o AD de todos os prédio e com a base de dados do site (SQL Server).
A solução que encontramos (eu e a equipe que trabalha comigo), não é a melhor, nem a mais segura, mas sim, a que resolveu nosso problema. Vejamos então passo-a-passo:
1º) Foi criado um job no servidor SQL Server que exporta para um arquivo texto os logins e senhas dos alunos novos e dos alunos que alteraram a senha;
2º) Agendamos no “schedule tasks” do servidor SQL Server o upload do arquivo texto para um FTP;
3º) No servidor de cada prédio outro agendamento fazendo o download do arquivo texto;
4º) E por último, um script em VBS que atualiza o AD com as informações do arquivo texto, também foi agendado.
On Error Resume Next
' '================================================================================================================================
' Autor : Wesley de Menezes Flor
' Descrição : Cria/Altera usuário e senha no AD com os dados de um arquivo texto.
'================================================================================================================================
'===================================================================================================================================
' Função que altera a opção do "User canoot change password" do AD
' Origem: http://msdn2.microsoft.com/en-us/library/aa746399.aspx
'===================================================================================================================================
Sub SetUserCannotChangePassword(strDomain, strUser, strUserCred, strPassword, fUserCannotChangePassword)
Dim fUser
Const ADS_UF_PASSWD_CANT_CHANGE = &H40
strPath = "WinNT://" & strDomain & "/" & strUser
If "" <> strUserCred Then
' Bind to the group with the specified username and password.
Set fUser = GetObject("WinNT:").OpenDSObject(strPath, strUserCred, strPassword, 1)
Else
' Bind to the group with the current credentials.
Set fUser = GetObject(strPath)
End If
lUserFlags = fUser.Get("userFlags")
If fUserCannotChangePassword Then
lUserFlags = lUserFlags Or ADS_UF_PASSWD_CANT_CHANGE
Else
lUserFlags = lUserFlags And Not ADS_UF_PASSWD_CANT_CHANGE
End If
' Modify the userFlags property.
fUser.Put "userFlags", lUserFlags
' Commit the changes to the server.
fUser.SetInfo
Set fUser = Nothing
End Sub
'===================================================================================================================================
' GRAVA ARQUIVO DE LOG
' EX: Call LogWrite ( Err, fsoFile, "texto", "comando" )
'===================================================================================================================================
Sub LogWrite ( Erro, fsTxt, Descricao, Comando )
If Erro.Number <> 0 Then
fsTxt.WriteLine( """" & Now() & """;" & Erro.Number & ";""" & Erro.Description & """;"""& Comando &""" " )
WScript.Quit
Else
fsTxt.WriteLine( """" & Now() & """;" & Erro.Number & ";""" & Descricao & """;"""& Comando &""" " )
End If
End Sub
' CONSTANTES ADSI
' Fonte: http://msdn2.microsoft.com/en-us/library/aa772300.aspx
Const ADS_SECURE_AUTHENTICATION = 1, ADS_USE_ENCRYPTION = 2, ADS_SERVER_BIND = 512, ADS_UF_DONT_EXPIRE_PASSWD = &H10000
' CONSTANTES FILE SYSTEM OBJECT
Const ForReading = 1, ForWrite = 2, ForAppending = 8
' OBJETOS DE DOMINIO LOCAL
Set objRootDSE = GetObject("LDAP://RootDSE")
ouDomain = objRootDSE.Get("DefaultNamingContext") ' Resultado ==> DC=dominio,DC=com,DC=br
Domain = Replace( Replace(ouDomain, "DC=", ""), ",", ".") ' Resultado ==> dominio.com.br
nt4Domain= Mid(Domain, 1, InStr(Domain, ".")-1 ) ' EX.: dominio.com.br = dominio
' DIRETÓRIO ATUAL / ARQUIVO DE LOG
scFile = WScript.ScriptFullName ' C:\SCRIPT\alunos-users.vbs
Dir = Left( scFile, InstrRev(scFile, "\") ) ' C:\SCRIPT\
Set objRootDSE = Nothing
' ALIMENTA VARIÁVEIS COM OS ARMENTOS
Set WshNetwork = WScript.CreateObject("WScript.Network")
Servidor = WshNetwork.ComputerName
Set WshNetwork = Nothing
' UNIDADE ORGANIZACIUONAL (OU) ONDE ESTÃO OS USUÁRIO QUE TERÃO A SENHA ALTERADA
strOU = "OU=Alunos,OU=Usuarios" & "," & ouDomain ' OU=Alunos,OU=Usuarios
' GRUPO DOS ALUNOS CRIADOS
ouGrupo = "CN=Grupo Alunos,OU=Alunos,OU=Usuarios" & "," & ouDomain ' CN=Grupo Alunos,OU=Alunos,OU=Usuarios
' ARQUIVO COM OS USUÁRIOS QUE SERÃO CRIADOS
SourcePath = Dir & "alunos-users.txt"
sDir = Mid( SourcePath, 1, InStrRev(SourcePath, "\") )
Tabela = Mid( SourcePath, InStrRev(SourcePath, "\") + 1 )
' ARQUIVO TEXTO SEM TÍTULO
' FONTE: http://www.connectionstrings.com/?carrier=textfile
txtConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="& sDir &";Extended Properties=""text;HDR=No;FMT=Delimited(;)"";"
' INFORMAÇÕES DA TABELA/ARQUIVO
RA = 0
Aluno = 1
SenhaRA = 2
Faculdade = Array(3,4)
Curso = Array(5,6)
' TRATAMENTO DO USUÁRIO DE LOGIN E DOMINIO
adUser = nt4Domain & "\" & AdUser ' dominio\username
DomainServer = Servidor & "." & Domain ' servidor.dominio.com.br
' OBJETOS DO ARQUIVO DE LOG
LogFile = Dir & Servidor & "-" & nt4Domain & "-log.csv"
Set fso = CreateObject("Scripting.FileSystemObject")
Set fLog = fso.OpenTextFile(LogFile, ForAppending, True)
' CABEÇALHO DE ARQUIVO DE LOG
Set txt = fso.GetFile(LogFile)
If txt.Size = 0 Then fLog.WriteLine( """Data/Hora"";Código do Erro;""Descrição do Erro"";""Comando""" )
Set txt = Nothing
Call LogWrite ( Err, fLog, "Início do processo.", "" )
' ABRE CONEXÕES COM O SERVIDOR AD E SQL/TXT
Set oConn = CreateObject("ADODB.Connection")
Set rsSQL = CreateObject("ADODB.RecordSet")
Set rsTMP = CreateObject("ADODB.RecordSet")
Set rsAD = CreateObject("ADODB.RecordSet")
oConn.Provider = "ADsDSOOBJECT"
oConn.Open "DS Query"
Call LogWrite( Err, fLog, "ADO Conn - Aberta um conexão com o AD.", "Open DS Query")
' ABRE TABELA DO SQL / TXT
' CursorLocation, CursorType,
Const adUseNone = 1, adUseServer = 2, adUseClient = 3
Const adOpenUnspecified = -1, adOpenForwardOnly = 0, adOpenKeyset = 1, adOpenDynamic = 2, adOpenStatic = 3
Const adLockUnspecified = -1, adLockReadOnly = 1, adLockPessimistic = 2, adLockOptimistic = 3, adLockBatchOptimistic = 4
rsSQL.CursorLocation = adUseClient
rsSQL.CursorType = adOpenForwardOnly
rsSQL.LockType = adLockReadOnly
rsSQL.Open "SELECT * FROM [" & Tabela & "]", txtConn
If Not rsSQL.EOF Then rsSQL.MoveFirst
Call LogWrite( Err, fLog, "ADO RS - Tabela de origem aberta (SQL/TXT)", rsSQL.Source)
' OBJ DOMINIO
Set oDomain = GetObject("LDAP://"& DomainServer & "/" & strOU)
Call LogWrite( Err, fLog, "OU Principal aberta.", "GetObject(LDAP:).OpenDSObject(LDAP://"& DomainServer & "/" & strOU & ", adUser, adPass, 1)" )
' VARRE OS USUÁRIOS DA 'OU' ESPECIRFICADA
While Not rsSQL.EOF AND Err.Number = 0
' QUERY QUE SERÁ EXECUTADA NO AD
strQuery = "SELECT ADsPath, cn, Name, givenName, initials, sn, samAccountName, department, telephoneNumber, mail, userPrincipalName, distinguishedName, homeDirectory, homeDrive, canonicalName, scriptPath, userAccountControl FROM 'LDAP://" & DomainServer & "' WHERE objectCategory='user' AND samAccountName = '"& rsSQL.Fields(RA) &"'"
' VERIFICA SE O USUÁRIO EXISTE NO AD
rsAD.Open strQuery, oConn
' SENHA QUE SERÁ GRAVADA NO AD
strPass = Trim(rsSQL.Fields(SenhaRA))
' CRIA O USUÁRIO SE ELE NÃO EXISTIR
If rsAD.EOF Then
' OU DO CURSO DO ALUNO
ouCurso = rsSQL.Fields(Faculdade(0)) & "-" & rsSQL.Fields(Curso(0))
deCurso = rsSQL.Fields(Faculdade(1)) & " - " & rsSQL.Fields(Curso(1))
' CRIA/ABRE A OU DO CURSO
rsTmp.Open "SELECT * FROM 'LDAP://"& DomainServer & "/" & strOU &"' WHERE name='"& ouCurso &"' AND objectCategory='organizationalUnit'", oConn
If rsTmp.EOF Then
' CRIA A 'OU' DO CURSO
Set oCurso = oDomain.Create("organizationalUnit", "ou=" & ouCurso)
oCurso.Put "Description", deCurso
oCurso.SetInfo
Call LogWrite( Err, fLog, "LDAP SetInfo - OU 'OU="& ouCurso &"' do curso foi criada.", "Criar ou=" & ouCurso )
' DESTRÓI
Set oCurso = Nothing
End If
rsTmp.Close
' ABRE O GRUPO DE USUÁRIOS
Set oGrupo = GetObject("LDAP://"& DomainServer & "/"& ouGrupo)
' CRIA O USUÁRIO
Set oCurso = GetObject("LDAP://"& DomainServer & "/OU="& ouCurso & "," & strOU)
Set oUser = oCurso.Create("User", "cn=" & rsSQL.Fields(RA).Value)
oUser.Put "sAMAccountName", rsSQL.Fields(RA).Value ' Nome de Logon do usuário (anterior ao Windows 2000)
oUser.SetInfo
oUser.AccountDisabled = False
oUser.Put "Description", rsSQL.Fields(Aluno).Value ' Descrição
oUser.Put "displayName", rsSQL.Fields(Aluno).Value ' Display Name
oUser.Put "userPrincipalName", rsSQL.Fields(RA).Value & "@" & Domain ' Nome de Logon do usuário
oUser.Put "userAccountControl", ADS_UF_DONT_EXPIRE_PASSWD ' A senha nunca expira
oUser.SetPassword(strPass) ' Senha
oUser.SetInfo ' Salvar
Call SetUserCannotChangePassword( DomainServer, rsSQL.Fields(RA).Value, "", "", True )
ouUser = "LDAP://"& DomainServer & "/" & "CN=" & rsSQL.Fields(RA).Value & ",OU="& ouCurso & "," & strOU
oGrupo.Add ouUser
Call LogWrite( Err, fLog, "LDAP - Usuário '"& rsSQL.Fields(RA).Value &"' do aluno(a) '"& rsSQL.Fields(Aluno).Value &"' foi criado e a senha alterada para '"& strPass &"'.", "Criar usuário: " & rsSQL.Fields(RA).Value )
Set oUser = Nothing
Set oCurso = Nothing
Set oGrupo = Nothing
Else
' ALTERA A SENHA DO USUÁRIO NO AD
Set oUser = GetObject(rsAD.Fields("ADsPath"))
oUser.SetPassword(strPass) ' Senha
oUser.Put "displayName", rsSQL.Fields(Aluno).Value ' Display Name
oUser.Put "Description", rsSQL.Fields(Aluno).Value ' Display Name
oUser.SetInfo
Call LogWrite( Err, fLog, "LDAP SetInfo - '"& rsAD.Fields("ADsPath") &"' Senha alterada para '"& strPass &"'.", "Alterar senha do usuário: " & rsAD.Fields("samAccountName") )
Set oUser = Nothing
End If
rsAD.Close
' PRÓXIMO REGISTRO NO SQL
rsSQL.MoveNext
Wend
rsSQL.Close
oConn.Close
' LOG DO FIM DO PROCESSO
Call LogWrite( Err, fLog, "Fim do processo.", "" )
' FECHA ARQUIVO DE LOG
fLog.Close
' DESTRÓI OBJETOS
Set rsSQL = Nothing
Set rsAD = Nothing
Set rsTmp = Nothing
Set oCmd = Nothing
Set oConn = Nothing
Set oDomain = Nothing
Set fso = Nothing
Set fLog = Nothing
Dúvidas, críticas ou sugestões, envie seu comentário.
Abraços e até o próximo post.
Nenhum comentário:
Postar um comentário