Is there a way in Visual Basic to check if the user's password is set to never expire in Active Directory?
I've found a way to find the last date it was changed, but I can't find the other available options.
Dim de As DirectoryServices.DirectoryEntry = GetUser(uDetails.username)
Dim objUser = GetObject(de.Path)
If objUser.PasswordLastChanged < DateTime.Now.AddMonths(-3) Then
...
Where can I find a list of all available objUser properties?
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
if(user != null)
{
// one of the properties exposed is "PasswordNeverExpires" (bool)
if(user.PasswordNeverExpires)
{
// do something here....
...
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
For .NET 2.0 you can use some LDAP. The magic part is userAccountControl:1.2.840.113556.1.4.803:=65536. The first part is the property that you want to search, the second means "bitwise AND" and the third is the bitwise flag to check, in this case the 17th bit. You can see more on the bitwise AND and OR in Active Directory in How to query Active Directory by using a bitwise filter.
In the code below update the SearchRoot variable with your domain controller (DC) and FQDN.
Imports System.DirectoryServices
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
''//Bind to the root of our domain
''// YOU_DOMAIN_CONTROLLER should be one of your DCs
''// EXAMPLE and COM are the parts of your FQDN
Dim SearchRoot As DirectoryEntry = New DirectoryEntry("LDAP://YOUR_DOMAIN_CONTROLLER/dc=EXAMPLE,dc=COM")
''//Create a searcher bound to the root
Dim Searcher As DirectorySearcher = New DirectorySearcher(SearchRoot)
''//Set our filer. The last part is dumb but that is the way that LDAP was built.
''//It basically does a bitwise AND looking for the 17th bit to be set on that property "userAccountControl" which is the "password never expires" bit
''//See this if you care to learn more http://support.microsoft.com/kb/269181
Searcher.Filter = "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))"
''//Find all of the results
Dim Results = Searcher.FindAll()
Dim DE As DirectoryEntry
''//Loop through each result
For Each R As SearchResult In Results
''//Get the result as a DirectoryEntry object
DE = R.GetDirectoryEntry()
''//Output the object name
Console.WriteLine(DE.Name)
Next
End Sub
End Class
public bool isPasswordExpired(String p_UserName, String p_DomainName)
{
bool m_Check=false;
int m_Val1 = (int)de1.Properties["userAccountControl"].Value;
int m_Val2 = (int) 0x10000;
if (Convert.ToBoolean(m_Val1 & m_Val2))
{
m_Check = true;
} //end
return m_Check
}
You could use the following code originally from here that I've translated from C# and modified a little bit according to your question (added a getter):
Dim pwdNeverExpires = getPasswordNeverExpires("Tim")
setPasswordNeverExpires("Tim", True)
' See http://msdn.microsoft.com/en-us/library/aa772300(VS.85).aspx
<Flags()> _
Private Enum ADS_USER_FLAG_ENUM
ADS_UF_SCRIPT = 1
' 0x1
ADS_UF_ACCOUNTDISABLE = 2
' 0x2
ADS_UF_HOMEDIR_REQUIRED = 8
' 0x8
ADS_UF_LOCKOUT = 16
' 0x10
ADS_UF_PASSWD_NOTREQD = 32
' 0x20
ADS_UF_PASSWD_CANT_CHANGE = 64
' 0x40
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128
' 0x80
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 256
' 0x100
ADS_UF_NORMAL_ACCOUNT = 512
' 0x200
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 2048
' 0x800
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 4096
' 0x1000
ADS_UF_SERVER_TRUST_ACCOUNT = 8192
' 0x2000
ADS_UF_DONT_EXPIRE_PASSWD = 65536
' 0x10000
ADS_UF_MNS_LOGON_ACCOUNT = 131072
' 0x20000
ADS_UF_SMARTCARD_REQUIRED = 262144
' 0x40000
ADS_UF_TRUSTED_FOR_DELEGATION = 524288
' 0x80000
ADS_UF_NOT_DELEGATED = 1048576
' 0x100000
ADS_UF_USE_DES_KEY_ONLY = 2097152
' 0x200000
ADS_UF_DONT_REQUIRE_PREAUTH = 4194304
' 0x400000
ADS_UF_PASSWORD_EXPIRED = 8388608
' 0x800000
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216
' 0x1000000
End Enum
Protected Overridable Function getPasswordNeverExpires(ByVal userName As String) As Boolean
Const userNameString As String = "userName"
Const userFlagsString As String = "userFlags"
Dim machineName As String = Environment.MachineName
Dim userInThisComputerDirectoryEntry As DirectoryEntry = getUserInThisComputerDirectoryEntry(machineName, userName)
If userInThisComputerDirectoryEntry Is Nothing Then
Throw New ArgumentException("not found in " & machineName, userNameString)
End If
Dim userFlagsProperties As PropertyValueCollection = userInThisComputerDirectoryEntry.Properties(userFlagsString)
Dim userFlags As ADS_USER_FLAG_ENUM = CType(userFlagsProperties.Value, ADS_USER_FLAG_ENUM)
Return userFlags = (userFlags Or ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD)
End Function
Protected Overridable Sub setPasswordNeverExpires(ByVal userName As String, ByVal passwordNeverExpires As Boolean)
Const userNameString As String = "userName"
Const userFlagsString As String = "userFlags"
Dim machineName As String = Environment.MachineName
Dim userInThisComputerDirectoryEntry As DirectoryEntry = getUserInThisComputerDirectoryEntry(machineName, userName)
If userInThisComputerDirectoryEntry Is Nothing Then
Throw New ArgumentException("not found in " & machineName, userNameString)
End If
Dim userFlagsProperties As PropertyValueCollection = userInThisComputerDirectoryEntry.Properties(userFlagsString)
Dim userFlags As ADS_USER_FLAG_ENUM = CType(userFlagsProperties.Value, ADS_USER_FLAG_ENUM)
Dim newUserFlags As ADS_USER_FLAG_ENUM = userFlags
If passwordNeverExpires Then
newUserFlags = newUserFlags Or ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD
Else
newUserFlags = newUserFlags And (Not ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD)
End If
userFlagsProperties.Value = newUserFlags
userInThisComputerDirectoryEntry.CommitChanges()
End Sub
Protected Overridable Function getUserInThisComputerDirectoryEntry(ByVal machineName As String, ByVal userName As String) As DirectoryEntry
Dim computerDirectoryEntry As DirectoryEntry = getComputerDirectoryEntry(machineName)
Const userSchemaClassName As String = "user"
Return computerDirectoryEntry.Children.Find(userName, userSchemaClassName)
End Function
Protected Overridable Function getComputerDirectoryEntry(ByVal machineName As String) As DirectoryEntry
'Initiate DirectoryEntry Class To Connect Through WINNT Protocol
' see: http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.path.aspx
Const pathUsingWinNTComputerMask As String = "WinNT://{0},computer"
Dim path As String = String.Format(pathUsingWinNTComputerMask, machineName)
Dim thisComputerDirectoryEntry As New DirectoryEntry(path)
Return thisComputerDirectoryEntry
End Function
You have to add a reference to System.DirectoryServices. I have tested it on Windows Server 2008 with .NET Framework 4 (it should also work under 2.0) without Active Directory. But check it out yourself and feel free to extend it to get/set other properties as well or connect to other machines (SomeDomain/OtherComputerName instead of Environment.MachineName).
Related
I'm consume an external webservice for sending data, using a web application in asp.net and Visual Studio 2010. The
sending of data must be digitally signed using a digital signature. The webservice contains the Signature class, where I
can fill all required values (SignedInfo, SignatureValue, KeyInfo).
I'm trying to fill the KeyInfo structure with the certificate like this:
Dim Sig As New RSP.SignatureType
(...)
Sig.SignedInfo = Sig_info
(...)
Sig.SignatureValue = Sig_value
Dim rspKey_info As New RSP.KeyInfoType()
Dim rspX509 As New RSP.X509DataType()
Dim arrCertificate As X509Certificate2()
arrCertificate = myF.ReturnCertificateCC()
rspKey_info.ItemsElementName = New RSP.ItemsChoiceType2(0) {}
rspKey_info.ItemsElementName(0) = RSP.ItemsChoiceType2.X509Data
rspKey_info.Items = New Object(0) {}
rspX509.ItemsElementName = New RSP.ItemsChoiceType2(0) {}
rspX509.ItemsElementName(0) = RSP.ItemsChoiceType2.X509Data
rspX509.Items = New Object(0) {}
rspX509.Items(0) = arrCertificate (0)
Sig.KeyInfo = rspKey_info
xmlString = myF.SerializeAnObject(Sig)
When I try to serialize the Signature Object, an error occur:
"Error generating the XML document."
InnerException:
"{ " The System.Security.Cryptography.X509Certificates.X509Certificate2 type was not expected . Use XmlInclude or
SoapInclude attribute to specify types that are not known statically. "}"
Public Function SerializeAnObject(ByVal obj As Object) As String
Dim doc As System.Xml.XmlDocument = New XmlDocument()
Dim serializer As System.Xml.Serialization.XmlSerializer = New System.Xml.Serialization.XmlSerializer(obj.GetType())
Dim stream As System.IO.MemoryStream = New System.IO.MemoryStream()
Try
serializer.Serialize(stream, obj)
stream.Position = 0
doc.Load(stream)
Return doc.InnerXml
Catch ex As Exception
Return ""
Finally
stream.Close()
stream.Dispose()
End Try
'#utilização
'dim xmlObject As string = SerializeAnObject(myClass)
End Function
Please help me...
I'm at several days trying to solve this...
Thanks in advance!
Regards!
rspX509.ItemsElementName = New RSP.ItemsChoiceType(0) {}
rspX509.ItemsElementName(0) = RSP.ItemsChoiceType.X509Certificate
rspX509.Items = New Object(0) {}
rspX509.Items(0) = arrCertificate (0)
rspKey_info.Items(0) = rspX509
I am totally lost. I build a Universal App (VB.net) which is consuming a web service on my (Azure Website Vb.net).
My Universal APP (UA) is sending userdata (Username an EmployeeNR) to a webservice and the Webservice is checking that data.
With TripleDES I encrypted the EmployeeNr and Username in the Universal and send it to the WebService. Now i am struggling how to decrypt the TripleDES on my WebService.
In the Universal App I work with Windows.Security.Cryptography which is not available on the Webservice site (asp.net).
I can only use System.Security.Cryptography.
I can encrypt and decrypt on Windows App site.
I also can encrpyt and decrypt on the Web Service site.
But if I pass an encrypted String form Win App to Web Service. Decryption is not working.
Problem is: On both sides, I use the same STRING, same Key and TripleDES encryption, but the result is different.
MY Encryption side - Windows Universal APP
Function myencrptor(ByVal Plaintext As String, ByVal mykey As String) As String
Dim crypt As SymmetricKeyAlgorithmProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.TripleDesCbcPkcs7)
Dim PlainTextbuffer As IBuffer = CryptographicBuffer.ConvertStringToBinary(Plaintext, BinaryStringEncoding.Utf8)
Dim mykeybuffer As IBuffer = CryptographicBuffer.ConvertStringToBinary(mykey, BinaryStringEncoding.Utf8)
Dim magickey As CryptographicKey = crypt.CreateSymmetricKey(mykeybuffer)
Dim signed As IBuffer = CryptographicEngine.Encrypt(magickey, PlainTextbuffer, Nothing)
Dim verschlüsselt As String = CryptographicBuffer.EncodeToBase64String(signed)
Return verschlüsselt
End Function
My Server Side
Partial Class regal_appsync_Default
Inherits System.Web.UI.Page
Public NotInheritable Class Simple3Des
Private xTripleDES As New TripleDESCryptoServiceProvider
Sub New(ByVal key As String)
' Initialize the crypto provider.
xTripleDES.Key = TruncateHash(key, xTripleDES.KeySize \ 8)
xTripleDES.IV = TruncateHash("", xTripleDES.BlockSize \ 8)
End Sub
Private Function TruncateHash(ByVal key As String, ByVal length As Integer) As Byte()
Dim sha1 As New SHA1CryptoServiceProvider
' Hash the key.
Dim keyBytes() As Byte = System.Text.Encoding.UTF8.GetBytes(key)
Dim hash() As Byte = sha1.ComputeHash(keyBytes)
' Truncate or pad the hash.
ReDim Preserve hash(length - 1)
Return hash
End Function
Public Function EncryptData(ByVal plaintext As String) As String
' Convert the plaintext string to a byte array.
Dim plaintextBytes() As Byte = System.Text.Encoding.UTF8.GetBytes(plaintext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the encoder to write to the stream.
Dim encStream As New CryptoStream(ms,
xTripleDES.CreateEncryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
encStream.FlushFinalBlock()
' Convert the encrypted stream to a printable string.
Return Convert.ToBase64String(ms.ToArray)
End Function
Public Function DecryptData(ByVal encryptedtext As String) As String
' Convert the encrypted text string to a byte array.
Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the decoder to write to the stream.
Dim decStream As New CryptoStream(ms, xTripleDES.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
decStream.Write(encryptedBytes, 0, encryptedBytes.Length)
decStream.FlushFinalBlock()
' Convert the plaintext stream to a string.
Return System.Text.Encoding.UTF8.GetString(ms.ToArray)
End Function
End Class
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Lbl1.Text = myEncoding(Txt1.Text)
End Sub
Protected Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Lbl1.Text = myDecoding(Lbl1.Text)
End Sub
Function myEncoding(ByVal plainText As String) As String
Dim wrapper As New Simple3Des("012345678901234567891234")
Dim cipherText As String = wrapper.EncryptData(plainText)
Return cipherText
End Function
Function myDecoding(ByVal cipherText As String) As String
' DecryptData throws if the wrong password is used.
Dim wrapper As New Simple3Des("012345678901234567891234")
Try
Dim plainText As String = wrapper.DecryptData(cipherText)
Return plainText
Catch ex As System.Security.Cryptography.CryptographicException
Return "problem"
End Try
End Function
End Class
looking forward to any helpful tips!
best wishes
hendrik
All --
I am able to retieve the FullName value
I am trying to retrieve an email address from Active Directory but using the following code in my ASP.Net Web Forms project that is using Windows Authentication:
Dim wi As System.Security.Principal.WindowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent()
Dim a As String() = wi.Name.Split(New Char() {"\"c}) '' Context.User.Identity.Name.Split('\')
Dim ADEntry As System.DirectoryServices.DirectoryEntry = New System.DirectoryServices.DirectoryEntry(Convert.ToString("WinNT://" + a(0) + "/" + a(1)))
Dim Name As String = ADEntry.Properties("FullName").Value.ToString()
Dim Email As String = ADEntry.Properties("mail").Value.ToString()
when I get to the line of code where I'm try to retrieve the email address I get an "Object reference not set to an instance of an object." error. I have tried using EmailAddress, E-Mail. I think the problem is that I am simply using the wrong keyword. I am able to retrieve the FullName value.
Thanks to Davide Piras who send me this link, I found a suitable solution:
Dim wi As System.Security.Principal.WindowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent()
Dim a As String() = wi.Name.Split(New Char() {"\"c}) '' Context.User.Identity.Name.Split('\')
Dim dc As PrincipalContext = New PrincipalContext(ContextType.Domain, "DomainName")
Dim adUser As UserPrincipal = UserPrincipal.FindByIdentity(dc, a(1))
Dim Email As String = adUser.EmailAddress
This code works for me..
Reference to System.DirectoryServices.AccountManagement
static string GetADUserEmailAddress(string username)
{
using (var pctx = new PrincipalContext(ContextType.Domain))
{
using (UserPrincipal up = UserPrincipal.FindByIdentity(pctx, username))
{
return up != null && !String.IsNullOrEmpty(up.EmailAddress) ? up.EmailAddress : string.Empty;
}
}
}
to use it:
lblEmail.Text = GetADUserEmailAddress(Request.ServerVariables["AUTH_USER"]);
I am using wicked code sqlsitemapprovider or it's VB version. Most of the things are going OK! But when I wanted to hide some of the nodes from appearing on menu while staying shown on sitemappath I cannot figure it out. I tried to change the sqlsitemapprovider code but was unsuccessfull. I have found David Sussman's (from sp.net) answer. but it was for a .sitemap file. So how can I manage to do the same with the sql sitemap provider mentioned above.
I added a column named visible to my SiteMap table it's type is bit and then I have done these changes (Sorry for such long code):
Imports System
Imports System.Web
Imports System.Data.SqlClient
Imports System.Collections.Specialized
Imports System.Configuration
Imports System.Web.Configuration
Imports System.Collections.Generic
Imports System.Configuration.Provider
Imports System.Security.Permissions
Imports System.Data.Common
Imports System.Data
Imports System.Web.Caching
''' <summary>
''' Summary description for SqlSiteMapProvider
''' </summary>
<SqlClientPermission(SecurityAction.Demand, Unrestricted:=True)> _
Public Class SqlSiteMapProvider
Inherits StaticSiteMapProvider
Private Const _errmsg1 As String = "Basamak no bulunamadı"
Private Const _errmsg2 As String = "Çift Basamak No"
Private Const _errmsg3 As String = "Üst Basamak Bulunamadı"
Private Const _errmsg4 As String = "Hatalı Üst Basamak"
Private Const _errmsg5 As String = "Bağlantı dizesi bulunamadı veya boş"
Private Const _errmsg6 As String = "Bağlantı dizesi bulunamadı"
Private Const _errmsg7 As String = "Bağlantı dizesi boş"
Private Const _errmsg8 As String = "Hatalı sqlCacheDependency"
Private Const _cacheDependencyName As String = "__SiteMapCacheDependency"
Private _connect As String
'Database connection string
Private _database As String, _table As String
'Database info for SQL Server 7/2000 cache dependency
Private _2005dependency As Boolean = False
'Database info for SQL Server 2005 cache dependency
Private _indexID As Integer, _indexTitle As Integer, _indexUrl As Integer, _indexDesc As Integer, _indexRoles As Integer, _indexParent As Integer, _indexvisible As Boolean
Private _nodes As New Dictionary(Of Integer, SiteMapNode)(16)
Private ReadOnly _lock As New Object()
Private _root As SiteMapNode
'Added...Declare an arraylist to hold all the roles this menu item applies to
Public roles As New ArrayList
Public Overloads Overrides Sub Initialize(ByVal name As String, ByVal config As NameValueCollection)
'Verify that config isn't null
If config Is Nothing Then
Throw New ArgumentNullException("config")
End If
'Assign the provider a default name if it doesn't have one
If [String].IsNullOrEmpty(Name) Then
Name = "SqlSiteMapProvider"
End If
' Add a default "description" attribute to config if the
' attribute doesnt exist or is empty
If String.IsNullOrEmpty(config("description")) Then
config.Remove("description")
config.Add("description", "SQL site map provider")
End If
' Call the base class's Initialize method
MyBase.Initialize(Name, config)
' Initialize _connect
Dim connect As String = config("connectionStringName")
If [String].IsNullOrEmpty(connect) Then
Throw New ProviderException(_errmsg5)
End If
config.Remove("connectionStringName")
If WebConfigurationManager.ConnectionStrings(connect) Is Nothing Then
Throw New ProviderException(_errmsg6)
End If
_connect = WebConfigurationManager.ConnectionStrings(connect).ConnectionString
If [String].IsNullOrEmpty(_connect) Then
Throw New ProviderException(_errmsg7)
End If
' Initialize SQL cache dependency info
Dim dependency As String = config("sqlCacheDependency")
If Not [String].IsNullOrEmpty(dependency) Then
If [String].Equals(dependency, "CommandNotification", StringComparison.InvariantCultureIgnoreCase) Then
SqlDependency.Start(_connect)
_2005dependency = True
Else
' If not "CommandNotification", then extract database and table names
Dim info As String() = dependency.Split(New Char() {":"c})
If info.Length <> 2 Then
Throw New ProviderException(_errmsg8)
End If
_database = info(0)
_table = info(1)
End If
config.Remove("sqlCacheDependency")
End If
' SiteMapProvider processes the securityTrimmingEnabled
' attribute but fails to remove it. Remove it now so we can
' check for unrecognized configuration attributes.
If config("securityTrimmingEnabled") IsNot Nothing Then
config.Remove("securityTrimmingEnabled")
End If
' Throw an exception if unrecognized attributes remain
If config.Count > 0 Then
Dim attr As String = config.GetKey(0)
If Not [String].IsNullOrEmpty(attr) Then
Throw New ProviderException("Unrecognized attribute: " + attr)
End If
End If
End Sub
Public Overloads Overrides Function BuildSiteMap() As SiteMapNode
SyncLock _lock
' Return immediately if this method has been called before
If _root IsNot Nothing Then
Return _root
End If
' Query the database for site map nodes
Dim connection As New SqlConnection(_connect)
Try
Dim command As New SqlCommand("proc_GetSiteMap", connection)
command.CommandType = CommandType.StoredProcedure
' Create a SQL cache dependency if requested
Dim dependency As SqlCacheDependency = Nothing
If _2005dependency Then
dependency = New SqlCacheDependency(command)
ElseIf Not [String].IsNullOrEmpty(_database) AndAlso Not String.IsNullOrEmpty(_table) Then
dependency = New SqlCacheDependency(_database, _table)
End If
connection.Open()
Dim reader As SqlDataReader = command.ExecuteReader()
_indexID = reader.GetOrdinal("ID")
_indexUrl = reader.GetOrdinal("Url")
_indexTitle = reader.GetOrdinal("Title")
_indexDesc = reader.GetOrdinal("Description")
_indexRoles = reader.GetOrdinal("Roles")
_indexParent = reader.GetOrdinal("Parent")
_indexvisible = reader.GetOrdinal("visible")
If reader.Read() Then
' Create the root SiteMapNode and add it to the site map
_root = CreateSiteMapNodeFromDataReader(reader)
AddNode(_root, Nothing)
' Build a tree of SiteMapNodes underneath the root node
While reader.Read()
' Create another site map node and add it to the site map
Dim node As SiteMapNode = CreateSiteMapNodeFromDataReader(reader)
AddNode(node, GetParentNodeFromDataReader(reader))
End While
' Use the SQL cache dependency
If dependency IsNot Nothing Then
HttpRuntime.Cache.Insert(_cacheDependencyName, New Object(), dependency, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, _
New CacheItemRemovedCallback(AddressOf OnSiteMapChanged))
End If
End If
Finally
connection.Close()
End Try
' Return the root SiteMapNode
Return _root
End SyncLock
End Function
Protected Overloads Overrides Function GetRootNodeCore() As SiteMapNode
SyncLock _lock
BuildSiteMap()
Return _root
End SyncLock
End Function
' Helper methods
Private Function CreateSiteMapNodeFromDataReader(ByVal reader As DbDataReader) As SiteMapNode
' Make sure the node ID is present
If reader.IsDBNull(_indexID) Then
Throw New ProviderException(_errmsg1)
End If
' Get the node ID from the DataReader
Dim id As Integer = reader.GetInt32(_indexID)
' Make sure the node ID is unique
If _nodes.ContainsKey(id) Then
Throw New ProviderException(_errmsg2)
End If
' Get title, URL, description, and roles from the DataReader
Dim title As String = IIf(reader.IsDBNull(_indexTitle), Nothing, reader.GetString(_indexTitle).Trim())
'Dim url As String = IIf(reader.IsDBNull(_indexUrl), Nothing, reader.GetString(_indexUrl).Trim())
'Dim url As String = ReplaceNullRefs(reader, _indexUrl)
Dim url As String = String.Empty
If Not (reader.IsDBNull(_indexUrl)) Then
url = reader.GetString(_indexUrl).Trim()
Else
url = ""
End If
'Eliminated...see http://weblogs.asp.net/psteele/archive/2003/10/09/31250.aspx
'Dim description As String = IIf(reader.IsDBNull(_indexDesc), Nothing, reader.GetString(_indexDesc).Trim())
'Added line below and 'ReplaceNUllRefs' func
Dim description As String = ReplaceNullRefs(reader, _indexDesc)
'Changed variable name from 'roles' to 'rolesN' and added line 230 to dump all roles into an arrayList
Dim rolesN As String = IIf(reader.IsDBNull(_indexRoles), Nothing, reader.GetString(_indexRoles).Trim())
Dim rolelist As String() = Nothing
If Not [String].IsNullOrEmpty(rolesN) Then
rolelist = rolesN.Split(New Char() {","c, ";"c}, 512)
End If
roles = ArrayList.Adapter(rolelist)
Dim visible As Boolean = ReplaceNullRefs(reader, _indexvisible)
' Create a SiteMapNode
Dim node As New SiteMapNode(Me, id.ToString(), url, title, description, rolelist, _
Nothing, Nothing, Nothing)
' Record the node in the _nodes dictionary
_nodes.Add(id, node)
' Return the node
Return node
End Function
Private Function ReplaceNullRefs(ByVal rdr As SqlDataReader, ByVal rdrVal As Integer) As String
If Not (rdr.IsDBNull(rdrVal)) Then
Return rdr.GetString(rdrVal)
Else
Return String.Empty
End If
End Function
Private Function GetParentNodeFromDataReader(ByVal reader As DbDataReader) As SiteMapNode
' Make sure the parent ID is present
If reader.IsDBNull(_indexParent) Then
'**** Commented out throw, added exit function ****
Throw New ProviderException(_errmsg3)
'Exit Function
End If
' Get the parent ID from the DataReader
Dim pid As Integer = reader.GetInt32(_indexParent)
' Make sure the parent ID is valid
If Not _nodes.ContainsKey(pid) Then
Throw New ProviderException(_errmsg4)
End If
' Return the parent SiteMapNode
Return _nodes(pid)
End Function
Private Sub OnSiteMapChanged(ByVal key As String, ByVal item As Object, ByVal reason As CacheItemRemovedReason)
SyncLock _lock
If key = _cacheDependencyName AndAlso reason = CacheItemRemovedReason.DependencyChanged Then
' Refresh the site map
Clear()
_nodes.Clear()
_root = Nothing
End If
End SyncLock
End Sub
End Class
and I get this error:
*Özel Durum Ayrıntıları: System.IndexOutOfRangeException: visible
Kaynak Hatası:
Satır 154: _indexRoles = reader.GetOrdinal("Roles")
Satır 155: _indexParent = reader.GetOrdinal("Parent")
Satır 156: _indexvisible = reader.GetOrdinal("visible")
Satır 157:
Satır 158: If reader.Read() Then
Kaynak Dosya: D:\Websites\kaihl\App_Code\SqlSiteMapProvider.vb Satır: 156*
What I want is to tell sqlsitemapprovider to include an attribute within each sitemapnode called visible="true/false". Since this will be an extra attribute for sitemappath and menu (I think) this code would be doing the hiding job in menu not in breadcrumb (according to David Sussman's reply to a similar files .sitemap based thread as I linked above in my question):
Protected Sub Menu1_MenuItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.MenuEventArgs) Handles Menu1.MenuItemDataBound
Dim node As SiteMapNode = CType(e.Item.DataItem, SiteMapNode)
' check for the visible attribute and if false
' remove the node from the parent
' this allows nodes to appear in the SiteMapPath but not show on the menu
If Not String.IsNullOrEmpty(node("visible")) Then
Dim isVisible As Boolean
If Boolean.TryParse(node("visible"), isVisible) Then
If Not isVisible Then
e.Item.Parent.ChildItems.Remove(e.Item)
End If
End If
End If
End Sub
how to achieve this? thank you.
Update: I have found something very close at this page but still unable to deploy the solution.
Dim atts As NameValueCollection = Nothing
Dim attributeString As String = reader("attributes").ToString().Trim()
If Not String.IsNullOrEmpty(attributeString) Then
atts = New NameValueCollection()
Dim attributePairs() As String = attributeString.Split(";")
For Each attributePair As String In atts
Dim attributes() As String = attributePair.Split(":")
If attributes.Length = 2 Then
atts.Add(atts(0), attributes(1))
End If
Next
End If
Dim node As New SiteMapNode(Me, id.ToString(), url, title, description, rolelist, _
atts, Nothing, Nothing)
At last I have found a solution. And it is here. Thanks so much to Kadir ÖZGÜR, Sanjay UTTAM, David Sussman.
Checkout this link. he overides the IsAccessibleToUser property on the SiteMapprovider to selectivly show nodes based on the role of the current user. you caould change the condiftion to suit your needs.
I am trying to write some code to check the AD password age during a user login and notify them of the 15 remaining days. I am using the ASP.Net code that I found on the Microsoft MSDN site and I managed to add a function that checks the if the account is set to change password at next login. The login and the change password at next login works great but I am having some problems with the check for the password age.
This is the VB.Net code for the DLL file:
Imports System
Imports System.Text
Imports System.Collections
Imports System.DirectoryServices
Imports System.DirectoryServices.AccountManagement
Imports System.Reflection 'Needed by the Password Expiration Class Only -Vince
Namespace FormsAuth
Public Class LdapAuthentication
Dim _path As String
Dim _filterAttribute As String
'Code added for the password expiration added by Vince
Private _domain As DirectoryEntry
Private _passwordAge As TimeSpan = TimeSpan.MinValue
Const UF_DONT_EXPIRE_PASSWD As Integer = &H10000
'Function added by Vince
Public Sub New()
Dim root As New DirectoryEntry("LDAP://rootDSE")
root.AuthenticationType = AuthenticationTypes.Secure
_domain = New DirectoryEntry("LDAP://" & root.Properties("defaultNamingContext")(0).ToString())
_domain.AuthenticationType = AuthenticationTypes.Secure
End Sub
'Function added by Vince
Public ReadOnly Property PasswordAge() As TimeSpan
Get
If _passwordAge = TimeSpan.MinValue Then
Dim ldate As Long = LongFromLargeInteger(_domain.Properties("maxPwdAge")(0))
_passwordAge = TimeSpan.FromTicks(ldate)
End If
Return _passwordAge
End Get
End Property
Public Sub New(ByVal path As String)
_path = path
End Sub
'Function added by Vince
Public Function DoesUserHaveToChangePassword(ByVal userName As String) As Boolean
Dim ctx As PrincipalContext = New PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Domain)
Dim up = UserPrincipal.FindByIdentity(ctx, userName)
Return (Not up.LastPasswordSet.HasValue)
'returns true if last password set has no value.
End Function
Public Function IsAuthenticated(ByVal domain As String, ByVal username As String, ByVal pwd As String) As Boolean
Dim domainAndUsername As String = domain & "\" & username
Dim entry As DirectoryEntry = New DirectoryEntry(_path, domainAndUsername, pwd)
Try
'Bind to the native AdsObject to force authentication.
Dim obj As Object = entry.NativeObject
Dim search As DirectorySearcher = New DirectorySearcher(entry)
search.Filter = "(SAMAccountName=" & username & ")"
search.PropertiesToLoad.Add("cn")
Dim result As SearchResult = search.FindOne()
If (result Is Nothing) Then
Return False
End If
'Update the new path to the user in the directory.
_path = result.Path
_filterAttribute = CType(result.Properties("cn")(0), String)
Catch ex As Exception
Throw New Exception("Error authenticating user. " & ex.Message)
End Try
Return True
End Function
Public Function GetGroups() As String
Dim search As DirectorySearcher = New DirectorySearcher(_path)
search.Filter = "(cn=" & _filterAttribute & ")"
search.PropertiesToLoad.Add("memberOf")
Dim groupNames As StringBuilder = New StringBuilder()
Try
Dim result As SearchResult = search.FindOne()
Dim propertyCount As Integer = result.Properties("memberOf").Count
Dim dn As String
Dim equalsIndex, commaIndex
Dim propertyCounter As Integer
For propertyCounter = 0 To propertyCount - 1
dn = CType(result.Properties("memberOf")(propertyCounter), String)
equalsIndex = dn.IndexOf("=", 1)
commaIndex = dn.IndexOf(",", 1)
If (equalsIndex = -1) Then
Return Nothing
End If
groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1))
groupNames.Append("|")
Next
Catch ex As Exception
Throw New Exception("Error obtaining group names. " & ex.Message)
End Try
Return groupNames.ToString()
End Function
'Function added by Vince
Public Function WhenExpires(ByVal username As String) As TimeSpan
Dim ds As New DirectorySearcher(_domain)
ds.Filter = [String].Format("(&(objectClass=user)(objectCategory=person)(sAMAccountName={0}))", username)
Dim sr As SearchResult = FindOne(ds)
Dim user As DirectoryEntry = sr.GetDirectoryEntry()
Dim flags As Integer = CInt(user.Properties("userAccountControl").Value)
If Convert.ToBoolean(flags And UF_DONT_EXPIRE_PASSWD) Then
'password never expires
Return TimeSpan.MaxValue
End If
'get when they last set their password
Dim pwdLastSet As DateTime = DateTime.FromFileTime(LongFromLargeInteger(user.Properties("pwdLastSet").Value))
' return pwdLastSet.Add(PasswordAge).Subtract(DateTime.Now);
If pwdLastSet.Subtract(PasswordAge).CompareTo(DateTime.Now) > 0 Then
Return pwdLastSet.Subtract(PasswordAge).Subtract(DateTime.Now)
Else
Return TimeSpan.MinValue
'already expired
End If
End Function
'Function added by Vince
Private Function LongFromLargeInteger(ByVal largeInteger As Object) As Long
Dim type As System.Type = largeInteger.[GetType]()
Dim highPart As Integer = CInt(type.InvokeMember("HighPart", BindingFlags.GetProperty, Nothing, largeInteger, Nothing))
Dim lowPart As Integer = CInt(type.InvokeMember("LowPart", BindingFlags.GetProperty, Nothing, largeInteger, Nothing))
Return CLng(highPart) << 32 Or CUInt(lowPart)
End Function
'Function added by Vince
Private Function FindOne(ByVal searcher As DirectorySearcher) As SearchResult
Dim sr As SearchResult = Nothing
Dim src As SearchResultCollection = searcher.FindAll()
If src.Count > 0 Then
sr = src(0)
End If
src.Dispose()
Return sr
End Function
End Class
End Namespace
And this is the Login.aspx page:
sub Login_Click(sender as object,e as EventArgs)
Dim adPath As String = "LDAP://DC=xxx,DC=com" 'Path to your LDAP directory server
Dim adAuth As LdapAuthentication = New LdapAuthentication(adPath)
Try
If (True = adAuth.DoesUserHaveToChangePassword(txtUsername.Text)) Then
Response.Redirect("passchange.htm")
ElseIf (True = adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text)) Then
Dim groups As String = adAuth.GetGroups()
'Create the ticket, and add the groups.
Dim isCookiePersistent As Boolean = chkPersist.Checked
Dim authTicket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, _
txtUsername.Text, DateTime.Now, DateTime.Now.AddMinutes(60), isCookiePersistent, groups)
'Encrypt the ticket.
Dim encryptedTicket As String = FormsAuthentication.Encrypt(authTicket)
'Create a cookie, and then add the encrypted ticket to the cookie as data.
Dim authCookie As HttpCookie = New HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
If (isCookiePersistent = True) Then
authCookie.Expires = authTicket.Expiration
End If
'Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie)
'Retrieve the password life
Dim t As TimeSpan = adAuth.WhenExpires(txtUsername.Text)
'You can redirect now.
If (passAge.Days = 90) Then
errorLabel.Text = "Your password will expire in " & DateTime.Now.Subtract(t)
'errorLabel.Text = "This is"
'System.Threading.Thread.Sleep(5000)
Response.Redirect("http://somepage.aspx")
Else
Response.Redirect(FormsAuthentication.GetRedirectUrl(txtUsername.Text, False))
End If
Else
errorLabel.Text = "Authentication did not succeed. Check user name and password."
End If
Catch ex As Exception
errorLabel.Text = "Error authenticating. " & ex.Message
End Try
End Sub
`
Every time I have this Dim t As TimeSpan = adAuth.WhenExpires(txtUsername.Text) enabled, I receive "Arithmetic operation resulted in an overflow." during the login and won't continue.
What am I doing wrong? How can I correct this? Please help!!
Thank you very much for any help in advance.
Vince
Ok I tried to use a different approach.
Here are the functions converted from C#:
Public Function PassAboutToExpire(ByVal userName As String) As Integer
Dim passwordAge As TimeSpan
Dim currentDate As DateTime
Dim ctx As PrincipalContext = New PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Domain)
Dim up = UserPrincipal.FindByIdentity(ctx, userName)
'Return (Not up.LastPasswordSet.HasValue)
'returns true if last password set has no value.
Dim pwdLastSet As DateTime = DateTime.FromFileTime(LongFromLargeInteger(up.LastPasswordSet))
currentDate = Now
passwordAge = currentDate.Subtract(pwdLastSet)
If passwordAge.Days > 75 Then
'If pwdLastSet.Subtract(passwordAge).CompareTo(DateTime.Now) > 0 Then
'Dim value As TimeSpan = pwdLastSet.Subtract(passwordAge).Subtract(DateTime.Now)
'If (value.Days > 75) Then
Return passwordAge.Days
'End If
Else
Return False
'already expired
End If
End Function
Private Function LongFromLargeInteger(ByVal largeInteger As Object) As Long
Dim type As System.Type = largeInteger.[GetType]()
Dim highPart As Integer = CInt(type.InvokeMember("HighPart", BindingFlags.GetProperty, Nothing, largeInteger, Nothing))
Dim lowPart As Integer = CInt(type.InvokeMember("LowPart", BindingFlags.GetProperty, Nothing, largeInteger, Nothing))
Return CLng(highPart) << 32 Or CUInt(lowPart)
End Function
And here is the code snippet from the logon.aspx page:
sub Login_Click(sender as object,e as EventArgs)
Dim adPath As String = "LDAP://DC=xzone,DC=com" 'Path to your LDAP directory server
Dim adAuth As LdapAuthentication = New LdapAuthentication(adPath)
Try
If (True = adAuth.DoesUserHaveToChangePassword(txtUsername.Text)) Then
Response.Redirect("http://mypass.nsu.edu")
ElseIf (adAuth.PassAboutToExpire(txtUsername.Text) > 0) Then
Response.Redirect("http://www.yahoo.com")
Now when I try to login I receive the exception error: Error authenticating. Method 'System.DateTime.HighPart' not found.
and I don't know why. Anyone has any idea?
I would use the DateDiff function to determine the remaining number of days rather than using currentDate.Subtract
Dim passwordAge As Integer = (CInt)DateDiff(DateInterval.Day, Now, up.LastPasswordSet))
That will return an integer representing the number of days between now and when the password will need to be set.