Render different errors for different pipelines (:api and :browser)? - api

In my current Phoenix project I have both a :browser pipeline and a :api pipeline. I want to render different error messages for each pipeline. However, I'm not sure how to achieve it.
My router.ex is like:
scope "/api", AppWeb do
pipe_through(:api)
# ...
end
scope "/admin", AppWeb do
pipe_through :browser
# ...
end
I want all requests to non-existing routes under /admin to render a HTTP error template, but all requests to any other route to render a JSON error template.
In config.exs I have
render_errors: [view: AppWeb.ErrorView, accepts: ~w(json html)]
However, I'm not sure how to proceed with the error view.
It seems that the template_not_found/2 function will be automatically called, whenever a routing error occurs, however, this function doesn't have a conn argument. Its arguments are template and assigns.
Should I try to inspect the assigns to try to determine which route the incoming request was trying to access? Trying to inspect the template didn't seem to be helpful, and the template attempted to be rendered all seem to end with .html extension, even if I try to visit a route under /api.

As #JoséValim pointed out, the reason why I didn't correctly see JSON error messages is because I was visiting the pages via a browser. If I correctly set the header Accept: application/json in my request, it worked.
In template_not_found function in error_view.ex, it seems to suffice to just write Phoenix.Controller.status_message_from_template(template).

Related

Can't render iframe on another domain using rack-cors

I'm trying to render an iframe of App A within App B.
App A is a local Rails 5.0 app and is using https.
App B is hosted on Heroku and is using https.
I've tried implementing the rack-cors gem but with no success, and I've tried all the suggestions I can find on StackOverflow.
My cors.rb file, within App A:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'https://app-b.herokuapp.com'
resource '/url/on/app_a/*',
headers: :any,
methods: :any
end
end
My config.ru file (I've tried with and without this):
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run Rails.application
require 'rack/cors'
use Rack::Cors do
allow do
origins 'https://app-b.herokuapp.com'
resource '/url/on/app_a/*',
headers: :any,
methods: :any
end
end
The error I get is: Refused to display 'https://app-a.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
I am not sure if this is specifically to rack-cors, but I do know that the header 'X-Frame-Options' is intentionally set to 'sameorigin' for at least Rails 5. Most likely to prevent developers from unintentionally allowing someone to wrap their server in an iframe.
According to the docs, we can see that if the server sets this response as not 'sameorigin', then the browser will allow the HTML code to run. So what we need is to remove that header away. Chris Peters does a great job at this post. To save a click
class SomeController < ApplicationController
after_action :allow_iframe
private
def allow_iframe
response.headers.except! 'X-Frame-Options'
end
end
To apply this to all endpoints simply place the after_action line and the function code in the application controller, but I would suggest limiting this to only specific pages/controllers.

How to pass original URI, with arguments, to Traefik ErrorPage handler specified in `query`?

I'm trying to use nginx to serve a custom error page using the Error Page middleware so that 404 requests to a lambda service (which I don't control) can be handled with a custom error page. I want to be able to get the context of this original request on that error page, either in Nginx for further forwarding, or else as a header for further handling e.g. in PHP or whatnot so I can provide contextual links on the 404 page.
However, right now after the redirection to Nginx in Traefik's ErrorPage middleware it seems the request has lost all the headers and data from the original service query.
The relevant part of my dockerfile:
traefik.port=8080
traefik.protocol=http
traefik.docker.network=proxy
traefik.frontend.rule=PathPrefix:/myservice;ReplacePathRegex:^/myservice/(.*) /newprefix/$$1
traefik.frontend.errors.myservice.status=404
traefik.frontend.errors.myservice.service=nginx
traefik.frontend.errors.myservice.query=/myservice-{status}
Nginx receives the forwarded 404 request, but the request URI comes through as nothing more than the path /myservice-404 specified in query (or /, if I omit traefik.frontend.errors.myservice.query). After the ReplacePathRegex I have the path of the original request available in the HTTP_X_REPLACED_PATH header, but any query arguments are no longer accessible in any header, and nginx can't see anything else about the original URI. For example, if I requested mysite.com/myservice/some/subpath?with=parameters, the HTTP_X_REPLACED_PATH header will show /myservice/some/subpath but not include the parameters.
Is it possible in Traefik to pass another service the complete context about the original request?
What I'm really looking for is something like try_files, where I could say "if this traefik request fails, try this other path instead", but I'd settle for being able to access the original, full request arguments within the handling backend server. If there was a way to send Nginx a request with the full path and query received by Traefik, that would be ideal.
tl;dr:
I am routing a request to a specific service in Traefik
If that request 404s, I want to be able to pass that request to Nginx for further processing / a contextual error page
I want Nginx and/or the page which receives the ErrorPage redirect to be able to know about the request that 404'd in the service
Unfortunately this is not possible with Traefik. I tried to achieve something similar but I realized that the only information that we are able to pass to the error page is the HTTP code, that's it.
The only options available are mentioned in their docs: https://doc.traefik.io/traefik/middlewares/errorpages/

