Search code examples
quarkus

OIDC authorization handling if webrequest is POST


We have 2 applications and they are connected via an IFrame integration where application A is constructing a POST request (form submit) to application B. Everything works fine if user is authorized already in application B. In case the user is not authorized in application B.

  1. Application A constructs POST request for application B
  2. User is redirected to OIDC provider (our case Microsoft)
  3. Redirected back to callback url of application B and redirected to previous original page
  4. Page is blank as step 3 is not passing the body from step 1. Page is retrieved via GET not POST

I understand that this is how OIDC should work but I have to get it working. What I have tried already is to create RouteFilter with 1000 priority. This is the latest state of my code but body is always null.

Quarkus version: 2.16.12


    @Inject
    CurrentVertxRequest request;

    @RouteFilter(1000)
    void myFilter(RoutingContext rc) {
        Buffer body = request.getCurrent().request().body().result();
        rc.response().headersEndHandler(new Handler<Void>() {
            @Override
            public void handle(Void event) {
                int statusCode = rc.response().getStatusCode();
                if (statusCode == 401) {
                    rc.redirect("back").result();
                }
                if (rc.request().path().endsWith(LaunchHtml.PATH)) {
                    if (statusCode == 302 || statusCode == 401 || statusCode == 403) {
                        if (result != null) {
                            String key = UUID.randomUUID().toString();
                            rc.response().addCookie(new CookieImpl(PREVIOUS_PAYLOAD, key));
                            PAYLOAD_STORE.put(key, body.toString());
                        }
                    }
                }
            }
        });
        rc.next();
    }

Solution

  • If somebody else needs to "hack" it - here is a solution.

      @RouteFilter(1000)
    void myFilter(RoutingContext rc) {
        String key = UUID.randomUUID().toString();
        if (rc.request().method() == HttpMethod.POST && rc.request().path().endsWith(LaunchHtml.PATH)) {
            rc.response().addCookie(new CookieImpl(PREVIOUS_PAYLOAD, key));
        }
        rc.response().headersEndHandler(new Handler<Void>() {
            @Override
            public void handle(Void event) {
                int statusCode = rc.response().getStatusCode();
                if (rc.request().path().endsWith(LaunchHtml.PATH)) {
                    if (statusCode == 302 || statusCode == 401 || statusCode == 403) {
                        RouterImpl router = new RouterImpl(null);
                        RoutingContext routingContext = new RoutingContextImpl(rc.mountPoint(), router, rc.request(), Sets.newHashSet()) {
                            @Override
                            public void next() {
                                Buffer result = body().buffer();
                                if (result != null) {
                                     PAYLOAD_STORE.put(key, result.toString());
                                }
                            }
                        };
                        BodyHandler.create().handle(routingContext);
    
                    }
                }
            }
        });
        rc.next();
    }
    

    BodyHandler is not getting called if authentication fails and user is redirected to OIDC provider. Therefore I am calling it myself in self-created routing context. I was hoping for nicer design but BodyHandler is calling at the end next() on RoutingContext. I would opt rather for utility method.