Use Active Directory to populate Request.Credentials to access webservice - asp.net

Is there a way to detect the AD credentials of a user and use them to create a NetworkCredential object that can be used to query a webservice? An excerpt of my code is below, basically I'm querying a GIS database through a webservice and the webservice requires Windows AD authentication.
Currently this is a manual process and so we just hardcode our own AD credentials into the variables up top and it works fine but I'd like the page the detect someone's AD credentials and use them to create the NetworkCredential object so we can have our internal customers use the page as well.
Public Function getJSON(ByVal url As String) As String
Dim HTMLSource As String = ""
Dim Request As WebRequest = WebRequest.Create(url)
Request.Credentials = New NetworkCredential(username, password, domain)
Dim Response As WebResponse = Request.GetResponse
Dim SR As StreamReader
SR = New StreamReader(Response.GetResponseStream)
HTMLSource = SR.ReadToEnd
SR.Close()
Return HTMLSource
End Function

Let to user delegate his Kerberos credential to your server/service, extract that during authentication, impersonate and perform your request on behalf of the user.

Related

get html for current page in secure site

I am trying to extract the html of my current page. To do it is pretty simple
private string GetHtml()
{
WebClient myClient = new WebClient();
string myPageHTML = null;
byte[] requestHTML;
// Gets the url of the page
string currentPageUrl = Request.Url.ToString();
UTF8Encoding utf8 = new UTF8Encoding();
requestHTML = myClient.DownloadData(currentPageUrl);
myPageHTML = utf8.GetString(requestHTML);
Response.Write(myPageHTML);
return myPageHTML;
}
But my problem I am having is, if this page is behind a secure section, the WebClient is effectively unauthenticated, so the server will just return the "Login screen" instead.
Can I pass my cookie or my session to this WebClient?

After authentication,page redirects back to login page

I have a simple login page as below:
protected void btnLogIn_Click(object sender, EventArgs e)
{
FormsAuthentication.Initialize();
string CS = ConfigurationManager.ConnectionStrings["IS"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
con.Open();
SqlCommand cmd = new SqlCommand("Select Roles from tblRegisteredUsers where Email=#Email and Password=#Password",con);
cmd.Parameters.AddWithValue("#Email", txtEmail.Text);
cmd.Parameters.AddWithValue("#Password", txtPassword.Text);
SqlDataReader rdr = cmd.ExecuteReader();
if(rdr.Read())
{
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
txtEmail.Text,
DateTime.Now,
DateTime.Now.AddMinutes(30),
true,
rdr.GetString(0),
FormsAuthentication.FormsCookiePath);
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,hash);
if(ticket.IsPersistent) cookie.Expires=ticket.Expiration;
Response.Cookies.Add(cookie);
string returnUrl = Request.QueryString["returnUrl"];
if(returnUrl==null) returnUrl="/";
Response.Redirect(returnUrl);
}
else
{
lblMessage.Text = "Invalid Email/Password.Please try again.";
}
rdr.Close();
}
}
I have used folder level roles authentication with each folder having its own web.config file.I am sure that the user gets authenticated successfully because the see the username in loginName.This is definitely a redirection issue.What can i do to redirect the users to my Homepage after successful login?
Is anybody still helping me on this?
just a suggestion. you may redirect to homepage or if required then create a global variable and maintain the last visited page url in it. hope it helps
string returnUrl = Request.QueryString["returnUrl"];
I think your query string fetch null value thats why it statifises the IF condition and take the return URL as '/' so it redirects to current page.
Put a debug point near the highlighted portion and see what value you are getting for return url
Instead of
string returnUrl = Request.QueryString["returnUrl"];
if(returnUrl==null) returnUrl="/";
Response.Redirect(returnUrl);
just write
Response.Redirect(<"your url for the homepage">);
Eg
For MVC application it will be Response.Redirect("/home/index");
You will have to redirect to another page like this:
Response.Redirect("myhomepage.aspx");
you need to provide your page name with .aspx extension at the end unlike that in MVC where you needed to provide the URL.

