Message Boards

JAX RS Whiteboard vs. CXF

thumbnail
Christoph Rabel, modified 5 Years ago.

JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
I have just tried to create a rest application (Whiteboard) in Liferay 7.1 and I have also tried to deploy one of our "old" 7.0 rest modules. Both work. Very nice.

But I have a few questions now:

a) Will CXF continue to be supported?
b) Is it correct, that the Whiteboard implementation always requires OAuth 2.0 authentication?
c) Or is there a way to allow anonymous access? (I tried it, but couldn't find a way)

I am asking, because we currently use the CXF implementation a lot and it works pretty well for us. We also use custom contexts to inject company, user, locale into the requests.

d) Btw. how do I get the current user in the whiteboard rest example?
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Bump.
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
Hi,

a) as far as I know the only implementation of JAX-RS Whiteboard available is that of Apache Aries, and it will keep on relying on CXF.

b) It is not correct. OOTB the only enabled authorization mechanism for JAX-RS applications is OAuth2, but you can enable others such as PortalSession or Basic, but it not advised to do so for third party applications. If you want to enable, for example, basic in your application you can add a property:

auth.verifier.auth.verifier.BasicAuthHeaderAuthVerifier.urls.includes=/*
to the service. If you are using DS you can do so either in the code or using a configuration file. You can enable that for all applications if you configure:

com.liferay.portal.security.auth.verifier.internal.tracker.AuthVerifierFilterTracker

which is the responsible of default values for applications with a file like this:
com.liferay.portal.security.auth.verifier.internal.tracker.AuthVerifierFilterTracker.config:

default.registration.property=["filter.init.auth.verifier.BasicAuthHeaderAuthVerifier.urls.includes=/*","filter.init.auth.verifier.OAuth2RESTAuthVerifier.urls.includes=*"
but as I said before OAuth2 should be the preferred way as it does not involve sending the credentials to authorize requests.

c) You can allow anonymous access. You need to set:

auth.verifier.guest.allowed=true

for the application, which is false by default in that version. And then either specify that your resources allow to be accessed without scope (using @RequiresNoScope or the ConfigurableScopeChecker) or disable the scope checker for good with:

oauth2.scopechecker.type=none
for the application.

We are looking for ways to provide more flexibility to all these in the future. But the defaults using OAuth2 should really be the preferred for production applications.

I hope this helps.

Carlos.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Thanks alot.
The most common usecase for our services is to use them for rest calls on pages. So we usually need:

-) Anonymous access
-) If authenticated, we still want the user

OAuth2 is really valuable, but for different usecases.

So, with the new whiteboard scheme, I would do the same as before, just add a couple of properties:


@Component(
    property = {
        "auth.verifier.guest.allowed=true",
        "oauth2.scopechecker.type=none"
    },
    service = Application.class
)
public class MyApplication extends Application {
&nbsp; public Set<object> getSingletons() {
&nbsp;&nbsp;&nbsp; Set<object> singletons = new HashSet&lt;&gt;();
&nbsp;&nbsp;&nbsp; singletons.add(this);
&nbsp;&nbsp;&nbsp; singletons.add(userContextProvider);
...
  }

&nbsp;&nbsp;&nbsp; @POST
&nbsp;&nbsp;&nbsp; @Consumes(MediaType.APPLICATION_JSON)
&nbsp;&nbsp;&nbsp; @Produces(MediaType.APPLICATION_JSON)
&nbsp;&nbsp;&nbsp; public Response doSearch(@Context User user, ...) throws PortalException { ...

<br>Of course, assuming there is a UserContextProvider available. If I had the requirement that some interfaces need authentication, I am not 100% what to do with the RequiresNoScope annotation. Put it on the resource class<br><br><pre><code>
@RequiresNoScope
@Component(immediate = true, service = MyResource.class)
public class MyResource {</code></pre><br>or<br><br><pre><code>@Component(immediate = true, service = MyResource.class)
public class MyResource {

    @GET
    @RequiresNoScope
    public Response someRequest()</code></pre><br><br> annnotate the methods with @RequiresNoScope.<br><br><br>Note:<br>I think, this system is already very flexible, but it isn't well documented.</object></object>
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
Hi,
if you use "oauth2.scopechecker.type=none" there is no need to use "@RequiresNoScope".

So I believe for your use case you want to add "auth.verifier.auth.verifier.PortalSessionAuthVerifier.urls.includes=/*" property to your application's properties.

If you want the application to require the "UserContextProvider" to be present remember that the JAX-RS Whiteboard allows you to do so with a property:

osgi.jaxrs.extension.select=(component.name=my.extension)

this way the application will never be started by the whiteboard unless the extensions needed are present.

so your component would look like:

@Component(
    property = {
        "auth.verifier.auth.verifier.PortalSessionAuthVerifier.urls.includes=/*",
        "auth.verifier.guest.allowed=true",
        "oauth2.scopechecker.type=none",
        "osgi.jaxrs.extension.select=(component.name=your.user.context.provider.extension)"
    },
    service = Application.class
)

but take into account that, by doing this, you might open security holes if you don't program your resources very carefully. So you need to be really careful.

Hope this helps.

Carlos.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Yes, I understood that I don't need "@RequiresNoScope" when adding the property. I was just musing.

I tested it a bit now.
I don't seem to need PortalSessionAuthVerifier. This works:


@Component(
&nbsp;&nbsp; &nbsp;property = {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings",
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;JaxrsWhiteboardConstants.JAX_RS_NAME + "=Greetings.Rest",
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"oauth2.scopechecker.type=none",
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"auth.verifier.guest.allowed=true",
&nbsp;&nbsp; &nbsp;},
&nbsp;&nbsp; &nbsp;service = Application.class
)
public class RestTestApplication extends Application {

&nbsp;&nbsp; &nbsp;@Reference
&nbsp;&nbsp; &nbsp;UserContextProvider userContextProvider;
&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;public Set<object> getSingletons() {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Set<object> singletons = new HashSet&lt;&gt;();
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; singletons.add(this);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; singletons.add(userContextProvider);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return singletons;
&nbsp;&nbsp; &nbsp;}

&nbsp;&nbsp; &nbsp;@GET
&nbsp;&nbsp; &nbsp;@Path("/morning")
&nbsp;&nbsp; &nbsp;@Produces("text/plain")
&nbsp;&nbsp; &nbsp;public String hello(@Context User user) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return "Good morning, " + user;
&nbsp;&nbsp; &nbsp;}
}
<br>Secondly, when I add the line <br>"osgi.jaxrs.extension.select=(component.name=at.dccs.liferay.rest.context.UserContextProvider)"<br><br>it stops working. I get a 404 response and a redirect to the last path. UserContextProvider is basically a copy of the one in portal-workflow-rest.<br>https://github.com/liferay/com-liferay-portal-workflow<br><br>I could live with that, but the annotation way is a bit nicer than the "add to singleton" way.</object></object>
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
Hi again,

so you can use the whiteboard instead of Declarative Services to attach Resources and Extensions to an application. Using "osgi.jaxrs.application.select" properties on both resources and extensions you get that. "osgi.jaxrs.extension.select" will only work if you register the extensions to your applications using "osgi.jaxrs.application.select" on the extension.

The whiteboard should be a more flexible way for attaching extensions to applications. You can get the full specification here: https://osgi.org/specification/osgi.cmpn/7.0.0/service.jaxrs.html

Carlos.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
I think, I understand now. I have to do this, right?

@Component(name = My_Unique_UserContextProvider_Name)
public class UserContextProvider ...

@Component(
property = {
   ...
   "osgi.jaxrs.extension.select=(component.name=My_Unique_UserContextProvider_Name)"
},
service = Application.class
)
public class RestTestApplication extends Application {

About "jaxrs:check":
Thanks. And damn, it never ends. Now I need to research what /f/, /batch, /p/ do  emoticon
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
Hi again,
you need to mark your component as an extension using "osgi.jaxrs.extension=true" and you need to attach it to one (or many) applications using
osgi.jaxrs.application.select=(a.filter.for.your.application)
this way the whiteboard facilitates reusing extensions among different applications. Resources attaching applications can also request the extensions to be present individually (It does not have to be the application, since normally the resources are the ones making use of the extensions) using "osgi.jaxrs.extension.select".

All this should be described in the specification mentioned before.

Carlos.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Ah, "osgi.jaxrs.extension=true" is the key.

You confused me with
if you register the extensions to your applications using "osgi.jaxrs.application.select" on the extension.


which didn't make sense to me.
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
Christoph RabelAh, "osgi.jaxrs.extension=true" is the key.

You confused me with
if you register the extensions to your applications using "osgi.jaxrs.application.select" on the extension.


which didn't make sense to me.
well... according to the spec you need to attach the extension to applications putting a filter into "osgi.jaxrs.application.select" property. Otherwise the extension (or the resource) would only apply to default application. Nevertheless, IIRC, in jaxrs whiteboard versions prior to 1.0.4 there was a bug that made extensions without that property attach to all deployed applications. That's where the confusion might have come from.

Carlos.
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
I forgot to mention that you can also use gogo shell "jaxrs:check" command to get a summary of the status of the applications, resources and extensions in the jaxrs whiteboard in Liferay.

Carlos.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Ok, I have no idea how I should implement this osgi select stuff.

I have read most of the documentation now, copied the example code snippets and tried multiple versions now. Maybe I just make simple mistakes, but it doesn't work. The lack of feedback is also quite annoying. It simply doesn't work, without any error messages ...

I found a few things out, though. According to the documentation, this will never work as an extension:

public class UserContextProvider implements ContextProvider<user> {</user>
An extension has to implement specific interfaces and ContextProvider simply isn't among them.
Ok. Understood.

But ContextResolver is in the list, so I tried (in various variations):

@JaxrsExtension
@JaxrsName("configProvider")
@Component
public class ConfigProvider implements ContextResolver {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;@Override
&nbsp;&nbsp; &nbsp;public Object getContext(Class type) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return new String("Hello"); // Note: I also tried a "correct" implementation,but for an example it shouldn't matter
&nbsp;&nbsp; &nbsp;}
}
And in the Resource I tried to fetch the resolver:

@JaxrsExtensionSelect("(osgi.jaxrs.name=configProvider)")
...

public String hello(@Context Providers providers) {&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; 
     ContextResolver<string> provider = providers.getContextResolver(String.class, MediaType.WILDCARD_TYPE);
</string>
Nope, not working. provider is simply null. Btw.: The documentation seems to be wrong, I had to add a media type to the getContextResolver request.

Ok, then I tried the Resource example. ( 151.6.5 https://osgi.org/specification/osgi.cmpn/7.0.0/service.jaxrs.html )
Attach a resource to an application. That would be quite useful ...

Application:

@Component(
    property = {
        JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings",
        JaxrsWhiteboardConstants.JAX_RS_NAME + "=Greetings.Rest",
        "oauth2.scopechecker.type=none",
        "auth.verifier.guest.allowed=true"
    },
    service = Application.class
)
public class RestTestApplication extends Application {

Resource
:
@Component(
        property = {
                "oauth2.scopechecker.type=none",
                "auth.verifier.guest.allowed=true",
            },
        service = MyResource.class,
        scope = ServiceScope.PROTOTYPE)
@JaxrsResource
@JaxrsApplicationSelect("(osgi.jaxrs.name=Greetings.Rest)")
public class MyResource {
    @GET
    @Path("hello")
    @Produces("text/plain")
    public String getHello(){
        return "Hello ";
    }
}

I really would appreciate an example here.
Note: Strictly speaking: I don't need this, I can always put stuff in the singleton and you are probably busy with 7.2, so, we can shelve this. No sweat here. But it is also not trivial and the documentation is not sufficient. I think, this stuff could be very useful, when you are building restful webapplications.
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
Hi again,

I am sorry to hear you are having such a hard time and I really appreciate your feedback.

Let's go one by one.

ContextProviders are allowed as proprietary extensions in Aries JAX-RS Whiteboard since they are very often used. Alas JAX-RS spec did not provide a portable way to define those accross impls, which means those context providers are only going to work on Aries JAX-RS Whiteboard, not on other whiteboard implementation.

For feedback you can use "jaxrs:check" command in gogo shell or enable the debug level in "org.apache.aries.jax.rs.whiteboard", it should give you obnoxious report of everything that is going on in the whiteboard.

ContextResolvers are normally used to provide JAXB and/or JSON serialization contexts for types. I am not 100% sure but in your example you might be missing the type parameter (<String>) when you are registering the ContextResolver, but it is just a guess.

As a rule of thumb I would suggest to look at the ouput of "jaxrs:check" and also inpect the properties of the services in the running system. That should give you a pretty good idea of what might be missing. I am fine if you want to paste the outputs of your inquiries in case I can help.

We also believe this stuff is very useful, I am sorry to hear you are having such a hard time.

Carlos.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Carlos SierraHi again,

I am sorry to hear you are having such a hard time and I really appreciate your feedback.


Don't sweat it. I am glad, I get help with the whiteboard. I currently have a bit of spare time, so I play around with things I will need (or at least probably need).


ContextProviders are allowed as proprietary extensions in Aries JAX-RS Whiteboard since they are very often used. Alas JAX-RS spec did not provide a portable way to define those accross impls, which means those context providers are only going to work on Aries JAX-RS Whiteboard, not on other whiteboard implementation.


Ah, ok. So, adding a UserContextProvider should work? I am not sure, what I am doing wrong here, probably it is just a minor thing, an annotation, a property, ... But I am a bit clueless at the moment.


For feedback you can use "jaxrs:check" command in gogo shell or enable the debug level in "org.apache.aries.jax.rs.whiteboard", it should give you obnoxious report of everything that is going on in the whiteboard.


I tried jaxrs:check but I am not sure, how I should interpret the results. I see my application, but I don't think that my extensions work at all. They don't show up like e.g. Liferay.OAUTH2. Something I do, has to be wrong, but I am not sure what I am missing.

I will try to change the debug level of org.apache.aries.jax.rs.whiteboard, maybe it will give me some ideas.


ContextResolvers are normally used to provide JAXB and/or JSON serialization contexts for types. I am not 100% sure but in your example you might be missing the type parameter (<String>) when you are registering the ContextResolver, but it is just a guess.


I know, I also tried it with a type parameter, returning a MyContext<String> and similar things. I just deleted the stuff to post less code since it didn't make a difference. I still think that my extension is simply not registered at all.


As a rule of thumb I would suggest to look at the ouput of "jaxrs:check" and also inpect the properties of the services in the running system. That should give you a pretty good idea of what might be missing. I am fine if you want to paste the outputs of your inquiries in case I can help.


Thanks, I will try that later or to be more precise: probably on the weekend.
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
Maybe it is just that the

@JaxRsExtension @JaxRsName @JaxRsResource

annotations are not being processed and turned into properties? Maybe it is just as simple as that. You could try first putting the properties directly.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Carlos SierraMaybe it is just that the

@JaxRsExtension @JaxRsName @JaxRsResource

annotations are not being processed and turned into properties? Maybe it is just as simple as that. You could try first putting the properties directly.
YES. That's actually the problem. Setting the properties directly works.

Component(
        property = {
            JaxrsWhiteboardConstants.JAX_RS_NAME + "=myProvider",
            JaxrsWhiteboardConstants.JAX_RS_EXTENSION + "=true"
        }
    )
public class MyResolver implements ContextResolver<string>{

    @Override
    public String getContext(Class type) {
        return "Test";
    }
}

@Component(
    property = {
        JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings",
        JaxrsWhiteboardConstants.JAX_RS_NAME + "=Greetings.Rest",
        "oauth2.scopechecker.type=none",
        "auth.verifier.guest.allowed=true",
        "auth.verifier.auth.verifier.PortalSessionAuthVerifier.urls.includes=/*",
        "osgi.jaxrs.extension.select=(osgi.jaxrs.name=myProvider)"
    },
    service = Application.class
)
public class RestTestApplication extends Application {
...
    @GET
    @Path("/test")
    @Produces("text/plain")
    public String test(@Context Providers providers) {
        ContextResolver<string> provider = providers.getContextResolver(String.class, MediaType.WILDCARD_TYPE);
        String value = provider.getContext(String.class);
        return "Context " + value;
    }
}</string></string>

My resource also works,
Application Greetings.Rest (9629) /greetings

    GET / Consumes: null Produces: [text/plain]
    GET /morning Consumes: null Produces: [text/plain]
    GET /morning/{name} Consumes: null Produces: [text/plain]
    GET /test Consumes: null Produces: [text/plain]

    Attached extensions:
        Liferay.OAuth2 (5957)
        jaxb-json (1681)
        myProvider (9624)

    Attached resources:
        .generated.for.9627 (9627)
            GET /hello Consumes: null Produces: [text/plain]

I am very happy to have made progress here emoticon
Attaching resources to an application is marvelous.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Carlos Sierra
ContextProviders are allowed as proprietary extensions in Aries JAX-RS Whiteboard since they are very often used. Alas JAX-RS spec did not provide a portable way to define those accross impls, which means those context providers are only going to work on Aries JAX-RS Whiteboard, not on other whiteboard implementation.


It doesn't like it.

Extension .generated.for.9679 (9679) is not a valid extension type


If this should work in Liferay, is it per chance necessary to add some "dear osgi, don't be so strict" property?
Note: If this doesn't work, no big deal. I can always add it to the singleton. The most interesting thing I found out in this thread is the ability to attach resources to an existing application.
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
It doesn't like it.

Extension .generated.for.9679 (9679) is not a valid extension type
Can you paste how you are registering the ContextProvider... it should work. As you can see here it is supported as a valid interface.

Carlos.
thumbnail
Carlos Sierra, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Junior Member Posts: 32 Join Date: 5/21/13 Recent Posts
and make sure you are not including cxf classes in your bundle and that your bundle is importing CXF packages from the whiteboard. Otherwise the interface won't be seen as the same because they would come from different class loaders.
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
I see, yes, it should work. Maybe it is the "service=...". I think, I just copied this from the workflow context code.

import javax.ws.rs.ext.Provider;
import org.apache.cxf.jaxrs.ext.ContextProvider;
import org.apache.cxf.message.Message;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;

@Component(immediate = true,
property = {
        JaxrsWhiteboardConstants.JAX_RS_EXTENSION + "=true"
    },
    service = UserContextProvider.class)
@Provider
public class UserContextProvider implements ContextProvider<user> {</user>
thumbnail
Christoph Rabel, modified 5 Years ago.

RE: JAX RS Whiteboard vs. CXF

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Yes, it was the service=

@Component(immediate = true,
property = {
        JaxrsWhiteboardConstants.JAX_RS_EXTENSION + "=true"
    }
//    service = UserContextProvider.class
)
@Provider
public class UserContextProvider implements ContextProvider<User> {

After removing that line, the extension works! That line is perfectly fine when you use @Reference, but not when using it as an extension.

OK, THANKS ALOT for your help. I think, I understand the whiteboard far better than at the start of the week.