You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@syncope.apache.org by Bob Lannoy <bo...@gmail.com> on 2012/05/30 16:10:14 UTC

Tokens

Hi guys,

I've been looking at using the generate token functionality from the workflow.

I'm not sure how to go about because the current /activate method in
the UserController doesn't take into account a token that you can pass
from the outside.
For the moment I implemented my own activation method
/activate/{userId} with a token=<token> as query parameter.

Then there are two cases in which a token might be invalid:
- not the same token passed on input, where you might want to stay in
"activate" state
- token has expired in which case you might want to delete the user object

I added a method to the SyncopeUser to catch that
public boolean hasTokenExpired() {
        return !tokenExpireTime.after(new Date());
    }

If you guys agree I can put it into JIRA as a patch?

best regards

Bob

Re: Tokens

Posted by Bob Lannoy <bo...@gmail.com>.
Hi Francesco,

> Not at all, at least as far as I know :)
> Anyway, I've opened SYNCOPE-91 for taking care of this suggestion of
> yours (and more).

OK great.


> If you take a look at ActivitiUserWorkflowAdapter.delete() (this is
> called by UserController.delete()):
>
>        doExecuteTask(user, "delete", null);
>        userDAO.delete(user);
>
> This means that first the "delete" task is executed (possibly involving
> the Delete class, if workflow XML says so), then user is effectively
> deleted.
> Unfortunately, I don't think that userDAO.delete() can be called by the
> Delete class because it would be in a non-transactional scope; anyway,
> you can give it a try.
I tried that and it runs through the workflow activate -> activateGW
-> delete. I get strange error messages that the object has indeed
been deleted but it's still in the database and visible in console in
the "activate" state. I'll have to look into more detail.

> Alternatively, you can think to put users to be deleted in a "sink"
> status and to create a SchedTask for periodically cleaning up such
> sinked users.
OK maybe I'll try that.

>>> There is also a generic UserController.executeWorkflow() taking UserTO
>>> and task name as parameters for this purpose.
>> Ok this might be handy for my password reset flow. To be sure, an example
>> from the default workflow:
>> when the user is in "active" there are currently three paths. If I would
>> want to push the user to the suspend state I call the executeworkflow with
>> the userTO and "suspend" as taskId?
>
> Correct in principle, but consider that suspend() and reactivate() have
> their own methods. Such methods (alongside with activate()) will take
> care of forwarding the given action to underlying workflow + propagating
> the new user status to associated external resources, if requested /
> necessary.
I was only using them as an example. I was planning to use it for my
password reset functionality which also sends a token and sets a flag
on the user.
The front-end will handle the logic of activating & updating the password

In that case my workflow bit looks like
 <userTask id="active" name="Active"/>

    <sequenceFlow id="flow7" sourceRef="active" targetRef="activeGw"/>

    <exclusiveGateway id="activeGw"/>
    ...
    <sequenceFlow id="active2PasswordReset" sourceRef="activeGw"
targetRef="passwordreset">
      <conditionExpression xsi:type="tFormalExpression">${task ==
'passwordreset'}</conditionExpression>
    </sequenceFlow>
...
    <!-- will generate token and redirect to activate -->
    <serviceTask id="passwordreset" name="Generate token"
activiti:class="org.apache.syncope.core.workflow.activiti.GenerateToken"/>
    <sequenceFlow id="PWRflow1" sourceRef="passwordreset"
targetRef="activatePW"/>
...

So I need to call executeworkflow with the userTO and "passwordreset" as taskId?


The alternative is of course to add the passwordreset method in the
controller and handling in workflow, but that's on the roadmap ;)

best regards

Bob

Re: Tokens

Posted by Francesco Chicchiriccò <il...@apache.org>.
On 31/05/2012 20:55, Bob Lannoy wrote:
> On May 31, 2012 4:41 PM, "Francesco Chicchiriccò" <il...@apache.org>
> wrote:
>> Hi Bob,
>> I've finally had chance to take a closer look at your requirements and
>> was able to spend some time looking at how such requirements could be
>> implemented in Syncope with as less modifications as possible.
> It seems that I went a bit wild on the modification side of things ;)
> I have still some remarks/questions.
>
>> I've just fixed (you have to wait for Jenkis to deploy new artifacts)
>> our standard UserController.activate() in order to be effective; here it
>> goes the (fixed) flow:
>>
>> 1. UserController.activate() is called via REST: just be sure to call
>> this method with an UserTO object where you actually put the token as
>> provided by the user (UserTO.setToken()).
> Ok this is what I needed, I'll change my frontend.
> I find it somewhat strange to pass a userTO just for the userid and the
> token. Wouldn't a simpler activate method make more sense e.g.
> activate/{userid}?token=...? This is similar to the link the user gets. Or
> is this against rest-principles?

