cancel
Showing results for 
Search instead for 
Did you mean: 

Authentication alternatives for REST Webapp

b_schnarr
Champ in-the-making
Champ in-the-making
Hello at all,

we have an Enterprise Content Management System and want to trigger the activiti rest services from that ecm system. The ECM application and the activiti rest webapp are using the same LDAP directory. The problem is, that the rest services need username and password as basic authentication. When the user is logged into the ECM Application, it is not possible to readout the password of the current logged in user. So we can not send the login data to the rest webapp. Is there another possibility to send credentials to the rest services?

Thanks and best regards
Ben
23 REPLIES 23

b_schnarr
Champ in-the-making
Champ in-the-making
Thanks for your answer. Am am very new to Spring. It would be optimal to inject the configuration directly in the custom RestAuthenticator. But I have no idea which steps I have to do (even after studying spring docus). There are so many ways.

Would it be enough if I create a new bean in the activiti-context.xml like this
<code>
<bean id="RestAuthenticatorImpl" class="org.activiti.rest.common.filter.RestAuthenticatorImpl">
  <property name="LTPAToken" value="***" />
  <property name="LTPAPassword" value="***" />
</bean>
</code>
And then, creating the setter and getter for those attributes? Or do I have do to additional work? For example, I do not understand from where the bean id comes.

I know that this is not directly related to activiti, but it is very difficult to figure out those things in such a great project.

You wrote "The custom implementation fo the RestAuthenticator can be set on the instance of the org.activiti.rest.common.application.ActivitiRestApplication (or org.activiti.rest.service.application.ActivitiRestServicesApplication)."

What does that mean? In org.activiti.rest.common.application.ActivitiRestApplication I found this line here:
<code>   public void setRestAuthenticator(RestAuthenticator restAuthenticator) {
    this.restAuthenticator = restAuthenticator;
  }</code>

How can I set my Custom Rest Authenticator?

Thank you very mich for your help
Best regards
Ben

b_schnarr
Champ in-the-making
Champ in-the-making
I read the Activiti Rest documentation, there you can read: The custom RestAuthenticator should be set on the org.activiti.rest.service.application.ActivitiRestServicesApplication that is used in the RestletServlet. The easiest way for this to create a subclass of the ActivitiRestServicesApplication and use the custom implementation classname in the servlet-mapping.

As I am not a skilled Java-Developer, this is not enough for me. I created the class org.activiti.rest.common.filter.RestAuthenticatorImpl.java.

In the class ActivitiRestServicesApplication.java, I can´t see any possibility to set my custom implementation. In addition, what sense dies it make to create a subclass of the ActivitiRestServicesApplication.java?

It would be great if someone could give me a concrete example how I can set my CustomRestAuthenticator.
This is the last step to my goal 😉

Thank you very much and best regards
Ben

b_schnarr
Champ in-the-making
Champ in-the-making
I created a class <code>public class CustomActivitiRestServicesApplication extends ActivitiRestServicesApplication implements RestAuthenticator</code> in org.activiti.rest.service.application.CustomActivitiRestServicesApplication
In this method, I only implement the method <code>public boolean requestRequiresAuthentication(Request request)</code>
After implementing this, I altered the web.xml of the rest-webapp as following:

<code>
  <!– Restlet adapter –> 
  <servlet> 
    <servlet-name>RestletServlet</servlet-name> 
    <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
    <init-param>
      <!– Application class name –>
      <param-name>org.restlet.application</param-name>
      <param-value>org.activiti.rest.service.application.CustomActivitiRestServicesApplication</param-value>
    </init-param>
  </servlet>
</code>

But this has no effect, the rest webapp still wants to have basic credentials (even though the method always returns false)….
Should I explicitely call <code>setRestAuthenticator()</code> in my custom implementation?

Thanks and best regards
Ben

ssun
Champ on-the-rise
Champ on-the-rise
I wonder if you can approach this from a different angle. Can you not use LDAP for Activiti REST and simply have a user for ECM to call the REST api? You can still have a record of who did what in your ECM system and control access there.

manchandap
Champ in-the-making
Champ in-the-making
@frederikheremans Thanks for the continuous support on this. I am also facing the same problem where I want to disable the default Authentication mechanism of Activiti-REST. My Code changes and the problem that I am facing is explained as follows:

