MOD_CLUSTER - remove sticky session - jboss

I am using mod_cluster version 1.2.11.Final along with JBoss AS 7.2.0.Final (standalone-ha-full mode)
mod_cluster is setup with sticky sessions enabled, we typically have 2 or 3 JBoss servers running at the same time and rotate servers every evening to deploy updates
When we want to shutdown a JBoss server we disable all contexts for this node using the CLI command..
/subsystem=modcluster/:disable-context(virtualhost=my-webapp,context=/)
This stops any new sessions being routed to the node ok
We then wait 30min, but sometimes after this time there are still some sessions active
I have tried forcing them to logout and also removing the JSESSIONID cookie from the responses for these users, but they are still routed back to the same JBoss node (they are issued with a new JSESSIONID)
Is it possible to command mod_cluster to remove these sticky sessions?....or force them to another worker?
(I know I can just undeploy the application, but sometimes when there are a lot of active sessions remaining this causes the other server to crash with the sudden surge in demand)
Looking forward to hearing your suggestions

For anyone else having this problem, I created a workaround by registering a #WebFilter for the path /logout, within this filter I am invalidating the session and removing the JSESSIONID cookie, I then pass a redirect URI using a query param. The user is moved over to an alternative JBoss node and redirected to their original page. You just need to redirect them to /logout when the node shutdown is detected.
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
session.invalidate();
String redirectUri = "/index.xhtml";
if(request.getParameterMap().containsKey("redirect")) {
String[] vals = request.getParameterMap().get("redirect");
if(vals.length>0) {
redirectUri = vals[0];
}
}
Cookie[] userCookies = request.getCookies();
if (userCookies != null && userCookies.length > 0 ) {
for (int i = 0; i < userCookies.length; i++) {
if(userCookies[i].getName().equals("JSESSIONID")) {
Cookie jSessionId = userCookies[i];
jSessionId.setMaxAge(0);
response.addCookie(jSessionId);
}
}
}
response.sendRedirect(redirectUri);
}

Related

Strange issue with Vertx Http request

I configured an HTTPS website on AWS, which allows visiting from a white list of IPs.
My local machine runs with a VPN connection, which is in the white list.
I could visit the website from web browser or by the java.net.http package with the below code:
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://mywebsite/route"))
.GET() // GET is default
.build();
HttpResponse<Void> response = client.send(request,
HttpResponse.BodyHandlers.discarding());
But if I replaced the code with a Vertx implementation from io.vertx.ext.web.client package, I got a 403 forbidden response from the same website.
WebClientOptions options = new WebClientOptions().setTryUseCompression(true).setTrustAll(true);
HttpRequest<Buffer> request = WebClient.create(vertx, options)
.getAbs("https://mywebsite/route")
.ssl(true).putHeaders(headers);
request.send(asyncResult -> {
if (asyncResult.succeeded()) {
HttpResponse response = asyncResult.result();
}
});
Does anyone have an idea why the Vertx implementation is rejected?
Finally got the root cause. I started a local server that accepts the testing request and forwards it to the server on AWS. The testing client sent the request to localhost and thus "Host=localhost:8080/..." is in the request header. In the Vert.X implementation, a new header entry "Host=localhost:443/..." is wrongly put into the request headers. I haven't debug the Vert.X implementation so I have no idea why it behaviors as this. But then the AWS firewall rejected the request with a rule that a request could not come from localhost.

Unity WebClient SSL Timeout

