Using Tomcat Basic Auth with new WebApplicationInitializer - java

OK so I've previously used this technique with classic web.xml, but am having trouble getting it to work now that I'm using the WebApplicationInitializer.
My WebApplicationInitializer includes this code:
HttpConstraintElement constraint = new HttpConstraintElement(
TransportGuarantee.NONE,
new String[]{"sponsorUsers"});
ServletSecurityElement servletSecurity =
new ServletSecurityElement(constraint);
dispatcher.setServletSecurity(servletSecurity);
I'm trying to require basic auth (username+password) for any http methods for any resource request within the servlet.
All I get back is a 403 - no prompt for the username.
My suspicion is that I need to set the auth-method to BASIC, as I would in xml:
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>User Auth</realm-name>
</login-config>
But don't see the equivalent in the Java classes. Any help? Thanks!

A WebApplicationInitializer is basically the Spring extension of Servlet 3.0 ServletContainerInitializer.
There are a few things you cannot do with ServletContainerInitializer, or ServletContext to be more specific, and one of them is to configure some security components, ex login-config.
Instead you can have both a ServletContainerInitializer and a web.xml using the attribute metadata-complete set to false. For example,
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
metadata-complete="false" version="3.0">
In which you then add your <login-config> element.

Related

Java + TomEE. Websockets and Servlets in one project?

I'm writing a simple game with JavaEE Websocket technology. Using JSR356, my server-side socket class looks like following:
#ServerEndpoint(
value = "/sock",
decoders = { SocketDecoder.class }
)
public class CardsSocket {
....
#OnMessage
public void onMessage(final SocketInput message, final Session session) {
...
}
...
}
It works perfectly fine, and has no issues. But then I decided to create also some web page for info and stuff. So, without changing anything on previous class, I have created a new one:
#ServerEndpoint(value = "/cards")
public class CardsWebPage extends HttpServlet {
#Override
public void doGet(...) {
...
}
}
And configured web.xml file in WEB-INF directory.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>CardsWebPage</servlet-name>
<servlet-class>server.CardsWebPage</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CardsWebPage</servlet-name>
<url-pattern>/cards</url-pattern>
</servlet-mapping>
</web-app>
And there began troubles. My servelet works - browser shows page on localhost:8080/cards, but client-side socket class can no longer initiate - it falls with Exception:
"javax.websocket.DeploymentException: The HTTP response from the server [HTTP/1.1 404 Not Found] did not permit the HTTP upgrade to WebSocket"
, and nothing seems to fix it. Have I missed some documentation? Is it impossible for a single project to contain both servlets and websocket classes? Because, if I delete web.xml file, then sockets are starting to work like before. Server startup logs containing no warnings or errors in both cases.
Yeah, perhaps sparks is right, and I should simply deploy multiple projects.
Hi why decorating CardsWebPage with #ServerEndpoint? Nothing or if you can to get rid of web.xml #WebServlet should be fine.

JAX-RS (Jersey 2) - authorization using JSR 250 annotations

Intro
Jersey: 2.9
This part of Jersey documentation describes how to provide authorization for REST services. There are two ways to do that:
standard Servlet way, using configuration in web.xml
much better solution using JSR 250 annotations
The First approach works fine, but I cannot make the second work.
Case 1 (using web.xml):
This example works. It is for informational purpose. If you want just jump do the second one, which does not work.
Resource is very simple:
#Path("/HelloWorld")
public class HelloWorldResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String sayHelloWorld(){
return "Hello World!!!";
}
}
Security configuration is placed in web.xml file, which looks like that:
<web-app ...>
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<!-- SECURITY -->
<security-constraint>
<web-resource-collection>
<url-pattern>/rest/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>boss</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>DefaultRealm</realm-name>
</login-config>
</web-app>
This example works fine. When I try to access http://{myhost}:8080/{war_name}/rest/HelloWorld I have to provide username and password. This means that Realm and configuration in database is just fine. So there is no need to show it here.
Case 2 (JSR 250 annotations):
This example does not work. The resource is almost the same as in the first example, just some annotations are added:
#Path("/HelloWorld")
#PermitAll
public class HelloWorldResource {
#RolesAllowed("boss")
#GET
#Produces(MediaType.TEXT_PLAIN)
public String sayHelloWorld(){
return "Hello World!!!";
}
}
As you see, two annotations are added. It is the same security policy like in the first example, but defined using annotations insted of web.xml.
Now web.xml looks like that:
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>DefaultRealm</realm-name>
</login-config>
</web-app>
In addition new class is added (like described in documentation):
#ApplicationPath("rest")
public class MyApplication extends ResourceConfig {
public MyApplication() {
super(HelloWorldResource.class);
register(RolesAllowedDynamicFeature.class);
}
}
This class is important. As you see required RolesAllowedDynamicFeature is registered.
So two main steps:
- adding annotations to resource
- registering RolesAllowedDynamicFeature
are done.
Problem:
Second example does not work. Popup to provide username and password never shows up. Every time response is 403 Forbidden. This is not a problem with Realm and database configuration since this configuration works fine with the first example.
So the question is: what is wrong with my second implementation?
Tnaks in advance.
Instead of the ResourceConfig sub-class, try add this to you web.xml block
<init-param>
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.RolesAllowedResourcFilterFactory</param-value>
</init-param>

