Searching Active Directory from ASP.NET - asp.net

I have an asp.net website which searches Active Directory for user details using this code:
public static SearchResult GetUserProfileFromAD(string username)
{
DirectorySearcher searcher = new DirectorySearcher("(&(objectCategory=person)(sAMAccountName=" + username + "))");
return searcher.FindOne();
}
the website is working great on windows server 2003 and IIS5.
recently i move the website to a new windows server 2008 with IIS7.5
i Added application to iis and conect the website and i get this error:
The (&(objectCategory=person)(sAMAccountName=)) search filter is
invalid. Description: An unhandled exception occurred during the
execution of the current web request. Please review the stack trace
for more information about the error and where it originated in the
code.
Exception Details: System.ArgumentException: The
(&(objectCategory=person)(sAMAccountName=)) search filter is invalid.
when i run my website through Visual Studio it works. the problem is only from IIS.
Can someone help me?

Your "username" variable is blank, causing your filter to terminate in a equal sign (which is, in fact. invalid) Without knowing more about your setup, it's hard to say. But it sounds distinctly like you don't have the authentication set up correctly for the website on your new server - causing whatever routine you have to fill in the username to not get anything back.

The error is clearly because "username" is an empty string. This is most likely because you're users are logging into your web-site anonymously. Please ensure that anonymous access is disabled in IIS.
However, it would be helpful if you can show the code which calls GetUserProfileFromAD.

Seems to me that the variable username is not being populated, if you say that you moved it to IIS try to check again for the security options, probable Windows Authentication is not configured yet.

Related

SignalR WinAuth does not Work

I have a problem in SignalR connection with Win Auth. When I enable anonymous in IIS Authorize settings, it works but sometimes it gives HTTP 403 Forbidden error. After I researched, I found that I need to disable Anonymous Connections. But when disable and enable the windowsAuth in IIS then there is always HTTP 401.2 UnAuthorized error. How I can connect with WinAuth? For my project I need to use WinAuth.
Not1 : I am using Silverlight 5.
Not2 : I have already tried possible solutions on StackOverflow but none of them worked.
So why cant I use WinAuth? It is enabled everywhere in config files, in IIS settings as well as in my web.config.
I spent 2 days but still I could not find a solution. If you need more information just write a comment. I am not sure what else information I can share. I dont want to put here lots of unnecessary texts.
EDIT:
When I use this code, i.e if I enter the username and password explicitly then it works. Internet Explorer first uses Anonymous Authentication and then it fails then it uses NetworkCredentials directly. This is the code
hubConnection = new HubConnection("URL");
hub = hubConnection.CreateHubProxy("HUBNAME");
hubConnection.Credentials = new System.Net.NetworkCredential("ID", "PASSWORD");
(The ones with capital letters are specific to my app.)
So how can I get Windows Credentials for my Silverlight App? DefaultCredentials does not work for silverlight.
Have you added authorization to your hub?
[Authorize(Roles = "Admin")]
public class AdminAuthHub : Hub
{
}

Connection string "DefaultConnection" was not found when using ASP.NET Default Membership with EF 5 Code First

I have created my application domain model using EF 5 Code First. I am then attempting to hook that with the ASP.NET Default Membership provider by running aspnet_reqsql.exe utility to generate the membership tables in my database.
This seems to be working fine, because when I check the database in SQL Management Studio, all the membership tables are there, along with my Code First tables.
Now then, we I run my application, all seems good, it loads up and I can browse the pages. However, as soon as I browse something that requires membership (e.g. Login page) the application breaks. I get the Yellow Screen of Death with the following message:
Server Error in '/' Application.
Connection string "DefaultConnection" was not found.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Connection string "DefaultConnection" was not found.
Source File: c:\Users\XXX\Documents\Visual Studio 2012\Projects\YourApp\YourApp\Filters\InitializeSimpleMembershipAttribute.cs Line: 41
There is this thread by a User that faced a similar problem, however his solution is already implemented by me, the fact that I have to comment out the already existing connection string in web.config. I've done that, but still no success.
What am I doing wrong?
Where you call InitializeSimpleMembershipAttribute, if you still have "DefaultConnection" as the first parameter, then you need to change this to be the name of the connection you want it to use.
I managed to sort it out all thanks to Richard. Here is what I did:
I opened up my AccountController, in there on top of the class, you'll see this (if using ASP.NET MVC4):
[Authorize]
[InitializeSimpleMembership]
public class AccountController : Controller
{
// all code for controller here.
}
I then Right-Clicked on [InitializeSimpleMembership] and clicked Go To Definition.
Once there, if you scroll to the bottom, you'll see something like this:
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
Change DefaultConnection attribute to whatever you've named your EF Code First Context, and you're good to go.
Thanks Richard.

ASP.NET where does throw new exception error get displayed

