Apache CXF - JAX-RS Security - java

Working towards getting a Kerberos authenticated Web Service up and running and while Apache CXF seems to meet my requirements I'm struggling to get things started.
Hosting on Tomcat 7 and my super simple test service works but I can't figure out how to get CXF to provide security:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
#Path("test")
public class ItemResource {
public ItemResource() {
}
#GET
#Produces("application/json")
public String getJson(#QueryParam("name") int test) {
return "test";
}
}
Web.xml
<servlet>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>net.example.test/param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
The documentation says I can protect the Rest service with the org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter but I'm unsure as to how to do this.
Any help would be appreciated.

If you want to use CXF's KerberosAuthenticationFilter you have to use CXF as JAX-RS implementation, instead of Jersey.
You can find out how to do that on CXF JAX-RS help pages or in this tutorial. First you have to remove all configuration from web.xml because it is valid only for Jersey. Then follow the tutorial to create the service.
Finally you have to add mentioned KerberosAuthenticationFilter to CXF spring configuration like in the cited documentation.
EDIT:
Because linked tutorial indeed does not run I fixed it. You can download it from my github project RestWithCXF.
You might also find useful samples in samples\jax_rs of CXF distro.

Related

How to fix 'cannot be cast to javax.servlet.Servlet' error while trying to package REST App with Servlet