getting an exception while using DirectoryServices object

I am using Active Directory to authenticate a user logging into an ASP.NET web site on a corporate intranet. I am getting an error of "handle is invalid" on the following line of code:
Dim entry As DirectoryEntry = New DirectoryEntry(path, domainAndUsername, Password)
Here is my code I am using to authenticate.
Dim entry As DirectoryEntry = New DirectoryEntry(path, domainAndUsername, Password)
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
How do I track down this exception? Visual Studio says it is a CryptographicException
Thanks
Assuming you are on .NET 3.5.... and thinking the code translates well to VB you could use built-in method.
public bool isValidUser(string password,string username,string domain)
{
var isValid = false;
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain))
{
isValid = pc.ValidateCredentials(username, password);
}
return isValid;
}
I know it does not answer question as such, but could avoid getting the exception in the first place

Forward a QueryString to another Server

I have a webapp that accepts a messageid and status as a QueryString from an external server. I am migrating the webapp to a new server, but I need the new server to forward the QueryString to the old server in case the old server is still waiting for updates, and until I can get my clients migrated over.
The External website calls my webapp with ?MSGID=12345678&RESPONSE=0
eg:
http://dlrnotify.newserver.com/GetResponse.aspx?MSGID=12345678&RESPONSE=0
I need my code behind GetResponse.aspx to process the message locally, and then forward the request to the old server. eg, calling:
http://dlrnotify.oldserver.com/GetResponse.aspx?MSGID=12345678&RESPONSE=0
I don't really want to redirect the user to the old web server, just to pass the querystring on from my app.
I can get the QueryString by calling Response.QueryString.ToString() I just need to know how to post that to the old server without upsetting anything.
Sorry if this is a dumb question, I don't work with web apps very often and am obviously using the wrong search terms.
You can use HttpWebRequest and HttpWebResponse for this. Below is an example to use thses
Uri uri = new Uri("http://www.microsoft.com/default.aspx");
if(uri.Scheme = Uri.UriSchemeHttp)
{
HttpWebRequest request = HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
HttpWebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string tmp = reader.ReadToEnd();
response.Close();
Response.Write(tmp);
}
Sample Code on how to Post Data to remote Web Page using HttpWebRequest
Uri uri = new Uri("http://www.amazon.com/exec/obidos/search-handle-form/102-5194535-6807312");
string data = "field-keywords=ASP.NET 2.0";
if (uri.Scheme == Uri.UriSchemeHttp)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Post;
request.ContentLength = data.Length;
request.ContentType = "application/x-www-form-urlencoded";
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.Write(data);
writer.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string tmp = reader.ReadToEnd();
response.Close();
Response.Write(tmp);
}
After executing your code (process message) on the new server, manually generate a HttpWebRequest which should be to your old server with the same querystring as you already figured out to form.
I have a task which is same as your post. But there is a little more in that.
As we have two web applications, one in asp.net and other in PHP. In both we create user profiles. Now the task is to Create users in Asp.NET application and we need to save the same information in PHP application from Asp.Net app.
I am using the below code for that but it is not wroking, Can you please look at it and let me know what I am missing.
CookieContainer cookies = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(#"http://localhost/admin/config/popup_user_info_brand.php");
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.CookieContainer = cookies; // note this
request.Method = "POST";
string boundary = System.Guid.NewGuid().ToString();
string Username = "admin";
string Password = "admin";
if (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password))
{
request.Credentials = new NetworkCredential(Username, Password);
request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
StringBuilder sb = new StringBuilder();
sb.AppendLine("Content-Disposition: form-data; name=\"name\"");
sb.AppendLine("Singh");
sb.AppendLine("Content-Disposition: form-data; name=\"username\"");
sb.AppendLine("Singh123");
sb.AppendLine("Content-Disposition: form-data; name=\"email\"");
sb.AppendLine("a#b.com");
sb.AppendLine("Content-Disposition: form-data; name=\"password\"");
sb.AppendLine("P#ssword");
// This is sent to the Post
byte[] bytes = Encoding.UTF8.GetBytes(sb.ToString());
request.ContentLength = bytes.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Flush();
requestStream.Close();
using (WebResponse response = request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
HttpContext.Current.Response.Write(reader.ReadToEnd());
}
}
}
}
Note:- PHP web site is a 3rd party, we have no access on code.
Thanks,
Ginni.

