Kohana 3.3 force SSL in controller - ssl

I have a few controllers. HTTPS is redirected by the webserver (ligttpd) itself, but as a extra security-check I want PHP to redirect specific controllers to https.
Does Kohana contain a function to check if the url is running on SSL and to redirect it if needed?

Found out my own answer :)
Make a class called URL:
class URL extends Kohana_URL
{
public static function SSL()
{
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "") {
$redirect = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header("Location: $redirect");
}
}
}
Call it in your controller like this:
URL::ssl();
Please note: Using only above method is unsafe. You should redirect by server (Lighttpd/Nginx/Apache) too.

Related

Override routing in ASP.NET CORE 2.2 to implicitly route to an area if user have some permissions

I'm looking for an easy way to change routing behaviour a little and add extra area data into route data if the user has some sorts of permissions.
Let's say for regular user url site/shop/12 should route to ShopController
but for admin it should route to AdminArea/ShopController
Please, consider that this question isn't about HTTP redirect, it's about extending infrastructure on a framework level to allow extra functionality on Routing or controller invocation
You could use URL Rewriting Middleware to redirect the request for Admin user
1.Create a Redirect rule:
public class RewriteRules
{
public static void RedirectRequests(RewriteContext context)
{
//Your logic
var IsAdminRole = context.HttpContext.User.IsInRole("Admin");
if (IsAdminRole)
{
var request = context.HttpContext.Request;
string area = "AdminArea";
var path = request.Path.Value;
//Add your conditions of redirecting
if(path.Split("/")[1] != area)// If the url does not start with "/AdminArea"
{
context.HttpContext.Response.Redirect($"/{area}{ request.Path.Value }");
}
}
}
}
2.Use the middleware in Startup Configure method:
app.UseAuthentication();//before the Rewriter middleware
app.UseRewriter(new RewriteOptions()
.Add(RewriteRules.RedirectRequests)
);
Add logic to the controller method that handles site/shop/12 to check if the user is an admin, and if it is, redirect to to the proper admin area and controller.
var isAdmin = IsUserAnAdmin();
if (isAdmin) {
// This will redirect to the Index method defined in the ShopController
// in the area name AdminArea
return RedirectToAction("Index", "Shop", new { Area = "AdminArea" });
}
I think the best way is to set the correct URLs on the front-end and then validate the request on the end-point doing something like this:
[HttpGet]
[Route("v1.0/download/document")]
public IActionResult download_document(int id, string token)
{
try
{
if (token == null || isNotAdmin(token))
return Unauthorized();
That way your end-points are protected and you avoid redirections. Plus, in my opinion everything makes a lot more sense on the front-end

In Vertx I need to redirect all HTTP requests to the same URL but for HTTPS

I have written a Vertx-web handler in Koltin that redirects any request I receive that is HTTP to HTTPS, and I'm using context.request().isSSL to determine if the request is not SSL, and this worked fine until I put my code behind a load balancer. If the load balancer talks to my Vertx-web server on HTTPS then it thinks all user requests are HTTPS even if they are not. And if I change the load balancer to talk to Vertx-web on HTTP then every request is redirected endlessly even if already the user is using HTTPS.
Then I also see another problem, that the redirect using context.request().absoluteURI() goes to the private address instead of the publically available address that the user is actually talking to.
Is there a handler in Vertx-web that I'm missing that does this, or some idiomatic way to solve this? Should I just do this from JavaScript since it sees the real user address instead of trying a server-side redirect?
I'm coding in Kotlin, so any examples for that language are great!
Note: this question is intentionally written and answered by the author (Self-Answered Questions), so that solutions for interesting problems are shared in SO.
First, it is best if your proxy or load balancer can do this check and redirect for you since it has knowledge of the public URL and is a simpler process at that first contact with the user. But, you can also do it server-side with a little more complexity.
The flag you are checking, context.request().isSSL is only valid for the incoming connection to Vertx-web and does not consider the end-user's connect to your proxy or load balancer. You need to use the X-Forwarded-Proto header (and sometimes X-Forwarded-Scheme) and check the actual protocol of the user. And only if that header is not present you can use context.request().isSSL
You also need to externalize your own URL to be able to redirect on the server side to something that the browser can use to find you, your public URL.
First, there is a Kotlin function in this Stack Overflow answer for RoutingContext.externalizeUrl(), you will need it here:
I have a Vertx request and I need to calculate an externally visible (public) URL
Then knowing your public URL you can use the following handler which has default values for the intended public HTTPS port (default 443 will vanish from URL), which form of redirect (i.e. 302), and on any exceptions if the route should be failed or continued:
fun Route.redirectToHttpsHandler(publicHttpsPort: Int = 443, redirectCode: Int = 302, failOnUrlBuilding: Boolean = true) {
handler { context ->
val proto = context.request().getHeader("X-Forwarded-Proto")
?: context.request().getHeader("X-Forwarded-Scheme")
if (proto == "https") {
context.next()
} else if (proto.isNullOrBlank() && context.request().isSSL) {
context.next()
} else {
try {
val myPublicUri = URI(context.externalizeUrl())
val myHttpsPublicUri = URI("https",
myPublicUri.userInfo,
myPublicUri.host,
publicHttpsPort,
myPublicUri.rawPath,
myPublicUri.rawQuery,
myPublicUri.rawFragment)
context.response().putHeader("location", myHttpsPublicUri.toString()).setStatusCode(redirectCode).end()
} catch (ex: Throwable) {
if (failOnUrlBuilding) context.fail(ex)
else context.next()
}
}
}
}
A simpler version might be to just trust the context.externalizeUrl class and see if it has the correct protocol and port and redirect if not:
fun Route.simplifiedRedirectToHttpsHandler(publicHttpsPort: Int = 443, redirectCode: Int = 302, failOnUrlBuilding: Boolean = true) {
handler { context ->
try {
val myPublicUri = URI(context.externalizeUrl())
if (myPublicUri.scheme == "http") {
val myHttpsPublicUri = URI("https",
myPublicUri.userInfo,
myPublicUri.host,
publicHttpsPort,
myPublicUri.rawPath,
myPublicUri.rawQuery,
myPublicUri.rawFragment)
context.response().putHeader("location", myHttpsPublicUri.toString()).setStatusCode(redirectCode).end()
}
else {
context.next()
}
} catch (ex: Throwable) {
if (failOnUrlBuilding) context.fail(ex)
else context.next()
}
}
}

How to remove subdomains except one page in MVC

Users navigate in web site with subdomains like
xxx.abc.com/userpage/133,
yyy.abc.com/userpage/133,
zzz.abc.com/userpage/133,
qqq.abc.com/userpage/133
As you can see there are several subdomains exits in our website.
I want to remove subdomains if user leaves from /userpage/
Such as, if navigates to :
/ContactUs,
/Register
/ (root)
How can I remove subdomains except just one action in MVC 4.
Thanks.
The best method would be to let IIS handle it. You can use the URL Rewrite module to redirect any request other than /userpage/ where the domain is not the main one you want to use to the main domain.
If you insist on doing it through the MVC pipeline, your best bet is to use an action filter:
public class RedirectSubdomainFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.RequestContext.HttpContext.Request;
if (request.Url.Host != "maindomain.com" && !request.Url.AbsolutePath.StartsWith("/userpage/"))
{
filterContext.Result = new RedirectResult("http://maindomain.com" + request.Url.PathAndQuery);
}
base.OnActionExecuting(filterContext);
}
}
Then, in App_Start\FilterConfig.cs add:
filters.Add(new RedirectSubdomainFilter());
EDIT (05/26/2016)
I changed the action filter code above to use StartsWith instead of a direct comparison, as I neglected to notice that the URL may contain something after /userpage/.