I am trying to setup Angular 7 with a maven based back-end java project into a single war file. At the moment I am trying to configure the web.xml file where I am currently having this problem. I am not sure at all if my approach is valid or 'good' therefore I will first describe what I am trying to do (if you think better on this aspect please do correct me).
So I have a couple of JAX-RS classes which I'd like to serve as a REST API. For this purpose I have created corresponding javax.ws.rs.core.Application classes to provide these REST components. Then I am including the Application classes in the web.xml file. Below are the files:
web.xml
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>backend.backendservice.StammSolvaraJahrRestApplication</servlet-name>
<servlet-class>backend.backendservice.StammSolvaraJahrRestApplication</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>backend.backendservice.StammSolvaraJahrRestApplication</servlet-name>
<url-pattern>/rmz/*</url-pattern>
</servlet-mapping>
Another variation of web.xml that I tried
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>backend.backendservice.StammSolvaraJahrRestApplication</servlet-name>
<servlet-class>backend.backendservice.StammSolvaraJahrRestApplication</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>backend.backendservice.StammSolvaraJahrRestApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>backend.backendservice.StammSolvaraJahrRestApplication</servlet-name>
<url-pattern>/rmz/*</url-pattern>
</servlet-mapping>
Application class
public class StammSolvaraJahrRestApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> sets = new HashSet<>();
sets.add(StammSolvaraJahrRest.class);
return sets;
}
}
The error that I get is: java.lang.ClassCastException: backend.backendservice.StammSolvaraJahrRestApplication cannot be cast to javax.servlet.Servlet and if I remove the <servlet-class> then I'll get No servlet class has been specified for servlet. I am following https://docs.oracle.com/cd/E24329_01/web.1211/e24983/configure.htm#RESTF183 and How to deploy a JAX-RS application? among others but it seems not to be working.
There are two ways to define your JAX-RS servlet.
1) With Application Subclass like the one you have, you can skip the web.xml config and just add the application annotation
#ApplicationPath("resources")
public class StammSolvaraJahrRestApplication extends Application
2) With web.xml config
<servlet>
<display-name>JAX-RS Servlet</display-name>
<servlet-name>package.hierarchy.StammSolvaraJahrRestApplication</servlet-name>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>package.hierarchy.StammSolvaraJahrRestApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>JaxRSServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
If you skip the servlet mapping from the last one, it will use your your #ApplicationPath specified value, or "/resources" if the previous one is missing.
The problem is just what it says. This line in your web.xml requires a javax.servlet.Servlet:
<servlet-class>backend.backendservice.StammSolvaraJahrRestApplication</servlet-class>
Since an Application is not a javax.servlet.Servlet, you're getting the error at runtime when your XML file is processed.
If you can, I would suggest that you start with a Spring Boot starter application. Spring Boot handles all of this for you. It can even embed a Tomcat server inside a jar file so that you can run your server like a simple Java application. Doing this would save you having to worry about what you're dealing with here.

RESTfull API does not print content on a specific path using jersey framework and apache tomact server

I am quite new in programming, I am trying to create my first RESTfull API. I have created a server with Apache Tomcat/8.5.37 and I used jersey RESTfull web services. My problem is that class content (XML) is not printed on localhost:8080 using the path http://localhost:8080/JavaAPI/rest/hello
I created a tomcat server and used both JAX-RS 2.0 / Jersey 2.25.x and JAX-RS 2.1 / Jersey 2.26+ in the case of a versioning problem, none of them works. I just cannot think of what could be the problem.
package test;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Application;
#Path("/hello")
public class Hello {
#GET
#Produces(MediaType.TEXT_XML)
public String sayHello(){
String resource ="<? xml version='1.0' ?>" +
"<hello>, Hi, its XML</hello>";
return resource;
}
}
This is the configuration of REST service file:
<display-name>JavaAPI</display-name>
<servlet>
<servlet-name>JAVA API</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>test</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAVA API</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
This is a screenshot of current jersey's library:
lib
libcont
The expected outcome should be: , Hi, its XML to be printed on http://localhost:8080/JavaAPI/rest/hello and i get the follow 404 error :
Type: Status Report
Message: Not Found
Description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
Reason why this might not be duplicated question: Firstly, i have copy / pasted their code along with jerseys older version 1.x and the issue still remained. In my experience i believe there is issue on versioning since i have been using Tomcat 8.5 and i also get the following response from server:
TomcaterrTomcaterrcont
The guide that i have followed is : https://www.youtube.com/watch?v=5jQSat1cKMo&t=782s&list=LL2fRfBs2m2v1wyy_kKt8E9w&index=2
Try to change init-param configuration like this.
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>Test</param-value>
</init-param>
Also consider changing package name to follow Java naming conventions:
Packages:
The prefix of a unique package name is always written in all-lowercase ASCII letters and should be one of the top-level domain names, like com, edu, gov, mil, net, org.
Subsequent components of the package name vary according to an organisation’s own internal naming conventions.
Examples:
com.sun.eng
com.apple.quicktime.v2
// java.lang packet in JDK
java.lang
The problem is also in mapping. Try to check
http://localhost:8080/JavaAPI/hello

Configuring provider packages in web.xml with Jersey

I am working on a web service and I get very strange error.
This is the line from my web.xml:
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>service</param-value>
</init-param>
As I know, <param-value> has to be referred in to the package my main application is. However, my application is in rest.main package, but the web service works only with the service value as defined above.
What is the problem, can somebody explain me these lines?
Have a look at the documentation regarding the jersey.config.server.provider.packages configuration property:
Defines one or more packages that contain application-specific resources and providers. If the property is set, the specified packages will be scanned for JAX-RS root resources and providers.
Servlet 2.x containers
This setting is frequently used in the web.xml deployment descriptor to instruct Jersey to scan these packages and register any found resources and providers automatically:
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
org.foo.myresources,org.bar.otherresources
</param-value>
</init-param>
With this setting, Jersey will automatically discover the resources and providers in the selected packages. By default, Jersey will recursively scan the sub-packages as well.
Servlet 3.x containers
For Servlet 3.x containers, no web.xml is necessary at all. Instead, an #ApplicationPath annotation can be used to annotate a custom Application or ResourceConfig subclass and define the base application URI for all JAX-RS resources configured in the application.
Use the following to defined the packages that will be scanned:
#ApplicationPath("resources")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("org.foo.myresources,org.bar.otherresources");
}
}
For more details, check the deployment section of the Jersey documentation.
Important
Always use the qualified name of the package;
Use , or ; as delimiter when declaring multiple packages.
You just need to add the package name to the
Form an Example if I have placed my resource class in com.ft.resources package
then I have to add the package name in
<init-param>
<!-- For Jersey 2.x -->
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.ft.resources</param-value>
</init-param>
Hope this might resolve your issue
If the application consists only resources and providers stored in particular packages, Jersey can scan them and register automatically.
<web-app>
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>org.foo.rest;org.bar.rest</param-value>
</init-param>
...
</servlet>
...
</web-app>
The param-value refers to the packages which will be scanned automatically.

PreAuthorize annotation doesn't work with jersey

I'm trying to secure a jersey service using spring security annotations without any luck.
I've added this section to web.xml:
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.test.proj.ui.web.rest;com.fasterxml.jackson.jaxrs</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.commons.ui.web.jersey.RestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Also enabled the pre-post-annotations using this on applicationContext:
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled" />
And this is my service class:
#Component
#Path("/user/{uid: .*}")
public class UserResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
#PreAuthorize("hasRole('ROLE_MANAGE_USER')")
public Response getUserDetail(#PathParam("uid") String uid) {
return "Hi, this is a test";
}
}
Spring security works well in authentication but the authorization doesn't work as expected and ignores the PreAuthorize annotation without any error or log.
I'm using Spring 3.2.4 and Spring Security 3.2.1 and Jersy 2.6.
any idea?
thanks
The spring component scan wasn't configured correctly! To solve the problem, only add component scan correctly and it works.
We were facing exactly the same problem. On the business layer #PreAuthorize annotation worked but on the REST resource didn't. The side effect of this situation was that Spring bean injection didn't work as well. Everything without any error.
The 100% working solution was to use RESTEasy instead of Jersey. They are quite similar so it was not much work.

Logging JSON request and response for jersey

I have a JAVA web application application, which exposes RESTful apis. My requirement is to log all the JSON requests and responses that are handled by the server.
Is there any parameter like -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true for JAX-WS?
I am also exploring AOP approach. What method signature should I add in the AOP pattern?
I am using Tomcat server and jersey for the JAX-RS implementation.
use LoggingFilter. Just add the following to your web.xml:
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
</init-param>
<!-- Enable Jersey tracing support in Glassfish -->
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter</param-value>
</init-param>
This worked for me (Jersey 2.x)

Categories