Shiro 1.2 not working with Guice (and Vaadin)

First time user, please be kind!
I have a bit of a problem configuring Shiro to filter Vaadin-generated pages using Guice.
I have looked online on various websites including the Apache Shiro's guides and etc. Problem is that most websites tend to do it the 'old' fashion way, i.e. using Shiro 1.1 (which doesn't have native Guice support).
So here is the problem. My pages don't get filtered through Shiro. I have tried a zillion different things including using AOP for method authentication, setting filters up manually in the web.xml. Even setting up a shiro.ini file (which I do NOT want to do under any circumstances).
So here is the list of things I am using:
- Shiro 1.2.0-SNAPSHOT
- Guice 3.0
- Vaadin 6.7.4
Here is my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>App</display-name>
<context-param>
<description>Vaadin production mode</description>
<param-name>productionMode</param-name>
<param-value>false</param-value>
</context-param>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.app.GuiceServletInjector</listener-class>
</listener>
</web-app>
Here is the Servlet Injector:
public class GuiceServletInjector extends GuiceServletContextListener {
private ServletContext servletContext;
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
servletContext = servletContextEvent.getServletContext();
super.contextInitialized(servletContextEvent);
}
#Override
protected Injector getInjector() {
return Guice.createInjector(new GuiceServletModule(), new ShiroConfigurationModule(servletContext));
}
Which then creates a ServletModule, which passes the request to the Vaadin app:
protected void configureServlets() {
bind(Application.class).to(VaadinMainWindow.class).in(ServletScopes.SESSION);
bind(BasicHttpAuthenticationFilter.class).in(Singleton.class);
filter("/*").through(BasicHttpAuthenticationFilter.class);
serve("/*", "*").with(VaadinApp.class);
}
Also during the injector stage, please notice that I create a ShiroConfigurationModule, which takes care of the realms and etc:
public class ShiroConfigurationModule extends ShiroWebModule {
#Inject
public ShiroConfigurationModule(ServletContext servletContext) {
super(servletContext);
}
#Override
protected void configureShiroWeb() {
bindRealm().to(ShiroBaseRealm.class).in(Singleton.class);
bind(Realm.class).to(ShiroBaseRealm.class).in(Singleton.class);
processMethodInterceptors();
}
private void processMethodInterceptors() {
MethodInterceptor interceptor = new AopAllianceAnnotationsAuthorizingMethodInterceptor();
bindInterceptor(any(), annotatedWith(RequiresRoles.class), interceptor);
bindInterceptor(any(), annotatedWith(RequiresPermissions.class), interceptor);
bindInterceptor(any(), annotatedWith(RequiresAuthentication.class), interceptor);
bindInterceptor(any(), annotatedWith(RequiresUser.class), interceptor);
bindInterceptor(any(), annotatedWith(RequiresGuest.class), interceptor);
}
}
The realm class returns 'true' for the supports(), but returns 'null' for everything, simulating that the user doesn't exists.
The chances of doing something wrong, or missing a step is very high. Can someone please care to explain what I'm missing so I can at least get a basic HTTP auth up?
Thanks a lot!
Mo.
Naturally the blog link has expired, and the site that is now redirected to contains no trace of that blog article whatsoever.
A copy of the article can be found here.
http://web.archive.org/web/20120413052117/http://www.mofirouz.com/wordpress/2012/01/guice-shiro-1-2-and-vaadingwt/
The crux of the answer: if you are using guice then you MUST include
filter("/*").through(GuiceShiroFilter.class)
in your ServletModule, or else NONE of the related shiro filters will ever get hit.
Right so after a lot of testing and messing about with Shiro (as well as finally using the 1.2-release), I got mine to work.
I've written a detailed answer on my site (primarily because it is easier to write!). Have a look:
http://www.mofirouz.com/wordpress/2012/01/guice-shiro-1-2-and-vaadingwt/
Good luck whoever out there!

doFilter not getting called