Phalcon forward to different module

Trying to work my way through setting up a phalcon mvc application.
I have 2 modules current set up for testing. "Frontend" and "Admin".
I have different views set up so I can confirm I am getting through to each of the modules. When I change the defaultnamespace and defaultmodule I can indeed see that both modules are being accessed fine and loading ok. I can see that the admin controllers are being accessed correctly and the frontend controllers are being accessed when I change this.
The problem I am currently having is when I try to authenticate a user and start the session I want to forward the request over from "Frontend" to "Admin":
return $this->dispatcher->forward(array(
'namespace' => 'Qcm\Admin\Controllers',
'action' => 'index',
'controller' => 'index'
));
Again I have confirmed these namespaces work fine. The problem is when I now forward onto the new namespace it can no longer find the admin index controller?
"Qcm\Admin\Controllers\IndexController handler class cannot be loaded"
However I have already confirmed that I can switch between the modules by changing the defaultnamespace/defaultmodule. Is this a limitation within the dispatcher that I can not forward to a different module?
Just to clarify I am also using the same url's so for example after login I want it to go back to '/' (root) but because it has forwarded to the admin module this should work fine correct?
The phalcon dispatcher can only forward to actions within the same module. It cannot forward you outside the current module. This restriction comes because the dispatcher is only aware of the module in which it is declared.
In order to forward to another module, you must instead return a redirect response from a controller action. In my case, I wanted to forward the user to a login screen or a 404 error page based on their ACL permissions in the beforeDispatch() method of a plugin. The dispatcher is native to this method, but cannot forward the user outside of the current module. Instead, I have the dispatcher forward the user to a controller in the same module that has a custom action that in turn performs the redirect.
// hack to redirect across modules
$dispatcher->forward(
array(
'controller' => 'security',
'action' => 'redirect',
'params' => array(
'redirect' => '/home/index/login'
),
)
);
return false; // stop progress and forward to redirect action
This means that each module needs to have a copy of this custom redirect action in one of its controllers. I accomplished this by putting the action in the base controller that all of my controllers extend from.
/**
* the phalcon dispatcher cannot forward across modules
* instead, forward to this shared action which can then redirect across modules
* */
public function redirectAction(){
$this->view->disable();
$params = $this->dispatcher->getParams();
$redirect = '/';
if( ! empty( $params['redirect'] ) ){
$redirect = $params['redirect'];
}
return $this->response->redirect( $redirect );
}
Because phalcon didn't add all modules to global loader, so the namespace is not registered. you need to register another module in current module bootstrap file, modify your Module.php as
class Module
{
public function registerAutoloaders()
{
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(array(
//Your current module namespaces here
....
//Another module namespaces here
'Qcm\Admin\Controllers' => 'controller path',
));
$loader->register();
}
}
The main reason it shows IndexController class not loaded is because you might not have added Dispatcher in that module or in the bootstrap file(depending on your approach)
Add
$debug = new \Phalcon\Debug();
$debug->listen();
to your code before
$application->handle()->getcontent();
to view erros.
Before the replacement line:
echo $application->handle()->getContent();
code:
$router = $this->getDi()->get("router");
$params = $router->getParams();
$modName = $router->getModuleName();
$url = null;
if ($modName == "admin" && isset($params[0])) {
$module = "/" . $params[0];
$controller = isset($params[1]) ? "/" . $params[1] . "/" : null;
$action = isset($params[2]) ? $params[2] . "/" : null;
$params = sizeof($params) > 3 ? implode("/", array_slice($params, 3)) . "/" : null;
$url = $module . $controller . $action . $params;
}
echo $application->handle($url)->getContent();