I'm working on a Unity project that is reliyng on fetching data from a web API I set up on a public webserver. The server is currently set to self-signed ssl and requires the client to send certification to be able to read the data, if the client fails to send the cert the website returns with "403 forbidden".
I've tested this in the browser and postman and everything works fine.
I've also tested the exact same function in a pure visual studio project and it worked like a charm.
However, when I try this function in Unity I am met with the WebException "The request timed out
".
The way I'm currently doing it is via a WebClient, with an overrided method of WebRequest:
private void Connect()
{
ServicePointManager.CheckCertificateRevocationList = false;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback += ignoreCertCallback;
ServicePointManager.Expect100Continue = true;
using (var wc = new CertificateWebClient())
{
try
{
var responseBytes = wc.DownloadString(url);
Debug.Log(responseBytes);
Debug.Log(wc.ResponseHeaders);
}
catch (WebException e)
{
Debug.Log(e.ToString());
}
}
}
Override of WebRequest:
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
X509Certificate2 certificate = new X509Certificate2(#"C:\temp\ClientCert.pfx", "password");
request.ServerCertificateValidationCallback = delegate (System.Object obj, X509Certificate X509certificate, X509Chain chain, System.Net.Security.SslPolicyErrors errors)
{
return true;
};
Debug.Log(request.RequestUri);
(request as HttpWebRequest).ClientCertificates.Add(certificate);
request.Timeout = 2000;
return request;
}
Important to note is that I've tried the exact same functions inside of Unity with the "client.badssl.com" and their cert, and that also worked like a charm, returning the correct error codes when no cert is sent and everything and If I turn off client certification on my website, everything also works like charm...
From What I understand, It might be Mono that might be the problem as the certification is self-signed and not from a verified CA... But i've not been able to find a workaround... so any help would be great
What are your BG settings? I mean: is it on AWS? Express/NodeJS? WebGL? I am facing the same issue but when testing locally it works like a charm
I would suggest: to check if it is an infrastructure problem you might want to create a certificate for your domain (eg 'goodboy.mytest.io") that is certified from some free SSL providers (I can say LetsEncrypt just for testing) and launch a local server that's using that certificate, then go in your "hosts" file (depending on OS that you are currently running) and mock your localhost as "goodboy.mytest.io", so you can check if connecting to that domain everything goes fine without additional layers (usually placed between connection "bouncing" on web)
I'm following up this too

Failed to connect GWT to BigCommerce API

Criteria: I'm trying to connect to a secured web service API called BigCommerce using GWT RequestBuilder.
This is my entry point:
public class GwtTest implements EntryPoint {
String url = "http://my-url-api/api/v2/products.xml"; // not the original url i'm using
#Override
public void onModuleLoad() {
url = URL.encode(url);
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
builder.setHeader("Authorization", "Basic XXX"); // I generated this from Postman app on Chrome where things work perfectly
builder.setHeader("Access-Control-Allow-Credentials", "true");
builder.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8888/");
builder.setHeader("Access-Control-Allow-Methods", "POST, GET, UPDATE, OPTIONS");
builder.setHeader("Access-Control-Allow-Headers", "x-http-method-override");
builder.setHeader("Content-Type", "application/xml");
try {
builder.sendRequest(url, new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
RootPanel.get().add(new HTML("Success: "+response.getText()));
}
#Override
public void onError(Request request, Throwable exception) {
RootPanel.get().add(new HTML("Failure (Response Error): "+exception));
}
});
} catch (RequestException e) {
RootPanel.get().add(new HTML("Failure Request Exception: "+e));
}
}
}
Errors encountered: I encounter the Same Origin Policy error at first:
Then After I disabled CORS on my browser I get the Perflight error:
Work-around: I was able to get results by disabling web security on Chrome but I don't think it's the right solution.
Trivial note: Please guide me on this one, guys, because I'm new to GWT and BigCommerce thanks.
Use a proxy servlet.
This is also the solution the GWT Openlayers wrappers uses.
https://github.com/geosdi/GWT-OpenLayers/blob/c3becee0cdd5eefdc40b18e4999c2744dc23363a/gwt-openlayers-server/src/main/java/org/gwtopenmaps/openlayers/server/GwtOpenLayersProxyServlet.java
Based on Rob Newton answer, if your application is pure front end, you can host your files on nginx and add some proxy_pass directive to your configuration, for example:
location ~* ^/bigcommerce/(.*) {
proxy_pass http://api.bigcommerce.com/$1$is_args$args;
}
So whenever you call http://hostaddress/bigcommerce/something, this will be forwared to http://api.bigcommerce.com/something. Headers are not forwared in this config, you can add more directives for that.
You could include a servlet in your webapp that acts as a proxy between the client and BigCommerce.
An alternative is to run a reverse proxy such as Apache httpd that makes requests to the BigCommerce server appear to be on the same host as your webapp.
Here is an example of an Apache httpd config file that will act as a reverse proxy for your webapp and an external service on a different host. To the browser both the webapp and the external service will appear to be running on the same host, which is what your want.
# file: /etc/httpd/conf.d/mywebapp.conf
<VirtualHost *:80>
ProxyPreserveHost On
# Forward requests to path /SomeExternalService to an external service
ProxyPass /SomeExternalService http://externalhost/
# Forward all other requests to a local webserver hosting your webapp,
# such as Tomcat listening on port 8081
ProxyPass / http://127.0.0.1:8081/
ProxyPassReverse / http://127.0.0.1:8081/
</VirtualHost>

ASP double hop request in kerberos delegation scenario

