unique derived attributes

12 views
Skip to first unread message

renemulder

unread,
Dec 16, 2011, 5:16:42 AM12/16/11
to syncope-users
Hi All,

I'm not sure whether this is already added in the trunk, but I would
very much like to put a uniqueness contraint on derived attributes (or
actually, we have the requirement that a combination of two attirbutes
must be unique for a user).

Is this already implemented and if not, is it scope for the future?

thanks in advance
René

Francesco Chicchiriccò

unread,
Dec 16, 2011, 6:06:43 AM12/16/11
to syncop...@googlegroups.com
Hi Rene,
there is nothing similar so far in the roadmap.

At the moment, actual values for derived attributes are not stored but evaluated upon request: this makes virtually impossible to enforce a constraint as the one you describe above.

In order to accomplish this, the internal logic should be changed:
  1. there should be 6 news tables: UDerAttrValue. UDerAttrUniqueValue, RDerAttrValue, RDerAttrUniqueValue, MDerAttrValue, MDerAttrAtrUniqueValue (for users, roles and memberships): we need this because the only effective way to enforce UNIQUE constraints is by delegating this check to the underlying database
  2. values for derived attributes should be evaluated upon user/role/membership creation or update and stored so that constraints check can take place (as it currently happens for plain attributes)
  3. values would be read from storage upon user/role/membership read (instead of evaluating on the fly)

it's nothing impossible but it's quite a considerable effort, so my question is: do you think this could be a common use case?

Anyway, you could implement this requirement in your overlay with limited effort.
Let's suppose that you currently have a derived schema C defined as A + ' ' + B, where A and B are plain schemas.
Now you would like to define a unique constraint on C but at the moment Syncope does support it, as said above.

What you can do is:
  • delete derived schema C
  • create a plain schema C with UNIQUE constraint
  • override UserController's create() and update() methods in order to
    • read A and B values from UserTO
    • add C to UserTO / UserMod and set its value according to the previous definition (A + ' ' + B)
    • call super.create() / super.update()

With this workaround you loose the ability to change the definition of C from console but you should be able to implement all the rest of your use case.

Regards.

-- 
Francesco Chicchiriccò

"Computer Science is no more about computers than astronomy
is about telescopes." (E. W. Dijkstra)

renemulder

unread,
Jan 13, 2012, 9:31:24 AM1/13/12
to syncope-users
Hi Francesco,

Thanks for the suggested workaround. I started implementing this
today, but ran into something:

How do i override only those two methods?

One option would be to copy UserController.java from the Syncope
project and make the changes i want. However, this isn't really
flexible, since i would have to update the file every time we would
upgrade the Syncope dependency.

The alternative would be to create my own class, say MyUserController,
and have it extend UserController, then overriding only create(...)
and update(...). However, then i'd need to tell Syncope in some way to
actually USE MyUserController instead of UserController and i could
find no such thing in the Spring configuration OR don't know how to do
it :(. Obviously, I would very much like to do this without copying &
modifying some existing spring configuration leading again to reduced
flexibility.

Which option did you have in mind when you suggested the solution
below?

Thanks in advance,

René


On Dec 16 2011, 12:06 pm, Francesco Chicchiriccò
<chicchiri...@gmail.com> wrote:
> On 16/12/2011 11:16, renemulder wrote:
>
> > Hi All,
>
> > I'm not sure whether this is already added in the trunk, but I would very much like to put a uniqueness contraint on derived attributes (or actually, we have the requirement that a combination of two attirbutes must be unique for a user).
>
> > Is this already implemented and if not, is it scope for the future?
>
> Hi Rene,
> there is nothing similar so far in the roadmap.
>
> At the moment, actual values for derived attributes are not stored but
> evaluated upon request: this makes virtually impossible to enforce a
> constraint as the one you describe above.
>
> In order to accomplish this, the internal logic should be changed:
>
>  1. there should be 6 news tables: UDerAttrValue. UDerAttrUniqueValue,
>     RDerAttrValue, RDerAttrUniqueValue, MDerAttrValue,
>     MDerAttrAtrUniqueValue (for users, roles and memberships): we need
>     this because the only effective way to enforce UNIQUE constraints is
>     by delegating this check to the underlying database
>  2. values for derived attributes should be evaluated upon
>     user/role/membership creation or update and stored so that
>     constraints check can take place (as it currently happens for plain
>     attributes)
>  3. values would be read from storage upon user/role/membership read
>     (instead of evaluating on the fly)
>
> it's nothing impossible but it's quite a considerable effort, so my
> question is: do you think this could be a common use case?
>
> Anyway, you could implement this requirement in your overlay with
> limited effort.
> Let's suppose that you currently have a derived schema C defined as A +
> ' ' + B, where A and B are plain schemas.
> Now you would like to define a unique constraint on C but at the moment
> Syncope does support it, as said above.
>
> What you can do is:
>
>   * delete derived schema C
>   * create a plain schema C with UNIQUE constraint
>   * override UserController's create() and update() methods in order to
>       o read A and B values from UserTO
>       o add C to UserTO / UserMod and set its value according to the
>         previous definition (A + ' ' + B)
>       o call super.create() / super.update()
>
> With this workaround you loose the ability to change the definition of C
> from console but you should be able to implement all the rest of your
> use case.
>
> Regards.
>
> --
> Francesco Chicchiricc�

Francesco Chicchiriccò

unread,
Jan 16, 2012, 3:13:39 AM1/16/12
to syncop...@googlegroups.com
On 13/01/2012 15:31, renemulder wrote:
> Hi Francesco,
>
> Thanks for the suggested workaround. I started implementing this
> today, but ran into something:
>
> How do i override only those two methods?
>
> One option would be to copy UserController.java from the Syncope
> project and make the changes i want. However, this isn't really
> flexible, since i would have to update the file every time we would
> upgrade the Syncope dependency.

I agree with you: this is bad :-)

