Jetty 8.1.9.v20130131 Web Socket issues - websocket

I do have a strange problem with jetty 8 websockets. I found several tutorials that pretty much show the same code, yet I get this error when I try to open the websocket from a local html page:
2013-02-05 13:14:03.467:INFO:oejs.Server:jetty-8.1.9.v20130131
2013-02-05 13:14:03.770:INFO:oejs.AbstractConnector:Started SelectChannelConnector#0.0.0.0:8080
2013-02-05 13:14:18.002:WARN:oejs.ServletHandler:/echo
java.lang.NullPointerException
at org.eclipse.jetty.websocket.WebSocketFactory.upgrade(WebSocketFactory.java:236)
at org.eclipse.jetty.websocket.WebSocketFactory.acceptWebSocket(WebSocketFactory.java:382)
at org.eclipse.jetty.websocket.WebSocketServlet.service(WebSocketServlet.java:104)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:457)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
Here is the Socket servlet:
public class ExampleWebSocketServlet extends WebSocketServlet {
private static final long serialVersionUID = 1L;
/**
* #see WebSocketServlet#WebSocketServlet()
*/
public ExampleWebSocketServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("OK");
out.close();
System.out.println("OK");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
getServletContext().getNamedDispatcher("default").forward(request, response);
}
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
return new EchoWebSocket();
}
}
and the WebSocket (for a simple Echo)
public class EchoWebSocket implements WebSocket.OnTextMessage {
private Connection con;
#Override
public void onClose(int closeCode, String message) {
}
#Override
public void onOpen(Connection con) {
this.con = con;
try {
con.sendMessage("Server received Web Socket upgrade ...");
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onMessage(String msg) {
System.out.println("Received: "+msg);
try {
con.sendMessage(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //send it back
}
}
My html page works fine with other websocket test servers, e.g. websocket.org
What could be wrong? I am on Eclipse, created a dynamic web project and use the jetty webapp run configuration. Also, when jetty starts up i can see that
/Users/sven.haiges/dev/jetty/jetty-distribution-8.1.9.v20130131/lib/jetty-websocket-8.1.9.v20130131.jar
is on the classpath.
Any help appreciated,thx!

I had a same problem with Run Jetty Run plugin. finally found solution.
go to run configuration
select your project name under jetty webapp on left panel
select jetty version 8.1 on right side under Jetty Tab
Apply / Run
that's all

Try using the Jetty 8.1.8 version.
Today, I had an issue creating a simple servlet via #WebServlet annotation. The jetty server did not respond and I could not figure out why. But when I suddenly changed back to version 8.1.8, everything worked fine.
Maybe it's a similar problem.

Related

How Can I Mock A Specific URL Path?

I am using okhttp to mock my http responses during my tests.
//Create a mock server
mockWebServer.start(8080)
mockWebServer.enqueue(MockResponse().setBody("").setResponseCode(HttpURLConnection.HTTP_OK))
However, this responds to every path as OK.
How do I mock a specific url instead of all of them?
Using Dispatcher
Dispatcher dispatcher = new Dispatcher() {
#Override
public MockResponse dispatch(RecordedRequest request) {
switch (request.getPath()) {
case "/get":
return new MockResponse().setResponseCode(200).setBody("test");
}
return new MockResponse().setResponseCode(404);
}
};
mockBackEnd.setDispatcher(dispatcher);
Above can be written inside your test method. You can have a bunch of URLs conditions there.
The mockwebserver can be started once like:
public static MockWebServer mockBackEnd;
#BeforeAll
static void setUp() throws IOException {
mockBackEnd = new MockWebServer();
mockBackEnd.start();
}
#AfterAll
static void tearDown() throws IOException {
mockBackEnd.shutdown();
}
Use #DynamicPropertySource to change any property with mockserver host/port.

Consume SOAP service using Quarkus

My project requirement is to consume a SOAP service and I am trying to use Quarkus for this purpose. What are the quarkus dependecies hwould I use to acheive this? Is there any sample application I can refer to?
In Spring we can use org.springframework.ws.client.core.support.WebServiceGatewaySupport is there anything similiar in Quarkus.
There is no SOAP client extension at the moment in Quarkus.
There is some discussion to include a CXF extension here : https://github.com/quarkusio/quarkus/issues/4005, you can join the discussion.
A PR is open (not yet finished) for SOAP WS support via CXF but not for SOAP client: https://github.com/quarkusio/quarkus/pull/5538
If you didn't plan to deploy to GraalVM (Quarkus can be deployed both in standard JVM mode and on GraalVM/SubstrateVM as a native application) you can still use any Java library with Quarkus but you will not have any integration with Quarkus itself. So using the CXF Client should works fine in JVM mode : https://cxf.apache.org/docs/how-do-i-develop-a-client.html
we have a new version on https://github.com/quarkiverse/quarkiverse-cxf that you can used for native. It is in beta and can be reference with maven central.
It can be done like #loicmathieu said.
In our realization we have Controller :
#Slf4j
#Path("/xxx")
public class EKWReactiveResource {
#Inject
RequestObject2WsdlRequestObjectConverter converter;
#POST
#Path("/xxxx")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_XML)
public Uni<Response<XsdResponseObject>> wyszukajKsiege(RequestObject request) {
return Uni.createFrom().item(request)
.onItem()
.invoke( req -> log.info(req.toString()))
.map(converter::convert)
.onItem()
.apply(ServiceClient::send);
}
}
ServiceClient :
#Slf4j
public final class ServiceClient {
private final static String ENDPOINT_HTTP = "XXXX";
private final static QName SERVICE_QNAME = new QName("XXXX", "XXXX");
private final static QName SERVICE_QNAME2 = new QName("XXXX", "XXXX");
private static XXXPortType portType;
static {
try {
URL endpointUrl = new URL(ENDPOINT_HTTP);
XXXService service = new XXXService(endpointUrl ,SERVICE_QNAME);
portType = service.getPort(SERVICE_QNAME2, XXXPortType.class);
} catch (MalformedURLException e) {
log.error(e.getMessage(), e);
}
}
public static Response<XsdResponseObject> send(RequestObject requestType) {
return portType.EndpointAsync(requestType);
}
}
And after this we must define ResponseMessageBodyWriter for AsyncResponseImpl> because for some reason it is unknown.
MessageBodyWriter example - you should better write isWriteable method i just dont do this perfectly because this is example only :
#Slf4j
#Provider
#Produces(MediaType.APPLICATION_XML)
public class XXXMessageBodyWriter implements MessageBodyWriter<AsyncResponseImpl<XsdResponseObject>> {
#Override
public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return AsyncResponseImpl.class.isAssignableFrom(aClass);
}
#Override
public void writeTo(AsyncResponseImpl<XsdResponseObject> asyncResponse, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
try {
XsdResponseObject responseObject = asyncResponse.get();
String marshalled = JAXBUtils.marshallToSOAP(responseObject);
log.info(String.format("Response : %s",marshalled));
outputStream.write(marshalled.getBytes());
} catch (InterruptedException | ExecutionException | JAXBException | ParserConfigurationException | SOAPException e) {
log.error(e.getMessage(),e);
}
}
}

Apache Camel based Udp server

I'm trying to use Apache Camel to create udp server which consumes syslog messages.
There are no examples how to do it correctly.
I wrote following route, which use custom serverInitializerFactory.
#Component
public class MainRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("netty4:udp://{{app.server.host}}:{{app.server.port}}?serverInitializerFactory=#udpSyslogFlowFactory&sync=false&textline=true")
.to("seda:rowLogs");
from("seda:rowLogs?concurrentConsumers={{app.concurrent-processors}}")
.to("bean:logParser");
}
}
Code of factory:
#Component
public class UdpSyslogFlowFactory extends ServerInitializerFactory {
private int maxLineSize = 1024;
private NettyConsumer consumer;
public UdpSyslogFlowFactory() {
super();
}
public UdpSyslogFlowFactory(NettyConsumer consumer) {
this();
this.consumer = consumer;
}
#Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline channelPipeline = ch.pipeline();
channelPipeline.addLast("encoder-SD", new StringEncoder(StandardCharsets.UTF_8));
channelPipeline.addLast("decoder-DELIM",
new DelimiterBasedFrameDecoder(maxLineSize, true, Delimiters.lineDelimiter()));
channelPipeline.addLast("decoder-SD", new StringDecoder(StandardCharsets.UTF_8));
channelPipeline.addLast("handler", new ServerChannelHandler(consumer));
}
#Override
public ServerInitializerFactory createPipelineFactory(NettyConsumer consumer) {
return new UdpSyslogFlowFactory(consumer);
}
}
It looks like incoming udp messages don't processed by references StringDecoder.
Anybody can provide full example of UDP Server with Camel which use simple text decoding of all incoming messages?
Instead of building the syslog-consumer and decoder by yourself, have a look at the Camel syslog DataFormat.
On the linked documentation page you can find syslog-consumer examples with netty and mina components.

