Get domain whatever local or webserver - asp.net

I wrote an ASP.NET web application. My application created a request with returning URL other e-commerce server. I want to get this.
http://www.stackoverflow.com/question/ask --> http://www.stackoverflow.com
http://localhost/stackoverflow/question/ask --> http://localhost/stackoverflow
I used Request.Url.AbsoluteUri. But it's not OK for typing address by user.
How can this be done?

Look at the server variables collection. That is the source of this raw data that the HttpApplication gets from IIS.
I think the specific string you are looking for can be found with by "http://" + HttpContext.Current.Request.ServerVariables["SERVER_NAME"]
EDIT
Looking at your question again, this won't work for the "http://localhost/stackoverflow". This is because it doesn't follow the same convention. If you are using the convention that the public site is http://www.domainname.com/ and your development site is http://localhost/domainname, then you could write a function that gets the site name like
public static string GetDomainUrl(){
var servername = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
bool isLocalHost = serverName.ToLowerInvariant().Contains("localhost);
if(isLocalHost){
var domain = serverName.Split(new Char[]{'/'})[1];
return string.Format(#"http://localhost/{0}", domain);
}
return string.Format(#"http://{0}", serverName);
}
Note: I wrote this in the SO textbox, so check it.

Related

Incomplete URL returned from application

I am creating an application in VS2013, using VB and webforms. I came to discover that the support for webforms is quite reduced, everybody seems to be going the MVC way. Anyway the issue I am having is request URL misses out the application name in the URL. As an example what what my problem is on my development machine it returns the complete URL but, on the test server where I created it as an application on IIS it misses out the application name, this make the link incomplete.
It returns
http://tsv/Account/Forgot.aspx
instead of
http://tsv/itstock/Account/Forgot.aspx
tsv is the name for my local test server
How can i make it include itstock to make my URL complete
The code that gives the error is found in the IdentityModels.vb
Public Shared Function GetResetPasswordRedirectUrl(code As String, request As HttpRequest) As String
Dim absoluteUri = "/Account/ResetPassword?" + CodeKey + "=" + HttpUtility.UrlEncode(code)
Return New Uri(request.Url, absoluteUri).AbsoluteUri.ToString()
End Function
NB: I am using ASPNET Identity.
Have you thought about prefixing the string? or is this a dynamic url? Try the below:
Public Shared Function GetResetPasswordRedirectUrl(code As String, request As HttpRequest) As String
Dim absoluteUri = "/itstock/Account/ResetPassword?" + CodeKey + "=" + HttpUtility.UrlEncode(code)
Return New Uri(request.Url, absoluteUri).AbsoluteUri.ToString()
End Function

ASP.NET Routing - GetRouteData does not work if path exists

I have a HttpModule which intercepts all requests and loads data from the database based on routing rules. However, I run into one problem all the time; GetRouteData only works if the path does not exist:
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
Assuming a request comes in for the url http://localhost/contact, I get the correct routing data relating to that url if that path does not exist in the file system. The problem appears when I want to customize the page at that url which I do by creating an aspx page in the path ~/contact/default.aspx. Once I do that, GetRouteData return null.
I have even tried creating a new HttpContext object, but I still can not retrieve route data if the page exists.
Has anyone ever run into this problem? Is there a solution/workaround?
All help will be greatly appreciated.
Set RouteCollection.RouteExistingFiles to true.
public static void RegisterRoutes(RouteCollection routes)
{
// Cause paths to be routed even if they exists physically
routes.RouteExistingFiles = true;
// Map routes
routes.MapPageRoute("...", "...", "...");
}
Beware though. IIS7 behaves a little differently than the server used when debugging within Visual Studio. I got bit by this when I deployed my application to the web. Check out this feedback I submitted to Microsoft Connection.

How to build an absolute URL for the host currently in use in an ASP.NET app

I am currently in a dev only phase of development, and am using the VS built-in web server, configured for a fixed port number. I am using the following code, in my MembershipService class, to build an email body with a confirmation link, but obviously this must change when I deploy to our prod host.
var url = string.Format("http://localhost:59927/Account/CompleteRegistration/{0}", newMember.PendingReplyId);
How can I build this URL to always reflect the host that the code is running on, e.g. when deployed to prod the URL should be http://our-live-domain.com/Account/..etc.
MORE INFO: This URL will is included in an email to a new user busy registering an account, so I cannot use a relative URL.
Have a setting for this in your web.config
Like this:
<appSettings>
<add key="BaseURL" value="http://localhost:59927/"/>
</appSettings>
Access the value from the code. If you store multiple values in the appSettings and use them all over your project, I'd avise to use a wrapper class.
public class AppSettingsWrapper
{
public static String BaseURL
{
get { return System.Configuration.ConfigurationManager.AppSettings["BaseURL"].ToString(); }
}
// you can also insert other values here, that need to be cast into a specific datatype
public static int DefaultPageID
{
get { return int.Parse(System.Configuration.ConfigurationManager.AppSettings["DefaultPageID"].ToString()); }
}
}
You can assemble your string like this:
String url = string.Format("{0}{1}", AppSettingsWrapper.BaseURL, ResolveUrl(String.Format("~/Account/CompleteRegistration/{0}", newMember.PendingReplyId)));
Upon deployment, you need to replace the settings from the appSettings section. You can do this by using web config transforms. Have a look at this article http://www.tomot.de/en-us/article/5/asp.net/how-to-use-web.config-transforms-to-replace-appsettings-and-connectionstrings, which shows you how to this. You would create solution configurations for your testserver and your production server
use appSettings section in web.conf it will allow you to configure setting for production server.
and use ConfigurationManager class for acces to appSetting section.
While you can always set the host name and port as a setting which can then be read at run time (Very useful if the machine you have has multiple host headers, which might be in the case of load balancing). You can work out the Url from the following components :
Request["SCRIPT_NAME"] eg "/default.aspx"
Request["SERVER_NAME"] eg "localhost"
Request["SERVER_PORT"] eg "80"
Hope that this helps.
Jonathan
new Uri(
Request.Url, // base URI from current context
"/Account/CompleteRegistration/1234" // address relative to the base URI, use / if needed
).ToString();
This results in http://your.server/Account/CompleteRegistration/1234 .
It works great for relative links, even if our current location is not root:
new Uri(
Request.Url, // we are at http://server/app/subfolder/page.aspx?q=1
"page2.aspx"
).ToString(); //produces http://server/app/subfolder/page2.aspx
BTW, since it's of System.Uri type (unlike Request.RawUrl which is a relative path string), it has tons of useful properties, but typically you will just use .ToString().
Although you can't use ~ (tilde) paths directly, it's very simple to resolve them, and you should do it when in doubt:
new Uri(
Request.Url,
Page.ResolveUrl("~/folder/test") // use this! tilde is your friend!!!
).ToString(); // this will always point to our app even if it's in a virtual folder instead of root

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.

Create dedicated URL for each user (ASP .net)

I would like to allow my users to have their own dedicated URL, for example if my URL is www.XYZ.com, my users will have www.NAME.XYZ.com OR www.XYZ.com/NAME.
At the moment you can see their page by going to www.XYZcom/Member.aspx?userID="012345"
Now I would like to somehow map the URL to the currect system.
I have no idea whatwhat I need to do, I have seem many websites that have done this, so I hope that it would be possible for me to do the same in ASP .net.
Thank you in Advance.
Cheers
If your domain name DNS record is pointing to the IP address of the site, you should be able to access the site using anything.XYZ.com.
When you create a users account, you need to asign them a unique subdomain name and then detect this when users get to the site using their domain name (see the code below)
/// <summary>
/// Gets the Current SubDomain
/// </summary>
/// <returns></returns>
public static string GetSubDomain()
{
string subDomain = String.Empty;
if (HttpContext.Current.Request.Url.HostNameType == UriHostNameType.Dns)
{
subDomain = Regex.Replace(HttpContext.Current.Request.Url.Host, "((.*)(\\..*){2})|(.*)", "$2");
}
if (subDomain.Length == 0)
{
subDomain = "www";
}
return subDomain;
}
If you need to do this with IIS and ASP.NET i think this method will work:
Use a DNS-host that will allow you do register wildcard-domains. That way you can register ****.xyz.com*** to point to your server.
Now comes the part you may not like; for this to work on IIS you will need to set up your site as "default web site". That way, all requests will come to your site, even if the subdomain is not in the list of headers for that site. This will not work if your site is hosted on a shared webhost.
Use Marks method to detect what domain the user has typed in.
HI,
You can use URL Rewriting in your application. Using this feature simply you can redirect URLs like : www.XYZ.com/012345 to the page: www.XYZ.com/Member.aspx?userID="012345". You can download URL Rewriter sample from microsoft website. after you add URLRewriter.dll reference to your website. After you add the following lines to your web.config file in your website:
<RewriterConfig>
<Rules>
<RewriterRule>
<LookFor>~/([a-z]+)-([a-z]+)\.html</LookFor>
<SendTo>~/Contact.aspx?FirstName=$1&LastName=$2</SendTo>
</RewriterRule>
</Rules>
</RewriterConfig>
The above code redirects(using URLRewriter library) URLs like www.mydomain.com/name-family.html to www.mydomain.com/Contact.aspx?FirstName=name&LastName=family you can change this to suite your needs. Content of LookFor tag are some regular expression for my case, you should write your own regular expression.
You can view the article and download the source code here at MSDN.

Resources