Microsoft KB Archive/842789

= You receive a &quot;logon failure: unknown user name or bad&quot; error message while accessing remote security-enhanced resources from an ASP.NET application =

Article ID: 842789

Article Last Modified on 4/3/2007

-

APPLIES TO


 * Microsoft ASP.NET 1.1
 * Microsoft ASP.NET 1.0

-





SUMMARY
''This article discusses the behavior of accessing a remote security-enhanced resource from a Microsoft ASP.NET application. The article contains the following workarounds for this behavior:''

 

In the Machine.config file, change the userName attribute and the password attribute of the processModel element.

 

Run the application under the identity of a user who has permissions to the remote security-enhanced resource by using the impersonation element in the Web.config file.

 

Change the password of the ASPNET user account to some known value, and then create the same ASPNET user account that uses the same password on the remote computer.

 

Access the remote security-enhanced resource by using a COM component that is running under the security context of a user account that has permissions to the remote security-enhanced resource.

 

Run the part of the code that is accessing the remote security-enhanced resource under the identity of a user who has permissions to the remote security-enhanced resource.

 

Call the WNetAddConnection2 function to open the connection to the remote security-enhanced resource, and then map the local drive to the remote security-enhanced resource in the code.



This article also includes detailed steps to reproduce the behavior.

<div class="symptoms_section">

SYMPTOMS
When you access remote security-enhanced resources from an ASP.NET application, you may receive the following error message:

Logon failure: unknown user name or bad password.

<div class="cause_section">

CAUSE
By default, an ASP.NET application runs under the security context of an ASPNET user account. The ASP.NET application accesses the remote security-enhanced resource by using the ASPNET user account when the following conditions are true:
 * When the impersonation feature is not turned on for the ASP.NET application
 * When the authentication method in Microsoft Internet Information Services (IIS) is set to anonymous access

However, the ASPNET user account may not have permissions to access the remote security-enhanced resource.

<div class="workaround_section">

WORKAROUND
To work around this behavior, use one of the following methods:
 * Use the Machine.config file
 * Use the impersonation feature in the Web.config file
 * Change the password of the ASPNET user account
 * Use a COM component to access the remote security-enhanced resource
 * Use the code impersonation feature
 * Call the WNetAddConnection2 function in your code

Use the Machine.config file
Change the userName attribute and the password attribute in the processModel element of the Machine.config file to the credentials of a user who has access to the remote security-enhanced resource. After you make this change, restart the computer. <processModel enable=&quot;true&quot; userName=&quot;<UserName>&quot; password=&quot;<Password>&quot;. . ./> Note  and   are placeholders for the credentials of a user who has access to the remote security-enhanced resource.

Important Do not to store clear-text passwords in the Machine.config file. Instead, use the Aspnet_setreg.exe utility to store encrypted passwords in the registry. For additional information about how to use the Aspnet_setreg utility, click the following article number to view the article in the Microsoft Knowledge Base:

329290 How to use the ASP.NET utility to encrypt credentials and session state connection strings

When you use this method, the change is global. This is a drawback because other Web applications and other Web services that are running on the computer where you make the change will also run in this new security context.

However, this is not the case for Microsoft Internet Information Services (IIS) 6.0 on Microsoft Windows Server 2003 because IIS uses application pools for Web applications and for Web services. Each application can run in its own application pool. Each application pool can be configured for the user name field and the password field. You can set this configuration under the security context of the worker process in the application pool where the application runs.

If you change the user account under the security context that the ASP.NET worker process is running in, you may also have to grant the correct permissions to that user account on some folders on the Web server to make the worker process run successfully.

For more information about how to create a custom account to run ASP.NET applications, visit the following Microsoft Developer Network (MSDN) Web site:

http://msdn2.microsoft.com/en-us/library/aa302396.aspx

back to the top

Use the impersonation feature in the Web.config file
You can set fixed identities that have access to the remote security-enhanced resource for specific virtual directories by using the following setting in the Web.config file for your application. <identity impersonate=&quot;true&quot; userName=&quot;<UserName>&quot; password=&quot;<Password>&quot;/> Note  and   are placeholders for the credentials of a user who has access to the remote security-enhanced resource.

