How to remove the context path when viewing authenticated content - authentication

I'm working on a grails application that sits on a server with another root.war application. Currently we use apache redirects to hide the context path (name of our grails application) as we already have a root.war and we don't want it to show on all our urls. This works for our public content. However, now that we've added some authenticated content with spring security core plugin it always redirects to include the context path. Hence, the url /authcontent/page.gsp is getting redirected to /appname/authcontent/page.gsp. Some folks have mentioned you can remove the context path by creating a separate virtual host in tomcat, but I was wondering if there's a way to override the mechanism that Spring Security uses to do the redirect in the filter chain. Perhaps overriding the RequestCacheAwareFilter? but I believe that filter only is used after the initial authentication. I've read through the spring security documentation but it doesn't talk as much about redirecting requests as much as the whole authentication and authorization process so I'm wondering if this is in the plugin itself. Any thoughts would be helpful.

You can remove the app context in the Config.groovy file:
environments {
development {
grails.logging.jul.usebridge = true
grails.serverURL = "http://localhost:8080"
grails.app.context = "/"
}
production {
grails.logging.jul.usebridge = false
grails.serverURL = "http://yourwebsite.com"
grails.app.context = "/"
}
}
Hope that helps.

There's number of ways of doing this. Two I tried were overriding the requestCache bean (but then you also had to override the DefaultSavedRequest) and overriding the redirectStategy bean which is what I'm using as it was simpler.

Related

Is it possible to configure Spring Cloud Gateway with a Rewrite rule for Vue Router's history mode?