Please help!
I need my asp application to request remote systems with credentials of impersonated user. But always get 401 Unauthorized errors.
I made all configurations from here: https://support.microsoft.com/en-us/help/810572/how-to-configure-an-asp-net-application-for-a-delegation-scenario
Kerberos is configured and working in my app and my test remote app(i see kerberos tickets in fiddler). Delegation, spns and everything is configured.
Thats my code usnig System.Net.Http.httpclient:
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
using (HttpClient client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Accept.Clear();
var method = new HttpMethod("GET");
var request = new HttpRequestMessage(method, "http://testdelegationapp.avp.ru/");
var response = client.SendAsync(request).Result;
}
In fact http request is made by Apppool account (I get 401 error when restricting access to Apppool account in remote app IIS)
Here: How to get HttpClient to pass credentials along with the request?
is claimed that HttpClient cant pass security token to another thread, and its better to use synchronous methods of System.Net.WebClient
Code using webclient:
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
try
{
string URI = "http://testdelegationapp.avp.ru/";
using (WebClient wc = new WebClient())
{
wc.UseDefaultCredentials = true;
string response = wc.DownloadString(URI);
}
}
finally
{
wic.Undo();
}
Result is even worse, the same 401 error, but in fiddler i can see that webclient using NTLM ticket to get to remote app!
Configuring of flowing tokens throw threads from here :Unable to authenticate to ASP.NET Web Api service with HttpClient
doesnt help either. SecurityContext.IsWindowsIdentityFlowSuppressed() is false.
WindowsIdentity.GetCurrent().Name and Thread.CurrentPrincipal.Identity.Name shows impersonated user as it should be.
All that time problem was in chrome browser, by default it prohobits kerberos delegation. You shoud add the following to registry:
Path: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome ;
string: AuthNegotiateDelegateWhitelist ;
value: *.avp.ru
So, now my working configuration is
HttpClient for web requests.
ASP impersonation ON in IIS if you want to execute all your app under
delegated credentials. If you want method specific delegation, then use:
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
wic.Undo();
HttpClient executes request in another thread , so in aspnet_config.config we need following changes:
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
You can find aspnet_config.config in:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\aspnet.config
C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet.config

GWT Client files in one Server & GWT Servlets in other Server

I'm trying to separate GWT Client & Server. If i'm not wrong, GWT client code is getting server reponses by connecting to the servlet we mentioned in GWT Project's web.xml. If So, can i host my GWT Servlets in one Tomcat Server & GWT Client code in other tomcat server ..?
Will it work ..? If so how to do that, i have already tried something working with hosted.html in GWT Client files. But it didn't worked
Yes, you can host client files in any web-server since they are static stuff, actually what you need is to pick your index.html, the .nocache.js and all the *.cache.(js|html) files and put them in any web server (apache, nginx, iis, jetty, etc).
You could even replace the index.html by any other html generator like php, jsp etc.
But of course the server side should be hosted in a servlet container.
What you have to be aware about, is that when the server with your static files are in a different domain than the servlet server, ajax requests will fail because of security constrains (see CORS).
To avoid that restriction there are many ways in gwt (gwtquery-jsonp, gwt-xdm, etc).
What I'm using is a filter (see code above) able to enable CORS when an options request is received.
You have to modify your client code as well to configure correctly the url of the servlet-container. Here is an example for changing the url with RequestFactory.
Client side code for RF:
myFactory = GWT.create(MyRFFactory.class);
DefaultRequestTransport transport = new DefaultRequestTransport();
transport.setRequestUrl("http://my.servletcontainer.com/gwtRequest");
myFactory.initialize(eventBus, transport);
web.xml configuration
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>my.namespace.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Server filter
public class CORSFilter implements Filter {
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String o = req.getHeader("Origin");
if ("options".equalsIgnoreCase(req.getMethod())) {
resp.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
if (o != null) {
resp.addHeader("Access-Control-Allow-Origin", o);
resp.addHeader("Access-Control-Allow-Methods",
"POST, GET, OPTIONS");
resp.addHeader("Access-Control-Allow-Headers",
"content-type,pageurl,x-gwt-permutation");
resp.setContentType("text/plain");
}
resp.getWriter().flush();
return;
}
if (o != null) {
resp.addHeader("Access-Control-Allow-Origin", o);
}
if (filterChain != null) {
filterChain.doFilter(req, resp);
}
}
#Override public void destroy() {
}
#Override public void init(FilterConfig arg0) throws ServletException {
}
}
The same question has been asked in the past.
gwt-split-client-and-server
What you can do is use the servlet as a proxy to another server, where you have implemented your model logic.