Important Do not to store clear-text passwords in the Machine.config file. Instead, use the Aspnet_setreg.exe utility to store encrypted passwords in the registry. For additional information about how to use the Aspnet_setreg utility, click the following article number to view the article in the Microsoft Knowledge Base:

329290 How to use the ASP.NET utility to encrypt credentials and session state connection strings

You can use one of the following accounts for impersonation:
 * A domain account
 * A &quot;mirrored&quot; local account

A &quot;mirrored&quot; local account has a matching user name and a matching password on two computers. You must use this account if the computers are in separate domains and do not have a trust relationship.

back to the top

Change the password of the ASPNET user account
By default, the ASP.NET worker process (Aspnet_wp.exe) runs under the ASPNET user account. The ASPNET user account is located under Local Users and Groups. This account has a strong password that is secured in the Local System Authority (LSA).

To use this method, follow these steps: <ol> In Local Users and Groups on the Web server, change the ASPNET account password to a known value.</li>  Replace the credentials in the processModel element in the Machine.config file with the following. <processModel enable=&quot;true&quot; userName=&quot;ASPNET&quot; password=&quot;<Password>&quot;. . ./> Note   is the placeholder for the password that you have assigned to the ASPNET user account. </li> On the remote computer, create an account that is named ASPNET and that has the same password as the ASPNET user account on the Web server.</li> Add the ASPNET account on the remote computer to the Access Control List (ACL) of the security-enhanced resource.</li></ol>

back to the top

Use a COM component to access the remote security-enhanced resource
<ol> Create an ActiveX component: <ol style="list-style-type: lower-alpha;"> Start Microsoft Visual Basic 6.0.</li> Create an ActiveX Dll project.</li> On the Project menu, click References. The References dialog box appears.</li> Click to select the Microsoft Scripting Runtime check box in the Available References list box to add the reference in your project.</li> Click OK.</li> Press CTRL+R to open Project Explorer, click Project1, and then press F4 to access the properties for the project.</li> Change the Name property to remoteAccess .</li> In Project Explorer, click Class1.cls, and then change the Name property to clsRemoteAccess .</li> On the File menu, click Save Project. The Save File As dialog box appears.</li> Save the class file as clsRemoteAccess.cls.</li> Save the project file as remoteAccess.vbp.</li> <li> Paste the following code in the code window of the clsRemoteAccess class: Public fs As New FileSystemObject Public txtStream As TextStream ' Public Function WriteToFile As Boolean On Error GoTo Erro Set txtStream = fs.OpenTextFile(&quot;\\<ServerName>\<ShareName>\<TextFileName>&quot;, ForAppending, False) ' txtStream.WriteLine (&quot;Hi i am able to write&quot;) txtStream.Close WriteToFile = True Exit Function Erro: WriteToFile = False End Function Note,  , and   are placeholders for these values in your environment. </li> <li>On the File menu, click Make remoteAccess.dll. The Make Project dialog box appears.</li> <li>Click OK.</li> <li>On the File menu, click Exit. The Microsoft Visual Basic dialog box appears.</li> <li>Click Yes.</li></ol> </li> <li>Create a COM+ application: <ol style="list-style-type: lower-alpha;"> <li>On a computer that is running the Microsoft Windows 2000 Advance Server operating system, click Start, point to Programs, point to Administrative Tools, and then click Component Services. The Component Services dialog box appears.</li> <li>Expand Component Services, expand Computers, expand My Computer, and then click COM+ Applications.</li> <li>Right-click COM+ Applications, click New, and then click Application. The Welcome to the COM Application Install Wizard wizard appears.</li> <li>Click Next.</li> <li>Click Create an empty application.</li> <li>In the Enter a name for the new application box, type remoteComponent, and then click Next.</li> <li>Click This user.</li> <li>In the User box, type the name of a user who has access to the remote security-enhanced resource.</li> <li>In the Password box, type the password for the user account.</li> <li>In the Confirm password box, type the password again.</li> <li>Click Next, and then click Finish.</li></ol> </li> <li>Add the ActiveX component to the COM+ application: <ol style="list-style-type: lower-alpha;"> <li>In the left pane of the Component Services dialog box, expand COM+ Applications, expand remoteComponent, and then click Components.</li> <li>Right-click Components, point to New, and then click Component. The Welcome to the COM Component Install Wizard wizard appears.</li> <li>Click Next.</li> <li>Click Install new component(s).</li> <li>Locate the remoteAccess.dll file that you created in step 1.</li> <li>Click Open, click Next, and then click Finish. This step installs the dynamic link library (DLL) in the COM+ application.</li></ol> </li> <li>Use the COM component in the ASP.NET application: <ol style="list-style-type: lower-alpha;"> <li>Start Microsoft Visual Studio .NET.</li> <li>On the File menu, point to New, and then click Project. The New Project dialog box appears.</li> <li>Under Project Types, click Visual Basic Projects.</li> <li>Under Templates, click ASP.NET Web Application, and then click OK.</li> <li>In Solution Explorer, right-click References, and then click Add Reference. The Add Reference dialog box appears.</li> <li>Click the COM tab.</li> <li>In the Component Name column, click remoteAccess.</li> <li>Click Select, and then click OK.</li> <li>In Solution Explorer, right-click the WebForm1.aspx file, and then click View Code.</li> <li> Paste the following code at the top of the WebForm1.aspx.vb file. Imports remoteAccess </li> <li>Locate the Page_Load method.</li> <li> Paste the following code in the Page_Load method. Dim objRemoteAccess As New clsRemoteAccessClass Dim blnWriteResult As Boolean '       blnWriteResult = objRemoteAccess.WriteToFile '       If (blnWriteResult) Then Response.Write(&quot;Success&quot;) Else Response.Write(&quot;Failed&quot;) End If </li> <li>On the Build menu, click Build Solution.</li> <li>On the Debug menu, click Start. You receive the success message in the browser.</li></ol> </li></ol>

back to the top

Use the code impersonation feature
By default, the ASP.NET worker process (Aspnet_wp.exe) runs under the security context of the ASPNET user account. To use this method, the user account under the security context that the ASP.NET worker process (Aspnet_wp.exe) runs in must be part of the &quot;Act as part of the operating system&quot; policy. You can use Local Security Policy in the Windows Administrative Tools to add the ASPNET user account to the &quot;Act as part of the operating system&quot; policy.

Note To use this method, you must maintain a list of user names and their corresponding passwords in your application. Because you are using those user names and passwords to connect to the remote security-enhanced resources from the code, you must make changes in your application when these user names or their corresponding passwords change. <ol> <li>Start Microsoft Visual Studio .NET</li> <li>On the File menu, point to New, and then click Project. The New Project dialog box appears.</li> <li>Select Visual Basic Projects under Project Types.</li> <li>Select ASP.NET Web Application under Templates.</li> <li>Click OK.</li> <li>Right-click the WebForm1.aspx file in the solution explorer window, and then click View Code.</li> <li> Add the following code at the top of the WebForm1.aspx.vb file. Imports System.IO Imports System.Security Imports System.Security.Principal </li> <li> Locate the Public Class WebForm1 Inherits System.Web.UI.Page statement and then add the following code after the Public Class WebForm1 Inherits System.Web.UI.Page statement. Dim LOGON32_LOGON_INTERACTIVE As Integer = 2 Dim LOGON32_PROVIDER_DEFAULT As Integer = 0 '   Declare Function LogonUserA Lib &quot;advapi32.dll&quot; (ByVal lpxzUsername As String, _                                            ByVal lpszDomain As String, _                                            ByVal lpszpassword As String, _                                            ByVal dwLogonType As Integer, _                                            ByVal dwLogonProvider As Integer, _                                            ByRef phToken As IntPtr) As Integer Declare Auto Function DuplicateToken Lib &quot;advapi32.dll&quot; ( _                                           ByVal ExistingTokenHandle As IntPtr, _                                            ByVal ImpersonationLevel As Integer, _                                            ByRef DuplicateTokenHandle As IntPtr) As Integer Declare Auto Function RevertToSelf Lib &quot;advapi32.dll&quot; As Long '   Declare Auto Function CloseHandle Lib &quot;Kernel32.dll&quot; (ByVal handle As IntPtr) As Long '   Dim impersonationContext As WindowsImpersonationContext </li> <li> Locate the Page_Load method, and then paste the following code in the Page_Load method. Try If impersonateValidUser(&quot;<UserName>&quot;, &quot;&quot;, &quot;<Password>&quot;) Then