Not at all, at least as far as I know :)
Anyway, I've opened SYNCOPE-91 for taking care of this suggestion of
yours (and more).

>> in your workflow XML. SyncopeUser.checkToken() will check if the token
>> is correct and still valid.
> As I explained in a previous post it makes sense to add a method to
> SyncopeUser that only checks for an expired token, e.g. hasTokenExpired().
> The workflow could then handle a wrong token and expired token as two
> different flows. I want to delete the user with an expired token. But I'm
> unable to, could you give an idea how this should be done in the Delete
> class of the workflow?

If you take a look at ActivitiUserWorkflowAdapter.delete() (this is
called by UserController.delete()):

        doExecuteTask(user, "delete", null);
        userDAO.delete(user);

This means that first the "delete" task is executed (possibly involving
the Delete class, if workflow XML says so), then user is effectively
deleted.
Unfortunately, I don't think that userDAO.delete() can be called by the
Delete class because it would be in a non-transactional scope; anyway,
you can give it a try.
Alternatively, you can think to put users to be deleted in a "sink"
status and to create a SchedTask for periodically cleaning up such
sinked users.

>> There is also a generic UserController.executeWorkflow() taking UserTO
>> and task name as parameters for this purpose.
> Ok this might be handy for my password reset flow. To be sure, an example
> from the default workflow:
> when the user is in "active" there are currently three paths. If I would
> want to push the user to the suspend state I call the executeworkflow with
> the userTO and "suspend" as taskId?

Correct in principle, but consider that suspend() and reactivate() have
their own methods. Such methods (alongside with activate()) will take
care of forwarding the given action to underlying workflow + propagating
the new user status to associated external resources, if requested /
necessary.

Regards.

-- 
Francesco Chicchiriccò

ASF Member, Apache Cocoon PMC and Apache Syncope PPMC Member
http://people.apache.org/~ilgrosso/


Re: Tokens

Posted by Bob Lannoy <bo...@gmail.com>.
On May 31, 2012 4:41 PM, "Francesco Chicchiriccò" <il...@apache.org>
wrote:
>
> Hi Bob,
> I've finally had chance to take a closer look at your requirements and
> was able to spend some time looking at how such requirements could be
> implemented in Syncope with as less modifications as possible.
It seems that I went a bit wild on the modification side of things ;)
I have still some remarks/questions.

> I've just fixed (you have to wait for Jenkis to deploy new artifacts)
> our standard UserController.activate() in order to be effective; here it
> goes the (fixed) flow:
>
> 1. UserController.activate() is called via REST: just be sure to call
> this method with an UserTO object where you actually put the token as
> provided by the user (UserTO.setToken()).
Ok this is what I needed, I'll change my frontend.
I find it somewhat strange to pass a userTO just for the userid and the
token. Wouldn't a simpler activate method make more sense e.g.
activate/{userid}?token=...? This is similar to the link the user gets. Or
is this against rest-principles?

> in your workflow XML. SyncopeUser.checkToken() will check if the token
> is correct and still valid.
As I explained in a previous post it makes sense to add a method to
SyncopeUser that only checks for an expired token, e.g. hasTokenExpired().
The workflow could then handle a wrong token and expired token as two
different flows. I want to delete the user with an expired token. But I'm
unable to, could you give an idea how this should be done in the Delete
class of the workflow?

>
> There is also a generic UserController.executeWorkflow() taking UserTO
> and task name as parameters for this purpose.
Ok this might be handy for my password reset flow. To be sure, an example
from the default workflow:
when the user is in "active" there are currently three paths. If I would
want to push the user to the suspend state I call the executeworkflow with
the userTO and "suspend" as taskId?

> Hope this helps.
Yes it does, thanks for your help.

Best regards
Bob

Re: Tokens

Posted by Francesco Chicchiriccò <il...@apache.org>.
Hi Bob,
I've finally had chance to take a closer look at your requirements and
was able to spend some time looking at how such requirements could be
implemented in Syncope with as less modifications as possible.

Let's start from creation / activation process:

1. user gets created (someone calls UserController.create() via REST)

2. the workflow calls GenerateToken that (as you correctly reported in
SYNCOPE-90) generates but doesn't persist the token: I am going to apply
Sarris's patch ASAP and fix this issue

3. assuming that an appropriate notification is defined, an e-mail in
sent to the user just created with an activation link containing the
value of the token generated

