Hi Martin, The point of this second design is that Organisation is your domain class, not part of the security module, so it can have whatever you want in it.
Cheers, Dan On 21 Nov 2014 09:46, "Martin Balmaceda" <[email protected]> wrote: > Greetings > > Thanks Dan, a great suggestion and not as crazy complicated as I was > expecting. > One question though: how extensible would the Organization be in this case? > I imagine every use case would require this class to represent something > different. > > On Thu, Nov 20, 2014 at 7:02 PM, Dan Haywood <[email protected] > > > wrote: > > > Hi folks, > > > > Great to see this thread with lots of useful contributions from everyone. > > > > ~~~ > > As Jeroen has said, we definitely intend to enhance the security module, > > though only as the exact requirements become clear. > > > > For Martin's requirement, to allow an Organization to be associated with > > the ApplicationUser, and also for Johan's that sounds similar, we > basically > > want to have somewhere to store the AppUser/Organization tuple. > > > > I can see two approaches. > > > > 1. store the AppUser/Org tuple in a subclass of ApplicationUser > > > > 2. store the AppUser/Org tuple as a separate entity (let's call it > > OrganizationUser) that is 1:1 with the AppUser, and then use contributed > > properties and actions to make it appear as if the Org is an actual > > property of ApplicatoinUser. > > > > So, in (1), OrganizationUser is-a ApplicatoinUser, in (2) ApplicatoinUser > > has-a OrganizatoinUser > > > > > > Obviously (1) is gonna be much easier to implement, but (2) is much more > > flexible and modular. > > > > > > Here's a sketch of how to implement (2): > > > > > > First, we have the Organization entity: > > > > public class Organization { > > > > // name property etc > > private String name; > > public String getName() { ... } > > public void setName(String name) { ... } > > > > > > > > // 1:m bidir collection of OrganizationUser, hidden > > Persistent(mappedBy="organization") > > private SortedSet<OrganizationUser> users; > > > > @Hidden > > public SortedSet<OrganizationUser> getUsers() { ... } > > public void setUsers(SortedSet<OrganizationUser> users) { ... } > > > > > > > > // 1:m derived collection of ApplicationUsers > > @NotPersisted > > @NotPersistent > > public List<ApplicationUser> getApplicationUsers() { > > return Lists.newArrayList( > > Iterables.transform(getUsers(), > > OrganizationUser.AS_USER)); > > } > > > > } > > > > > > > > Next, we have our OrganizatonUser, the tuple between Org and AppUser: > > > > public class OrganizationUser { > > > > public static Function<OrganizationUser, ApplicationUser> AS_USER = > > new Function<OrganizationUser, ApplicationUser>() { > > public ApplicationUser apply(OrganizationUser ou) { > > return ou.getApplicationUser(); > > } > > }; > > > > > > // the org (other side of the 1:m bidir relationship, see above) > > private Organization organization; > > public Organization getOrganization() { ... } > > public void setOrganization(Organization o) { ... } > > > > > > // the corresponding appUser > > private ApplicationUser applicationUser; > > public ApplicationUser getApplicationUser() { ... } > > public void setApplicationUser(ApplicationUser au) { ... } > > > > } > > > > > > Next, we have a service that will contribute: > > - 'organization' as a property to applicationUser > > - 'assignTo' as an action on applicationUser > > > > > > @DomainService > > public class OrganizationContributions { > > > > @NotInServiceMenu > > @ActionSemantics(As.SAFE) > > @NotContributed(As.ACTION) // ie contributed as property > > public Organization getOrganization(ApplicationUser appUser) { > > OrganizationUser orgUser = organizationUsers.findFor(appUser); > > return orgUser != null? orgUser.getOrganization(): null; > > } > > > > @NotInServiceMenu > > public ApplicationUser assignTo(ApplicationUser appUser, Organization > > organization) { > > organizationUsers.create(organization, appUser); > > return appUser; > > } > > > > @Inject > > private OrganizationUsers organizationUsers; > > > > } > > > > > > This delegates to an OrganizationUsers repo: > > > > > > @DomainService > > public class OrganizationUsers { > > > > @Programmatic > > public OrganizationUser findFor(ApplicationUser appUser) { > > return firstMatch(OrganizationUser.class, > "findByApplicationUser", > > "applicationUser", appUser); > > } > > > > @Programmatic > > public OrganizationUser create(Organization org, ApplicationUser > > appUser) { > > OrganizationUser ou = > newTransientInstance(OrganizationUser.class); > > ou.setOrganization(org); > > ou.setApplicationUser(appUser); > > persist(ou); > > return ou; > > } > > } > > > > > > > > The last bit of the puzzle is handling any deletions. For this we can > make > > the security module emit an appropriately strongly typed event, and then > > subscribe to it: > > > > @DomainService > > public class OrganizationSubscriptions { > > > > @Programmatic > > @PostConstruct > > public void postConstruct() { > > eventBusService.register(this); > > } > > > > @Subscribe > > public void on(ApplicationUser.Deleted ev) { > > if(ev.getPhase() == Phase.EXECUTING) { > > ApplicationUser appUser = ev.getApplicationUser(); > > OrganizationUser orgUser = > organizationUsers.findFor(appUser); > > if(orgUser != null) { > > // delete > > removeIfNotAlready(orgUser); > > } > > } > > } > > > > @Inject > > private EventBusService eventBusService; > > } > > > > > > ~~~~~~~ > > Of these two approaches, I would imagine you'll probably go with (1), but > > I'll update the security module so that either can be done. > > > > HTH > > Dan > > > > > > On 20 November 2014 16:11, Jeroen van der Wal <[email protected]> > wrote: > > > > > Martin: > > > Thanks for the compliments and keep us updated on your progress. > > > > > > Oscar: > > > Dan and I are on Holiday too: speaking at ApacheCon. Fortunately for us > > > laptops are obliged here :-) > > > > > > All good stuff that you mentioned, send more when you have time, a > domain > > > model maybe. As the security module is very fresh with little users It > > > shouldn't be hard to refactor it to accommodate more scenarios. Apache > > > Fortress is also acting in this space but I don't want to bring in an > > > additional component at this stage. But we might want to "borrow" some > of > > > their concepts. > > > > > > Cheers, > > > > > > Jeroen > > > > > > > > > > > > On Thu, Nov 20, 2014 at 2:23 PM, GESCONSULTOR <[email protected]> > > > wrote: > > > > > > > Hi all! > > > > > > > > I'm following the thread with a lot of interest. > > > > > > > > Problem is that this week I'm on holidays without access to the > laptop > > > > (first time ever and it's being great :) > > > > > > > > I find some points here, nearly all them mentioned before: > > > > - The need for a Tenant / Tenancy entity. > > > > - The need for an interface or abstract base entity that allows to > know > > > > the Tenant associated with an entity. > > > > - the need for the concept of "ownership", that in our case could be > > > > associated at least with a role (and perhaps with a specific user? If > > > > that's the case perhaps a common abstract parent entity for > > > > User and Role should be needed). > > > > - and probably the need for Role compositions (parent-child > > relationships > > > > or preferably m-n relationships - extended RBAC- for nested roles). > > > > - A property like "ownerByDefault" or similar that should reference > the > > > > owning Role (or User?) assigned by default to any entity created by > > this > > > > user (it could be changed or not afterwards depending on business > > logic). > > > > > > > > Adding something like that to current great implementation should > allow > > > > for easy (and really fine-grained) domain security. > > > > > > > > I don't have access to my list of other implementations so it could > > > change > > > > a bit, but basically that was the basis. > > > > > > > > HTH, > > > > > > > > Oscar > > > > > > > > > > > > > > > > > El 20/11/2014, a las 6:22, Jeroen van der Wal <[email protected] > > > > > > escribió: > > > > > > > > > > Hi Martin B, > > > > > > > > > > We added Tenancy to the security module which, in our case, > > represents > > > a > > > > > different legal entity and a users are assigned to a tenancy. We've > > > > looked > > > > > at RBAC [1] but were very pragmatic while implementing the module > ;-) > > > > > There's certainly room for improvement so if you can share your > > > thoughts, > > > > > requirements or entity model here we can perhaps align efforts. > > > > > > > > > > Oscar Bou, one of our other committers was very keen on this > subject > > > too. > > > > > Oscar: perhaps you want to pitch in too? > > > > > > > > > > And yes, please you can always fork it! > > > > > > > > > > Cheers, > > > > > > > > > > Jeroen > > > > > > > > > > [1] http://en.wikipedia.org/wiki/Role-based_access_control > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > On Thu, Nov 20, 2014 at 9:48 AM, Martin Balmaceda < > > > > > [email protected]> wrote: > > > > > > > > > >> Im not sure how using a Shiro role would work since they are > > > predefined > > > > yet > > > > >> organizations can be added/removed dynamically > > > > >> > > > > >> On Thu, Nov 20, 2014 at 10:37 AM, Martin Grigorov < > > > [email protected] > > > > > > > > > >> wrote: > > > > >> > > > > >>> Hi, > > > > >>> > > > > >>> I am not familiar with isis security module but isn't it possible > > to > > > > use > > > > >> a > > > > >>> (Shiro) Role as an Organization ? > > > > >>> > > > > >>> Martin Grigorov > > > > >>> Wicket Training and Consulting > > > > >>> https://twitter.com/mtgrigorov > > > > >>> > > > > >>>> On Thu, Nov 20, 2014 at 10:31 AM, <[email protected] > > > > > > wrote: > > > > >>>> > > > > >>>> > > > > >>>> > > > > >>>> > > > > >>>> - Hi Martin, maybe you can try a solution that I made and that > > works > > > > >> for > > > > >>>> me at the moment; > > > > >>>> I defined a 'an abstrat secure object' that has the properties > you > > > are > > > > >>>> looking for [1] > > > > >>>> > > > > >>>> [1] > > > > >> > > > > > > > > > > https://github.com/johandoornenbal/matching/blob/master/dom/src/main/java/info/matchingservice/dom/MatchingSecureMutableObject.java > > > > >>>> > > > > >>>> Thanks I agree, option 1 is much better. > > > > >>>> > > > > >>>> As for my user case: I have a system that hosts a number or > > > > >> organizations > > > > >>>> orthogonally. What I need to do is associate each user to > exactly > > 1 > > > > org > > > > >>> so > > > > >>>> that he/she can only see and modify information belonging to > that > > > org. > > > > >>>> > > > > >>>> After looking at the problem, I figure that the best way to do > it > > > > would > > > > >>> be > > > > >>>> to use the security module and add an Organization property to > > > > >>>> ApplicationUser. Unfortunately it seems I would have to fork the > > > > module > > > > >>> and > > > > >>>> add my custom Orgnization domain object to it. > > > > >>>> > > > > >>>> > > > > >>>> > > > > >>>> > > > > >>>> > > > > >>>> On Wed, Nov 19, 2014 at 5:54 PM, Dan Haywood > > > > >>>> wrote: > > > > >>>> > > > > >>>>>> On 19 November 2014 16:41, Jeroen van der Wal wrote: > > > > >>>>>> > > > > >>>>>> Just double-checked: the master branch of isis-module-security > > > uses > > > > >>> the > > > > >>>>>> latest and greatest version of Isis, 1.8.0-SNAPSHOT > > > > >>>>>> > > > > >>>>>> [1] > > > > >> > > > > > > > > > > https://github.com/isisaddons/isis-module-security/blob/master/pom.xml#L32-L36 > > > > >>>>> (though the screenshots in the README are still of 1.7.0) > > > > >>>>> > > > > >>>>> > > > > >>>>> > > > > >>>>> > > > > >>>>> > > > > >>>>>> On Wed, Nov 19, 2014 at 4:33 PM, Jeroen van der Wal > > > > > >>>>>> wrote: > > > > >>>>>> > > > > >>>>>>> Hi Martin, > > > > >>>>>>> > > > > >>>>>>> I would advice against option 2 because you lose an easy > update > > > > >>> path > > > > >>>> to > > > > >>>>>>> newer versions of the security module. > > > > >>>>> > > > > >>>>> +1 to that advice. > > > > >>>>> > > > > >>>>> > > > > >>>>> > > > > >>>>> > > > > >>>>>>> Tell us more about your use-case so we can see what the > options > > > > >>> are. > > > > >>>>> > > > > >>>>> In particular, is the additional information you need to store > > > > >>> mandatory > > > > >>>>> with no sensible default (ie would need to prompt for it), or > > would > > > > >> the > > > > >>>>> current signatures of the methods in ApplicationUsers domain > > > service > > > > >>>>> suffice? > > > > >>>>> > > > > >>>>> > > > > >>>>> > > > > >>>>> > > > > >>>>> > > > > >>>>>>> Cheers, > > > > >>>>>>> > > > > >>>>>>> > > > > >>>>>>> Jeroen > > > > >>>>>>> > > > > >>>>>>> On Wed, Nov 19, 2014 at 2:24 PM, Martin Balmaceda < > > > > >>>>>>> [email protected]> wrote: > > > > >>>> > > > > >>>> > > > > >>>> > > > > >>>> -- > > > > >>>> to do is to be. dobedobedo > > > > >> > > > > >> > > > > >> > > > > >> -- > > > > >> to do is to be. dobedobedo > > > > >> > > > > > > > > > > > > > -- > to do is to be. dobedobedo >
