FusionAuth / fusionauth-issues

FusionAuth issue submission project
https://fusionauth.io
91 stars 12 forks source link

Is there a way to configure a 'public path' ? #88

Open fabiosimeoni opened 5 years ago

fabiosimeoni commented 5 years ago

Any way to configure a 'public path' ?

I'm using FusionAuth behind a gateway (Ambassador), mapping an /auth/ route onto it, but the Location header of 302 redirects assumes always a root context deployment (e.g. point to /login rather than /auth/login, or /authorize rather than /auth/authorize, or ...).

Is there any configuration for a public path? Is fusionauth-app.url possibly related?

Thanks for your help!

robotdan commented 5 years ago

Hi @fabiosimeoni

If I understand correctly, the FusionAuth UI will redirect the browser to /login which will then redirect to /oauth2/authorize (for example).

In your case, you have FA running behind a proxy which adds an additional URL prefix of /auth/.

Are you using the re-write rules similar to this? https://www.getambassador.io/reference/rewrites/

This looks like it would map a request such as /auth/login to /login - which sounds like it would work ok. Is the specific issue that the initial re-write works, but then when FusionAuth requests a redirect to /login (for example) it is not re-written to /auth/login by Ambassador?

Is there any configuration for a public path? Is fusionauth-app.url possibly related?

This is something else - this is a URL (preferably on a private network) that a FusionAuth node can talk to another FusionAuth node when horizontally scaling.

fabiosimeoni commented 5 years ago

Hi, thanks for the super-prompt reply.

Yep that’s exactly it. All the 302 ( including the one from / to /login), construct a Location header under the assumption that FusionAuth is reachable at the root context. Envoy, upon which Ambassador is based, does not manipulate Locations (or indeed any other URI that the server may “introspect” in its responses), but expects applications to be configurable in this respect. I suppose either with a a “public path” (to use as a prefix in the construction of relative URIs) or a configurable deployment context (eg to be available under /auth). See here: https://github.com/datawire/ambassador/issues/1064.

My overall use case is to use FusionAuth (like ElasticSearch) as one component of a distributed application which sits entirely behind Ambassador. Browser requests to other components are intercepted by Ambassador, and to routed to an Auth Bridge that starts an OAuth2 dance with FusionAuth. So the bridge redirects to your Authorize endpoint using the mapping required by Ambassador to route the browser to FusionAuth.

On 4 Mar 2019, at 01:01, Daniel DeGroff notifications@github.com wrote:

Hi @fabiosimeoni

If I understand correctly, the FusionAuth UI will redirect the browser to /login which will then redirect to /oauth2/authorize (for example).

In your case, you have FA running behind a proxy which adds an additional URL prefix of /auth/.

Are you using the re-write rules similar to this? https://www.getambassador.io/reference/rewrites/