Implemented the <blockcode>org.activiti.rest.common.filter.RestAuthenticator</blockcode> inteface

<java>
import org.activiti.rest.common.filter.RestAuthenticator;
import org.restlet.Request;
import org.restlet.data.ClientInfo;
import org.restlet.security.User;

public class WFCRestAuthenticatorImpl implements RestAuthenticator  {

@Override
public boolean isRequestAuthorized(Request arg0) {
  System.out.println("####WFCRestAuthenticatorImpl.isRequestAuthorized()….");
  return false;
}

@Override
public boolean requestRequiresAuthentication(Request arg0) {
  System.out.println("####WFCRestAuthenticatorImpl.requestRequiresAuthentication()….");
  return false;
}
}
</java>

Created a custom class extending the <blockcode>org.activiti.rest.service.application.ActivitiRestServicesApplication</blockcode> to set custom Rest Authenticator implementation
<java>
public class WFCActivitiRestServicesApplication extends ActivitiRestServicesApplication {

public WFCActivitiRestServicesApplication() {
  System.out.println("####WFCActivitiRestServicesApplication.WFCActivitiRestServicesApplication()…");
  setRestAuthenticator(new WFCRestAuthenticatorImpl());
}
}
</java>
Updated the web.xml to use this custom implemenation
<blockcode>
  <servlet> 
    <servlet-name>RestletServlet</servlet-name> 
    <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
    <init-param>
      <!– Application class name –>
      <param-name>org.restlet.application</param-name>
      <param-value>WFCActivitiRestServicesApplication</param-value>
    </init-param>
  </servlet>
</blockcode>

<blockcode>The package names have been eliminated</blockcode>

The SOPs in my custom classes are printed on the console, indicating that Activiti is recognizing the classes.

When I start the Activiti-REST web app deployed on Tomcat 7, I get the following error on the console:
<blockcode>
Jul 25, 2014 12:21:18 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory C:\myApp\apache-tomcat-7.0.29\webapps\myActRest
12:21:19,257 [localhost-startStop-1] INFO  org.activiti.rest.common.servlet.ActivitiServletContextListener  - Booting Activiti Process Engine
12:21:19,267 [localhost-startStop-1] ERROR org.activiti.rest.common.servlet.ActivitiServletContextListener  - Could not start the Activiti REST API
</blockcode>