Code snippet..
if (regionalApprover == null)
{
throw new Exception(string.Format("The regional approver for {0} could not be found", companyData["Country"]));
}
How does the user actually see this error ?
The result of an unhandled exception depends on a variety of factors, including
where the web request is coming from,
the settings of the <customErrors> Element in your web.config and
the contents of Application_Error in your global.asax codebehind file.
In the default configuration, IIS will log the error into the Windows event log. In addition, it is shown in the browser by ASP.NET if the web request comes from localhost.
If you're trying to display an error message on the page (that the user is supposed to see), don't use Exceptions.
It's a much better idea to add an errors section to the page that you can add the messages to before showing the page to the user.

log4net permission issue to write to application event log when the user is not in admin group in Windows 2008 R2 and IIS 7

I am having log4net permission issue from ASP.Net 4.0 web application to write to application event log, when the user is not in administrator group in Windows 2008 R2 and IIS 7. We are using NT authentication and impersonation. Once I assign the user to admin group it works fine.
I tried with many permission settings like giving Authenticated Users full permission to Eventlog in registry etc. and none of them work. If any one can help that will be great.
When I had a similar issue with logging to eventlog from a .net 1.1 app on Windows 2003 server I did CustomSD entry as below link and it worked
http://mossipqueen.wordpress.com/2008/08/04/cannot-open-log-for-source-you-may-not-have-write-access/
The error I get is below from log4net internal log.
log4net:ERROR [EventLogAppender] Unable to write to event log [Application] using source [*******]
System.InvalidOperationException: Cannot open log for source '*******'. You may not have write access. ---> System.ComponentModel.Win32Exception: Access is denied
--- End of inner exception stack trace ---
at System.Diagnostics.EventLogInternal.OpenForWrite(String currentMachineName)
at System.Diagnostics.EventLogInternal.InternalWriteEvent(UInt32 eventID, UInt16 category, EventLogEntryType type, String[] strings, Byte[] rawData, String currentMachineName)
at System.Diagnostics.EventLogInternal.WriteEntry(String message, EventLogEntryType type, Int32 eventID, Int16 category, Byte[] rawData)
at System.Diagnostics.EventLog.WriteEntry(String source, String message, EventLogEntryType type, Int32 eventID, Int16 category, Byte[] rawData)
at log4net.Appender.EventLogAppender.Append(LoggingEvent loggingEvent)
Maybe I'm missing something here but it looks like a simple permissions issue for that user. By default they don't have access to write to the application log file. I know you played around with the permissions but I'm not sure exactly what permissions you assigned.
Here is a Microsoft article on doing exactly what you want to do to overcome the error you are seeing:
http://support.microsoft.com/kb/2028427
If you follow this, you should solve your issue. I hope this helps.

File permissions with FileSystemObject - CScript.exe says one thing, Classic ASP says another

