Reputation: 31
I am trying to build web application with latest possible technologies Jakarta Faces 4.0, OIDC Jakarta security, Elytron Oidc Client, Wildfly 27.0.1, Keycloak 21.0.2 (without adapter on wildfly).
Page works great, when i click on a secured link it redirects me to KeyCloak server loginpage for my realm, there i login and i am redirected back to the link i clicked.
Problem is when I login, then open two tabs(with secure url) and then logout in first one. In the second one all ajax click don't work anymore.
I am using omnifaces AjaxExceptionHandler.
<factory> <exception-handler-factory>org.omnifaces.exceptionhandler.FullAjaxExceptionHandlerFactory</exception-handler-factory> <exception-handler-factory>org.omnifaces.exceptionhandler.ViewExpiredExceptionHandlerFactory</exception-handler-factory></factory>
In a picture "Screenshot from 2023-04-16 21-45-22" is shown how request looks like when ajax button is pressed. Screenshot from 2023-04-16 21-45-22
On a picture "Screenshot from 2023-04-16 21-45-43" we can se a response. But because it is on ajax call I cannot use it. Screenshot from 2023-04-16 21-45-43
If i click on a new Location from header (Picture "Screenshot from 2023-04-16 21-45-22") authentication page is loaded and after successful login I get response:
<partial-response> <redirect url="/marketing_view/app/customers/index.xhtml"/> </partial-response>
On Wildfly I am using reverse proxy, so that I dont have problem with cross site scripting, when I am redirected to auth login page from ajax button and i dont want to change url when redirecting to login.
What I am thinking is that if my session is expired and I am clicking ajax button I should get <partial-response> <redirect
before http redirect on POST request. Redirect should not happen on ajax.
Can you tell me which component in Wildfly is making the response 302? I my project I have only OIDC and I am using Jakarta 10.
I would like to know what to do if ajax request is made when session is invalidated in other tab?
I also tried setting autodetect-bearer-only
and it makes a change. Redirect on POST request does not happen anymore and 401 is returned. With that setting I have a problem how to connect Jakarta Security and browser client. Ajax calls where working fine without that setting.
Upvotes: 1
Views: 478
Reputation: 606
Here is my solution based on the idea of baerer only for XHR requests. This solves the problem because bearer only requests will not be stored and presented to the user after relogin and if the session is timeout new XHR requests will be handled correctly and force a page reload to the IDP login page.
At first you need to configure the secure deployment. The important parts are autodetect-bearer-only and token-minimum-time-to-live. The first one detects automatically if the http request is a XHR request the second one refresh the token before it expires:
<subsystem xmlns="urn:wildfly:elytron-oidc-client:1.0">
<secure-deployment name="my-deployment.war">
<auth-server-url>http://localhost:8090</auth-server-url>
<ssl-required>EXTERNAL</ssl-required>
<autodetect-bearer-only>true</autodetect-bearer-only>
<realm>my-realm</realm>
<resource>my-resource-name</resource>
<token-minimum-time-to-live>60</token-minimum-time-to-live>
<credential name="secret" secret="my-secret"/>
</secure-deployment>
</subsystem>
Now add the bearer token to every XHR request and update it after a timeout to ensure not to use expired tokens. E.g for PrimeFaces 12 you can do it like this:
<!-- XHR Request needs to be bearer only so that in case of session timeout there is a correct redirect to IDP and the last XHR request to the server is not
presented to the user after relogin. See https://stackoverflow.com/a/77703420. Add the baerer token to every XHR request as Authorization header. After 45 seconds
we update the xhrBearerToken to ensure not to use expuired tokens. The interval needs to fit the token expiring time and the token-minimum-time-to-live in the oicd
client adapter needs also to fit to the update interval.
-->
<p:poll interval="45" update="xhrBearerToken" partialSubmit="true" immediate="true" ignoreAutoUpdate="true" />
<h:panelGroup id="xhrBearerToken">
<h:outputScript>
function getBearerToken() {
return '#{login.bearerToken}';
}
</h:outputScript>
</h:panelGroup>
<h:outputScript>
$(document).on('pfAjaxSend', function(xhr, settings) {
settings.setRequestHeader('Authorization', 'Bearer '+getBearerToken());
});
</h:outputScript>
Here the relevant bean methods:
public String getBearerToken() {
return getOidcSecurityContext().getTokenString();
}
public RefreshableOidcSecurityContext getOidcSecurityContext() {
return (RefreshableOidcSecurityContext) session.getAttribute(OidcSecurityContext.class.getName());
}
Here is a list of similar questions or bugs regarding this issue:
Keycloak: CORS issue after (JSF) AJAX call when the session has expired
Ajax call is redirected to keycloak page instead of returning patrial-response redirect first
https://lists.jboss.org/pipermail/keycloak-user/2016-May/006118.html
https://docs.wildfly.org/29/wildscribe/subsystem/elytron-oidc-client/secure-deployment/index.html
https://lists.jboss.org/pipermail/keycloak-user/2017-March/010010.html
https://lists.jboss.org/archives/list/[email protected]/thread/6NUOZCBZHWWN7SR6DUVVLWRKUFESGKNH/
Upvotes: 0