HAProxy http-request redirect a specific path to another path
Asked Answered
O

1

7

I am quite familiar with the HTTP protocol and a little bit of HAProxy, but I have never really messed with URL rewrites and redirects before. Now, I have 2 "simple" HTTP redirect requirements which I have been having a hard time figuring out.

  1. https://appserver.example.com should be redirected to https://appserver.example.com/myapp/webapp/?auth=saml to point the user to saml login page.
  2. https://appserver.example.com/?auth=standard should be redirected to https://appserver.example.com/myapp/webapp/?auth=standard

Requirement 1 works fine:

myuser:~ myuser$ curl -I https://appserver.example.com
HTTP/1.1 301 Moved Permanently
Content-length: 0
Location: https://appserver.example.com/myapp/webapp/?auth=saml
Connection: close

myuser:~ myuser$ 

But I am having a hard time on how to implement #2. The key to this, as I thought, is to add an acl, then another http-request redirect prefix line when the acl is matched.

acl is_auth_std path /?auth=standard
http-request redirect prefix /myapp/webapp/?auth=standard code 301 if is_auth_std

But apparently this is not enough. /?auth=standard still redirects to the supposed root URL:

myuser:~ myuser$ curl -I https://appserver.example.com/?auth=standard
HTTP/1.1 301 Moved Permanently
Content-length: 0
Location: https://appserver.example.com/myapp/webapp/?auth=saml
Connection: close

myuser:~ myuser$

These are the relevant sections of my haproxy.cfg file:

frontend myapp443-in
    mode http
    bind *:443 ssl crt /etc/haproxy/ssl/myapp.pem
    default_backend myapp443-out
    option forwardfor

    timeout client          60m
    timeout http-keep-alive 10s
    timeout http-request    5s
    timeout tarpit          60s

    acl is_websocket path_beg /myapp/webapp/
    acl is_websocket hdr(Upgrade) -i WebSocket
    acl is_websocket hdr_beg(Host) -i ws

    acl is_root path /

    capture request  header Host len 64

    http-request redirect scheme https code 301 if !{ ssl_fc }
    http-request redirect code 301 location https://%[hdr(host)]/myapp/webapp/?auth=saml if is_root
    acl is_auth_std path /?auth=standard
    http-request redirect prefix /myapp/webapp/?auth=standard code 301 if is_auth_std

backend myapp443-out
    cookie SRVID insert indirect nocache maxidle 30m maxlife 1h
    option forwardfor
    balance leastconn

    option ssl-hello-chk

    option httpchk GET /myapp/webapp/img/favicon.ico
    http-check expect status 200
    default-server inter 1s downinter 3s rise 15 fall 15
    timeout check 1s

    timeout server          60s
    timeout tunnel        3600s
    timeout queue           30s
    timeout connect          5s

    http-request add-header X-Forwarded-Proto https if { ssl_fc }

    redirect scheme https if !{ ssl_fc }

    http-response add-header Strict-Transport-Security max-age=31536000;\ includeSubdomains
    http-response add-header X-Content-Type-Options nosniff
    http-response add-header X-XSS-Protection 1;\ mode=block
    http-response add-header Referrer-Policy no-referrer
    http-response add-header Feature-Policy accelerometer\ 'none';\ ambient-light-sensor\ 'none';\ autoplay\ 'none';\ camera\ 'none';\ display-capture\ 'none';\ document-domain\ 'none';\ fullscreen\ 'none';\ execution-while-not-rendered\ 'none';\ execution-while-out-of-viewport\ 'none';\ gyroscope\ 'none';\ magnetometer\ 'none';\ microphone\ 'none';\ midi\ 'none';\ payment\ 'none';\ picture-in-picture\ 'none';\ publickey-credentials\ 'none';\ sync-xhr\ 'none';\ usb\ 'none';\ wake-lock\ 'none'

    server appserver-01 appserver-01:8443 weight 5 check ssl verify none cookie s1
    server appserver-02 appserver-02:8443 weight 5 check ssl verify none cookie s1

Any ideas what I am missing?

Thanks.

Octavia answered 4/6, 2020 at 13:8 Comment(1)
Try to use url fetch method instead of path. url concatenates the path and the query string.Phylogeny
W
4

You will need to use url_param to match params in the query string.

frontend myapp443-in
    mode http
    bind *:443 ssl crt /etc/haproxy/ssl/myapp.pem

    option forwardfor

    timeout client          60m
    timeout http-keep-alive 10s
    timeout http-request    5s
    timeout tarpit          60s

    # if not https => redirect, no need to check acls
    http-request redirect scheme https code 301 if !{ ssl_fc }

    acl is_websocket path_beg /myapp/webapp/
    acl is_websocket hdr(Upgrade) -i WebSocket
    acl is_websocket hdr_beg(Host) -i ws

    acl is_root path /

    acl is_not_auth_std url_param(auth) ! standard
    acl is_not_auth_saml url_param(auth) ! saml

    capture request  header Host len 64

    http-request redirect code 301 location https://%[hdr(host)]/myapp/webapp/?auth=standard if is_not_auth_std is_not_auth_saml

    http-request redirect code 301 location https://%[hdr(host)]/myapp/webapp/?auth=saml if is_root

    default_backend myapp443-out

The redirect prefix append a / which you maybe not want

Weald answered 4/6, 2020 at 21:42 Comment(6)
Thanks, I did try this, but I am still getting the same HTTP response.Octavia
Interesting because I have run some curls and I got the poper redirect curl -v 'http://127.0.0.1:8080/?auth=standard' => location: https://127.0.0.1:8080/myapp/webapp/?auth=standard. curl -v 'http://127.0.0.1:8080/' => location: https://127.0.0.1:8080/myapp/webapp/?auth=saml. Maybe you will need to rearrange the conf. I will update the answer with the whole frontendWeald
Thanks for this, but the browser fails with ERR_TOO_MANY_REDIRECTS. I would guess this happens since acl is_auth_std url_param(auth) standard takes in auth=standard regardless of the path. Any other way to consider the whole path /?auth=standard? ThanksOctavia
Ah yes you don't want to redirect when auth=standard is already set. I have updated the answer with is_not_* linesWeald
@Octavia doesn't the last adoption answer your question?Weald
i was supposed to add a rule/question to the post, hence the bounty, but forgot about it! :( anyway, your answer is enough for the concerns on the post, so thanks a lot!Octavia

© 2022 - 2024 — McMap. All rights reserved.