When I try to access a REST (/myActRest/service/deployments) , I get the following exception trace:
<blockcode>
Jul 25, 2014 12:02:05 PM org.restlet.resource.ServerResource doCatch
WARNING: Exception or error caught in server resource
Internal Server Error (500) - The server encountered an unexpected condition which prevented it from fulfilling the request
at org.restlet.resource.ServerResource.doHandle(ServerResource.java:517)
at org.restlet.resource.ServerResource.get(ServerResource.java:707)
at org.restlet.resource.ServerResource.doHandle(ServerResource.java:589)
at org.restlet.resource.ServerResource.doNegotiatedHandle(ServerResource.java:649)
at org.restlet.resource.ServerResource.doConditionalHandle(ServerResource.java:348)
at org.restlet.resource.ServerResource.handle(ServerResource.java:952)
at org.restlet.resource.Finder.handle(Finder.java:246)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Router.doHandle(Router.java:431)
at org.restlet.routing.Router.handle(Router.java:648)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:155)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:211)
at org.restlet.engine.application.ApplicationHelper.handle(ApplicationHelper.java:84)
at org.restlet.Application.handle(Application.java:381)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Router.doHandle(Router.java:431)
at org.restlet.routing.Router.handle(Router.java:648)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Router.doHandle(Router.java:431)
at org.restlet.routing.Router.handle(Router.java:648)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:211)
at org.restlet.Component.handle(Component.java:392)
at org.restlet.Server.handle(Server.java:516)
at org.restlet.engine.ServerHelper.handle(ServerHelper.java:72)
at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:152)
at org.restlet.ext.servlet.ServerServlet.service(ServerServlet.java:1089)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1770)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.NullPointerException
at org.activiti.rest.common.application.ActivitiRestApplication.authenticate(ActivitiRestApplication.java:105)
at org.activiti.rest.common.api.SecuredResource.authenticate(SecuredResource.java:171)
at org.activiti.rest.common.api.SecuredResource.authenticate(SecuredResource.java:167)
at org.activiti.rest.service.api.legacy.deployment.DeploymentsResource.getDeployments(DeploymentsResource.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.restlet.resource.ServerResource.doHandle(ServerResource.java:506)
… 59 more
</blockcode>

Looking at the method <blockcode>org.activiti.rest.common.application.ActivitiRestApplication.authenticate(ActivitiRestApplication.java:105)</blockcode> source code, it seems that the problem might be related to setting of a user as you have mentioned.
<blockcode>Also, best to populate the org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId() in this method,</blockcode>

Can you elaborate how to retrieve and set the user.

To prove my above point, I updated the Authenticator implementation to set the user name as follows:
<java>
public class WFCRestAuthenticatorImpl implements RestAuthenticator  {

@Override
public boolean isRequestAuthorized(Request arg0) {
  System.out.println("####WFCRestAuthenticatorImpl.isRequestAuthorized()….");
  return false;
}

@Override
public boolean requestRequiresAuthentication(Request arg0) {
  System.out.println("####WFCRestAuthenticatorImpl.requestRequiresAuthentication()….");
  //org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId()
  ClientInfo cInfo = arg0.getClientInfo();
  System.out.println("####WFCRestAuthenticatorImpl.requestRequiresAuthentication() ClientInfo: " + cInfo);
  User user = new User("kermit");
  cInfo.setUser(user);
  return false;
}
}
</java>

This resulted in the following exception
<blockcode>
Caused by: java.lang.NullPointerException
at org.activiti.rest.common.api.ActivitiUtil.getIdentityService(ActivitiUtil.java:70)
at org.activiti.rest.common.api.SecuredResource.authenticate(SecuredResource.java:178)
at org.activiti.rest.common.api.SecuredResource.authenticate(SecuredResource.java:167)
at org.activiti.rest.service.api.legacy.deployment.DeploymentsResource.getDeployments(DeploymentsResource.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.restlet.resource.ServerResource.doHandle(ServerResource.java:506)
… 59 more
</blockcode>

Looks like I am still missing something here in setting the user name and related stuff.

frederikherema1
Star Contributor
Star Contributor
I think, in requestRequiresAuthentication(), you should also setAuthenticated() to true, when creating the ClientInfo object. Setting the user doesn't automatically set that flag to true. If set to true, all BaseResource authenticate() calls will be fine…

manchandap
Champ in-the-making
Champ in-the-making
@frederikheremans thanks for your inputs.
I tried your suggestion but still getting the same exception. I am using Activiti 5.15. Here's my updated code:
<java>
public class WFCRestAuthenticatorImpl implements RestAuthenticator  {

@Override
public boolean isRequestAuthorized(Request arg0) {
  System.out.println("####WFCRestAuthenticatorImpl.isRequestAuthorized()….");
  return false;
}

@Override
public boolean requestRequiresAuthentication(Request arg0) {
  System.out.println("####WFCRestAuthenticatorImpl.requestRequiresAuthentication()….");
  //org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId()
  ClientInfo cInfo = arg0.getClientInfo();
  System.out.println("####WFCRestAuthenticatorImpl.requestRequiresAuthentication() ClientInfo: " + cInfo);
  User user = new User("kermit");
  cInfo.setUser(user);
  cInfo.setAuthenticated(true);
  //Authentication.setAuthenticatedUserId("kermit");
  return false;
}
}
</java>

frederikherema1
Star Contributor
Star Contributor
Have overlooked the actual cause of the exception. Seems to be NPE while getting the IdentityService… Did you change anything to the name of the process-engine (non-default) or altered the ActivitiUtilProvider?

manchandap
Champ in-the-making
Champ in-the-making
@frederikheremans thanks for your help
I was able to get it working with the above code. Probably there was some issue with the jar files in my WEB-INF\lib directory.
One more question. How can i populate the User object dynamically that is without hard coding. Does Activiti APIs have access to the HTTPRequest object or alternatively which Activiti API should I populate in my filter/servlet with the user name.

frederikherema1
Star Contributor
Star Contributor
You can access the HttpRequest in the "public boolean requestRequiresAuthentication(Request arg0) {" method you implemented. Use IdentityService.setAuthenticatedUserId(…) to let the engine know what user to take for actions that use the logged in user.