This looks like it would map a request such as /auth/login to /login- which sounds like it would work ok. Is the specific issue that the initial re-write works, but then when FusionAuth requests a redirect to/login(for example) it is not re-written to/auth/login` by Ambassador?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

robotdan commented 5 years ago

Thanks for the clarification @fabiosimeoni . I'll have to dig into this a bit further, I am not very knowledgeable about Ambassador.

Your link to issue #1064 is helpful, that does seem to be the same issue.

This sort of feels like setting the servlet context, but in this case we only want to change the redirect location. I'll have to do some additional investigation, I know some other folks are using Envoy, so this is something we should probably figure out.

Thanks for bringing this to our attention, more to come.

robotdan commented 5 years ago

I've been reading up on this and trying to identify a solution. It seems the feature set of Envoy / Ambassador doesn't necessarily make it a great fit for a full web application such as FusionAuth due to redirects etc. It seems better suited for APIs.

In theory we could add a configuration to understand the public root and build our redirects accordingly, I'd have to think this through some more to understand if there are any other edge cases not covered by this strategy.

Could you use the proxy only for requests under /api which do not rely upon redirects and utilize a separate strategy for the FusionAuth UI and OAuth workflows?

fabiosimeoni commented 5 years ago

Could you use the proxy only for requests under /api which do not rely upon redirects and utilize a separate strategy for the FusionAuth UI and OAuth workflows?

yes, that's what we're doing and most definitely works.

for the sake of discussion, what drew me to proxy FusionAuth was the idea that - differently from other IAM solutions, I could push it further and treat it as an application service in its own right, albeit third-party. A component in its own right, on par with frontends and backends we write ourselves, deployed like those in our Compose/Kubernetes clusters, not outside of it. This potential for 'embeddability' in an app is IMHO of great appeal, very dev-oriented, and it is an original stance when you compare it to the typical managed services for IAM.

But you're right, there's no need to expose your UI to browsers. User management occurs from our frontends, even when we integrate them with your APIs.

robotdan commented 5 years ago

Thanks for that additional information, I'll leave this issue open for a bit longer until we rule out adding a config for a public path configuration option.

Keep the feedback coming! Thanks @fabiosimeoni

robotdan commented 5 years ago

The current plan is to leave FusionAuth as-is - there are proxy configuration that support redirect re-writes. Some proxies that are built more for API banks / gateways may not work without additional configuration to ensure redirects (302) work properly.

fabiosimeoni commented 5 years ago

Ok, makes sense.

Just for completeness, it' worth bearing in mind that. it's not just redirects that break, also FusionAuth Admin UI is not using relative paths.

robotdan commented 5 years ago

Thanks for the additional info @fabiosimeoni - this probably needs some more investigation on our end then.

I'll re-open and set up a similar environment to see if we need to change anything to better support this scenario.

Thanks for your feedback!

fabiosimeoni commented 5 years ago

I do appreciate the goodwill, but let me put this into perspective: I think the problem emerges only in a class of use cases that you might well not consider high-priority (or maybe do not want to support at all).

The use case is when FusionAuth is embedded in a distributed application architecture, rather than being integrated with as an external IdP. In this “Bring Your Own Auth” approach, FusionAuth would share a reverse-proxy/api-gateway with other application components, hence would be routed under a "path prefix”. And this is where one needs more flexibility than it’s available right now. This is the use case I had in mind when I picked FusionAuth, preferring to managed services like Auth0, Okta, etc, and even to enterprise installations ala Keycloak, because it seemed the lightweight yet full-featured third-party product to embed as a "piece of my app". But maybe this is not a general or generally-agreed upon approach.

In terms of solutions, again I suspect the least painful route for you would be to make the ‘mount point' of FusionAuth in Tomcat - the context path in servlet jargon - configurable. Then I’d configure FusionAuth to run under /auth in Tomcat and map the prefix /auth trivially to /auth itself. You may not need to change anything else, I reckon. Perhaps :)

On 10 Apr 2019, at 16:38, Daniel DeGroff notifications@github.com wrote:

Reopened #88 https://github.com/FusionAuth/fusionauth-issues/issues/88.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/FusionAuth/fusionauth-issues/issues/88#event-2266320364, or mute the thread https://github.com/notifications/unsubscribe-auth/ADR8IfLTT1a_M5v_BVGeKhr-x0wEkEEEks5vffddgaJpZM4bbUh5.

robotdan commented 5 years ago

We have discussed using a servlet context, this is definitely an option. It has some drawbacks from our side due to how we support theming, etc.

Is your work around ok for now? It sounds like you've just configured the proxy to understand the URL path and modify the behavior?

Could you use the proxy only for requests under /api which do not rely upon redirects and utilize a separate strategy for the FusionAuth UI and OAuth workflows?

yes, that's what we're doing and most definitely works.

Really appreciate all the feedback and perspective, we do want to make FusionAuth as flexible as possible. We'll kick this around some more internally and see what we can come up with.

fabiosimeoni commented 5 years ago

I've configured my api gateway to route /oauth2, /images, /js, /fonts, /css to FA. So I had to let FA take the 'root' mapping because I couldn't prefix it. This works, but it's hardly ideal, elegant, or indeed stable (e.g. I might enable your next coolest feature from the login box and discover I also need to route /someotherpath).

I can live with it for now, sure. That's why I cared to relate my experience to the broader use case, so that you'd attach a value to that, rather than my immediate need. No expectations otherwise ;)

gmpreussner commented 5 years ago

I ran into the same problem using Apache as the reverse proxy, and I temporarily worked around it the same way @fabiosimeoni did. I think that adding an option to specify a public path, such as http://example.com/mydir/ would be great. So far, this has been the only gripe I have with FusionAuth. Everything else works amazing, and the setup was a breeze.

gmpreussner commented 5 years ago

I almost have a reverse proxy configuration working that doesn't require any global routes. There are two problems remaining:

  1. Some Ajax paths seem to be built in JavaScript, so they can't be reversed via mod_proxy_html, and I have to forward the route explicitly. This is probably not easily fixable in a reverse proxy without identifying the affected scripts and adding special replacement rules.
  2. While I can access all pages on the Admin back-end, I am not authorized to make any changes (i.e. Save button returns "You are not authorized" message). I suspect that this has to do with cookies, referrer URLs, or both. Any idea what I might be missing, @fabiosimeoni ?

My fully self-contained Apache config for mapping https://example.com/foo to http://localhost:9011 is as follows:

...
<Proxy *>
     Order allow,deny
     Allow from all
</Proxy>

ProxyPreserveHost Off
ProxyRequests Off

ProxyPassReverseCookieDomain localhost:9011 example.com
ProxyPassReverseCookiePath / /foo/

<Location /ajax/>
    RequestHeader unset Accept-Encoding
    ProxyPass http://localhost:9011/ajax/
</Location>

<Location /foo/>
    RequestHeader unset Accept-Encoding
    ProxyPass http://localhost:9011/
    ProxyPassReverse /

    ProxyHTMLLinks a href
    ProxyHTMLLinks area href
    ProxyHTMLLinks link href
    ProxyHTMLLinks img src longdesc usemap
    ProxyHTMLLinks object classid codebase data usemap
    ProxyHTMLLinks q cite
    ProxyHTMLLinks blockquote cite
    ProxyHTMLLinks ins cite
    ProxyHTMLLinks del cite
    ProxyHTMLLinks form action
    ProxyHTMLLinks input src usemap
    ProxyHTMLLinks head profile
    ProxyHTMLLinks base href
    ProxyHTMLLinks script src for

    ProxyHTMLEvents onclick ondblclick onmousedown onmouseup \
        onmouseover onmousemove onmouseout onkeypress \
        onkeydown onkeyup onfocus onblur onload \
        onunload onsubmit onreset onselect onchange

    ProxyHTMLEnable On
    ProxyHTMLExtended On
    ProxyHTMLURLMap http://localhost:9011 /foo
    ProxyHTMLURLMap ^// https:// R
    ProxyHTMLURLMap ^/ /foo/ R
</Location>
...

PS: The URL rewrite rule for "^//" is for protocol relative links, such as Gravatar images. I can probably find a better regex for "^/", so that it is not necessary.

gmpreussner commented 5 years ago

I found https://github.com/FusionAuth/fusionauth-issues/issues/112 and added the following:

RequestHeader set X-Forwarded-Proto https
RequestHeader set X-Forwarded-Host example.com
RequestHeader set X-Forwarded-Port 443

Unfortunately, it results in internal server errors when modifying FusionAuth resources.

I haven't tried to set the Origin header yet. Should that be the internal localhost URL?

robotdan commented 5 years ago

While I can access all pages on the Admin back-end, I am not authorized to make any changes (i.e. Save button returns "You are not authorized" message). I suspect that this has to do with cookies, referrer URLs, or both. Any idea what I might be missing.

As you mentioned in the latest comment, this is our CSRF protection - and it can be resolved by ensuring the proxy sets the X-Forwarded- headers.

When you were seeing the "You are not authorized" messages, did you see a warning on the dashboard about your configuration? If not, what version of FusionAuth are you running?

For example:

Screen Shot 2019-06-14 at 9 01 09 AM

Unfortunately, it results in internal server errors when modifying FusionAuth resources.

That isn't good.. can you share the exception you're seeing? There should be one in the log.

gmpreussner commented 5 years ago

I'll check this weekend if I can still find it in the logs. I decided to move FusionAuth to a separate server earlier this week, which is probably much safer from a security standpoint anyway, so I won't be able to repro it anymore.

leksa commented 5 years ago

Hello, jump in here. Because i have same issue. I had set Proxy Configuratio Warning above. But can't modify resources, including add user. Another 500 error is when i go to menu "System".

The log exception show me

PM ERROR io.fusionauth.app.primeframework.error.ExceptionExceptionHandler - An unhandled exception was thrown
java.lang.NumberFormatException: For input string: ": 443"

I use nginx as a proxy

robotdan commented 5 years ago

@leksa I think this is a separate issue, that bug has been fixed - but not yet released.

When viewing that form we add an X-XSS-Protection header so that the browser will not complain that the form input fields contain HTML and JavaScript (on the theme edit). When a validation error occurs in the form that header was not being re-added to display the error and a failure would occur. If you view your JavaScript console when you see that error in the UI you will see a message regarding XSS.

For input string: ": 443"

Can you tell me which input field this error was for?

leksa commented 5 years ago

Thank you @robotdan for the bugs info.

Can you tell me which input field this error was for?

I got 500 error when input the new user and open "System" menu

trevorr commented 5 years ago

I'm interested in this too, because I'd like to put a shared AWS load balancer in front of FA. AWS load balancers are slightly expensive to run one per microservice, so I share them when possible by using path prefix rules. They don't support rewriting the path (or modifying the request in any way), although rewriting doesn't help anyway in cases where the service needs to respond with links to itself (such as redirects). I can use the default action for now, but obviously that only works for one service.

jerryhopper commented 4 years ago

@leksa i have been getting 500 errors on a fresh install when submitting forms in the admin backend ( but behind a Apache proxy ) So i came up with a working configuration.

The line that fixes/breaks any submit actions for me is : RequestHeader unset Host

the error that i saw in the logs:

Caused by: java.net.URISyntaxException: Illegal character in authority at index 8: https://idp.yourserver.ext, idp.yourserver.ext

this is my actual working apache proxy config. ` RequestHeader unset Host

