I wanted to add a custom servlet extension to Keycloak which would install a http handler that gets invoked on every request sent to Keycloak and sets up some logging MDC context that our custom SPI code can use for logging the incoming request traces correctly.
Following the docs here I created a custom extension class:
public class UndertowHandlerExtension implements ServletExtension {
#Override
public void handleDeployment(DeploymentInfo deploymentInfo, ServletContext servletContext) {
deploymentInfo.addInnerHandlerChainWrapper(TraceIdCapturingHandler::new);
}
}
And have defined my custom http handler TraceIdCapturingHandler in the same JAR file. I also added a file to META-INF/services/io.undertow.servlet.ServletExtension and set the fully qualified reference to the extension class. I also updated my deployments jboss-deployment-structure.xml and added the following 2 entries as dependencies:
<module name="io.undertow.servlet" />
<module name="javax.servlet.api" />
However, when my deployment is created the extension is not being invoked and my filter is not executing. Is there something I am missing in terms of how to configure Wildfly for Keycloak so that my extension and handler are installed and used correctly?
EDIT:
After doing a bit of digging I realized I was headed down the wrong path. Looked at this repository and I think I need a custom RealResourceProvider as shown here which in turn can install my filter by obtaining an instance of ResteasyProviderFactory and invoking getContainerRequestFilterRegistry().registerSingleton().
Will try this out and report back.
Please see the edit above for my question. I was able to implement a RealmResourceProviderFactory instance that initialized the filters I needed on startup in the init() method:
#Override
public void init(Config.Scope scope) {
log.info("Initializing");
initializeKeycloakFilters();
}
private void initializeKeycloakFilters() {
ResteasyProviderFactory providerFactory = ResteasyProviderFactory.getInstance();
TraceIdCapturingFilter filter = new TraceIdCapturingFilter();
providerFactory.getContainerRequestFilterRegistry().registerSingleton(filter);
}
I would like to configure my project to not allow http requests with the following restrictions:
It must be a global restriction for all APIs (via web.config, script in the installer, etc.)
It must be hard coded(not pressing "Require SSL" on the APP in the IIS)
No "redirect"- just return error (403)
my ideal option would be to configure "Require SSL" by a script which runs in the installer.
This can be accomplished by writing a simple ActionFilter that inspects the request and responds when the scheme is not set to ssl. A very minimal implementation may look something like:
public class RequireHttpsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
}
}
}
To make this apply everywhere, you'll likely want to register it as a global filter in the WebAPI configuration when your application is bootstrapping. That would look something like:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new RequireHttpsAttribute());
// ... More configuration ...
}
}
If you search the web a bit, you can find many examples of similar filters with more robust logic that may better meet your needs.
I'm trying to have signalR hub as part of a plugin using MEF. But after calling ImportMany on a List<> object and then adding the catalog/container/ComposeParts part in the Application_Start() method of the Global.asax file, all I get is :
Uncaught TypeError: Cannot read property 'server' of undefined.
I've got no clue if the problem comes from my interface, the plugin, the global.asax file, or the javascript.
The interface:
public interface IPlugin
{
}
the plugin:
[Export(typeof(IPlugin))]
[HubName("testHub")]
public class TestHub : Hub, IPlugin
{
public string Message()
{
return "Hello World!";
}
}
in the Global.asax file:
[ImportMany(typeof (IPlugin))]
private IEnumerable<IPlugin> _plugins { get; set; }
protected void Application_Start()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(#"./Plugins"));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
RouteTable.Routes.MapHubs();
//log4net
log4net.Config.XmlConfigurator.Configure();
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
and finally the javascript:
$(document).ready(function () {
$.connection.hub.url = 'http://127.0.0.1/signalr/';
var proxy = $.connection.testHub;
$.connection.hub.start({ transport: ['webSockets', 'serverSentEvents', 'longPolling'] })
.done(function () {
proxy.invoke('Message').done(function(res) {
alert(res);
});
})
.fail(function () { alert("Could not Connect!"); });
});
the only information I've found was this post but I could not make it work. everything works fine when I add the reference manually, but when I have a look at "signalr/hubs" after loading the plugin, then there is not reference to my hub's method.
Thanks a lot for your help.
Your problem is that SignalR caches the generated "signalr/hubs" proxy script the first time it is requested. SignalR provides the cached script in response every subsequent request to "signalr/hubs".
SignalR not only caches the script itself, but it also caches the collection of Hubs it finds at the start of the process.
You can work around the cached proxy script issue by simply not using the proxy script, but that still won't enable you to actually connect to Hubs defined in assemblies that are loaded after the process starts.
If you want to be able to connect to such Hubs, you will need to implement your own IHubDescriptorProvider that is aware of Hubs defined in plugins loaded at runtime.
You can register your provider with SignalR's DependencyResolver which can be passed into SignalR via the Resolver property of the HubConfiguration object you pass into MapSignalR.
That said, it would probably be easier to restart the app pool/server process whenever a plugin is added to the "./Plugins" directory.
I'm attempting to use capabilities provided by maven profiles to build customized builds for different server environments. What I'm attempting to do is combine maven resource filtering
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
with it's profile mechanism
<profiles>
<profile>
<id>mock</id>
<properties>
<application-url>http://mock-server-url</application-url>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
to convert this value in a file named server.cfg
${application-url}
to something I can use here:
public interface ServerResource extends ClientBundle {
public static final ServerResource INSTANCE = GWT.create(ServerResource.class);
#Source("server.cfg")
public TextResource server();
}
I can see that the value's been replaced in WEB-INF/classes but it doesn't appear that GWT used the file with the replacement to create the application javascript. How can I do this?
Using GWT compiler permutations to apply this kind of configuration is in my opinion a very bad idea. One of the most common complaints about GWT is the time it takes to compile, and by doing this you're just adding to the problem.
Configuration should usually be read from configuration files (surprise!), like shown here.
Anyway, what you're trying to do seems to me impossible. You cannot tell the client-side code to which server it should connect. This would violate the same-origin policy! The app can only communicate with the server it came from.
To have different apps running in different URLs, you would need to deploy several GWT apps with different names (even if they are basically the same). Then, you would just have to type the correct URL for each app (version) in the browser, and it will "look" at the right app. So you could have URLs like this:
http://myserver.com/app1
http://myserver.com/app2
In order to make a request to a different app running in the same server as the GWT application, you can do something like this:
String serviceUrl = "/app2/someService"; // or some other String sourced from a config file, using a GWT ClientResource for example
RequestBuilder rb = new RequestBuilder(RequestBuilder.GET,
serviceUrl);
try {
// send request from app1 to app2
rb.sendRequest(null, new RequestCallback() {
#Override
public void onResponseReceived(Request request,
Response response) {
log.info("Response: " + response.getStatusText());
// if response is 200 it's ok, you can read the outputStream to see what's in there
}
#Override
public void onError(Request request, Throwable exception) {
log.warning("Request Error", exception);
// do something more
}
});
} catch (RequestException e) {
log.warning("Request Exception", e);
// getting here means trouble with the connection or service!
}
I solved what I was trying to accomplish without the use of maven profiles or the GWT ClientBundle (which I never did get to work in the way I had intended when I wrote the question).
Here were the main issues I hoped to solve using maven profiles and the workaround I employed to solve the issue at hand:
Use Mock MVP Models in Hosted Mode
// inside the initialization for my model locator
boolean hostedMode = GWT.getPermutationStrongName().equals("HostedMode");
if (hostedMode) {
// instantiate mock models
} else {
// instantiate real models to call REST web services
}
Provide real models with correct RESTful server URL
I was able to accomplish this because my GWT app and the RESTful web service url follow a set naming convention. I basically strip the trailing '/' from the URL and append '_services"
String createServicesBaseUrl() {
StringBuffer baseUrl = new StringBuffer(GWT.getHostPageBaseURL());
int length = baseUrl.length();
baseUrl.replace(length-1, length, "_services");
return baseUrl.toString();
}
Enable testing of as much of the MVP Presenter (Activities & Places) as I could
I was already injecting the model locator into my Activity classes, so replacing that with a mock model locator for use by JUnit was straightforward. I did the same for my views and abstracted away some of the other code which didn't seem to work outside of the browser (like the GWT PlaceController).
All in all my build is much the same, but I learned how to gain a lot of flexibility in testing, configuring the server instance my GWT application connects with, and which model my application uses (dependent on hosted vs server mode).
I am debugging a GWT application and I need to print some stuff to the console for testing purposes. System.out.println and GWT.log don't work. Does anyone have any ideas?
Quoting the documentation:
Adding GWT logging is really quite simple, as simple as the following code example. However — understanding how logging works, and
how to correctly configure it is important, so please do take the time
to read the rest of this document.
http://code.google.com/webtoolkit/doc/latest/DevGuideLogging.html
The simplest way to enable logging is:
# In your .gwt.xml file
<inherits name="com.google.gwt.logging.Logging"/>
# In your .java file
Logger logger = java.util.logging.Logger.getLogger("NameOfYourLogger");
logger.log(Level.SEVERE, "this message should get logged");
I needed to do this in the context of a GWT application that was deployed to an Android device/emulator via PhoneGap (and gwt-phonegap). Neither System.out.println() nor GWT logging as above (with module declaration) showed up in Android's logcat, so I resorted to a simple JSNI wrapper to console.log:
public void onModuleLoad()
{
Logger logger = Logger.getLogger("Test1.java");
logger.log(Level.INFO, "ash: starting onModuleLoad (1)"); // not in logcat
System.out.println( "ash: starting onModuleLoad (2)" ); // not in logcat
consoleLog( "ash: starting onModuleLoad (3)" ); // This shows up
...
}
native void consoleLog( String message) /*-{
console.log( "me:" + message );
}-*/;
To log to browsers console you can do it using native, in a very simple way. Very helpful in debugging.
If you add a native method like in below, you can send a string to it from where you want and it will log it in the browsers console.
public static native void console(String text)
/*-{
console.log(text);
}-*/;
For more information about using native in GWT:
http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html
In GWT version 2.6.0, method GWT.log writes message to browser console, you don't need to write native methods.
Just summing up the different possibilities shown in the answer's of mreppy and Strelok in one snippet. I also added one possible workaround for IE exceptions as described here: Why does JavaScript only work after opening developer tools in IE once?
java.util.logging.Logger logger = Logger.getLogger(this.getClass().getSimpleName());
native void jsConsoleLog(String message) /*-{
try {
console.log(message);
} catch (e) {
}
}-*/;
private void log(final String message) {
// Logs to Dev mode console only
GWT.log(message);
// Logs to Dev mode and JavaScript console (requires configuration)
this.logger.log(Level.FINEST, message);
// Logs to JavaScript console only
jsConsoleLog(message);
Yet another variation using the native console...
Add this class:
package XXX.XXX.XXX.XXX;
public class Debug {
private static boolean isEnabled_ = false;
public static void enable() { isEnabled_ = true; }
public static void setEnabled( final boolean isEnabled )
{ isEnabled_ = isEnabled; }
public static void log( final String s )
{ if( isEnabled_ ) nativeConsoleLog( s ); }
private static native void nativeConsoleLog( String s )
/*-{ console.log( s ); }-*/;
}
Then, enable debugging with it at some point, like upon starting the app:
public class XXXXXX implements EntryPoint {
#Override
public void onModuleLoad() {
Debug.enable();
...
}
}
Then just use it like so:
Debug.log("Hello World!");
I had this problem as well. The GWT log works but because it's all converted to javascript, it prints to the client output, so just view your browser's console and they will be there. In Google Chrome click the triple-line Customize button in the top right, click Tools-->Developer tools and the console will pop up. Your sought-after statements will be there. Also, Ctrl+Shift+I is the shortcut that brings it up. If you want to print to the server, I believe logger handlers and such are in order?
The documentation url in the first answer already gives the different configuration option to log to different places.
This framework i wrote offers you a usefull api and allows you to choose your server-side logging implementation.
Have a look :
https://code.google.com/p/gwt-usefull-logging/
I suggest you use GWT Developer mode It adds a little overhead cause the automatic compilation and code-allocating on the code server, but it's pretty clear when some exceptions arises in client side of your application. I mean, some times chrome console (or firebug or whatever browser debugging built-in tool) doesn't say too much in those situations, trust me, finding a NullPointerException is a pain in the neck when you try to figure out what is happening by alerting your code.
For printing to the browser console I am using something like this:
EventLogger.java
public class EventLogger {
public static void logEvent(String subsys, String grp, String type) {
logEvent(GWT.getModuleName(), subsys, grp,
Duration.currentTimeMillis(), type);
}
public static native void logEvent(String module, String subsys,
String grp, double millis, String type)
/*-{
if ($wnd.__gwtStatsEvent) {
$wnd.__gwtStatsEvent({
'moduleName':module,
'subSystem':subsys,
'evtGroup':grp,
'millis':millis,
'type':type
});
}
}-*/;
}
You can put alaert.Alert(""); in your gwt code compile it and run it you will get pop up on browser when you make request or at the action where you have placed that alert