cancel
Showing results for 
Search instead for 
Did you mean: 

Can not setAuthenticatedUserId in rest API if there is customization authentication

youtianhong
Champ in-the-making
Champ in-the-making
Hello everyone,

As we know, we can set the initiator like below code :

<startEvent id="request" activiti:initiator="initiator" />
The authenticated user must be set with the method BEFORE the process instance is started,
try {
  identityService.setAuthenticatedUserId("bono");
  runtimeService.startProcessInstanceByKey("someProcessKey");
} finally {
  identityService.setAuthenticatedUserId(null);
}


The problem is I want to start a new process with variables using the rest api, the command to start this is:
http://localhost:8080/activitirestservice/service/runtime/process-instances

I think it will be successful if we have not a custom authenticator in rest api service side.

The variables like below:

{
   "processDefinitionKey":"leave",
    "variables": [
      {
        "name":"applyUserId",
        "value":"Frank"
      }
   ]
}

The following words is jbarrez's feedback in http://forums.activiti.org/content/start-process-instance-user-using-rest-api#comment-30444.

We've got a unit test for this: ProcessInstanceCollectionResourceTest.testStartProcess().
I ran this here, and it fills the start user just fine (user is set by client.setChallengeResponse(ChallengeScheme.HTTP_BASIC, "kermit", "kermit");
)
Did you somehowe tweak the rest api or have a custom authenticator?


But the system did not write the 'applyUserId' in field start_user_id of table act_hi_procinst, it always was wrote the word 'system user' that was setted in override 'authenticate' method  by me.
like above mention by jbarrez, I think
the problem maybe was that I did a customization way to override 'authenticate' method.
I also think it will work fine when I remove this customzation, but we don't want to authenticate in rest service side.

So is there any solution for this case ? How can i pass userId in initiator and don't remove authentication  customization.
Any feedback will be greatly appreciated.
Thanks in advance!

To remove authentication in rest api service side, I did a customization,the following is my solution way
1. add customzation config in web.xml

  <!– 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>com.phzc.activiti.custom.filter.CustomActivitiRestServicesApplication</param-value>
    </init-param>
  </servlet>

2. Create class CustomActivitiRestServicesApplication, the activiti user guide don't mention that override authenticate method,
but for my testing, I need  override this method, otherwise authentication is still need.

public class CustomActivitiRestServicesApplication extends ActivitiRestServicesApplication {
   protected RestResponseFactory restResponseFactory;
          public CustomActivitiRestServicesApplication() {
       super();
       restAuthenticator = new RestAuthenticatorImpl();
       setRestAuthenticator(restAuthenticator);
     }
    @Override
     public String authenticate(Request request, Response response) {
        if(request.getClientInfo() != null) {
           if(request.getClientInfo().getUser() != null) {
              return request.getClientInfo().getUser().getIdentifier();
           }
        }
        return "system user";
     }
   }

3. Override requestRequiresAuthentication method

public class RestAuthenticatorImpl implements RestAuthenticator {
   @Override
   public boolean requestRequiresAuthentication(Request request) {
      return false;
   }
   @Override
   public boolean isRequestAuthorized(Request request) {
      return false;
   } 
}

2 REPLIES 2

balsarori
Champ on-the-rise
Champ on-the-rise
In your overrided authenticate method you need to return the user id that should be used. 

If your application uses custom authentication, you need to extract the current authenticated user id from the request. One way of doing that is as follows:

[java]
public String authenticate(Request request, Response response) {
// use org.restlet.ext.servlet.ServletUtils to get HttpServletRequest
    HttpServletRequest servletRequest = ServletUtils.getRequest(restletRequest);
   
    String userId = // Add whatever logic to retrieve user id to be used
    return userId;
  }
[/java]

If you want to use another user id (other than the current authenticated user id) for the initiator then you need to use a custom implementation of ProcessInstanceCollectionResource class and call identityService.setAuthenticatedUserId before starting the process.


Note that Restlet was replaced by Spring MVC since Activiti 5.16.4

Much Thanks balsarori for your detailed response.
Actuallty, I also thought that override ProcessInstanceCollectionResource  class and call identityService.setAuthenticatedUserId to solve this issue.
But this still has a problem, though this customization class can write the userId correctlly when we start a process instance, however we do other actions subsequently like 'claim task', 'complete task' etc, it will be overridden by "System user" which was written in 'authenticate' method again, because we know that every rest method has a validataion process like "if (!authenticate()) return null;" before invoking real API.
So I think we still need to modify 'authenticate' method, and receive the real userId in the client side.

I want to encapsulate rest api client side code, it's  like ActivitiClient.jar that can be embed in other web application.
So i don't how to create a dummy HttpServletRequest,Since HttpServletRequest is an interface
that is implemented by other web container
I tested it like you mention as below code
<code>
// use org.restlet.ext.servlet.ServletUtils to get HttpServletRequest
    HttpServletRequest servletRequest = ServletUtils.getRequest(restletRequest);

//client side java code
   org.restlet.resource.ClientResource clientResource = new ClientResource(uri);
  clientResource.setReference(uri);
  ClientInfo clientInfo = new ClientInfo();
  org.restlet.security.User user = new User();
  user.setIdentifier("Frank");
  clientInfo.setUser(user);
  clientResource.setClientInfo(clientInfo);
  //the other way
  org.restlet.Request request = clientResource.createRequest();
  Map map = new HashMap();
  map.put("user", "ygq");
  request.setAttributes(map);

</code>
For my debug in service side, I did not find the attribute in restletRequest or HttpServletRequest,
Do you know how to set this parameter in restlet client or how to  create a dummy HttpServletRequest ?
Thanks a lot again!


Regards,
Frank