Could you help to check why doFilter not getting called
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<filter>
<filter-name>roseFilter</filter-name>
<filter-class>net.paoding.rose.RoseFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>roseFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
</web-app>
class signature:
import org.springframework.web.filter.GenericFilterBean;
public class RoseFilter extends GenericFilterBean {
404 is returned while call http://localhost:8080/hello/world, I set the breakpoints at
doFilter, it seems doFilter not called?(I tried tomcat 6.0.18, 6.0.29, jdk1.6)
The filter won't be invoked when:
The filter class is missing in the classpath and/or is not loadable or instantiable. You should however have noticed it in the server's startup logs. Solution is to be found based on the interpretation of the exceptions/errors found in the server logs.
There's another filter running before in the chain which isn't calling FilterChain#doFilter(), but rather RequestDispatcher#forward() or include() which caused the subsequent filters in the chain being completely skipped (when they do not listen on FORWARD or INCLUDE dispatchers; they by default only listens on REQUEST dispatcher). Solution is either to fix the wrong filter, or to add <dispatcher>FORWARD</dispatcher> etc accordingly, or to rearrange the filter declarations in web.xml so that your new filter comes before the another filter (you in turn only need to ensure that your new filter is using the FilterChain#doFilter() properly :) ).
The request URL is plain wrong. You used http://localhost:8080/hello/world. With a filter listening on /*, this means that the webapp context should be ROOT or at least /hello. Verify your webapp context. I'd just retry with an URL which points to a valid JSP/Servlet inside the same webapp which generates a non-404 response. Does the filter then get called as well?
What's the web request look like? Can you try changing your url-pattern to *.jsp instead of / * ? If you are using something other than pure JSP then change it to whatever the request ending extension is (like for struts it is usually *.do).

jax-ws on glassfish3 init method

I've created simple jax-ws (anotated Java 6 class to web service) service and deploied it on glassfish v3. The web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app>
<servlet>
<servlet-name>MyServiceName</servlet-name>
<description>Blablabla</description>
<servlet-class>com.foo-bar.somepackage.TheService</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyServiceName</servlet-name>
<url-pattern>/MyServiceName</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
There is no sun-jaxws.xml in the war.
The service works fine but I have 2 issues:
I'm using apache common configuration package to read my configuration, so i have init function that calls configuration stuff.
1. How can I configure init method for jaxws service (like i can do for the servlets for example)
2. the load on startup parameter is not affecting the service, I see that for every request init function called again (and c-tor). How can I set scope for my service?
Thanks a lot,
How can I configure init method for jaxws service (like i can do for the servlets for example)
JAX-WS endpoints, both web and EJB, can have optional life-cycle methods that are automatically called if present. Any method can be used as a life-cycle method with the correct annotation:
#PostConstruct - Called by the container before the implementing class begins responding to web service clients.
#PreDestroy - Called by the container before the endpoint is removed from operation
So annotating your init() method with #PostConstruct should do the trick.
the load on startup parameter is not affecting the service, I see that for every request init function called again
Try to use the suggested annotation first. And if you are still facing unexpected behavior, post your code.
Thanks for the quick answer, Pascal.
BTW, I warmly suggest to use a "valid" servlet 2.5 or servlet 3.0 web.xml (using a version attribute in the web-app element and the xsd declaration).
I'm using 2.5 version, I just didn't paste this part in my post
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:j2ee="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<description>WebTier for the Login Manager Service</description>
<display-name>LoginManagerWAR</display-name>
<servlet>
<description>Endpoint for Login Manager Web Service</description>
<display-name>LoginManagerControllerService</display-name>
<servlet-name>LoginManagerController</servlet-name>
<servlet-class>loginmanager.controller.LoginManagerController</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LoginManagerController</servlet-name>
<url-pattern>/LoginManagerControllerService</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>54</session-timeout>
</session-config>
The PostConstruct works fine , thank you, but load-on-startup still didn't happen.
#WebService(
name="LoginManagerController",
serviceName="LoginManagerControllerService"
)
public class LoginManagerController {
private ILoginManager manager;
#Resource
private WebServiceContext wsContext;
#PostConstruct
private void init(){
.....
}
More over, now every client request makes 2 init() calls of the webservice:
like I can see in chainsaw, first called init() of the service, then it called again and then the actually client's function (I print the hash code of the webservice class instance and it the same instance for both calls!!!):
> Message Inside init() method ... controller=31641446
> Message login manager = 11229828
> .....init of elements....blablabla.....
> Message Exiting init() method
> Message Inside init() method ... controller=31641446
> Message login manager = 32361523
The controller is the service and the manager (wich hash code has been changed from first call to the second) created inside the init () of the controller.
I failed to understand what is wrong ....
UPDATE
It seems like a to glassfish v3 related issue (maybe my env setup or glassfish configuration). I tried this war on Sailfin and Glassfish V2 and its perfectly working ....

Categories