How to store custom data in ASP.NET Membership Cookie

Can anyone give me an example (or point me in the right direction) on how to store custom data in an ASP.NET Membership cookie?
I need to add some custom properties like UserID and URLSlug to the cookie and be able to retrieve the information in the same way one would retrieve the Username.
Edit:
I used Code Poet's example and came up with the following.
When I set a breakpoint at Dim SerializedUser As String = SerializeUser(userData) the value of userData is right. It has all the properties I expect it to have.
The problem I'm now running into is that when I get to Dim userdata As String = authTicket.UserData (breakpoint), the value is "". I'd love to figure out what I'm doing wrong.
Here's the code.
Imports System
Imports System.Web
Imports System.Web.Security
Namespace Utilities.Authentication
Public NotInheritable Class CustomAuthentication
Private Sub New()
End Sub
Public Shared Function CreateAuthCookie(ByVal userName As String, ByVal userData As Domain.Models.UserSessionModel, ByVal persistent As Boolean) As HttpCookie
Dim issued As DateTime = DateTime.Now
''# formsAuth does not expose timeout!? have to hack around the
''# spoiled parts and keep moving..
Dim fooCookie As HttpCookie = FormsAuthentication.GetAuthCookie("foo", True)
Dim formsTimeout As Integer = Convert.ToInt32((fooCookie.Expires - DateTime.Now).TotalMinutes)
Dim expiration As DateTime = DateTime.Now.AddMinutes(formsTimeout)
Dim cookiePath As String = FormsAuthentication.FormsCookiePath
Dim SerializedUser As String = SerializeUser(userData)
Dim ticket = New FormsAuthenticationTicket(0, userName, issued, expiration, True, SerializedUser, cookiePath)
Return CreateAuthCookie(ticket, expiration, persistent)
End Function
Public Shared Function CreateAuthCookie(ByVal ticket As FormsAuthenticationTicket, ByVal expiration As DateTime, ByVal persistent As Boolean) As HttpCookie
Dim creamyFilling As String = FormsAuthentication.Encrypt(ticket)
Dim cookie = New HttpCookie(FormsAuthentication.FormsCookieName, creamyFilling) With { _
.Domain = FormsAuthentication.CookieDomain, _
.Path = FormsAuthentication.FormsCookiePath _
}
If persistent Then
cookie.Expires = expiration
End If
Return cookie
End Function
Public Shared Function RetrieveAuthUser() As Domain.Models.UserSessionModel
Dim cookieName As String = FormsAuthentication.FormsCookieName
Dim authCookie As HttpCookie = HttpContext.Current.Request.Cookies(cookieName)
Dim authTicket As FormsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value)
Dim userdata As String = authTicket.UserData
Dim usersessionmodel As New Domain.Models.UserSessionModel
usersessionmodel = DeserializeUser(userdata)
Return usersessionmodel
End Function
Private Shared Function SerializeUser(ByVal usersessionmodel As Domain.Models.UserSessionModel) As String
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Dim mem As New IO.MemoryStream
bf.Serialize(mem, usersessionmodel)
Return Convert.ToBase64String(mem.ToArray())
End Function
Private Shared Function DeserializeUser(ByVal serializedusersessionmodel As String) As Domain.Models.UserSessionModel
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Dim mem As New IO.MemoryStream(Convert.FromBase64String(serializedusersessionmodel))
Return DirectCast(bf.Deserialize(mem), Domain.Models.UserSessionModel)
End Function
End Class
End Namespace
Here's where I create all the magic. This method is in a "BaseController" class that inherits System.Web.Mvc.Controller
Protected Overrides Function CreateActionInvoker() As System.Web.Mvc.IActionInvoker
If User.Identity.IsAuthenticated Then ''# this if statement will eventually also check to make sure that the cookie actually exists.
Dim sessionuser As Domain.Models.UserSessionModel = New Domain.Models.UserSessionModel(OpenIdService.GetOpenId(HttpContext.User.Identity.Name).User)
HttpContext.Response.Cookies.Add(UrbanNow.Core.Utilities.Authentication.CustomAuthentication.CreateAuthCookie(HttpContext.User.Identity.Name, sessionuser, True))
End If
End Function
And here's how I try and retrieve the info.
Dim user As Domain.Models.UserSessionModel = CustomAuthentication.RetrieveAuthUser
First of all ASP.Net Membership providers don't write any cookies, Authentication cookies are written by FormsAuthentication.
And secondly, why interfere into authentication cookie at all. You can do this in a seperate cookie altogether. Here's how you can do that.
Writing the keys-values into cookie.
//create a cookie
HttpCookie myCookie = new HttpCookie("myCookie");
//Add key-values in the cookie
myCookie.Values.Add("UserId", "your-UserId");
myCookie.Values.Add("UrlSlug", "your-UrlSlug");
//set cookie expiry date-time, if required. Made it to last for next 12 hours.
myCookie.Expires = DateTime.Now.AddHours(12);
//Most important, write the cookie to client.
Response.Cookies.Add(myCookie);
Reading the keys-values from cookie.
//Assuming user comes back after several hours. several < 12.
//Read the cookie from Request.
HttpCookie myCookie = Request.Cookies["myCookie"];
if (myCookie == null)
{
//No cookie found or cookie expired.
//Handle the situation here, Redirect the user or simply return;
}
//ok - cookie is found.
//Gracefully check if the cookie has the key-value as expected.
if (!string.IsNullOrEmpty(myCookie.Values["UserId"]))
{
string UserId= myCookie.Values["UserId"].ToString();
//Yes UserId is found. Mission accomplished.
}
if (!string.IsNullOrEmpty(myCookie.Values["UrlSlug"]))
{
string UrlSlug = myCookie.Values["UrlSlug"].ToString();
//Yes key2 is found. Mission accomplished.
}
If at all you need to disturb the
authentication cookie, though not
advisable, This is how you may do it.
Writing the keys-values into cookie.
//create a cookie
HttpCookie myCookie = FormsAuthentication.GetAuthCookie("UserName", true);
//Add key-values in the cookie
myCookie.Values.Add("UserId", "your-UserId");
myCookie.Values.Add("UrlSlug", "your-UrlSlug");
//set cookie expiry date-time, if required. Made it to last for next 12 hours.
myCookie.Expires = DateTime.Now.AddHours(12);
//Most important, write the cookie to client.
Response.Cookies.Add(myCookie);
Reading the keys-values from cookie.
//Assuming user comes back after several hours. several < 12.
//Read the cookie from Request.
HttpCookie myCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (myCookie == null)
{
//No cookie found or cookie expired.
//Handle the situation here, Redirect the user or simply return;
}
//ok - cookie is found.
//Gracefully check if the cookie has the key-value as expected.
if (!string.IsNullOrEmpty(myCookie.Values["UserId"]))
{
string UserId= myCookie.Values["UserId"].ToString();
//Yes UserId is found. Mission accomplished.
}
if (!string.IsNullOrEmpty(myCookie.Values["UrlSlug"]))
{
string UrlSlug = myCookie.Values["UrlSlug"].ToString();
//Yes key2 is found. Mission accomplished.
}
Depending on the scenario, using a separate cookie might be a viable option, but in my opinion is sub optimal for several reasons including the simple fact that you have to manage multiple cookies as well as managing the lifetime of the cookie.
The most reliable strategy for incorporating custom information into your forms ticket is to leverage the userData field of the ticket. That is exactly what it is there for.
You can easily store custom data in the userData field of the ticket.
There are a few concerns to be aware of regarding the size of the data to be stored in the ticket that are explained here
And here is a small class that can help in the task of storing custom data in your forms ticket.

Resources