I have a classic ASP page - written in JScript - that's using Scripting.FileSystemObject to save files to a network share - and it's not working. ("Permission denied")
The ASP page is running under IIS using Windows authentication, with impersonation enabled.
If I run the following block of code locally via CScript.exe:
var objNet = new ActiveXObject("WScript.Network");
WScript.Echo(objNet.ComputerName);
WScript.Echo(objNet.UserName);
WScript.Echo(objNet.UserDomain);
var fso = new ActiveXObject("Scripting.FileSystemObject");
var path = "\\\\myserver\\my_share\\some_path";
if (fso.FolderExists(path)) {
WScript.Echo("Yes");
} else {
WScript.Echo("No");
}
I get the (expected) output:
MY_COMPUTER
dylan.beattie
MYDOMAIN
Yes
If I run the same code as part of a .ASP page, substituting Response.Write for WScript.Echo I get this output:
MY_COMPUTER
dylan.beattie
MYDOMAIN
No
Now - my understanding is that the WScript.Network object will retrieve the current security credentials of the thread that's actually running the code. If this is correct - then why is the same user, on the same domain, getting different results from CScript.exe vs ASP? If my ASP code is running as dylan.beattie, then why can't I see the network share? And if it's not running as dylan.beattie, why does WScript.Network think it is?
Your problem is clear. In the current implementation you have only impersonation of users and no delegation. I don't want to repeat information already written by Stephen Martin. I only want to add at least three solutions. The classical way of delegation which Stephen Martin suggests is only one way. You can read some more ways here: http://msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_delegation. I see three practical ways of you solving your problem:
Convert the impersonation token of the user to a token with delegation level of impersonation or to a new primary token. You can do this with respect of DuplicateToken or DuplicateTokenEx.
Use S4U2Self (see http://msdn.microsoft.com/en-us/magazine/cc188757.aspx and http://msdn.microsoft.com/en-us/library/ms998355.aspx) to receive a new token from the old one with respect of one simple .NET statement WindowsIdentity wi = new WindowsIdentity(identity);
You can access another server with respect of one fixed account. It can be a computer account on an account of the application pool of the IIS. It can be another fixed defined account which one will only use for access to the file system.
It is important to know which version of Windows Server you have on the server where IIS is running and which Domain Function Level you have in Active Directory for your Domain (you see this in "Active Directory Domain and Trusts" tool if you select your domain and choose "Raise Domain Functional Level"). It is also interesting to know under which account the application pool of the IIS runs.
The first and the third way will always work. The third way can be bad for your environment and for the current permission in the file system. The second one is very elegant. It allows control of which servers (file server) are accessed from IIS. This way has some restrictions and it needs some work to be done in Active Directory.
Because you use classic ASP, a small scriptable software component must be created to support your implementation.
Which way do you prefer?
UPDATED based on the question from comment: Because you use classic ASP you can not use a Win32 API directly, but you can write a small COM component in VB6 or in .NET which use APIs which you need. As an example you can use code from http://support.microsoft.com/kb/248187/en. But you should do some other things inside. So I explain now which Win32 API can help you to do everything what you need with tokens and impersonation.
First of all a small explanation about impersonation. Everything works very easy. There are always one primary token under which the process runs. To any thread another token (thread token) can be assigned. To do this one needs to have a token of a user hUserToken and call API ImpersonateLoggedOnUser(hUserToken);.
To go back to the original process token (for the current thread only) you can call RevertToSelf() function. The token of user will be received and already impersonated for you by IIS, because you so configured your Web Site. To go back to the original process token you should implement calling of the function RevertToSelf() in your custom COM component. Probably, if you need to do nothing more in the ASP page, it will be enough, but I recommend you be more careful and save current users token in a variable before operation with files. Then you make all operations with file system and at the end reassign users token back to the current thread. You can assign an impersonation token to a thread with respect of SetThreadToken(NULL,hUserToken);. To give (save) current thread token (user token in your case) you can use OpenThreadToken API. It must work.
UPDATED 2: Probably the usage of RevertToSelf() function at the end of one ASP page would be already OK for you. The corresponding C# code can be so:
Create a new Project in C# of the type "Class Library" with the name LoginAdmin. Paste the following code inside
using System;
using System.Runtime.InteropServices;
namespace LoginAdmin {
[InterfaceTypeAttribute (ComInterfaceType.InterfaceIsDual)]
public interface IUserImpersonate {
[DispId(1)]
bool RevertToSelf ();
}
internal static class NativeMethods {
[DllImport ("advapi32.dll", SetLastError = true)]
internal static extern bool RevertToSelf ();
}
[ClassInterface (ClassInterfaceType.AutoDual)]
public class UserImpersonate : IUserImpersonate {
public UserImpersonate () { }
public bool RevertToSelf () {
return NativeMethods.RevertToSelf();
}
}
}
Check in project properties in "Build" part "Register for COM interop". In "Signing" part of the project check Sign the assembly and in "Choose a strong name key file" choose <New...>, then type any filename and password (or check off "protect my key..."). At the end you should modify a line from AssemblyInfo.cs in Properties part of the project:
[assembly: ComVisible (true)]
After compiling this project you get two files, LoginAdmin.dll and LoginAdmin.tlb. The DLL is already registered on the current computer. To register if on the other computer use RegAsm.exe.
To test this COM DLL on a ASP page you can do following
<%# Language="javascript" %>
<html><body>
<% var objNet = Server.CreateObject("WScript.Network");
Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");
var objLoginAdmin = Server.CreateObject("LoginAdmin.UserImpersonate");
var isOK = objLoginAdmin.RevertToSelf();
if (isOK)
Response.Write("RevertToSelf return true<br/>");
else
Response.Write("RevertToSelf return false<br/>");
Response.Write("One more time after RevertToSelf()<br/>");
Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");
var fso = Server.CreateObject("Scripting.FileSystemObject");
var path = "\\\\mk01\\C\\Oleg";
if (fso.FolderExists(path)) {
Response.Write("Yes");
} else {
Response.Write("No");
}%>
</body></html>
If the account used to run the IIS application pool has access to the corresponding network share, the output will be look like following
Current user: Oleg
Current user's domain: WORKGROUP
RevertToSelf return true
One more time after RevertToSelf()
Current user: DefaultAppPool
Current user's domain: WORKGROUP
Yes
Under impersonation you can only access securable resources on the local computer you cannot access anything over the network.
On Windows when you are running as an impersonated user you are running under what is called a Network token. This token has the user's credentials for local computer access but has no credentials for remote access. So when you access the network share you are actually accessing it as the Anonymous user.
When you are running a process on your desktop (like CScript.exe) then you are running under an Interactive User token. This token has full credentials for both local and remote access, so you are able to access the network share.
In order to access remote resources while impersonating a Windows user you must use Delegation rather then Impersonation. This will involve some changes to your Active directory to allow delegation for the computer and/or the users in your domain. This can be a security risk so it should be reviewed carefully.

Resources