I am using Spring Cloud Gateway as an API-Gateway and also as a webserver hosting the static files (html/js/css) of an Vue.js SPA.
Preclaimer: I'm not able to change this (bad) architecture due to organisational constraints.
Currently, I'm using the default Vue Router hash mode, meaning client-side routing of the Vue app is accomplished via an URL hash like
http://hostname/#/route?parameter1=true
Because the Spring Cloud Gateway also acts as an Authentication gateway, it redirects to an OAuth2/OpenID SSO server, and by doing that, the route information of the URL hash is dropped after the redirect.
I'm trying to change this behaviour by switching to Vue Router's history mode, which would enable URLs like
http://hostname/route?parameter1=true
and therefore, routing information would "survive" SSO redirects.
To do that, Vue Router documentation includes some examples for additional Webserver configuration (like mod_rewrite for Apache etc.).
Sadly there is no example included for my very special case ;-)
I scanned the documentation of Spring Cloud Gateway, but didn't find a match for this case.
So in short:
Is it possible to configure Spring Cloud Gateway to match Vue Router's history mode requirements?
You could fix it from the Spring Boot side. I mean, you could:
Enable the Vue Router history mode like explained in the documentation here
Build a Spring Boot forwarding controller like this:
#RequestMapping(value = "{_:^(?!index\\.html|api).$}")
public String redirectApi() {
LOG.info("URL entered directly into the Browser, so we need to redirect...");
return "forward:/";
}
It basically forwards all routes to front end except: /, /index.html, /api, /api/**.
Here you can find a more detailed example.
It can be done with a custom RouterFunction:
#Bean
public RouterFunction<ServerResponse> vueHistoryModeCatchAllRoute(
#Value("classpath:/static/index.html") final Resource indexHtml) {
HandlerFunction<ServerResponse> serveIndexHtmlFunction = request -> ok().contentType(MediaType.TEXT_HTML)
.bodyValue(indexHtml);
String firstApiSegmentExcludes = "api|actuator|js|img|css|fonts|favicon\\.ico";
return route(GET("/{path:^(?!" + firstApiSegmentExcludes + ").*}"), serveIndexHtmlFunction)
.and(route(GET("/{path:^(?!" + firstApiSegmentExcludes + ").*}/**"),
serveIndexHtmlFunction));
}
This will serve the index.html (containing the Vue.js app) for all requests, which do not match one of the excluded paths (firstApiSegmentExcludes).

How to change base url?

I am not sure the title of the question is correct, but I'll try to explain what I need.
We host multiple web applications on a single machine, so
https://localhost:8080
and
https://localhost:8081
point to different applications.
Meanwhile, API gateway maps request without dropping the URL suffix:
https://api.domain.com/service1/Home/Index
turns into
https://localhost:8080/service1/Home/Index
and
https://api.domain.com/service2/Home/Index
into
https://localhost:8081/service2/Home/Index
I would like the app's root ~ to resolve to hostUrl+suffix where suffix is a configured value.
I used this blogpost to globally prefix all the routes for controllers and pages, but now I struggle with static files.
I am able to virtually move wwwroot:
app.UseStaticFiles(new StaticFileOptions
{
RequestPath = $"/{GlobalPrefix}"
});
but <link href="~/bootstrap/css/bootstrap.css" rel="stylesheet" /> does not contain GlobalPrefix part when rendered.
So I would like to add this GlobalPrefix to whatever base URL site is hosted at. Be it a self-hosted app or in IIS.
P.S. RTFM =)
Using app.UsePathBase("/myPath")(https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.usepathbaseextensions.usepathbase?view=aspnetcore-2.2) is working in that case.
There have been changes in ASP.NET Core 2 regarding that (http://github.com/aspnet/Announcements/issues/226). Also, be aware of a strange behavior: http://github.com/aspnet/HttpAbstractions/issues/893

Routing requests using cloudflare to different web applications

I currently have two web apps that are set up in cloudflare with the following CNAMEs. Both are keystonejs applications.
app1.example.com ===pointing to ===> AWS ALB 1
app2.example.com ===pointing to ===> AWS ALB 2
I have Cloudflare Enterprise set up, so i'm able to use the "Render Override" feature in my page rules. I have 2 page rules set up using the following:
www.example.com ===render override ===> app1.example.com
www.example.com/app2/* ===render override ===> app2.example.com
Now in order to access the keystonejs application on app2.example.com. The application is called using app2.example.com/pa
The problem that i'm facing is that render override doesnt allow me to use sub paths, and i do not want to use the forwarding rule. Do i need to make my keystone application accessible through the root url, namely app2.example.com/ ? or is there another way to do this? Otherwise, would i need to use a reverse proxy? such as nginx ?
Thanks
Note: Since you are an enterprise customer, I highly recommend contacting your Customer Success Manager and/or Solutions Engineer at Cloudflare. They are there to help with exactly these kinds of questions. That said, I'll answer the question here for the benefit of self-serve customers.
I think when you say "Render Override" you actually mean "Resolve Override". This setting changes the DNS lookup for the request such that it is routed to a different origin IP address than it would be normally.
Note that Resolve Override does not rewrite the request in any way; it only routes it to a different server. So, a request to www.example.com/app2/foo will go to the server app2.example.com, but the path will still be /app2/foo (not /foo), and the Host header will still be Host: www.example.com.
It sounds like in your case you really want /app2/* to be rewritten to /pa/*, in addition to redirecting to a different origin. You can accomplish this using Cloudflare Workers, which lets you execute arbitrary JavaScript on Cloudflare's edge. Here's what the script might look like:
addEventListener("fetch", event => {
event.respondWith(handle(event.request));
});
async function handle(request) {
let url = new URL(request.url) // parse the URL
if (url.pathname.startsWith("/app2/")) {
// Override the target hostname.
url.host = "app2.example.com"
// Replace /app2/ with /pb/ in the path.
url.pathname = "/pb/" + url.pathname.slice("/app2/".length)
// Send the request on to origin.
return fetch(url, request)
} else {
// Just override the hostname.
url.host = "app1.example.com"
// Send the request on to origin.
return fetch(url, request)
}
}
With this deployed, you can remove your Resolve Override page rules, as they are now covered by the Worker script.
Note that the above script actually does rewrite the Host header in addition to the path. If you want the Host header to stay as www.example.com, then you will need to use the cf.resolveOverride option. This is only available to enterprise customers; ask your CSM or SE if you need help using it. But, for most cases, you actually want the Host header to be rewritten, so you probably don't need this.

Servicestack Swagger UI endpoint not behaving as expected with UseHttpsLinks

Using 4.0.31, my AppHost Configure method is declared like this:
public override void Configure(Funq.Container container)
{
HostConfig hc = new HostConfig()
{ HandlerFactoryPath = "api", UseHttpsLinks = true };
SetConfig(hc);
Plugins.Add(new CorsFeature());
Plugins.Add(new SwaggerFeature());
...
}
I was under the impression that this would set the url for swagger-ui to be the https version of ../api/resources, however I'm still getting the regular http endpoint in the swagger URL textbox, like:
http://example.com/myapp/api/resources
Our web servers are behind load-balancers that perform SSL offloading (and require SSL), so the URL should be:
https://example.com/myapp/api/resources
On a positive note, using 'UseHttpsLinks' actually allows swagger-ui to function once you fix the endpoint url. It didn't work at all without it!
I'm overriding the swagger url property using a replacement index.html via the Virtual File System as a hack -- since in the development, QA, and staging environments, the url property is pointing to production...(not so good)
Config.UseHttpsLinks has been expanded to also apply to the BaseUrl where it now changes http:// urls to https:// in this commit.
This change is available from v4.0.33+ that's now available on MyGet.

Dynamically setting the BaseUrl within configuration in Symfony2

I know that within Symfony2's configuration, there is no reference to the base url, as there is no request; the application could either run in cli or within a web server, and therefore we cannot rely on request. But still, I have configuration that asks for stylesheets or javascript base url (such as the JQueryHelperBundle, where you can set your jquery local path - being the local url). The thing is, is there a way to dynamically set a base url for the configuration, without having to change it so that:
The application can move from any directory under development, whether www/myproject or www/foo/myproject without having to change the settings
Production would work the same, except that rewriting the base url with apache would be detected (virtualhosting is common, where the baseurl is mapped to the web directory as '/').
Is there a way to get that base url information? Would using the difference between $_SERVER['DOCUMENT_ROOT'] minus the kernel root dir be a way to detect such base url? But what about virtualhost rebasing the url to / on the web directory? Hardcoding the base url completely couples the project to where it stands in development, and moving project around would require to change the base url everytime, which is annoying.
So, is there a way to dynamically detect the base url within Symfony2's configuration, according to the environment, without depending on the request?
I had to do that in a service, so I injected the router service in my own service and then:
$baseUrl = $router->getContext()->getHost();
But I considered it more as an hack that a real fixture of Symfony2 framework. For instance, in Controller you can generate absolute url easily (example from the symfony book):
$router->generate('blog_show', array('slug' => 'my-blog-post'), true);
And in the twig template, you have the {{ url }} function
I hope this help