RequestHeader set X-Forwarded-Proto "https"

RequestHeader set X-Forwarded-Port "443"

RequestHeader set X-Forwarded-Host "idp.yourserver.ext"

ProxyPass / http://192.168.1.140:9011/

ProxyPassReverse / http://192.168.1.140:9011/ `

i hope this helps you ( and others )

robotdan commented 4 years ago

Related https://github.com/FusionAuth/fusionauth-issues/issues/470

w-k-s commented 4 years ago

I'm interested in this too, because I'd like to put a shared AWS load balancer in front of FA. AWS load balancers are slightly expensive to run one per microservice, so I share them when possible by using path prefix rules. They don't support rewriting the path (or modifying the request in any way), although rewriting doesn't help anyway in cases where the service needs to respond with links to itself (such as redirects). I can use the default action for now, but obviously that only works for one service.

Hi @trevorr ,

Were you able to work around this somehow?

trevorr commented 4 years ago

Were you able to work around this somehow?

I'm still just letting FA have the default action, so other apps have to use a path or Host header condition. If you don't have a problem setting up DNS aliases for each app, the Host header approach works well. The biggest complication with that is needing a private DNS zone and server if you don't want your internal host/app names in a public DNS zone.

fabiosimeoni commented 3 years ago

HI there,

I come back to this issue almost two years after I initially posted, would it be correct to say that the problem is still open? That is, that there's no easy way to access FA UI and APIs 'under' a particular route from the root context (e.g. https://<host>:<port>/iam/<fa-resources-here>)?