Dim fs As New FileStream(&quot;\\<ServerName>\<ShareName>\<TextFileName>&quot;, FileMode.Append) Dim w As New StreamWriter(fs) Try w.Write(w.NewLine) w.WriteLine(&quot;Hi how are you&quot;) w.Close fs.Close Catch w.Close fs.Close End Try '               undoImpersonation Response.Write(&quot;Success&quot;) Else Response.Write(&quot;Failure&quot;)

End If       Catch ex As Exception Response.Write(ex.Message) Response.Write(vbNewLine & User.Identity.Name) Response.Write(vbNewLine) Response.Write(vbNewLine & Principal.WindowsIdentity.GetCurrent.Name) End Try Note,  ,  ,  , and   are placeholders for these values in your environment. and  are the values for the credential of the user who has access to the   file on the remote computer. </li> <li> Locate the End Sub statement and then paste the following code after the End Sub statement. '   Private Function impersonateValidUser(ByVal userName As String, _        ByVal domain As String, ByVal password As String) As Boolean Dim tempWindowsIdentity As WindowsIdentity Dim token As IntPtr = IntPtr.Zero Dim tokenDuplicate As IntPtr = IntPtr.Zero impersonateValidUser = False '       If RevertToSelf Then If LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, _               LOGON32_PROVIDER_DEFAULT, token) <> 0 Then If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then tempWindowsIdentity = New WindowsIdentity(tokenDuplicate) impersonationContext = tempWindowsIdentity.Impersonate If Not impersonationContext Is Nothing Then impersonateValidUser = True End If               End If            End If        End If        ' If Not tokenDuplicate.Equals(IntPtr.Zero) Then CloseHandle(tokenDuplicate) End If       ' If Not token.Equals(IntPtr.Zero) Then CloseHandle(token) End If       ' End Function '   Private Sub undoImpersonation impersonationContext.Undo End Sub </li> <li>On the Build menu, click Build Solution.</li> <li>On the Debug menu, click Start. You receive the success message in the browser.</li></ol>

Note To use this method, you must maintain a list of user names and their corresponding passwords in your application. Because you are using those user names and passwords to connect to the remote security-enhanced resources from the code, you must make changes in your application when these user names or their corresponding passwords change.

back to the top

Call the WNetAddConnection2 function in your code
To use this method, you must call the WNetAddConnection2 function. The WNetAddConnection2 function makes a connection to a network resource. The function can redirect a local device to the network resource.