Forcing Errors For Unstubbed Routes With Cypress

I am testing a Gatsby app/site with Cypress. It makes a number of calls to an api from a variety of pages. We have taken the decision to stub and mock all these requests, so our tests should never hit our live api.
I was looking for a way to have Cypress error if a request to any of our API endpoints was made that wasn't stubbed, and I found the force404 config param (docs) for cy.server which enforces a 404 to be returned for any routes that aren't stubbed. This works well, but actually too well. Gatsby uses XHRs internally to preload other pages (amongst other things) and this causes all those to return 404s as well, effectively breaking the app.
Is there a way to configure cy.server to only return 404s from routes that aren't stubbed that are on a particular domain. For example if our api domain is api.example.com. Is there a way to configure cy.server to return a 404 only for requests to api.example.com that are not stubbed, while leaving requests to other domains, or the same domain untouched.
Did you try whitelisting? You could add a rule here to whiletlist all domains that are not your server's
https://docs.cypress.io/api/commands/server.html#Change-the-default-whitelisting
cy.server({
whitelist: (xhr) => {
// specify your own function that should return
// truthy if you want this xhr to be ignored,
// not logged, and not stubbed.
}
})

Seeing bundle files path in login url and redirecting multiple times

I'm using mvc4 and .Net 4.5 in my project with SSL. Now, on localhost and even on server, the login page gets redirect a bunch of times and then loads without and css on page. In browser debugger I get error as:
Uncaught SyntaxError: Unexpected token <http://localhost:55248/Account/Login? ReturnUrl=%2fbundles%2fjqueryval%3fv%3dWrBNyT_GYLXAZ7iWD7vDdFccq24m7v_9MPi3rcQ8FO01&v=WrBNyT_GYLXAZ7iWD7vDdFccq24m7v_9MPi3rcQ8FO01...
I'm using bundling and code snippet as below.
bundles.Add(new ScriptBundle("~/bundles/BaseJs")
.Include("~/Scripts/jquery-{version}.js")
.Include("~/Scripts/jqueryui/jquery-ui.js")
.Include("~/Scripts/bootstrap.js"));
The syntax error is from the error page being loaded as JavaScript (when it's obviously not JavaScript). It's a red herring. The true problem is that your JavaScript file is needing authorization in the first place.
Typically, this wouldn't be an issue. By default, anything with an extension (.js, for example) is ignored by MVC and handled directly by IIS. Worst case scenario, there, IIS doesn't have permission to read the file, and you end up with a 403 Forbidden. It would end there, as an IIS-level 403 would not trigger a login page redirect, mostly because, again, MVC is not involved.
However, if you've bungled around the with default setup, such that MVC is now handling all requests, even for static files. Then, the action that's being triggered to handle the request to your JavaScript file is requiring authorization, and therefore is redirecting to the login page. So find out what action is being hit and either remove the requirement for it to be authorized or have the right action serve the file. Or, ideally, leave things as they should be and let IIS do what IIS does best and serve the static files.
EDIT
I wasn't paying attention to the fact that bundles are rendered without a file extension. However, the steps to correct the issue are largely the same. Something is mostly likely off with your routing, and the request for the bundle is actually being caught by one of your actions, particularly one that requires authorization. Look out for catch-all routes and make sure that you're not using a route like "bundles" anywhere in your RouteConfig.cs or any of your Route attributes, if you're using attribute routing.
First try to include your bundles like that :
.Include( "~/Scripts/jquery-{version}.js",
"~/Scripts/jqueryui/jquery-ui.js",
"~/Scripts/bootstrap.js"
);
Include takes string[] as parameter and you don't need to call include for each row. Then you should debug your bundles to see which js is giving the error.
Try to comment out rows 1 by 1 to see what would be the result. The problem is definatelly in your bundles, I also had these kind of errors. If you can provide more code - > snippet from the view, of the css loading and bundles and stuff like that I would be able to help you more.

apache2 module custom http header

I'm try to redirect a illegal access and bring user to a log-in page, if user get permission and continue to access original, I need to keeping original request url. I try to write original url into http header zone, but I cannot retrieve this data from client.
Did apache2 or other module ignore custom http heaer? or I just miss something?
(BTW: I dont like use querystring, think about maybe next page still come as a redirection)
code example:
ap_set_content_type(r, "text/html");
apr_table_add(r->headers_out, "Location", conf->authurl);
apr_table_add(r->headers_out, "RequestUrl", url);
return HTTP_MOVED_TEMPORARILY;
// following code will be work fine.
apr_table_add(r->err_headers_out, "RequestUrl", url);
see as:
https://source.jasig.org/cas-clients/mod_auth_cas/tags/mod_auth_cas-1.0.9.1/src/mod_auth_cas.c