I'd love to be able to use FA in my next project without the workarounds that I used two years ago (which proved brittle at time, as expected). Thanks!

mooreds commented 3 years ago

@fabiosimeoni Yes, it would be correct to say this is still an open issue. Unfortunately we've not been able to get to this. We've been working on lots of other features (see the release notes) :) .

This is definitely toward the top of the list of requested features by both the community and some of our customers, but unfortunately we haven't had a chance to implement it, and I don't know when it will be resolved.

If you'd like a guaranteed timeline for implementation, please contact us to discuss a professional services agreement.

fabiosimeoni commented 3 years ago

thanks @mooreds, no worries

@fabiosimeoni Yes, it would be correct to say this is still an open issue. Unfortunately we've not been able to get to this. We've been working on lots of other features (see the release notes) :) .

I noticed! FusionAuth looks great and thanks for making it broadly available.

This is definitely toward the top of the list of requested features by both the community and some of our customers, but unfortunately we haven't had a chance to implement it, and I don't know when it will be resolved.

sure, I just wanted to make extra sure I hadn't missed some new knob outside the scope of the ticket.

I am experimenting now with port-based routing. Instead of intercepting requests to FusionAuth based on a path that FusionAuth can't possibly know about and preserve in responses and redirects, I can get my gateway to operate at tcp-level and listen on a port dedicated to FusionAuth, and for which no path rewriting is required.