> The alternative would be to create my own class, say MyUserController,
> and have it extend UserController, then overriding only create(...)
> and update(...). However, then i'd need to tell Syncope in some way to
> actually USE MyUserController instead of UserController and i could
> find no such thing in the Spring configuration OR don't know how to do
> it :(. Obviously, I would very much like to do this without copying &
> modifying some existing spring configuration leading again to reduced
> flexibility.

Well, AFAIK you can label your MyUserController as

@Controller
@RequestMapping("/user")

and overridden methods as

@PreAuthorize("hasRole('USER_CREATE')")
@RequestMapping(method = RequestMethod.POST,
value = "/mycreate")
public UserTO create(...

@PreAuthorize("hasRole('USER_UPDATE')")
@RequestMapping(method = RequestMethod.POST,
value = "/myupdate")
public UserTO update(

i.e. you can bind updated REST services at /user/mycreate (instead of
standard /user/create) and /user/myupdate (instead of standard
/user/update).

Unfortunately I don't know how to disable former binding to /user/create
- this is pure Spring 3 stuff: I'll try to seek for this but please
report here if you get something.

The ugliest part of this is that, in order to make console calling the
updated service, you must override - and this time by completely
replacing - org.syncope.console.rest.UserRestClient.

Hum... it seems to me that we should put something in roadmap as
improvement for this.

WDYT?

> Which option did you have in mind when you suggested the solution
> below?
>
> Thanks in advance,
>

> Ren�
>
>
> On Dec 16 2011, 12:06 pm, Francesco Chicchiricc�

Francesco Chicchiricc�

renemulder

unread,
Jan 24, 2012, 10:10:15 AM1/24/12
to syncope-users
Hi!

I'm glad that the issue landed. Currently, I've overlayed the entire
controller, but obviously placed the injected logic in a separate
class. This could also be an indication for a more flexible solution:
addition of hooks. So to give you an idea of the current solution,
here is a snippet of UserController.java. The rest of the controller
is entirely the same to keep the manual step of upgrading to a later
version of syncope as simple as possible.

public SyncopeUser update(SyncopeUser user, UserMod userMod,
Set<Long> mandatoryRoles, Set<String> mandatoryResources)
throws WorkflowException, NotFoundException,
PropagationException {

// change UserTO for composite unique attribute
ILS_UNIEKE_IDENTIFIER
BnlUserController bnlController = new BnlUserController();
bnlController.update(user, userMod, mandatoryRoles,
mandatoryResources);


// First of all, let's check if update is allowed
Map<String, Object> inputs = new HashMap<String, Object>();
inputs.put(Constants.SYNCOPE_USER, user);
inputs.put(Constants.USER_MOD, userMod);

So all that happens in the bnlController is that the userTo gets
modified -> the attribute holding the composite unique attirbute gets
filled.

If Spring doesn't support partial overlays, which is basicly what
would be perfect, an alternative could be to create a package of Hooks
that by default have an empty implementation. so instead of
bnlController.update(..) something like preUserUpdateHook.execute(..);

One could overlay the implemetation for preUserUpdateHook or overlay
the spring configuration that sets the implementing class.

kind regards,
René

On Jan 16, 9:13 am, Francesco Chicchiriccò <chicchiri...@gmail.com>
wrote:
Reply all
Reply to author
Forward
0 new messages