Using PERMESSAGE_DEFLATE causing native memory leak in JETTY9.3.11

We are using jetty version 9.3.11 Version jetty container for deploying our application
we are using tyrus client for connecting client to websocket server that we have deployed.
when i connect using the following code:
WebSocket ws = null;
try {
ws = new WebSocketFactory().createSocket(server)
.addListener(new NotifierAdapter(userId, channel))
.addExtension(WebSocketExtension.PERMESSAGE_DEFLATE).connect();
} catch (WebSocketException we) {
connect(server, userId, channel);
}catch(Exception e)
{
e.printStackTrace();
}return ws;
Around 8000 connections my machine was taking 40% Memory
But with the sight modification of code(removing deflate extension)
try {
ws = new WebSocketFactory().createSocket(server)
.addListener(new NotifierAdapter(userId, channel))
.connect();
} catch (WebSocketException we) {
connect(server, userId, channel);
}catch(Exception e)
{
e.printStackTrace();
}return ws;
Was able to connect to 15000 connections with only 15% Memory
Is there any leak with respective to deflaters even in latest version of Jetty server..
Is there any way to disable PERMESSAGE_DEFLATE in server side of jetty..
Also we are using spring websocket passing jettyrequestupgrade strategy
Spring config code is as follows:
#Configuration
#EnableWebMvc
#EnableAspectJAutoProxy
#EnableWebSocket
public class WebMVCConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
private static final String NOTIFIER_ENDPOINT_URL = "/notificationHandler";
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(socketHandler(), NOTIFIER_ENDPOINT_URL).setAllowedOrigins("*");
}
#Bean
public WebSocketHandler socketHandler() {
return new NotificationSocketHandler();
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public DefaultHandshakeHandler handshakeHandler() {
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setInputBufferSize(8192);
policy.setIdleTimeout(600000);
WebSocketServerFactory ws=new WebSocketServerFactory(policy);
ws.getExtensionFactory().unregister("permessage-deflate");
return new DefaultHandshakeHandler(new JettyRequestUpgradeStrategy(ws));
}
}
Although i did un register of permessage-deflate when i connect from browser in response header i can see that flag still enabled any other changes should be made in containter for this??
Or is there any problem with spring websocket configuration:
Also response header is as follows:
Connection:Upgrade
Sec-WebSocket-Accept:xbbUnu7pDWs9Q0st4T1LzsIfqao=
Sec-WebSocket-Extensions:permessage-deflate
Upgrade:WebSocket
I think the bug below havent been resolved yet.
https://github.com/eclipse/jetty.project/issues/293
Is there any workaround for this(Explicit configuration in jetty server to disable PERMESSAGE_DEFLATE in jetty server container or spring config for Jetty
After searching i couldnt find any solution on server container/code configuration with spring websocket was not working ..
As a workaround i wrote a interceptor which will remove the parameter Sec Websocket entension from the header..so that server will send response without this extension
The reason for the memory leak is a JVM bug with Deflate implementations in the JVM Classpath.
Setting up an ObjectPool just delays the inevitable, it will just slow down the memory leak.
If you have access to the WebSocketServletFactory then ...
factory.getExtensionFactory().unregister("permessage-deflate");
If you only have access via JSR-356, then implement a custom Configurator and strip the permessage-deflate extension out during the extension negotiation.
public class StripExtensionsConfigurator extends ServerEndpointConfig.Configurator
{
#Override
public List<Extension> getNegotiatedExtensions(List<Extension> installed,
List<Extension> requested)
{
return Collections.emptyList();
}
}

Map Shiro's AuthenticationException with Jersey's ExceptionMapper

Preface
First of all, my sincerest apologies for this question being extremely long, but I honestly have no idea on how to shorten it, since each part is kind of a special case. Admittedly, I may be blind on this since I am banging my head against the wall for a couple of days now and I am starting to get desperate.
My utmost respect and thankfulness to all of you who read through it.
The aim
I would like to be able to map Shiro's AuthenticationException and it's subclasses to JAX-RS Responses by using Jersey ExceptionMappers, set up using a Guice 3.0 Injector which creates an embedded Jetty.
The environment
Guice 3.0
Jetty 9.2.12.v20150709
Jersey 1.19.1
Shiro 1.2.4
The setup
The embedded Jetty is created using a Guice Injector
// imports omitted for brevity
public class Bootstrap {
public static void main(String[] args) throws Exception {
/*
* The ShiroWebModule is passed as a class
* since it needs a ServletContext to be initialized
*/
Injector injector = Guice.createInjector(new ServerModule(MyShiroWebModule.class));
Server server = injector.getInstance(Server.class);
server.start();
server.join();
}
}
The ServerModule binds a Provider for the Jetty Server:
public class ServerModule extends AbstractModule {
Class<? extends ShiroWebModule> clazz;
public ServerModule(Class <?extends ShiroWebModule> clazz) {
this.clazz = clazz;
}
#Override
protected void configure() {
bind(Server.class)
.toProvider(JettyProvider.withShiroWebModule(clazz))
.in(Singleton.class);
}
}
The JettyProvider sets up a Jetty WebApplicationContext, registers the ServletContextListener necessary for Guice and a few things more, which I left in to make sure no "side effects" may be hidden:
public class JettyProvider implements Provider<Server>{
#Inject
Injector injector;
#Inject
#Named("server.Port")
Integer port;
#Inject
#Named("server.Host")
String host;
private Class<? extends ShiroWebModule> clazz;
private static Server server;
private JettyProvider(Class<? extends ShiroWebModule> clazz){
this.clazz = clazz;
}
public static JettyProvider withShiroWebModule(Class<? extends ShiroWebModule> clazz){
return new JettyProvider(clazz);
}
public Server get() {
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/");
// Set during testing only
webAppContext.setResourceBase("src/main/webapp/");
webAppContext.setParentLoaderPriority(true);
webAppContext.addEventListener(
new MyServletContextListener(injector,clazz)
);
webAppContext.addFilter(
GuiceFilter.class, "/*",
EnumSet.allOf(DispatcherType.class)
);
webAppContext.setThrowUnavailableOnStartupException(true);
QueuedThreadPool threadPool = new QueuedThreadPool(500, 10);
server = new Server(threadPool);
ServerConnector connector = new ServerConnector(server);
connector.setHost(this.host);
connector.setPort(this.port);
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(new NCSARequestLog());
HandlerCollection handlers = new HandlerCollection(true);
handlers.addHandler(webAppContext);
handlers.addHandler(requestLogHandler);
server.addConnector(connector);
server.setStopAtShutdown(true);
server.setHandler(handlers);
return server;
}
}
In MyServletContextListener, I created a child injector, which gets initialized with the JerseyServletModule:
public class MyServletContextListener extends GuiceServletContextListener {
private ServletContext servletContext;
private Injector injector;
private Class<? extends ShiroWebModule> shiroModuleClass;
private ShiroWebModule module;
public ServletContextListener(Injector injector,
Class<? extends ShiroWebModule> clazz) {
this.injector = injector;
this.shiroModuleClass = clazz;
}
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
this.servletContext = servletContextEvent.getServletContext();
super.contextInitialized(servletContextEvent);
}
#Override
protected Injector getInjector() {
/*
* Since we finally have our ServletContext
* we can now instantiate our ShiroWebModule
*/
try {
module = shiroModuleClass.getConstructor(ServletContext.class)
.newInstance(this.servletContext);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
/*
* Now, we create a child injector with the JerseyModule
*/
Injector child = injector.createChildInjector(module,
new JerseyModule());
SecurityManager securityManager = child
.getInstance(SecurityManager.class);
SecurityUtils.setSecurityManager(securityManager);
return child;
}
}
The JerseyModule, a subclass of JerseyServletModule now put everything together:
public class JerseyModule extends JerseyServletModule {
#Override
protected void configureServlets() {
bindings();
filters();
}
private void bindings() {
bind(DefaultServlet.class).asEagerSingleton();
bind(GuiceContainer.class).asEagerSingleton();
serve("/*").with(DefaultServlet.class);
}
private void filters() {
Map<String, String> params = new HashMap<String, String>();
// Make sure Jersey scans the package
params.put("com.sun.jersey.config.property.packages",
"com.example.webapp");
params.put("com.sun.jersey.config.feature.Trace", "true");
filter("/*").through(GuiceShiroFilter.class,params);
filter("/*").through(GuiceContainer.class, params);
/*
* Although the ExceptionHandler is already found by Jersey
* I bound it manually to be sure
*/
bind(ExceptionHandler.class);
bind(MyService.class);
}
}
The ExceptionHandler is extremely straightforward and looks like this:
#Provider
#Singleton
public class ExceptionHandler implements
ExceptionMapper<AuthenticationException> {
public Response toResponse(AuthenticationException exception) {
return Response
.status(Status.UNAUTHORIZED)
.entity("auth exception handled")
.build();
}
}
The problem
Now everything works fine when I want to access a restricted resource and enter correct principal/credential combinations. But as soon as enter a non-existing user or a wrong password, I want an AuthenticationException to be thrown by Shiro and I want it to be handled by the above ExceptionHandler.
Utilizing the default AUTHC filter provided by Shiro in the beginning, I noticed that AuthenticationExceptions are silently swallowed and the user is redirected to the login page again.
So I subclassed Shiro's FormAuthenticationFilter to throw an AuthenticationException if there is one:
public class MyFormAutheticationFilter extends FormAuthenticationFilter {
#Override
protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request,
ServletResponse response) {
if(e != null){
throw e;
}
return super.onLoginFailure(token, e, request, response);
}
}
And I also tried it with throwing the exception e wrapped in a MappableContainerException.
Both approaches cause the same problem: Instead of the exception being handled by the defined ExceptionHandler, a javax.servlet.ServletException is thrown:
javax.servlet.ServletException: org.apache.shiro.authc.AuthenticationException: Unknown Account!
at org.apache.shiro.web.servlet.AdviceFilter.cleanup(AdviceFilter.java:196)
at org.apache.shiro.web.filter.authc.AuthenticatingFilter.cleanup(AuthenticatingFilter.java:155)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:148)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.shiro.guice.web.SimpleFilterChain.doFilter(SimpleFilterChain.java:41)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at com.google.inject.servlet.FilterDefinition.doFilter(FilterDefinition.java:163)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:58)
at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:118)
at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:113)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:499)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:744)
Caused by: org.apache.shiro.authc.AuthenticationException: Unknown Account!
at com.example.webapp.security.MyAuthorizingRealm.doGetAuthenticationInfo(MyAuthorizingRealm.java:27)
at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:568)
at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)
at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:267)
at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198)
at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106)
at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:270)
at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:256)
at org.apache.shiro.web.filter.authc.AuthenticatingFilter.executeLogin(AuthenticatingFilter.java:53)
at org.apache.shiro.web.filter.authc.FormAuthenticationFilter.onAccessDenied(FormAuthenticationFilter.java:154)
at org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(AccessControlFilter.java:133)
at org.apache.shiro.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:162)
at org.apache.shiro.web.filter.PathMatchingFilter.isFilterChainContinued(PathMatchingFilter.java:203)
at org.apache.shiro.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:178)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:131)
... 32 more
The question, after all
Given that the environment can't be changed, how can I achieve that a server instance still can be requested via Guice, while Shiro's exceptions are handled with Jersey's auto discovered ExceptionMappers?
This question is much too complicated for me to reproduce on my side, but I saw a problem that I think is the answer and I'll delete this answer if I turn out to be wrong.
You do this:
#Provider
#Singleton
public class ExceptionHandler implements
ExceptionMapper<AuthenticationException> {
Which is correct, you are supposed to bind with both of those annotations as in this question. However, what you do differently is this:
/*
* Although the ExceptionHandler is already found by Jersey
* I bound it manually to be sure
*/
bind(ExceptionHandler.class);
The annotations in a class definition have lower priority than that in a module's configure() method, meaning you are erasing the annotations when you bind "it manually just to be sure". Try erasing that line of code and see if that fixes your problem. If it doesn't fix the problem, leave it deleted anyway, because I am certain that it is at least part of the problem - that statement erases those essential annotations.
I've not found a way to do this either. It looks like the Jersey filters/handlers aren't active on the Shiro servlet stack during authentication. As a work-around specifically for the AuthenticationException I opted to override the AdviceFilter::cleanup(...) method on my AuthenticatingFilter and return a custom message directly.
public class MyTokenAuthenticatingFilter extends AuthenticatingFilter {
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
// regular auth/token creation
}
#Override
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing) throws ServletException, IOException {
HttpServletResponse httpResponse = (HttpServletResponse)response;
if ( null != existing ) {
httpResponse.setContentType(MediaType.APPLICATION_JSON);
httpResponse.getOutputStream().write(String.format("{\"error\":\"%s\"}", existing.getMessage()).getBytes());
httpResponse.setStatus(Response.Status.FORBIDDEN.getStatusCode());
existing = null; // prevent Shiro from tossing a ServletException
}
super.cleanup(request, httpResponse, existing);
}
}
When authentication is successful the ExceptionMappers work fine for exceptions thrown within the context of the Jersey controllers.

Resources