This would be good enough for me, as I'm not exposing your UI to end users, only to admins and operators, so it seems reasonable that it should be accessed 'out-of-band'.

And after a first run in staging, all seems to work pretty well. So far.

mooreds commented 3 years ago

That's awesome and a great workaround, @fabiosimeoni !

I feel like I should gather all these workarounds and document them...

fabiosimeoni commented 3 years ago

one caveat though, when you enable tls on the the new port and terminate it at the gateway, your checks for CSRF notice a protocol discrepancy between https of the browser request and http of the gateway request to FusionAuth. This causes POST failures.

I cannot tell the gateway to add X-FORWARDED-PROTO headers, as it's operating at L4 and doesn't see http headers.

So one needs to either terminate tls at FusionAuth itself (replacing the self-signed certificates that you ship).

Or one can continue to terminate it at the gateway (with the certificates one was already using), but have the gateway initiate another https request to FusionAuth. Your self-signed certificates do not require user consent for this last leg.

I used the latter option, so all tls termination remains at the gateway while the original request and the proxied requests remain identical. The theoretical cost is the overhead of two https handshakes, but that's totally immaterial for my use case.

mooreds commented 3 years ago

For anyone else with this issue, there are proxy configurations that work here: https://github.com/FusionAuth/fusionauth-contrib/tree/master/Reverse%20Proxy%20Configurations/

In particular: https://github.com/FusionAuth/fusionauth-contrib/blob/master/Reverse%20Proxy%20Configurations/nginx/nginx.nonrootpath.excerpt.conf may be helpful.

yaskoo commented 2 years ago

I wonder if supporting the X-Forwarded-Prefix header would be easier to integrate. Recently I had to fix a similar issue in a Spring Boot app which used Spring HATEOAS and this resolved the issue.

yuriy-maftiyak-verint commented 2 years ago

The workaround, https://github.com/FusionAuth/fusionauth-contrib/blob/master/Reverse%20Proxy%20Configurations/nginx/nginx.nonrootpath.excerpt.conf, does not work for deployment at my organization.

The workaround has a separate proxy rule for the /admin path, but at this path, we have another product deployed.

shimshon70 commented 2 years ago

Our requirement is to install FusionAuth (standalone) in a non-root context path. We should have option to mention "Server Base URL" field in configuration. Rewrite rule in reverse proxy solution proposed above is not working, it is not maintainable, and performance affecting. For example something like this

mooreds commented 2 years ago

Thanks for the input, @shimshon70 and @yuriy-maftiyak-verint .

Please make sure you upvote the issue. If you have a support contract, please open a support ticket. Both of these feedback mechanisms help us determine future effort.

Here's our general roadmap guidance: https://fusionauth.io/docs/v1/tech/core-concepts/roadmap/

surya-maximl commented 2 years ago

