Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do I call an MVC Action via a WebRequest and validate the request through Active Directory?
    primarykey
    data
    text
    <p>I know the title is a mouthful. I've got most things in place already. I just need confirmation on if I can do what I'm attempting.</p> <p>I'm using ASP.NET MVC 3. I have one application that has controller that I use like a web service. There is a single method on the controller and it returns a string, which is json. This method authenticates the user against active directory. </p> <p>The application that performs a WebRequest to the above one is also an MVC application. This application (in order to query AD without a specific user name and password) is using impersonation in the web.config. The application impersonates an account that has permission to query AD; however, the information of the user on the page (such as what groups they're in) is what I validate against.</p> <p>In short (and I don't entirely understand this part), the impersonation is strictly so ASP.NET can query Active Directory. Users loading the page are still seen as themselves when I query active directory for their information.</p> <p>The AD code looks like the following (this code works):</p> <pre><code> public static ADUserInfo GetUserInfo(IPrincipal User) { StringBuilder userAdInfo = new StringBuilder(); ADUserInfo userInfo = new ADUserInfo(); String domain = ConfigurationManager.AppSettings["ADdomain"]; try { using (var context = new PrincipalContext(ContextType.Domain, domain)) { if (User == null) userAdInfo.AppendLine("User is null."); else if (User.Identity == null) userAdInfo.AppendLine(" User is not null. User.Identitiy is."); else userAdInfo.AppendLine(" Neither User nor User.Identity is null. " + User.Identity.Name); using (var user = UserPrincipal.FindByIdentity(context, User.Identity.Name)) { userInfo.FullName = user.Name; userInfo.Email = user.EmailAddress; userInfo.AssociateId = user.EmployeeId; userInfo.DomainName = User.Identity.Name; userInfo.SamAccountName = user.SamAccountName; userInfo.DistinguishedUserName = user.DistinguishedName; } } } catch (Exception e) { LogUtil.WriteException(e); } return userInfo; } </code></pre> <p>The IIS site for this application does not allow anonymous access. </p> <p>The service method that uses AD information works fine. The issue seems to be passing credentials through a WebRequest to call this method and get JSON returned.</p> <p>My WebRequest code to call the action looks like: </p> <pre><code> public class WebRequestUtil { public static StreamReader GetWebRequestStream( string url, string contentType, bool useDefaultCredentials) { var request = WebRequest.Create(url); request.ContentType = contentType; request.ImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation; //request.UseDefaultCredentials = useDefaultCredentials; //ICredentials ic = new NetworkCredential(); //request.Credentials = var response = (HttpWebResponse)request.GetResponse(); return new StreamReader(response.GetResponseStream()); } } </code></pre> <p>I'm playing with the ImpersonationLevel...hasn't worked yet....</p> <p>The MVC 3 action being called via the WebRequest looks something like:</p> <pre><code>public class ProxyServiceController : Controller { public ProxyServiceController() { } public string CheckForProxy(string applicationName, string associateId) { RequestResultDetails requestDetails = new RequestResultDetails(); string json = string.Empty; //This correctly gets the Active directory information for the user //and fills out a custom ADUserInfo object. **ADUserInfo adUserInfo = ADService.GetUserInfo(this.User);** try { if (!ADService.DoesUrlDataMatchAD( adUserInfo, associateId) ) { throw new Exception(StaticText.UserDataMismatch); } resultList = //query db for data given the associateId if (resultList.ListIsNotNullOrEmpty()) { requestDetails.RelationshipExists = true; } else { requestDetails.RelationshipExists = false; } requestDetails.Details = resultList; } catch (Exception e) { LogUtil.WriteException(e); requestDetails.ErrorProcessingRequest = true; requestDetails.ErrorDetails = ErrorProcessing.GetFullExceptionDetails(e); } json = JsonConvert.SerializeObject(requestDetails); LogUtil.Write("json: " + json); return json; } } </code></pre> <p>So what happens is that, if I go to the MVC 3 Controller/Action directly in the browser via a url like: </p> <p>http://:90/MyApp/Service.aspx/CheckForProxy/Reporting/555</p> <p>I can see the correct JSON on the page. However, if I make a WebRequest call to this same URL from another application that is on the same server, Active Directory doesn't seem like it can be polled. This is definitely some kind of permissions issue, but I'm not sure how to resolve it so the service sees the user's Active Directory information.</p> <p>The problem here is that the credentials being passed to the service are those of the account the calling application is impersonating. What do I change to get the service mvc application to see the user performing the WebRequest (well the app makes the call, but the user loads the app) and not the account that application is impersonating?</p> <p>I'm open to other thoughts or methods for handling this communication.</p> <p><strong>SOLUTION PER jmrnet COMMENT</strong></p> <p>Wow, that comment was spot on. I have no idea what kind of web magic is being worked, but I revised my web request method to: </p> <pre><code> public static StreamReader GetWebRequestStream( string url, string contentType, bool useDefaultCredentials, IPrincipal user) { var impersonationContext = ((WindowsIdentity)user.Identity).Impersonate(); var request = WebRequest.Create(url); try { request.ContentType = contentType; request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested; request.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials; var response = (HttpWebResponse)request.GetResponse(); return new StreamReader(response.GetResponseStream()); } catch (Exception e) { impersonationContext.Undo(); throw e; } } </code></pre> <p>And this accurately passes along the principal user's identity.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload