Message Boards

Auth in Jax-rs liferay 7.2

Alessio luna, modified 4 Years ago.

Auth in Jax-rs liferay 7.2

New Member Posts: 5 Join Date: 11/18/19 Recent Posts
Hi everybody,I'm sorry but after 2 full work days of trying I'm very confused and stressed, so maybe I will appear strange but If I dont find a solution I cant sleep well. So let's get straight to the point.My ultimate goal:
Im developing multiple portlet based on angular 8 that call different liferay "services" to display things.
Calling service-builders via Liferay.Service (via javascript) it's a cake everything is just smooth and fine.
Now I need to develop a "custom service" not based on service builder, there is no persistence, I just need to do some calculation
based on user logged in and other data coming from different *localServices.

This is where my troubles began.
I tried to make a "rest" service via blade (i.e blade create -t rest blabla), it comes with something like this:
@Component( 
        property = { 
            JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings", 
            JaxrsWhiteboardConstants.JAX_RS_NAME + "=Greetings.Rest",
            "auth.verifier.guest.allowed=false"
        }, 
        service = Application.class)

following the docs from:https://portal.liferay.dev/docs/7-2/frameworks/-/knowledge_base/f/jax-rsI end up having a service exposed to : localhost:8080/o/greetings
Thats cool, the only problem I dont know how to call it with sessionID from BROWSER or from Liferay.Service(..) using an already logged in user
Give it simple, I want be non logged go to localhost:8080/ogreetings via browser or via Liferay.Service(..) and see "forbidden blabla fuck you."
Then I want to login in liferay using standard login form at localhost:8080/ then after auth I want go to localhost:8080/o/greetings via browser 
or Liferay.Service(localhost:8080/o/@@@@ blabla) and see the response from service.

So it's a "simple" matter of how to configure the authentication and authorization of a brand new Rest service deployed to /o/greetings.I cant use Oauth2, there is no point to get an access token just for 1 service out of the 6 (service-builder) I'm calling just fine with Liferay.Service(..)[Javascript api] 

I want just auth via sessionID like the ones from /api/json-ws (seamless).

Thanks to everybody that will save me emoticon
p.s using liferay:portal/7.2.0-ga1/liferay-ce-portal-tomcat-7.2.0-ga1-20190531153709761.tar.gz
thumbnail
Christoph Rabel, modified 4 Years ago.

RE: Auth in Jax-rs liferay 7.2

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Alessio luna, modified 4 Years ago.

RE: Auth in Jax-rs liferay 7.2

New Member Posts: 5 Join Date: 11/18/19 Recent Posts
First of all, thanks for your answer. I tried following the thread but found some inconsistencies from what I see.
I ended up with a working service with some difference:


@Component(
   property = {
      JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE+ "=/greetings",
      JaxrsWhiteboardConstants.JAX_RS_NAME+ "=Greetings.Rest",
         "auth.verifier.guest.allowed=true",
         "oauth2.scopechecker.type=none",
         /*"liferay.access.control.disable=true",*/
         /*"auth.verifier.auth.verifier.PortalSessionAuthVerifier.urls.includes=/*"*/
   },
   service = Application.class
)
public class ItemsServiceApplication extends Application {

   public Set<object> getSingletons() {
      return Collections.<object>singleton(this);
   }

   @GET
   @Produces("text/plain")
   public String working(@Context HttpServletRequest request) throws PortalException {

      User user=PortalUtil.getUser(request);
      if(user.isDefaultUser()){
         throw new PortalException("Not logged, byeeeeeeeeeeeeee");
      }

      return user.getFullName(); //&lt;-- it works!
   }<br>The difference between my liferay version and that example is:<br>if I just use&nbsp; "auth.verifier.guest.allowed=true", "oauth2.scopechecker.type=none", still doesnt work. I get this message even if logged in:&lt;Forbidden&gt;&lt;message&gt;Access denied to com.packet.test#working&lt;/message&gt;&lt;/Forbidden&gt;<br>But If I put&nbsp;"liferay.access.control.disable=true", then I can avoid also the&nbsp;oauth2.scopechecker.type, I can call the endpoint from browser and console.<br>I find all this configuration thing really really confusing. Basically I'm still unable to use the "portalSession", If I put the&nbsp; /*"auth.verifier.auth.verifier.PortalSessionAuthVerifier.urls.includes=/*"*/ <br>At that point i dont get the message&nbsp;&lt;Forbidden&gt;&lt;message&gt; but a Redirect to localhost:8080 and I see in liferay console:<br>2019-11-19 08:54:10.792 WARN &nbsp;[http-nio-8080-exec-3][code_jsp:?] {code="403", msg="Authorization required", uri=/o/greetings/}<br>How Am I suppose to authenticate here using PortalSession ?<br>Thanks!</object></object>
Alessio luna, modified 4 Years ago.

RE: Auth in Jax-rs liferay 7.2

New Member Posts: 5 Join Date: 11/18/19 Recent Posts
bump. I 'm still not able to use regular portalSession auth in jaxrs. Ended up to keep the endpoint public with the user.isDefaultUser() test. This is a bad practice because for example to use getExpandoBridge.getAttribute I have to modify the Service Access Policy of expandoBridge#getData and on top of this make custom fields viewable by "guest", even if I'm tenchincally logged in. Can someone please help or point me out where to read "how to use portalsession auth in jax-rs ?"
thumbnail
Christoph Rabel, modified 4 Years ago.

RE: Auth in Jax-rs liferay 7.2

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Well, it is a bit complicated and I am not 100% sure, I understand all of it. So, if I am wrong here, please correct me.
But as far as I know:

AuthVerifiers just provide you with a user, if there are credentials (e.g. through Basic Auth), they provide the authorization context .
So:
User without cookie/credentials accesses the API -> guest user is set.
Cookie, Username/PW, <something else> is sent with the request -> user is set.
Consider it a form of "autologin". If something is in the request, that allows authentication, the Verifier will make sure that the credentials are processed when accessing the API.
OAuth is a different beast. OAuth is all about authorization, it isn't about authentication:
OAuth tests if access is allowed by a scope. With none, you can tell the system, that you don't want OAuth and the scope shouldn't be checked. OAuth works on the path, so accessing /a/b/c might be allowed using OAuth. But it doesn't check permissions per se, or who you are.
It could be compared to a bus ticket. If you have a ticket, you can use the bus. But it doesn't matter, who you are, just that you have the ticket.
And then there is AccessControlled:
It is also about authorization, but it was already there in Liferay 6. It is about allowing access to call single functions.
You can find an example in Control Panel -> Configuration -> Service Access Policy
Take a look at SYSTEM_DEFAULT. It allows access to com.liferay.portal.kernel.service.CountryService.getCountries() for authenticated users. When you set "liferay.access.control.disable=true", then you disable that check and allow access to your service to guest users.
Alessio luna, modified 4 Years ago.

RE: Auth in Jax-rs liferay 7.2

New Member Posts: 5 Join Date: 11/18/19 Recent Posts
Thanks for your answer. Probably I articulated too much the question and missleaded the response. Lets keep it simple:
I have a jax-rs:

@Component(
	property = {
		JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/items",
		JaxrsWhiteboardConstants.JAX_RS_NAME + "=Items.Rest",
		"auth.verifier.guest.allowed=false",

	},
	service = Application.class
)
public class itemsRESTApplication extends Application {
	public Set<object> getSingletons() {
		return Collections.<object>singleton(this);
	}

	@GET
	@Produces("application/json")
	public String working(){return "hello!";}
<br>I want to be able to call this endpoint /o/test just because I'm already logged in in liferay. So no guest allowed but I just want session ID from browser like every call you do in api/jsonws and so on. How to setup this jaxrs/liferay configuration for let this happen ? Because If I try to call with browser the above service I get in console: <br>2019-11-27 10:32:15.159 WARN&nbsp; [http-nio-8080-exec-5][code_jsp:175] {code="403", msg="Authorization required", uri=/o/items}<br>Even if I AM logged in as Administrator.<br><br>Thanks</object></object>
thumbnail
Christoph Rabel, modified 4 Years ago.

RE: Auth in Jax-rs liferay 7.2

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
You need to add an access policy to SYSTEM_DEFAULT.
In your code here, OAuth is required. So you would need to send an OAuth token to access the methods.
You can disable oauth (add  "oauth2.scopechecker.type=none" to the properties), but as you found out, you will be blocked by the access control.
To get around that, go to Control Panel -> Configuration -> Service Access Policy -> System_Default (it already contains getCountries and getRegions).
Add your own class/method to it.
package.itemsRESTApplication#working
or maybe even
package.itemsRESTApplication#*
if you want to allow access to all methods of your class.
Enrico Costanzi, modified 3 Years ago.

RE: Auth in Jax-rs liferay 7.2

New Member Posts: 7 Join Date: 8/4/20 Recent Posts
I'm having the same issue with Liferay Community Edition Portal 7.3.0 CE GA1.
The problem: Logged in users cannot invoke the JAX-RS API, receiving a 403 error.
I defined the component

@Component(
        property = {
                JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/issue-admin-rest-api/project",
                JaxrsWhiteboardConstants.JAX_RS_NAME + "=Project.Configuration",
                "auth.verifier.guest.allowed=false",
                "oauth2.scopechecker.type=none"
        },
        service = Application.class
)
public class AdminRestAPIApplication extends Application {
...


Now I'm logged in as Administrator but every ajax call from the browser returns a 403 error. The response is:
[code]

    <title>Http Status 403 - http-status-code[403]</title>


<h1>Http Status 403 - http-status-code[403]</h1>
<p>
    Message: Authorization required</p>
<p>
    Resource: /o/issue-admin-rest-api/project/FPT</p>


I want to be enable the PortalSessionAuthVerifier for it. So that logged in users (non guest) will be able to invoke this API. I tried to:
- add the method to the Service Access Policy
- go to System Settings > Web Api > CXF ENDPOINTS and add a cxf endpoint on /issue-admin-rest-api and /issue-admin-rest-api/project using auth.verifier.PortalSessionAuthVerifier.urls.includes=*
​​​​​​​- go to System Settings > API Authentication > Portal Sessions and to enable the path /o/issue-admin-rest-api*

​​​​​​​None of the above works, i keep getting a 403 as a response. Am I missing something?
thumbnail
Christoph Rabel, modified 3 Years ago.

RE: Auth in Jax-rs liferay 7.2

Liferay Legend Posts: 1554 Join Date: 9/24/09 Recent Posts
Please increase the loglevel of these two packages:
com.liferay.portal.servlet.filters.authverifier
com.liferay.portal.security.auth.verifier.internal.portal.session
(In Server Administration - > LogLevel -> Click Add button and add them)
I suspect that you send no CSRF token. It is mandatory for PortalSessionAuthVerifier to grant you a "Success" state.
Enrico Costanzi, modified 3 Years ago.

RE: RE: Auth in Jax-rs liferay 7.2

New Member Posts: 7 Join Date: 8/4/20 Recent Posts

That was the problem, thank you. 

2020-12-01 11:07:41.853 DEBUG [http-nio-8080-exec-10][PortalSessionAuthVerifier:80] Unable to verify CSRF token for /o/greetings: User 38201 did not provide a valid CSRF token for /o/greetings

thumbnail
Andre Kreienbring, modified 3 Years ago.

RE: Auth in Jax-rs liferay 7.2

Regular Member Posts: 152 Join Date: 12/18/06 Recent Posts
Hi, I can confirm that users who are logged in can access my REST service. Must be another issue here.

How do you authenticate when you call your service(s)? At least by default only existing accounts can access them. So the most basic thing is to use Basic Authentication.

Having said that I wonder how  "auth.verifier.guest.allowed=false", makes sense? Guest  has no password...
Anyway, I added that to my service and still saw the exact same behavior as before.
Enrico Costanzi, modified 3 Years ago.

RE: Auth in Jax-rs liferay 7.2

New Member Posts: 7 Join Date: 8/4/20 Recent Posts
Thank you @Andre, which version of liferay are you trying on?
I'm invoking the service via jquery ajax call in a ftl portlet visibile only to logged in users. The cookie header is passed with the JSESSIONID in it so I was expecting liferay to accept api call.
Having said that I wonder how  "auth.verifier.guest.allowed=false", makes sense? Guest  has no password...
I'm not sure I understand the question. Only real authenticated user can invoke the api so I disabled the guest access to avoid anonymous user to use it. If I'm not mistaken this is the way to do it.
thumbnail
Andre Kreienbring, modified 3 Years ago.

RE: Auth in Jax-rs liferay 7.2

Regular Member Posts: 152 Join Date: 12/18/06 Recent Posts
Hi, i'm working with 7.3.2. And Guest can not access my services by default. With or without this "auth.verifier.guest.allowed=false" setting.
Have you tried Postman or Curl with Basic Authentication while an account is logged in?
Enrico Costanzi, modified 3 Years ago.

RE: Auth in Jax-rs liferay 7.2

New Member Posts: 21 Join Date: 2/11/17 Recent Posts

You can invoke the jax-rs endpoint using Liferay.Util.fetch. Using this method the x-csrf-token header is sent and the endpoint responds correctly.

If you want to call it via jquery (as I was trying to do) you have to disable cors.

<%@ include file="/init.jsp" %>
<script
        src="https://code.jquery.com/jquery-3.5.1.min.js"
        integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
        crossorigin="anonymous"></script>

<script>
    $(document).ready(function(){
        // works only if cors is disabled
        $.get('/o/greetings', function (data){
            console.log(data);
        })

        // always works, the fetch method sends the x-csrf-token header
        Liferay.Util.fetch('/o/greetings', {
            method: 'GET'
        }).then(resp => console.log(resp));
    });
</script>
<p>
    <b><liferay-ui:message key="myapp.caption"/></b>
</p>

To disable cors add `"auth.verifier.auth.verifier.PortalSessionAuthVerifier.check.csrf.token=false"` property to your component.

@Component(
    property = {
        JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings",
        JaxrsWhiteboardConstants.JAX_RS_NAME + "=Greetings.Rest",
        "oauth2.scopechecker.type=none",
        "auth.verifier.auth.verifier.PortalSessionAuthVerifier.check.csrf.token=false"
    },
    service = Application.class
)
public class MyRestApiApplication extends Application {
...