4. user clicks the link that calls an activate() REST service

5. assuming that an appropriate notification is defined, a welcome
e-mail is sent to the user


AFAIU, (2) used to be problematic but Sarris and you found an easy fix,
while (4) is still problematic.

I've just fixed (you have to wait for Jenkis to deploy new artifacts)
our standard UserController.activate() in order to be effective; here it
goes the (fixed) flow:

1. UserController.activate() is called via REST: just be sure to call
this method with an UserTO object where you actually put the token as
provided by the user (UserTO.setToken()).

2. UserController.setStatus() is called with userTO.getToken() as
parameter - this is my fix

3. AbstractUserWorkflowAdapter.activate(user, token) is called, then
ActivitiUserWorkflowAdapter.doActivate()

4. at this point the workflow is triggered: the 'activate' task is
called, and the 'token' workflow variable now contains the value
originally provided by the user; hence you could write something like:

syncopeUser.checkToken(token)

or

syncopeUser.removeToken()

in your workflow XML. SyncopeUser.checkToken() will check if the token
is correct and still valid.

The whole idea is that you should not be required - except for very rare
and particular cases - to tweak UserController in order to implement
your custom workflow: it should be enough to customize the XML for this.

There is also a generic UserController.executeWorkflow() taking UserTO
and task name as parameters for this purpose.

Hope this helps.

Regards.

On 31/05/2012 09:10, Bob Lannoy wrote:
> Hi Francesco,
>
> just to keep you updated, I've attached my workflow.
> I'm able to send a token and call my own activate/{userId} REST method
> with the token from the mail.
>
> I'm unable to delete the user when the token has expired. I noticed
> that the Delete.java is nearly empty. I tried a userDAO.delete(user)
> in a custom delete class but the user stays visible in console (and is
> still in the database).
>
> I also started working on a password reset mechanism also based on the
> token approach but I'm still looking for the best way.
> For the moment I added a "pwreset" task which I also put into the
> workflow java classes and an additional rest-method to launch the
> task.
>
> regards
>
> Bob
>
>> Hi Bob,
>> I don't have time today, but I'll take a look at this tomorrow and I
>> hope I'll come back to you with something meaningful about workflow,
>> token and activate.
>>
>> Regards.
-- 
Francesco Chicchiriccò

ASF Member, Apache Cocoon PMC and Apache Syncope PPMC Member
http://people.apache.org/~ilgrosso/


Re: Tokens

Posted by Bob Lannoy <bo...@gmail.com>.
Hi Francesco,

just to keep you updated, I've attached my workflow.
I'm able to send a token and call my own activate/{userId} REST method
with the token from the mail.

I'm unable to delete the user when the token has expired. I noticed
that the Delete.java is nearly empty. I tried a userDAO.delete(user)
in a custom delete class but the user stays visible in console (and is
still in the database).

I also started working on a password reset mechanism also based on the
token approach but I'm still looking for the best way.
For the moment I added a "pwreset" task which I also put into the
workflow java classes and an additional rest-method to launch the
task.

regards

Bob

> Hi Bob,
> I don't have time today, but I'll take a look at this tomorrow and I
> hope I'll come back to you with something meaningful about workflow,
> token and activate.
>
> Regards.
>
> --
> Francesco Chicchiriccò
>
> ASF Member, Apache Cocoon PMC and Apache Syncope PPMC Member
> http://people.apache.org/~ilgrosso/
>

Re: Tokens

Posted by Francesco Chicchiriccò <il...@apache.org>.
On 30/05/2012 16:10, Bob Lannoy wrote:
> Hi guys,
>
> I've been looking at using the generate token functionality from the workflow.
>
> I'm not sure how to go about because the current /activate method in
> the UserController doesn't take into account a token that you can pass
> from the outside.
> For the moment I implemented my own activation method
> /activate/{userId} with a token=<token> as query parameter.
>
> Then there are two cases in which a token might be invalid:
> - not the same token passed on input, where you might want to stay in
> "activate" state
> - token has expired in which case you might want to delete the user object
>
> I added a method to the SyncopeUser to catch that
> public boolean hasTokenExpired() {
>         return !tokenExpireTime.after(new Date());
>     }
>
> If you guys agree I can put it into JIRA as a patch?

Hi Bob,
I don't have time today, but I'll take a look at this tomorrow and I
hope I'll come back to you with something meaningful about workflow,
token and activate.

Regards.

-- 
Francesco Chicchiriccò

ASF Member, Apache Cocoon PMC and Apache Syncope PPMC Member
http://people.apache.org/~ilgrosso/