I'm trying to deny access all IPs to the /Admin with a couple exceptions. The Orchard CMS 1.8.1 app is running on IIS 8.5.
I'm experimenting with IP Restrictions rule, but it seems to me that is not the right tool, as I could only set access rights on folders not individual pages.
(Managed to deny access to TheAdmin theme.)
I've tried the below snippet with no luck:
<location path="Admin">
<system.webServer>
<security>
<ipSecurity allowUnlisted="false">
</ipSecurity>
</security>
</system.webServer>
</location>
http://www.iis.net/configreference/system.webserver/security/ipsecurity
Also tried to create a Virtual Directory for Users/Account/LogOn for the root directory and set its access rights, but that didn't work either.
I was thinking to set URL Rewrites for the /Admin, but not really sure about how to start or what logic should I follow.
Any suggestions?
If I understand your motives correctly, I think it would be best to write a filter module, that will give you full control over what will happen under what condition.
[OrchardFeature("FeatureDefinedInModuleTxtManifest")]
public class AdminAccessFilter : FilterProvider, IAuthorizationFilter
{
private readonly IAuthorizer _authorizer;
public AdminAccessFilter(IAuthorizer authorizer)
{
_authorizer = authorizer;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void OnAuthorization(AuthorizationContext filterContext)
{
if (!AdminFilter.IsApplied(filterContext.RequestContext) || !_authorizer.Authorize(StandardPermissions.AccessAdminPanel))
{
// Not an admin area or no permission already, do nothing
return;
}
var request = filterContext.HttpContext.Request;
var userIp =
request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? // Proxy
request.UserHostAddress;
if (userIp != "100.100.100.100") // Your logic for denying access
{
Logger.Fatal("Unauthorized admin access detected from {0}", userIp);
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
Related
I am creating a new site for one of my client. Their old site was developed using wordpress and hence it has 100s of broken urls like below:
http://www.example.com/best-gym-in-town/
http://www.example.com/video-gallery/
http://www.example.com/fun-stuff/
http://www.example.com/are-you-a-diabetes-patient/
http://www.example.com/john-in-media/
http://www.example.com/photo-gallery/
http://www.example.com/nutrition-program-that-suits-your-lifestyl/
http://www.example.com/our-range-of-fitness-tests/
http://www.example.com/corporate-group-workshops/some-article/another-article
I am developing the new site in asp.net mvc 5. I want to write an httpRedirect rule in web.config that can redirect any of the above url to home or any specific page.
so far this is how I am thinking of the solution
<location path="about-me">
<system.webServer>
<httpRedirect enabled="true" destination="/home"
httpResponseStatus="Permanent" />
</system.webServer>
</location>
But I have to write 100s of such entries in web.config. I am looking for a better and efficient alternative
In Global.asax, hook into the Application_BeginRequest method and redirect to the homepage from there
protected void Application_BeginRequest(object sender, EventArgs e)
{
try
{
if (HttpContext.Current.Request.Url.AbsolutePath.Contains("-")){
HttpContext.Current.Response.RedirectPermanent("/");
}
}
catch (ThreadAbortException){}
}
Optionally, you could hook into the Application_Error method inside Global.asax instead and detect 404's from there
protected void Application_Error(Object sender, EventArgs e)
{
var exception = Server.GetLastError();
if (exception != null && exception == 404)
{
try
{
Response.Clear();
Server.ClearError();
Response.Redirect("/");
}
}
catch (ThreadAbortException){}
}
}
Using glimpse I'm able to access the session information accept when using the RuntimeEvent.ExecuteResource. Without this the axd file is exposed and I'd rather have it disabled unless specific users are logged in. The session will be null in both examples below. Also I've tried having the class implement IRequiresSessionState but that didn't help either.
namespace Glimpse
{
public class GlimpseSecurityPolicy:IRuntimePolicy
{
public RuntimePolicy Execute(IRuntimePolicyContext policyContext)
{
try
{
var name = HttpContext.Current.Session["username"];
var name2 = policyContext.GetHttpContext().Session["username"];
}
catch (Exception)
{
}
// You can perform a check like the one below to control Glimpse's permissions within your application.
// More information about RuntimePolicies can be found at http://getglimpse.com/Help/Custom-Runtime-Policy
// var httpContext = policyContext.GetHttpContext();
// if (!httpContext.User.IsInRole("Administrator"))
// {
// return RuntimePolicy.Off;
// }
return RuntimePolicy.On;
}
public RuntimeEvent ExecuteOn
{
// The RuntimeEvent.ExecuteResource is only needed in case you create a security policy
// Have a look at http://blog.getglimpse.com/2013/12/09/protect-glimpse-axd-with-your-custom-runtime-policy/ for more details
get { return RuntimeEvent.EndRequest | RuntimeEvent.ExecuteResource; }
}
}
}
The reason for this is that the Glimpse HttpHandler which processes the requests for Glimpse.axd does not implement the IRequireSessionState interface.
It is that HttpHandler that will eventually execute all IRuntimePolicy instances that have RuntimeEvent.ExecuteResource configured as part of the ExecuteOn property value.
I think the easiest solution for you is to create your own IHttpHandler that implements the IRequireSessionState interface and forwards all calls to the Glimpse HttpHandler as shown below.
public class SessionAwareGlimpseHttpHandler : IHttpHandler, IRequiresSessionState
{
private readonly HttpHandler _glimpseHttpHandler =
new Glimpse.AspNet.HttpHandler();
public void ProcessRequest(HttpContext context)
{
_glimpseHttpHandler.ProcessRequest(context);
}
public bool IsReusable
{
get { return _glimpseHttpHandler.IsReusable; }
}
}
Don't forget to update your web.config to use that handler instead of the original one:
...
<system.webServer>
...
<handlers>
<add name="Glimpse" path="glimpse.axd" verb="GET" type="YourNamespace.SessionAwareGlimpseHttpHandler, YourAssembly" preCondition="integratedMode" />
</handlers>
...
</system.webServer>
...
Once all this is in place, you should be able to access the Session inside your IRuntimePolicy.
I want to host a very simple razor page inside a self host SS app.
I need the / path to resolve to the default.cshtml - this works out of the box.
But i need to access the user auth session inside the view. To do this I am guessing I need a service to create the model for default.cshtml
Everything I have tried so far doesn't work and I can't create a DefaultRequest with route / as that isn't allowed.
Anyone got any clues as to what I need to do?
I have tried with fall back route but no luck:
[FallbackRoute("/{Path*}")]
public class Fallback
{
public string Path { get; set; }
}
public class DefaultService : Service
{
public DefaultService ()
{
}
public object Get(Fallback request){
return new HttpResult() // #6
{
View = "Rockstars" // #1
};
}
}
Your typed UserAuth session is directly accessible in your Razor Views base ViewPageBase with base.SessionAs, e.g:
#{
var session = base.SessionAs<CustomUserSession>();
}
You've also got access to your dynamic session bag with base.SessionBag as well as base.IsAuthenticated to determine if the user is authenticated or not.
Fallback Route
In order to invoke a Service to handle your default page you need to use a Fallback Route, e.g:
[FallbackRoute("/{Path*}")]
public class DefaultPage
{
public string Path { get; set; }
}
A Fallback Service can be used to handle every unmatched request including the root / page.
My Web Api when run locally (in Release mode) will return any errors in this format:
{
"Message": "An error has occurred.",
"ExceptionMessage": "No text specified",
"ExceptionType": "System.Exception",
"StackTrace": null
}
But after deployment/publish to an Azure VM, only this remains:
{
"Message": "An error has occurred."
}
API code:
try
{
var msg = ...
new MessageService().SaveMessage(msg)); // <-- does some checks; may throw.
return Ok();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
I'd like it to be more detailed on Azure, like the local result.
Can this be achieved, and if so, how?
I already (temporarily) removed <compilation xdt:Transform="RemoveAttributes(debug)" /> from the <system.web> part of Web.Release.config, and then re-deployed, but that made no difference.
Or am I using the wrong approach/pattern?
Obviously technical details should be limited, but right now we get no details at all.
You could try adding the following to your Global.asax:
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
Note: I wouldn't recommend that you keep this setting on in a production environment.
If instead you use
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Default;
then you can use the system.webServer error switch e.g.
<system.webServer>
<httpErrors errorMode="Detailed" existingResponse="PassThrough">
</httpErrors>
</system.webServer>
Note the existingResponse attribute to preserve the error message.
I had the same problem, the post is three years old, things have changed a little. If you setup a new Azure Mobile App with Visual Studio 2017 there is no longer a Global.asax.cs. I searched for hours, where to put this IncludeErrorDetailPolicy. It won't work without that setting.
You do it in your Startup.MobileApp.cs:
public partial class Startup
{
public static void ConfigureMobileApp(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
new MobileAppConfiguration()
.UseDefaultConfiguration()
.ApplyTo(config);
Don't forget, in your Web.config you also need to set:
<system.webServer>
<httpErrors errorMode="Detailed" existingResponse="PassThrough">
</httpErrors>
</system.webServer>
Don't use that for production environment!
For Web API 2, you can implement a custom IExceptionLogger that utilizes Azure Application Insights. Something like this:
using Microsoft.ApplicationInsights;
using System.Web.Http.ExceptionHandling;
namespace Your.Namespace.Here
{
public class TelemetryExceptionLogger : ExceptionLogger
{
private readonly TelemetryClient telemetryClient;
public TelemetryExceptionLogger(TelemetryClient telemetryClient)
{
this.telemetryClient = telemetryClient;
}
public override void Log(ExceptionLoggerContext context)
{
if (context != null && context.Exception != null)
{
telemetryClient.TrackException(context.Exception);
}
base.Log(context);
}
}
}
Then you need to register it with Web API:
using Microsoft.ApplicationInsights;
using System.Web.Http;
using System.Web.Http.ExceptionHandling;
using Your.Namespace.Here;
namespace Some.Other.Namespace.Or.The.Same
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// --- Normal Web API configuration here ---
config.Services.Add(typeof(IExceptionLogger), new TelemetryExceptionLogger(new TelemetryClient()));
}
}
}
For this to work, you will need to have set up Application Insight in Azure and for your VS project, but that is a story for another time :)
For more information, see Application Insights: Exception Telemetry
I have a scenario with the same error, and the problem was a copy&paste in the route header attribute of a method. I have the same route for two methods
[Route("test/Method1")]
public IHttpActionResult Method1(){...}
[Route("test/Method1")]
public IHttpActionResult Method2(){...}
Check the new methods and Routes added.
I have registered AppSettings within my AppHost as shown below:
container.Register<IAppSettings>(new AppSettings());
I have added following settings within my web.config file:
<appSettings>
<add key="baseaddress" value="http://example.com" />
<add key="credential" value="{Username:foo,Password:bar}" />
</appSettings>
That's my service:
public class ExampleService : Service
{
public IAppSettings Settings { get; set; }
public void Post(ExampleRequest request)
{
// NOT WORKING -> always NULL!
var credentials = Settings.Get<Credential>("credential", null);
// OK
var baseUrl = Settings.GetString("baseaddress");
// more code...
}
}
This is my Credential class:
public class Credential
{
public string Username { get; set; }
public string Password { get; set; }
}
The baseUrl is always set but the credentials variable is always NULL and I don't know why...
In the latest v4.0.31 of ServiceStack there's First Class support for AppSettings so you don't have to register it yourself as it's already registered for you:
container.Register<IAppSettings>(new AppSettings());
But I've tested this and it works as expected where it deserializes into a populated Credential instance with:
var credential = AppSettings.Get<Credential>("credential", null);
Are you sure you're using the exact key names? as your last sentence uses baseUrl and credentials but your appSettings says baseaddress and credential.
You would need something like this in your config <security mode="TransportWithMessageCredential"> to automatically add a security header to your post. Or you need to add and parse your own headers. You don't show your full web config or a sample call to your "Post" so I am running on some assumptions here.