Redirect HTTP to HTTPS in MVC4 Mobile Application

In My MVC4 Mobile application i have registration, login page and remaining pages. i would like to redirect user to HTTPS connection for all sensitive information pages like registration and login pages and HTTP to remailing pages.
I prefer you to use conditional functionality putting the class
public class RequireHttpsConditional : RequireHttpsAttribute
{
protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
{
var useSslConfig = ConfigurationManager.AppSettings["UseSSL"];
if (useSslConfig != null)
{
if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The requested resource can only be accessed via SSL.");
}
var request = filterContext.HttpContext.Request;
string url = null;
int sslPort;
if (Int32.TryParse(useSslConfig, out sslPort) && sslPort > 0)
{
url = "https://" + request.Url.Host + request.RawUrl;
if (sslPort != 443)
{
var builder = new UriBuilder(url) { Port = sslPort };
url = builder.Uri.ToString();
}
}
if (sslPort != request.Url.Port)
{
filterContext.Result = new RedirectResult(url);
}
}
}
}
and using this [RequireHttpsConditional] above the action result.
i have got this code somewhere in internet and is working fine for me.
in web.config appsettings use <add key="UseSSL" value="443" />
and in the controller above the action result you need put
[RequireHttpsConditional]
public ActionResult SignIn()
{
}
In IIS where you have your project right click and click "Edit Bindings" then you add a custom type https and port no 443 (you can change it)
Note this will work only in production environment. when executed locally it wont be working.
When you execute it locally you have request.Url.Host which will return you only localhost and missing your port number. so if you use it in MVC you will find error loading page for your pages where you put this code.
So this will work when you have the host assigned instead of using the localhost with a specific port number.
Within the controller actions that you wish to be HTTPS add the following code to the top of the method (of course you can simply add this to its own method and then call it):
if (!HttpContext.Request.IsSecureConnection)
{
var url = new UriBuilder(HttpContext.Request.Url);
url.Scheme = "https";
Response.Redirect(url.Uri.AbsoluteUri);
}
It is recommended though that you keep HTTPS on throughout your site to protect against a MITM attack against the auth cookie.