Note To use this method, you must maintain a list of user names and their corresponding passwords in your application. Because you are using those user names and passwords to connect to the remote security-enhanced resources from the code, you must make changes in your application when these user names or their corresponding passwords change. <ol> <li>Start Microsoft Visual Studio .NET</li> <li>On the File menu, point to New, and then click Project. The New Project dialog box appears.</li> <li>Under Project Types, click Visual Basic Projects.</li> <li>Under Templates, click ASP.NET Web Application, and then click OK.</li> <li>In Solution Explorer, right-click the WebForm1.aspx file, and then click View Code.</li> <li> Add the following code at the top of the WebForm1.aspx.vb file. Imports System.IO Imports System.Runtime.InteropServices </li> <li> Add the following code after the Public Class WebForm1 Inherits System.Web.UI.Page statement. '   Structure NETRESOURCE Public dwScope As Int32 Public dwType As Int32 Public dwDisplayType As Int32 Public dwUsage As Int32 Public lpLocalName As String Public lpRemoteName As String Public lpComment As String Public lpProvider As String End Structure '   Public Const NO_ERROR As Int32 = 0 Public Const CONNECT_UPDATE_PROFILE As Int32 = &H1 Public Const RESOURCETYPE_DISK As Int32 = &H1 '   Declare Function WNetAddConnection2 Lib &quot;mpr.dll&quot; Alias _ &quot;WNetAddConnection2A&quot; (ByRef lpNetResource As NETRESOURCE, _     <MarshalAs(UnmanagedType.LPStr)> ByVal lpPassword As String, <MarshalAs(UnmanagedType.LPStr)> ByVal lpUserName As String, _      ByVal dwFlags As Int32) As Int32 '   Declare Function WNetCancelConnection2 Lib &quot;mpr.dll&quot; Alias _ &quot;WNetCancelConnection2A&quot; (ByVal lpName As String, _   ByVal dwFlags As Long, ByVal fForce As Long) As Long </li> <li>Locate the Page_Load method.</li> <li> Paste the following code in the Page_Load method. Try '           Dim Result As Long Dim theNetResource As NETRESOURCE theNetResource.dwType = RESOURCETYPE_DISK theNetResource.lpRemoteName = &quot;\\<ServerName>\<ShareName>&quot; theNetResource.lpLocalName = &quot;X:&quot; '           Result = WNetAddConnection2(theNetResource, &quot;<Password>&quot;, &quot;<Domain\UserName>&quot;, CONNECT_UPDATE_PROFILE) '           If (Result = NO_ERROR) Then '               Dim fs As New FileStream(&quot;X:\<TextFileName>&quot;, FileMode.Append) Dim w As New StreamWriter(fs) '               Try w.Write(w.NewLine) w.WriteLine(&quot;Hi how are you&quot;) w.Close fs.Close Response.Write(&quot;Success&quot;) Catch Response.Write(&quot;Failed&quot;) w.Close fs.Close End Try '           Else Response.Write(&quot;Failed&quot;) End If           ' Result = WNetCancelConnection2(theNetResource.lpLocalName, 0, 0) '       Catch '       End Try ' Note ,  ,  ,  , and   are placeholders for these values in your environment. and  are the values for the credential of the user who has access to the   file on the remote computer. </li> <li>On the Build menu, click Build Solution.</li> <li>On the Debug menu, click Start. You receive the success message in the browser.</li></ol>

back to the top

<div class="status_section">

STATUS
This behavior is by design.

<div class="moreinformation_section">

Steps to reproduce the behavior
In these steps, you write to a text file that is located on another computer in the same network. This text file is secured from being accessed through other computers in the network. <ol> <li>Start Microsoft Visual Studio .NET</li> <li>On the File menu, point to New, and then click Project. The New Project dialog box appears.</li> <li>Under Project Types, click Visual Basic Projects.</li> <li>Under Templates, click ASP.NET Web Application.</li> <li>Click OK.</li> <li>In Solution Explorer, right-click the WebForm1.aspx file, and then click View Code.</li> <li> Add the following code at the top of the Webform1.aspx.vb file. Imports System.IO Imports System.Security </li> <li>Locate the Page_Load method.</li> <li> Paste the following code in the Page_Load method. Try Dim fs As New FileStream(&quot;\\<ServerName>\<ShareName>\<TextFileName>&quot;, FileMode.Append) Dim w As New StreamWriter(fs) '           Try w.Write(w.NewLine) w.WriteLine(&quot;Hi how are you&quot;) w.Close fs.Close Catch w.Close fs.Close End Try '       Catch ex As Exception Response.Write(ex.Message) End Try Note,  , and   are placeholders for these values in your environment. </li> <li>On the Build menu, click Build Solution.</li> <li>On the Debug menu, click Start.</li></ol>

You may receive the error message that is mentioned in the &quot;Symptoms&quot; section.

<div class="references_section">