The workaround, https://github.com/FusionAuth/fusionauth-contrib/blob/master/Reverse%20Proxy%20Configurations/nginx/nginx.nonrootpath.excerpt.conf, does not work for deployment at my organization.

The workaround has a separate proxy rule for the /admin path, but at this path, we have another product deployed.

Hi @yuriy-maftiyak-verint, do you really need to proxy pass the /admin path? If not you can remove it from the Nginx config.

MikoverseAllar commented 1 year ago

This is also one of the biggest issues we've faced when using FusionAuth. We can route it on its own subdomain but we want to proxy a subdir for internal admin purposes that will never be exposed to the public.

For now we can set up a local proxy and access it but this inability to use relative paths is a big thorn in our side in an otherwise mostly easy to use deployment. Our api requests are being handled fine, but the admin panel not using relative paths is frustrating. We will most likely drop it back to a subdomain but it is the only service in our entire tech stack that doesn't support relative url paths. But as this is for admin UI and internal network access only, we can work around it.

MPH-DZP commented 1 year ago

+1

jandeschuttere commented 1 year ago

While setting up FusionAuth I had the same issue. Having support for this as part of the application itself would be helpful. I did notice the template files are using the request.contextPath variable as a prefix for the relative paths that I checked so I'm hopeful a configuration is possible to allow to define that variable in the near future.

I'm in luck however, the main application is publicly available via its own URL so I was able to configure the k8s ingress nginx config by defining the following annotation:

    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header Accept-Encoding "";
      sub_filter '<head>' '<head> <base href="https://_THE_PUBLIC_DOMAIN_">';

This configures the relative paths to reference that domain instead. The receiving end does require to be set up to allow cors but as this is only for loading images and JS and such, you are able to define a wildcard on the allow-origin header and have the allow-credentials to be false.

robotdan commented 1 year ago

Internal: Let's review so we can either prioritize or close the issue.

mooreds commented 1 year ago

I thought that moving off of tomcat was driven in part by this feature.

ajmueller commented 10 months ago

I'm currently evaluating FusionAuth as a replacement for Auth0 and ran across this exact issue. Thank you to @fabiosimeoni and @gmpreussner for your comments above. I ended up doing exactly what Fabio did here, but had to also proxy /app. This was in a test Vue 3 app using the Vue SDK.

Our use-case is that we use a single development Auth0 tenant for local development as well as shared development and PR preview environments. Hoping for a similar architecture with FusionAuth, we want to use a single hosted FusionAuth instance for these environments. For local development the fix was in Vite config and for our other environments it will be in AWS Amplify (presumably their rewrites/redirects functionality will suffice for this, but I haven't tested that yet).

Proxying all FusionAuth traffic under a single path (e.g. /auth) would simplify our configurations greatly, but also allow us to use the paths like /images or /css for our own assets instead of FusionAuth's.

mooreds commented 10 months ago

Thanks for your feedback @ajmueller . Please don't forget to upvote the issue if you haven't already, as community votes are incorporated into our roadmap.

MikoverseAllar commented 10 months ago

wMi6ADWhCX

krtvelaz commented 4 months ago

I am using this nginx configuration deploying a pod in the same deployment of fusionAuth, so it goes out on port 8080 with the path /fa

`map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream fusionauth { server container-fusionauth:9011; } server { listen 8080; servername ;

location /fa/ {
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-Proto http;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port 8080;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Accept-Encoding "";
    sub_filter       'action="/'  'action="/fa/';
    sub_filter       'href="/'  'href="/fa/';
    sub_filter       'href="/admin/'  'href="/fa/admin/';
    sub_filter       'src="/images'  'src="/fa/images';
    sub_filter       'src="/js'  'src="/fa/js';
    sub_filter_once  off;
    proxy_pass http://container-fusionauth/;
}

location / {
    return 301 http://$host:8080/fa$request_uri;
}

} `

mooreds commented 4 months ago

Thanks @krtvelaz !

Please consider submitting this to our fusionauth-contrib repo: https://github.com/FusionAuth/fusionauth-contrib/tree/main/Reverse%20Proxy%20Configurations which has a number of reverse proxy configurations.