I don't think it is common that permissions checked in the UI are different than permissions checked when the input from the UI is processed. In fact, I don't think I've ever run into that problem. The problem I have run into over and over is that in almost every toolkit and framework around (with just a few exceptions) you have to configure or code the permission checks twice, and they often get accidently out of sync (causing either usability problems or security vulnerabilities). If we're going to talk about extensions to the form widget or other things for security purposes, I think we should talk about this redundancy problem because it IS an issue for the framework and one that people talk about when comparing the OFBiz framework to certain competing modern frameworks... -David On Apr 30, 2009, at 4:42 PM, Adrian Crum wrote: > No, I'm not saying I disagree with you. You totally missed my point. > I don't think anyone is suggesting removing permissions checking > from the UI or the services. Let's get that settled right away. > > Jacopo is asking for a way to control the display of screen widgets > based on the user's permissions. You said: "The trick is how do we > setup permissions so that we set them up once and they function in > both places?" Maybe I'm misunderstanding your question. It sounds to > me like you're suggesting a single method could be used in both > scenarios, so I responded that the requirements are different - so a > single method wouldn't work. > > We're already using permissions to control the UI - and they are the > same ones used in the service calls. The problem is, it's hard to > implement. I believe all that's being suggested here is some new > widget attributes or something to make it easier. > > -Adrian > > David E Jones wrote: >> On Apr 30, 2009, at 4:09 PM, Adrian Crum wrote: >>> David E Jones wrote: >>>> In other words, it is nice to check permissions on the client >>>> side and/or show permission impact in the UI, but that just >>>> improves the UI... it doesn't actually enforce any of those >>>> permissions checks because it is really easy to change HTML and/ >>>> or spoof a request (ie users with valid credentials that can do >>>> other things could then get around permissions that are only >>>> checked in the UI). >>> >>> I think Jacopo's interest is an improved UI. Why render a Create >>> New button when the user doesn't have the permission to create >>> anything? >> Yeah, that's what I said... ie with phrases like "that just >> improves the UI" and "in the UI for user convenience". >>>> The trick is how do we setup permissions so that we set them up >>>> once and they function in both places (ie in the input processing >>>> for the actual security, and in the UI for user convenience)? >>> >>> Is that even possible? The UI might contain multiple paths to >>> follow, with each path requiring a different permission. Service >>> invocations are generally a single path with a single permission. >>> >>> In other words, the UI might need to know the user's create, >>> update, and delete permissions in order to render the screen, but >>> the user action will result in only one service invocation - which >>> requires only one of those user permissions. >>> >>> I thought about this a while back, and toyed with the idea of >>> making the screen widgets permissions-aware. >> So, are you saying that you disagree with what I wrote about the >> purposes of permissions in different places, ie: >> 1. input processing: for security >> 2. UI artifacts: for user convenience (improved UI) >> Maybe what I wrote wasn't clear enough, so I'll say it again: >> permission checking in the UI is USELESS for security, it only >> helps for an improved user experience. >> I would even go so far as to assert that if anyone doesn't >> understand this then they don't understand how web-based >> applications work, and the applications they write will be full of >> security holes. >> This is why in OFBiz we REQUIRE security for services (or other >> input processing logic) and it is OPTIONAL in the UI. >> -David |
In reply to this post by Jacopo Cappellato-4
FYI and I only realized this the other day but beanshell supports exactly this type of feature where you can specify things @and, @or and etc. for use in xml files http://www.beanshell.org/manual/syntax.html#Document_Friendly_Entities
I wonder if we do this it might be worth following the same convention. Regards Scott HotWax Media On 1/05/2009, at 5:34 AM, Jacopo Cappellato wrote:
smime.p7s (3K) Download Attachment |
I like that idea. Less chance that an unintended conversion would occur.
-Adrian Scott Gray wrote: > FYI and I only realized this the other day but beanshell supports > exactly this type of feature where you can specify things @and, @or and > etc. for use in xml > files http://www.beanshell.org/manual/syntax.html#Document_Friendly_Entities > > I wonder if we do this it might be worth following the same convention. > > Regards > Scott > > HotWax Media > http://www.hotwaxmedia.com <http://www.hotwaxmedia.com/> > > On 1/05/2009, at 5:34 AM, Jacopo Cappellato wrote: > >> Adrian, >> >> this is really interesting. >> However I think it is time to start thinking to define our own xml >> friendly keywords for && and || operators; I would like to express >> that statement with something like this: >> >> <set field="hasPermission" value="${(hasPermission['update:context1'] >> OR hasPermission['update:context2']) AND >> hasPermission['update:context3']}" type="Boolean"/> >> >> Jacopo >> >> >> On Apr 30, 2009, at 7:20 PM, Adrian Crum wrote: >> >>> <set field="hasPermission" value="${(hasPermission['update:context1'] >>> || hasPermission['update:context2']) && >>> hasPermission['update:context3']}" type="Boolean"/> >>> >>> or something like that. I'm still working out the details. >>> >>> -Adrian >>> >>> Andrew Zeneski wrote: >>>> That sounds cool. I'm not sure what that would really look like, but >>>> nevertheless sounds really cool! :) If you need anything from me let >>>> me know... >>>> Andrew >>>> On Apr 30, 2009, at 1:00 PM, Adrian Crum wrote: >>>>> Andrew Zeneski wrote: >>>>>> I'd be happy to discuss additional changes as well (which aren't >>>>>> yet documented) like adding support to check multiple permissions >>>>>> at once, returning a Map of results from that permission check. >>>>>> So, if you or anyone else has a wish list for security, let me >>>>>> know so I can get it all incorporated at the same time. >>>>> >>>>> Btw, I'm working on adding an extension to the UEL that will allow >>>>> permission expressions. >>>>> >>>>> >>>>> -Adrian >> > |
I'm trying to come up with a use case where this sort of logic would
be applicable, but I just cannot think of any. I can think of cases where we will conditionally want to check a single permission but OR/ AND permissions together for a UI element? When displaying a list of items, I might add a link to an update form, in which I would only show the link if update permission available. Same with delete, but I wouldn't check these in the same place, rather with each link. Also, I might use <display/> for read only users instead of text boxes (I really like Jacopo's use-when idea). But when would I really ever want to check them in an AND/OR fashion? Keeping in mind now, that the permission system handles granularity, as long as we are intelligent when defining permissions I believe a single permissions should be able to handle most cases. With the exception of UIs where we would want to display different things based on a different base permission, even then a single call using the new findMatchingPermissions() would totally do the trick. Andrew On Apr 30, 2009, at 7:43 PM, Adrian Crum wrote: > I like that idea. Less chance that an unintended conversion would > occur. > > -Adrian > > Scott Gray wrote: >> FYI and I only realized this the other day but beanshell supports >> exactly this type of feature where you can specify things @and, @or >> and etc. for use in xml files http://www.beanshell.org/manual/syntax.html#Document_Friendly_Entities >> I wonder if we do this it might be worth following the same >> convention. >> Regards >> Scott >> HotWax Media >> http://www.hotwaxmedia.com <http://www.hotwaxmedia.com/> >> On 1/05/2009, at 5:34 AM, Jacopo Cappellato wrote: >>> Adrian, >>> >>> this is really interesting. >>> However I think it is time to start thinking to define our own xml >>> friendly keywords for && and || operators; I would like to express >>> that statement with something like this: >>> >>> <set field="hasPermission" value="$ >>> {(hasPermission['update:context1'] OR >>> hasPermission['update:context2']) AND >>> hasPermission['update:context3']}" type="Boolean"/> >>> >>> Jacopo >>> >>> >>> On Apr 30, 2009, at 7:20 PM, Adrian Crum wrote: >>> >>>> <set field="hasPermission" value="$ >>>> {(hasPermission['update:context1'] || >>>> hasPermission['update:context2']) && >>>> hasPermission['update:context3']}" type="Boolean"/> >>>> >>>> or something like that. I'm still working out the details. >>>> >>>> -Adrian >>>> >>>> Andrew Zeneski wrote: >>>>> That sounds cool. I'm not sure what that would really look like, >>>>> but nevertheless sounds really cool! :) If you need anything >>>>> from me let me know... >>>>> Andrew >>>>> On Apr 30, 2009, at 1:00 PM, Adrian Crum wrote: >>>>>> Andrew Zeneski wrote: >>>>>>> I'd be happy to discuss additional changes as well (which >>>>>>> aren't yet documented) like adding support to check multiple >>>>>>> permissions at once, returning a Map of results from that >>>>>>> permission check. So, if you or anyone else has a wish list >>>>>>> for security, let me know so I can get it all incorporated at >>>>>>> the same time. >>>>>> >>>>>> Btw, I'm working on adding an extension to the UEL that will >>>>>> allow permission expressions. >>>>>> >>>>>> >>>>>> -Adrian >>> |
In reply to this post by David E Jones-3
On Apr 30, 2009, at 11:38 PM, David E Jones wrote: > > On Apr 30, 2009, at 11:07 AM, Jacopo Cappellato wrote: > >> >> On Apr 30, 2009, at 6:50 PM, Andrew Zeneski wrote: >> >>> ... I'd be happy to discuss additional changes as well (which >>> aren't yet documented) like adding support to check multiple >>> permissions at once, returning a Map of results from that >>> permission check. So, if you or anyone else has a wish list for >>> security, let me know so I can get it all incorporated at the same >>> time. >>> >>> Andrew >> >> this is probably off topic here, but an enhancement I would like to >> see in the form widgets is the ability for the widget model/ >> renderer to automatically select the proper field type according to >> the permissions of the user: this is something that can be already >> done using some scriptlets and the use-when attributes but it is >> pretty complex. >> I don't have a clear idea at the moment but the first options that >> I can think of are: >> 1) a new field type "display-update": it will be "display" if the >> user has view permissions; it will be "update" if the user has >> write permissions >> 2) add, a required-permission attribute to the field element: this >> will act as the use-when permission; or maybe adding something like >> use-when="${ofbiz:hasPermission(UPDATE)}" >> 3) submit buttons will be disabled if the user doesn't have proper >> permissions >> 4) base/default permissions could be set as an attribute in the >> form element or derived from the service (if auto-fields is used) > > How would we handle the "redundant" permission problem? Probably #4 in my wish list would be closer to that: we could get the permission service associated to the service specified by the "auto- field" service and use it to derive the permissions for the form. We may want to refactor the permission services to return the list of permissions for a given action instead of just a boolean (or in addition to it). For example: the permission service, instead of answering the question: "does the user X has UPDATE permission for the QUOTE action?" could be refactored to answer the question: "what are the permissions that user X has for the QUOTE process?" if I have a form associated to the updateQuote service, but the user has only READ permission for the QUOTE process, then the service will return a permission error when called by the user, and the form will render as a display form, without a submit button (or with a disabled one). Jacopo > > > In other words, it is nice to check permissions on the client side > and/or show permission impact in the UI, but that just improves the > UI... it doesn't actually enforce any of those permissions checks > because it is really easy to change HTML and/or spoof a request (ie > users with valid credentials that can do other things could then get > around permissions that are only checked in the UI). Because of this > it is still necessary to check all permissions in services > processing incoming data, otherwise we have a security hole that is > pretty easy to exploit (well, if people realize it is there anyway). > > The trick is how do we setup permissions so that we set them up once > and they function in both places (ie in the input processing for the > actual security, and in the UI for user convenience)? > > -David > smime.p7s (3K) Download Attachment |
In reply to this post by Andrew Zeneski-2
As I mentioned in another reply, the permission expressions could replace scripts. I agree there would probably be little use for them in the UI. -Adrian --- On Thu, 4/30/09, Andrew Zeneski <[hidden email]> wrote: > From: Andrew Zeneski <[hidden email]> > Subject: Re: svn commit: r770084 - in /ofbiz/trunk/framework/example: ./ config/ data/ entitydef/ security/ servicedef/ widget/example/ > To: [hidden email] > Date: Thursday, April 30, 2009, 7:31 PM > I'm trying to come up with a use case where this sort of > logic would be applicable, but I just cannot think of any. I > can think of cases where we will conditionally want to check > a single permission but OR/AND permissions together for a UI > element? > > When displaying a list of items, I might add a link to an > update form, in which I would only show the link if update > permission available. Same with delete, but I wouldn't > check these in the same place, rather with each link. > > Also, I might use <display/> for read only users > instead of text boxes (I really like Jacopo's use-when > idea). But when would I really ever want to check them in an > AND/OR fashion? > > Keeping in mind now, that the permission system handles > granularity, as long as we are intelligent when defining > permissions I believe a single permissions should be able to > handle most cases. With the exception of UIs where we would > want to display different things based on a different base > permission, even then a single call using the new > findMatchingPermissions() would totally do the trick. > > Andrew > > On Apr 30, 2009, at 7:43 PM, Adrian Crum wrote: > > > I like that idea. Less chance that an unintended > conversion would occur. > > > > -Adrian > > > > Scott Gray wrote: > >> FYI and I only realized this the other day but > beanshell supports exactly this type of feature where you > can specify things @and, @or and etc. for use in xml files > http://www.beanshell.org/manual/syntax.html#Document_Friendly_Entities > >> I wonder if we do this it might be worth following > the same convention. > >> Regards > >> Scott > >> HotWax Media > >> http://www.hotwaxmedia.com > <http://www.hotwaxmedia.com/> > >> On 1/05/2009, at 5:34 AM, Jacopo Cappellato wrote: > >>> Adrian, > >>> > >>> this is really interesting. > >>> However I think it is time to start thinking > to define our own xml friendly keywords for && and > || operators; I would like to express that statement with > something like this: > >>> > >>> <set field="hasPermission" > value="${(hasPermission['update:context1'] OR > hasPermission['update:context2']) AND > hasPermission['update:context3']}" > type="Boolean"/> > >>> > >>> Jacopo > >>> > >>> > >>> On Apr 30, 2009, at 7:20 PM, Adrian Crum > wrote: > >>> > >>>> <set field="hasPermission" > value="${(hasPermission['update:context1'] || > hasPermission['update:context2']) && > hasPermission['update:context3']}" > type="Boolean"/> > >>>> > >>>> or something like that. I'm still > working out the details. > >>>> > >>>> -Adrian > >>>> > >>>> Andrew Zeneski wrote: > >>>>> That sounds cool. I'm not sure > what that would really look like, but nevertheless sounds > really cool! :) If you need anything from me let me know... > >>>>> Andrew > >>>>> On Apr 30, 2009, at 1:00 PM, Adrian > Crum wrote: > >>>>>> Andrew Zeneski wrote: > >>>>>>> I'd be happy to discuss > additional changes as well (which aren't yet documented) > like adding support to check multiple permissions at once, > returning a Map of results from that permission check. So, > if you or anyone else has a wish list for security, let me > know so I can get it all incorporated at the same time. > >>>>>> > >>>>>> Btw, I'm working on adding an > extension to the UEL that will allow permission expressions. > >>>>>> > >>>>>> > >>>>>> -Adrian > >>> |
In reply to this post by jonesde
Andrew,
I thought we were getting away from using the <required-permissions> element and using the <permission-service> element instead. If this type of change is made in other components, it will break a lot of code - because some components use permission service SECAs. -Adrian [hidden email] wrote: > Author: jaz > Date: Thu Apr 30 06:23:18 2009 > New Revision: 770084 > > URL: http://svn.apache.org/viewvc?rev=770084&view=rev > Log: > Refactored Example Application to use new security mechanics - JIRA OFBIZ-2392 ... > Modified: ofbiz/trunk/framework/example/servicedef/services.xml > URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/example/servicedef/services.xml?rev=770084&r1=770083&r2=770084&view=diff > ============================================================================== > --- ofbiz/trunk/framework/example/servicedef/services.xml (original) > +++ ofbiz/trunk/framework/example/servicedef/services.xml Thu Apr 30 06:23:18 2009 > @@ -27,29 +27,37 @@ > <!-- Example & Related Services --> > <service name="createExample" default-entity-name="Example" engine="entity-auto" invoke="create" auth="true"> > <description>Create a Example</description> > - <permission-service service-name="exampleGenericPermission" main-action="CREATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="create:example"/> > + </required-permissions> > <auto-attributes include="pk" mode="OUT" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > <override name="exampleTypeId" optional="false"/> > <override name="statusId" optional="false"/> > - <override name="exampleName" optional="false"/> > + <override name="exampleName" optional="false"/> > </service> > <service name="updateExample" default-entity-name="Example" engine="entity-auto" invoke="update" auth="true"> > <description>Update a Example</description> > - <permission-service service-name="exampleGenericPermission" main-action="UPDATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="update:example:${exampleId}"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > <attribute name="oldStatusId" type="String" mode="OUT" optional="false"/> > </service> > <service name="deleteExample" default-entity-name="Example" engine="entity-auto" invoke="delete" auth="true"> > <description>Delete a Example</description> > - <permission-service service-name="exampleGenericPermission" main-action="DELETE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="delete:example:${exampleId}"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > <service name="createExampleStatus" default-entity-name="ExampleStatus" engine="simple" > location="component://example/script/org/ofbiz/example/example/ExampleServices.xml" invoke="createExampleStatus" auth="true"> > <description>Create a ExampleStatus</description> > - <permission-service service-name="exampleGenericPermission" main-action="CREATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="update:example:status:${exampleId}"/> > + </required-permissions> > <auto-attributes include="all" mode="IN" optional="false"> > <exclude field-name="statusDate"/> > <exclude field-name="statusEndDate"/> > @@ -58,7 +66,9 @@ > > <service name="createExampleItem" default-entity-name="ExampleItem" engine="entity-auto" invoke="create" auth="true"> > <description>Create a ExampleItem</description> > - <permission-service service-name="exampleGenericPermission" main-action="CREATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="create:example:item:${exampleId}"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > <override name="exampleItemSeqId" mode="OUT"/> <!-- make this OUT rather than IN, we will automatically generate the next sub-sequence ID --> > @@ -66,60 +76,78 @@ > </service> > <service name="updateExampleItem" default-entity-name="ExampleItem" engine="entity-auto" invoke="update" auth="true"> > <description>Update a ExampleItem</description> > - <permission-service service-name="exampleGenericPermission" main-action="UPDATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="update:example:item:${exampleId}"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > </service> > <service name="deleteExampleItem" default-entity-name="ExampleItem" engine="entity-auto" invoke="delete" auth="true"> > <description>Delete a ExampleItem</description> > - <permission-service service-name="exampleGenericPermission" main-action="DELETE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="delete:example:item:${exampleId}"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > > <!-- ExampleFeature Services --> > <service name="createExampleFeature" default-entity-name="ExampleFeature" engine="entity-auto" invoke="create" auth="true"> > <description>Create a ExampleFeature</description> > - <permission-service service-name="exampleGenericPermission" main-action="CREATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="create:example:feature"/> > + </required-permissions> > <auto-attributes include="pk" mode="OUT" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > <override name="description" optional="false"/> > </service> > <service name="updateExampleFeature" default-entity-name="ExampleFeature" engine="entity-auto" invoke="update" auth="true"> > <description>Update a ExampleFeature</description> > - <permission-service service-name="exampleGenericPermission" main-action="UPDATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="update:example:feature"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > </service> > <service name="deleteExampleFeature" default-entity-name="ExampleFeature" engine="entity-auto" invoke="delete" auth="true"> > <description>Delete a ExampleFeature</description> > - <permission-service service-name="exampleGenericPermission" main-action="DELETE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="delete:example:feature"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > > <service name="createExampleFeatureAppl" default-entity-name="ExampleFeatureAppl" engine="entity-auto" invoke="create" auth="true"> > <description>Create a ExampleFeatureAppl</description> > - <permission-service service-name="exampleGenericPermission" main-action="CREATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="create:example:feature:${exampleFeatureId}"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > <override name="fromDate" optional="true"/> > </service> > <service name="updateExampleFeatureAppl" default-entity-name="ExampleFeatureAppl" engine="entity-auto" invoke="update" auth="true"> > <description>Update a ExampleFeatureAppl</description> > - <permission-service service-name="exampleGenericPermission" main-action="UPDATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="update:example:feature:${exampleFeatureId}"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > </service> > <service name="deleteExampleFeatureAppl" default-entity-name="ExampleFeatureAppl" engine="entity-auto" invoke="delete" auth="true"> > <description>Delete a ExampleFeatureAppl</description> > - <permission-service service-name="exampleGenericPermission" main-action="DELETE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="delete:example:feature:${exampleFeatureId}"/> > + </required-permissions> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > > <!-- Permission Services --> > + <!-- @deprecated > <service name="exampleGenericPermission" engine="simple" > location="component://example/script/org/ofbiz/example/ExamplePermissionServices.xml" invoke="exampleGenericPermission"> > <implements service="permissionInterface"/> > </service> > + --> > > <!-- Example ServiceTest Service --> > <service name="testCreateExampleService" engine="simple" |
Adrian,
I will start a new thread to discuss this, but before I do I want to make sure there isn't something I neglected to account for. Could you please provide an example of such a service which uses SECA permission services? Andrew On May 1, 2009, at 12:04 PM, Adrian Crum wrote: > Andrew, > > I thought we were getting away from using the <required-permissions> > element and using the <permission-service> element instead. > > If this type of change is made in other components, it will break a > lot of code - because some components use permission service SECAs. > > -Adrian > > [hidden email] wrote: >> Author: jaz >> Date: Thu Apr 30 06:23:18 2009 >> New Revision: 770084 >> URL: http://svn.apache.org/viewvc?rev=770084&view=rev >> Log: >> Refactored Example Application to use new security mechanics - JIRA >> OFBIZ-2392 > > ... > > >> Modified: ofbiz/trunk/framework/example/servicedef/services.xml >> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/example/servicedef/services.xml?rev=770084&r1=770083&r2=770084&view=diff >> = >> = >> = >> = >> = >> = >> = >> = >> = >> ===================================================================== >> --- ofbiz/trunk/framework/example/servicedef/services.xml (original) >> +++ ofbiz/trunk/framework/example/servicedef/services.xml Thu Apr >> 30 06:23:18 2009 >> @@ -27,29 +27,37 @@ >> <!-- Example & Related Services --> >> <service name="createExample" default-entity-name="Example" >> engine="entity-auto" invoke="create" auth="true"> >> <description>Create a Example</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="CREATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="create:example"/> >> + </required-permissions> <auto-attributes >> include="pk" mode="OUT" optional="false"/> >> <auto-attributes include="nonpk" mode="IN" optional="true"/> >> <override name="exampleTypeId" optional="false"/> >> <override name="statusId" optional="false"/> >> - <override name="exampleName" optional="false"/> >> + <override name="exampleName" optional="false"/ >> > </service> >> <service name="updateExample" default-entity-name="Example" >> engine="entity-auto" invoke="update" auth="true"> >> <description>Update a Example</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="UPDATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="update:example:$ >> {exampleId}"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> <auto-attributes include="nonpk" mode="IN" optional="true"/> >> <attribute name="oldStatusId" type="String" mode="OUT" >> optional="false"/> >> </service> >> <service name="deleteExample" default-entity-name="Example" >> engine="entity-auto" invoke="delete" auth="true"> >> <description>Delete a Example</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="DELETE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="delete:example:$ >> {exampleId}"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> </service> >> <service name="createExampleStatus" default-entity- >> name="ExampleStatus" engine="simple" >> location="component://example/script/org/ofbiz/example/ >> example/ExampleServices.xml" invoke="createExampleStatus" >> auth="true"> >> <description>Create a ExampleStatus</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="CREATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="update:example:status:$ >> {exampleId}"/> >> + </required-permissions> >> <auto-attributes include="all" mode="IN" optional="false"> >> <exclude field-name="statusDate"/> >> <exclude field-name="statusEndDate"/> >> @@ -58,7 +66,9 @@ >> <service name="createExampleItem" default-entity- >> name="ExampleItem" engine="entity-auto" invoke="create" auth="true"> >> <description>Create a ExampleItem</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="CREATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="create:example:item:$ >> {exampleId}"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> <auto-attributes include="nonpk" mode="IN" optional="true"/> >> <override name="exampleItemSeqId" mode="OUT"/> <!-- make >> this OUT rather than IN, we will automatically generate the next >> sub-sequence ID --> >> @@ -66,60 +76,78 @@ >> </service> >> <service name="updateExampleItem" default-entity- >> name="ExampleItem" engine="entity-auto" invoke="update" auth="true"> >> <description>Update a ExampleItem</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="UPDATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="update:example:item:$ >> {exampleId}"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> <auto-attributes include="nonpk" mode="IN" optional="true"/> >> </service> >> <service name="deleteExampleItem" default-entity- >> name="ExampleItem" engine="entity-auto" invoke="delete" auth="true"> >> <description>Delete a ExampleItem</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="DELETE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="delete:example:item:$ >> {exampleId}"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> </service> >> <!-- ExampleFeature Services --> >> <service name="createExampleFeature" default-entity- >> name="ExampleFeature" engine="entity-auto" invoke="create" >> auth="true"> >> <description>Create a ExampleFeature</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="CREATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="create:example:feature"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="OUT" optional="false"/> >> <auto-attributes include="nonpk" mode="IN" optional="true"/> >> <override name="description" optional="false"/> >> </service> >> <service name="updateExampleFeature" default-entity- >> name="ExampleFeature" engine="entity-auto" invoke="update" >> auth="true"> >> <description>Update a ExampleFeature</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="UPDATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="update:example:feature"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> <auto-attributes include="nonpk" mode="IN" optional="true"/> >> </service> >> <service name="deleteExampleFeature" default-entity- >> name="ExampleFeature" engine="entity-auto" invoke="delete" >> auth="true"> >> <description>Delete a ExampleFeature</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="DELETE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="delete:example:feature"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> </service> >> <service name="createExampleFeatureAppl" default-entity- >> name="ExampleFeatureAppl" engine="entity-auto" invoke="create" >> auth="true"> >> <description>Create a ExampleFeatureAppl</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="CREATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="create:example:feature:$ >> {exampleFeatureId}"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> <auto-attributes include="nonpk" mode="IN" optional="true"/> >> <override name="fromDate" optional="true"/> >> </service> >> <service name="updateExampleFeatureAppl" default-entity- >> name="ExampleFeatureAppl" engine="entity-auto" invoke="update" >> auth="true"> >> <description>Update a ExampleFeatureAppl</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="UPDATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="update:example:feature:$ >> {exampleFeatureId}"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> <auto-attributes include="nonpk" mode="IN" optional="true"/> >> </service> >> <service name="deleteExampleFeatureAppl" default-entity- >> name="ExampleFeatureAppl" engine="entity-auto" invoke="delete" >> auth="true"> >> <description>Delete a ExampleFeatureAppl</description> >> - <permission-service service- >> name="exampleGenericPermission" main-action="DELETE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="delete:example:feature:$ >> {exampleFeatureId}"/> >> + </required-permissions> >> <auto-attributes include="pk" mode="IN" optional="false"/> >> </service> >> <!-- Permission Services --> >> + <!-- @deprecated >> <service name="exampleGenericPermission" engine="simple" >> location="component://example/script/org/ofbiz/example/ >> ExamplePermissionServices.xml" invoke="exampleGenericPermission"> >> <implements service="permissionInterface"/> >> </service> >> + --> >> <!-- Example ServiceTest Service --> >> <service name="testCreateExampleService" engine="simple" |
Look in the Asset Maintenance component.
-Adrian Andrew Zeneski wrote: > Adrian, > > I will start a new thread to discuss this, but before I do I want to > make sure there isn't something I neglected to account for. Could you > please provide an example of such a service which uses SECA permission > services? > > Andrew > > On May 1, 2009, at 12:04 PM, Adrian Crum wrote: > >> Andrew, >> >> I thought we were getting away from using the <required-permissions> >> element and using the <permission-service> element instead. >> >> If this type of change is made in other components, it will break a >> lot of code - because some components use permission service SECAs. >> >> -Adrian >> >> [hidden email] wrote: >>> Author: jaz >>> Date: Thu Apr 30 06:23:18 2009 >>> New Revision: 770084 >>> URL: http://svn.apache.org/viewvc?rev=770084&view=rev >>> Log: >>> Refactored Example Application to use new security mechanics - JIRA >>> OFBIZ-2392 >> >> ... >> >> >>> Modified: ofbiz/trunk/framework/example/servicedef/services.xml >>> URL: >>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/example/servicedef/services.xml?rev=770084&r1=770083&r2=770084&view=diff >>> >>> ============================================================================== >>> >>> --- ofbiz/trunk/framework/example/servicedef/services.xml (original) >>> +++ ofbiz/trunk/framework/example/servicedef/services.xml Thu Apr 30 >>> 06:23:18 2009 >>> @@ -27,29 +27,37 @@ >>> <!-- Example & Related Services --> >>> <service name="createExample" default-entity-name="Example" >>> engine="entity-auto" invoke="create" auth="true"> >>> <description>Create a Example</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="CREATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission permission="create:example"/> >>> + </required-permissions> <auto-attributes >>> include="pk" mode="OUT" optional="false"/> >>> <auto-attributes include="nonpk" mode="IN" optional="true"/> >>> <override name="exampleTypeId" optional="false"/> >>> <override name="statusId" optional="false"/> >>> - <override name="exampleName" optional="false"/> >>> + <override name="exampleName" optional="false"/> >>> </service> >>> <service name="updateExample" default-entity-name="Example" >>> engine="entity-auto" invoke="update" auth="true"> >>> <description>Update a Example</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="UPDATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="update:example:${exampleId}"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> <auto-attributes include="nonpk" mode="IN" optional="true"/> >>> <attribute name="oldStatusId" type="String" mode="OUT" >>> optional="false"/> >>> </service> >>> <service name="deleteExample" default-entity-name="Example" >>> engine="entity-auto" invoke="delete" auth="true"> >>> <description>Delete a Example</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="DELETE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="delete:example:${exampleId}"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> </service> >>> <service name="createExampleStatus" >>> default-entity-name="ExampleStatus" engine="simple" >>> >>> location="component://example/script/org/ofbiz/example/example/ExampleServices.xml" >>> invoke="createExampleStatus" auth="true"> >>> <description>Create a ExampleStatus</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="CREATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="update:example:status:${exampleId}"/> >>> + </required-permissions> >>> <auto-attributes include="all" mode="IN" optional="false"> >>> <exclude field-name="statusDate"/> >>> <exclude field-name="statusEndDate"/> >>> @@ -58,7 +66,9 @@ >>> <service name="createExampleItem" >>> default-entity-name="ExampleItem" engine="entity-auto" >>> invoke="create" auth="true"> >>> <description>Create a ExampleItem</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="CREATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="create:example:item:${exampleId}"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> <auto-attributes include="nonpk" mode="IN" optional="true"/> >>> <override name="exampleItemSeqId" mode="OUT"/> <!-- make this >>> OUT rather than IN, we will automatically generate the next >>> sub-sequence ID --> >>> @@ -66,60 +76,78 @@ >>> </service> >>> <service name="updateExampleItem" >>> default-entity-name="ExampleItem" engine="entity-auto" >>> invoke="update" auth="true"> >>> <description>Update a ExampleItem</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="UPDATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="update:example:item:${exampleId}"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> <auto-attributes include="nonpk" mode="IN" optional="true"/> >>> </service> >>> <service name="deleteExampleItem" >>> default-entity-name="ExampleItem" engine="entity-auto" >>> invoke="delete" auth="true"> >>> <description>Delete a ExampleItem</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="DELETE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="delete:example:item:${exampleId}"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> </service> >>> <!-- ExampleFeature Services --> >>> <service name="createExampleFeature" >>> default-entity-name="ExampleFeature" engine="entity-auto" >>> invoke="create" auth="true"> >>> <description>Create a ExampleFeature</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="CREATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission permission="create:example:feature"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="OUT" optional="false"/> >>> <auto-attributes include="nonpk" mode="IN" optional="true"/> >>> <override name="description" optional="false"/> >>> </service> >>> <service name="updateExampleFeature" >>> default-entity-name="ExampleFeature" engine="entity-auto" >>> invoke="update" auth="true"> >>> <description>Update a ExampleFeature</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="UPDATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission permission="update:example:feature"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> <auto-attributes include="nonpk" mode="IN" optional="true"/> >>> </service> >>> <service name="deleteExampleFeature" >>> default-entity-name="ExampleFeature" engine="entity-auto" >>> invoke="delete" auth="true"> >>> <description>Delete a ExampleFeature</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="DELETE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission permission="delete:example:feature"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> </service> >>> <service name="createExampleFeatureAppl" >>> default-entity-name="ExampleFeatureAppl" engine="entity-auto" >>> invoke="create" auth="true"> >>> <description>Create a ExampleFeatureAppl</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="CREATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="create:example:feature:${exampleFeatureId}"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> <auto-attributes include="nonpk" mode="IN" optional="true"/> >>> <override name="fromDate" optional="true"/> >>> </service> >>> <service name="updateExampleFeatureAppl" >>> default-entity-name="ExampleFeatureAppl" engine="entity-auto" >>> invoke="update" auth="true"> >>> <description>Update a ExampleFeatureAppl</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="UPDATE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="update:example:feature:${exampleFeatureId}"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> <auto-attributes include="nonpk" mode="IN" optional="true"/> >>> </service> >>> <service name="deleteExampleFeatureAppl" >>> default-entity-name="ExampleFeatureAppl" engine="entity-auto" >>> invoke="delete" auth="true"> >>> <description>Delete a ExampleFeatureAppl</description> >>> - <permission-service service-name="exampleGenericPermission" >>> main-action="DELETE"/> >>> + <required-permissions join-type="AND"> >>> + <check-permission >>> permission="delete:example:feature:${exampleFeatureId}"/> >>> + </required-permissions> >>> <auto-attributes include="pk" mode="IN" optional="false"/> >>> </service> >>> <!-- Permission Services --> >>> + <!-- @deprecated >>> <service name="exampleGenericPermission" engine="simple" >>> >>> location="component://example/script/org/ofbiz/example/ExamplePermissionServices.xml" >>> invoke="exampleGenericPermission"> >>> <implements service="permissionInterface"/> >>> </service> >>> + --> >>> <!-- Example ServiceTest Service --> >>> <service name="testCreateExampleService" engine="simple" > > |
In reply to this post by Andrew Zeneski-2
I'd like to move the discussion of the new Authz security
implementation to this thread. To start off the discussion I will briefly describe what I would like to propose as the NEW best practices. 1. Single point of contact for ALL security checks, instead of having security embedded in functionality, or tied to services directly, the API should be the governor of all security. This means no more writing security logic in the functionality, and no more permission services attached directly to functionality (services or ecas). This is a bad design IMHO because it spreads the permission logic around in multiple places and makes it impossible to get the same results when checking permissions from different framework tools. -- We want to be consistent, and be able to obtain the same information from the UI or screen/form as we would get from a service call. -- Main point of contact is the Authorization interface. 2. Permission services become Dynamic Access (DA). Now instead of having permission services attached to services, we have Dynamic Access implementations which can be a compiled Java object, a Groovy script or a Service. My personal preference here is the Groovy script, but the API current supports all three. This DA logic is attached to a permission instead of a service. -- This allows for extending or changing the permission logic for a specific implementation/customization/application much easier. Since the DAs are all data driven, changing the seed data you can change the logic which is used. This means you no longer have to customize the services or logic in OFBiz to change the way authorization is handled for your company (or client); one less thing to worry about when merging customizations with the open source project. -- for groovy use "component://path/to/script.groovy" in the dynamicAccess field on SecurityPermission. -- for services use "service:serviceName" in the dynamicAccess field on SecurityPermission -- for objects use "org.ofbiz.path.to.Object (which implements DynamicAccess)" in the dynamicAccess field on SecurityPermission 3. Avoid having to check multiple permissions, for example PARTYMGR_UPDATE or PARTYMGR_ADMIN. Instead we use a new permission format which embeds all permissions which will be accepted: Example: update:party:contact:10000 - Update the contact information for party 10000 This will allow anyone who has: "update" or "update:party" or "update:party:contact" or is granted record level access by the DA logic. 4. Define permission for users, not admins. Instead of looking for a static permission, set the permission to be checked at the most granular level. When doing so, admin users will always have permission and the API will handle user access using DA logic. -- see: http://docs.ofbiz.org/x/JR4 That's enough to get started, http://docs.ofbiz.org/x/-B0 contains a lot more details; interested parties are encouraged to read it through. Andrew |
After reviewing the Asset Maintenance component's method of overriding
security, I understand the concern from Adrian in the other thread. This is something I left off the email below so I thought I would amend it now. While this is a really creative workaround for the limitations in the current security implementation, it is by no means an ideal solution. It is even more logic spread out in even more places making understanding and customizing authorization even more cumbersome. For these exact situations, the auto-grant functionality was implemented. So, instead of using ECAs to override permissions, you would define seed data (in the Asset Maint component, SFA, etc) which define which permissions are granted when a user is granted a specific application permission. There is a Use Case defined in the document (http://docs.ofbiz.org/x/- B0) which explains how this would work for the SFA application. Just for the record, nothing will break. The two frameworks can live side by side during the migration process. It is my plan to knock this out as quickly as possible, one application at a time. Also, I believe HWM is going to help by providing some resources to assist in the effort. Andrew On May 1, 2009, at 1:36 PM, Andrew Zeneski wrote: > I'd like to move the discussion of the new Authz security > implementation to this thread. To start off the discussion I will > briefly describe what I would like to propose as the NEW best > practices. > > 1. Single point of contact for ALL security checks, instead of > having security embedded in functionality, or tied to services > directly, the API should be the governor of all security. This means > no more writing security logic in the functionality, and no more > permission services attached directly to functionality (services or > ecas). This is a bad design IMHO because it spreads the permission > logic around in multiple places and makes it impossible to get the > same results when checking permissions from different framework tools. > > -- We want to be consistent, and be able to obtain the same > information from the UI or screen/form as we would get from a > service call. > -- Main point of contact is the Authorization interface. > > 2. Permission services become Dynamic Access (DA). Now instead of > having permission services attached to services, we have Dynamic > Access implementations which can be a compiled Java object, a Groovy > script or a Service. My personal preference here is the Groovy > script, but the API current supports all three. This DA logic is > attached to a permission instead of a service. > > -- This allows for extending or changing the permission logic for a > specific implementation/customization/application much easier. Since > the DAs are all data driven, changing the seed data you can change > the logic which is used. This means you no longer have to customize > the services or logic in OFBiz to change the way authorization is > handled for your company (or client); one less thing to worry about > when merging customizations with the open source project. > > -- for groovy use "component://path/to/script.groovy" in the > dynamicAccess field on SecurityPermission. > -- for services use "service:serviceName" in the dynamicAccess field > on SecurityPermission > -- for objects use "org.ofbiz.path.to.Object (which implements > DynamicAccess)" in the dynamicAccess field on SecurityPermission > > 3. Avoid having to check multiple permissions, for example > PARTYMGR_UPDATE or PARTYMGR_ADMIN. Instead we use a new permission > format which embeds all permissions which will be accepted: > > Example: update:party:contact:10000 - Update the contact information > for party 10000 > > This will allow anyone who has: > "update" or "update:party" or "update:party:contact" or is granted > record level access by the DA logic. > > 4. Define permission for users, not admins. Instead of looking for a > static permission, set the permission to be checked at the most > granular level. When doing so, admin users will always have > permission and the API will handle user access using DA logic. > > -- see: http://docs.ofbiz.org/x/JR4 > > That's enough to get started, http://docs.ofbiz.org/x/-B0 contains a > lot more details; interested parties are encouraged to read it > through. > > > Andrew > > > > > > > |
In reply to this post by Andrew Zeneski-2
--- On Fri, 5/1/09, Andrew Zeneski <[hidden email]> wrote: > From: Andrew Zeneski <[hidden email]> > Subject: Authz API Discussion (was re: svn commit: r770084) > To: [hidden email] > Date: Friday, May 1, 2009, 10:36 AM > 1. Single point of contact for ALL security checks, instead > of having security embedded in functionality, or tied to > services directly, the API should be the governor of all > security. This means no more writing security logic in the > functionality, and no more permission services attached > directly to functionality (services or ecas). This is a bad > design IMHO because it spreads the permission logic around > in multiple places and makes it impossible to get the same > results when checking permissions from different framework > tools. I don't understand what this means. Looking at the changes you made in the Example component, you still have permissions tied to the service definitions. Then you have permissions being checked in the screen widgets. From my perspective, nothing changed except the format of the permission string. Where is the "single point of contact" in the Example component? > 3. Avoid having to check multiple permissions, for example > PARTYMGR_UPDATE or PARTYMGR_ADMIN. Instead we use a new > permission format which embeds all permissions which will be > accepted: I don't see that being done explicitly in our current code. The OFBizSecurity class does that automatically. Any permission check is done with the ADMIN permission first, then the requested permission. > 4. Define permission for users, not admins. Instead of > looking for a static permission, set the permission to be > checked at the most granular level. When doing so, admin > users will always have permission and the API will handle > user access using DA logic. I disagree. I might want my application to behave differently if an admin is using it. Without an admin permission (or attribute), how will I know if a user is in an admin role? -Adrian |
In reply to this post by Andrew Zeneski-2
--- On Fri, 5/1/09, Andrew Zeneski <[hidden email]> wrote: > After reviewing the Asset Maintenance component's method > of overriding security, I understand the concern from Adrian > in the other thread. This is something I left off the email > below so I thought I would amend it now. > > While this is a really creative workaround for the > limitations in the current security implementation, it is by > no means an ideal solution. It is even more logic spread out > in even more places making understanding and customizing > authorization even more cumbersome. > > For these exact situations, the auto-grant functionality > was implemented. So, instead of using ECAs to override > permissions, you would define seed data (in the Asset Maint > component, SFA, etc) which define which permissions are > granted when a user is granted a specific application > permission. I read the Auto-Grant section. The question is, where is the seed data shown in your code example located? If it's it the SFA component, then the permissions are still spread around. All that has changed is instead of having permission-modifying SECAs in components, you have permission-modifying seed data in components. How was anything "centralized?" I don't mean to pour cold water on your enthusiasm, it's just that I don't see where anything is being added or improved. It looks basically the same, only slightly different. -Adrian |
In reply to this post by Andrew Zeneski-2
I see this new security framework as big step forward. The existing
security system is way too static, I mean permission rules are embedded in services such that users always need ofbiz DSL (mini lang) experts to do simple stuff (good job security, If there were customers). New system opens up doors for building tools that will make Ofbiz Administrators life lot easy. Like now I can write tools that will scan all the services/ forms/screen/menu widgets (may request entries in controller) and present me a tree of 1) Artifacts like services, screens, forms. Resources that you will like to secure. 2) List of different levels of permissions. Artifact node will show permission needed and children nodes that are list of users who have access the them. Permission node can list users who have those permission and list of artifacts that are allowed to use at that level. Administrator will be able to add or remove user or change level of access. If done right permissions in special purpose applications will be much more manageable. Auto-grant functionality can be {quote} extended {quote}, we can connect it with date model that stores permission dependency. e.g When user is granted "update:sfa:contact:10000" permission, How will security framework know that its same as "update:party:10000"? We can setup data for mapping special purpose permissions with fundamental permissions. So when security framework finds that called service requires "update:party:10000" permission and user does not have it then figure out if user have permissions that are equivalent or better then "update:party:10000" permission. Auto-grant concept can be extended for securing higher level (compound) services that in turn call multiple services. Just an idea, if we make our request secured like services, then we can secure our UI components because they know request id. > > Also, I believe HWM is going to help by providing some resources to > assist in the effort. +1 Whatever we decide, I am happy we are thinking about it. Regards Anil Patel On May 1, 2009, at 2:23 PM, Andrew Zeneski wrote: > After reviewing the Asset Maintenance component's method of > overriding security, I understand the concern from Adrian in the > other thread. This is something I left off the email below so I > thought I would amend it now. > > While this is a really creative workaround for the limitations in > the current security implementation, it is by no means an ideal > solution. It is even more logic spread out in even more places > making understanding and customizing authorization even more > cumbersome. > > For these exact situations, the auto-grant functionality was > implemented. So, instead of using ECAs to override permissions, you > would define seed data (in the Asset Maint component, SFA, etc) > which define which permissions are granted when a user is granted a > specific application permission. > > There is a Use Case defined in the document (http://docs.ofbiz.org/x/-B0 > ) which explains how this would work for the SFA application. > > Just for the record, nothing will break. The two frameworks can live > side by side during the migration process. It is my plan to knock > this out as quickly as possible, one application at a time. > Also, I believe HWM is going to help by providing some resources to > assist in the effort. > +1 > Andrew > > On May 1, 2009, at 1:36 PM, Andrew Zeneski wrote: > >> I'd like to move the discussion of the new Authz security >> implementation to this thread. To start off the discussion I will >> briefly describe what I would like to propose as the NEW best >> practices. >> >> 1. Single point of contact for ALL security checks, instead of >> having security embedded in functionality, or tied to services >> directly, the API should be the governor of all security. This >> means no more writing security logic in the functionality, and no >> more permission services attached directly to functionality >> (services or ecas). This is a bad design IMHO because it spreads >> the permission logic around in multiple places and makes it >> impossible to get the same results when checking permissions from >> different framework tools. >> >> -- We want to be consistent, and be able to obtain the same >> information from the UI or screen/form as we would get from a >> service call. >> -- Main point of contact is the Authorization interface. >> >> 2. Permission services become Dynamic Access (DA). Now instead of >> having permission services attached to services, we have Dynamic >> Access implementations which can be a compiled Java object, a >> Groovy script or a Service. My personal preference here is the >> Groovy script, but the API current supports all three. This DA >> logic is attached to a permission instead of a service. >> >> -- This allows for extending or changing the permission logic for a >> specific implementation/customization/application much easier. >> Since the DAs are all data driven, changing the seed data you can >> change the logic which is used. This means you no longer have to >> customize the services or logic in OFBiz to change the way >> authorization is handled for your company (or client); one less >> thing to worry about when merging customizations with the open >> source project. >> >> -- for groovy use "component://path/to/script.groovy" in the >> dynamicAccess field on SecurityPermission. >> -- for services use "service:serviceName" in the dynamicAccess >> field on SecurityPermission >> -- for objects use "org.ofbiz.path.to.Object (which implements >> DynamicAccess)" in the dynamicAccess field on SecurityPermission >> >> 3. Avoid having to check multiple permissions, for example >> PARTYMGR_UPDATE or PARTYMGR_ADMIN. Instead we use a new permission >> format which embeds all permissions which will be accepted: >> >> Example: update:party:contact:10000 - Update the contact >> information for party 10000 >> >> This will allow anyone who has: >> "update" or "update:party" or "update:party:contact" or is granted >> record level access by the DA logic. >> >> 4. Define permission for users, not admins. Instead of looking for >> a static permission, set the permission to be checked at the most >> granular level. When doing so, admin users will always have >> permission and the API will handle user access using DA logic. >> >> -- see: http://docs.ofbiz.org/x/JR4 >> >> That's enough to get started, http://docs.ofbiz.org/x/-B0 contains >> a lot more details; interested parties are encouraged to read it >> through. >> >> >> Andrew >> >> >> >> >> >> >> > |
In reply to this post by Adrian Crum-2
On May 1, 2009, at 4:23 PM, Adrian Crum wrote: > > --- On Fri, 5/1/09, Andrew Zeneski <[hidden email]> > wrote: >> From: Andrew Zeneski <[hidden email]> >> Subject: Authz API Discussion (was re: svn commit: r770084) >> To: [hidden email] >> Date: Friday, May 1, 2009, 10:36 AM >> 1. Single point of contact for ALL security checks, instead >> of having security embedded in functionality, or tied to >> services directly, the API should be the governor of all >> security. This means no more writing security logic in the >> functionality, and no more permission services attached >> directly to functionality (services or ecas). This is a bad >> design IMHO because it spreads the permission logic around >> in multiple places and makes it impossible to get the same >> results when checking permissions from different framework >> tools. > > I don't understand what this means. Looking at the changes you made > in the Example component, you still have permissions tied to the > service definitions. Then you have permissions being checked in the > screen widgets. From my perspective, nothing changed except the > format of the permission string. Where is the "single point of > contact" in the Example component? What changed is that now the permission logic is NOT tied directly to the service itself. The logic is tied to the permission. So ANY call to authz.hasPermission() the EXACT same code runs that checks the permission. That is the single point of contact, the hasPermission() method. The checks in the screen definition runs the same code as the checks in service definition. So now one advantage is, the update or delete button which is displayed in the UI if the user has permission will display (even if they do not have the static permission associated with their account) if the user can edit that specific item. It won't display for other items which the user cannot modify. > >> 3. Avoid having to check multiple permissions, for example >> PARTYMGR_UPDATE or PARTYMGR_ADMIN. Instead we use a new >> permission format which embeds all permissions which will be >> accepted: > > I don't see that being done explicitly in our current code. The > OFBizSecurity class does that automatically. Any permission check is > done with the ADMIN permission first, then the requested permission. Okay, so that was a bad example. How about CATALOG_UPDATE or CATALOG_ROLE_UPDATE instead as an example. Instead a simple permission defined as update:catalog:${catalogId} would take care of both of these. If the user has the static 'update:catalog' permission it would be granted (like a catalog admin might have), otherwise it would run the DA logic to determine if the user has permission to update that specific catalog. One single permission, can handle most if not all cases when defined properly. > >> 4. Define permission for users, not admins. Instead of >> looking for a static permission, set the permission to be >> checked at the most granular level. When doing so, admin >> users will always have permission and the API will handle >> user access using DA logic. > > I disagree. I might want my application to behave differently if an > admin is using it. Without an admin permission (or attribute), how > will I know if a user is in an admin role? Then we will create an 'admin' base permission. I didn't see the need for it, b/c I can't think of anything in which I would say "don't show this to people who can access/create/read/update/delete; only show it to an admin". I have nothing against this, just couldn't think of any really useful cases. Do you have something specific in mind? Andrew |
In reply to this post by Adrian Crum-2
Don't worry, I expected some level of resistance to a change of this
magnitude, plus this requires a very different way of thinking so I planned on having to explain it, I tried to cover everything in the document, but that's impossible to do :) This is VERY similar to the existing security implementation, and very similar to other security APIs out there (JSecurity, Spring Security, etc). The slight differences are: Easier to understand and follow. Reading the new permission string format, you can see what is being checked. Nothing is hidden. The logic used to determine granular access control it defined on the permission itself. No more guessing where permission logic is located. It is much easier to extend, create seed data which overwrites the default permission logic references and use your own custom logic to determine access. No need to override service definitions or patch code (well once the migration is complete) or comment out ECAs. So, now my questions for you are: What is missing? What does this new API NOT do, which you are looking for? Andrew On May 1, 2009, at 4:37 PM, Adrian Crum wrote: > > I read the Auto-Grant section. The question is, where is the seed > data shown in your code example located? If it's it the SFA > component, then the permissions are still spread around. All that > has changed is instead of having permission-modifying SECAs in > components, you have permission-modifying seed data in components. > How was anything "centralized?" > > I don't mean to pour cold water on your enthusiasm, it's just that I > don't see where anything is being added or improved. It looks > basically the same, only slightly different. > > -Adrian > > > > |
In reply to this post by Andrew Zeneski-2
--- On Fri, 5/1/09, Andrew Zeneski <[hidden email]> wrote: > What changed is that now the permission logic is NOT tied > directly to the service itself. The logic is tied to the > permission. So ANY call to authz.hasPermission() the EXACT > same code runs that checks the permission. That is the > single point of contact, the hasPermission() method. > > The checks in the screen definition runs the same code as > the checks in service definition. So now one advantage is, > the update or delete button which is displayed in the UI if > the user has permission will display (even if they do not > have the static permission associated with their account) if > the user can edit that specific item. It won't display > for other items which the user cannot modify. I must be missing something. Still using the Example component as an example: the service definition called a service permission, which called a script, which ultimately called Security.hasPermission. Your modification has the service definition use the <required-permissions> which ultimately calls authz.hasPermission(). So, both methods end up calling a single hasPermission() method. What changed? The only difference I see is that the permission string moved from a script to the service definition. Is that the desired benefit? > >> 3. Avoid having to check multiple permissions, for > example > >> PARTYMGR_UPDATE or PARTYMGR_ADMIN. Instead we use > a new > >> permission format which embeds all permissions > which will be > >> accepted: > > > > I don't see that being done explicitly in our > current code. The OFBizSecurity class does that > automatically. Any permission check is done with the ADMIN > permission first, then the requested permission. > > Okay, so that was a bad example. How about CATALOG_UPDATE > or CATALOG_ROLE_UPDATE instead as an example. Instead a > simple permission defined as update:catalog:${catalogId} > would take care of both of these. If the user has the static > 'update:catalog' permission it would be granted > (like a catalog admin might have), otherwise it would run > the DA logic to determine if the user has permission to > update that specific catalog. The idea of specifying some kind of parameter in the permission is interesting. The question is, (speaking as a user) What does that parameter do? > >> 4. Define permission for users, not admins. > Instead of > >> looking for a static permission, set the > permission to be > >> checked at the most granular level. When doing so, > admin > >> users will always have permission and the API will > handle > >> user access using DA logic. > > > > I disagree. I might want my application to behave > differently if an admin is using it. Without an admin > permission (or attribute), how will I know if a user is in > an admin role? > > Then we will create an 'admin' base permission. I > didn't see the need for it, b/c I can't think of > anything in which I would say "don't show this to > people who can access/create/read/update/delete; only show > it to an admin". I have nothing against this, just > couldn't think of any really useful cases. Do you have > something specific in mind? Maybe that could be expressed as :component:admin. -Adrian |
Some of these questions in the discussions so far give me the feeling
that the write up Andrew put in confluence hasn't been read, is that the case? Anyway I'm a +1 for the new auth framework, I think it give us more power AND simplicity. Will it need improvement over time? of course it will but I think it's a much better base to work from. Inline On 2/05/2009, at 9:45 AM, Adrian Crum wrote: > > > --- On Fri, 5/1/09, Andrew Zeneski <[hidden email]> > wrote: >> What changed is that now the permission logic is NOT tied >> directly to the service itself. The logic is tied to the >> permission. So ANY call to authz.hasPermission() the EXACT >> same code runs that checks the permission. That is the >> single point of contact, the hasPermission() method. >> >> The checks in the screen definition runs the same code as >> the checks in service definition. So now one advantage is, >> the update or delete button which is displayed in the UI if >> the user has permission will display (even if they do not >> have the static permission associated with their account) if >> the user can edit that specific item. It won't display >> for other items which the user cannot modify. > > I must be missing something. Still using the Example component as an > example: the service definition called a service permission, which > called a script, which ultimately called Security.hasPermission. > Your modification has the service definition use the <required- > permissions> which ultimately calls authz.hasPermission(). So, both > methods end up calling a single hasPermission() method. What changed? > > The only difference I see is that the permission string moved from a > script to the service definition. Is that the desired benefit? required on the service without having to find a service def and then it's method. The newer permissions are more intelligent so you don't need to write a service for every variation in auth requirements. > > >>>> 3. Avoid having to check multiple permissions, for >> example >>>> PARTYMGR_UPDATE or PARTYMGR_ADMIN. Instead we use >> a new >>>> permission format which embeds all permissions >> which will be >>>> accepted: >>> >>> I don't see that being done explicitly in our >> current code. The OFBizSecurity class does that >> automatically. Any permission check is done with the ADMIN >> permission first, then the requested permission. >> >> Okay, so that was a bad example. How about CATALOG_UPDATE >> or CATALOG_ROLE_UPDATE instead as an example. Instead a >> simple permission defined as update:catalog:${catalogId} >> would take care of both of these. If the user has the static >> 'update:catalog' permission it would be granted >> (like a catalog admin might have), otherwise it would run >> the DA logic to determine if the user has permission to >> update that specific catalog. > > The idea of specifying some kind of parameter in the permission is > interesting. The question is, (speaking as a user) What does that > parameter do? > >>>> 4. Define permission for users, not admins. >> Instead of >>>> looking for a static permission, set the >> permission to be >>>> checked at the most granular level. When doing so, >> admin >>>> users will always have permission and the API will >> handle >>>> user access using DA logic. >>> >>> I disagree. I might want my application to behave >> differently if an admin is using it. Without an admin >> permission (or attribute), how will I know if a user is in >> an admin role? >> >> Then we will create an 'admin' base permission. I >> didn't see the need for it, b/c I can't think of >> anything in which I would say "don't show this to >> people who can access/create/read/update/delete; only show >> it to an admin". I have nothing against this, just >> couldn't think of any really useful cases. Do you have >> something specific in mind? > > Maybe that could be expressed as :component:admin. figuring out how to add it. smime.p7s (3K) Download Attachment |
In reply to this post by Andrew Zeneski-2
Don't get me wrong, I'm not resisting change. I commented on your design document that I'm in support of a security refactor. I'm sure others in the community would support that too. The problem is, this wasn't discussed with the community beforehand. No one was given an opportunity to provide input. It appears (and I know that this might not be true) that the design was created, some coding had been done, and THEN a document was drawn up and code committed shortly afterward. My recommendation would be to reboot this entire process to give the community a chance to be involved in the design. We should: 1. Send an email to the dev mailing list (and optionally the user list) asking for comments on the existing security framework and what they would like to see changed. 2. Compile the list into a set of design objectives. 3. Send the list to the dev mailing list and ask for suggestions for implementing the design objectives. 4. Compile a list of implementations and send it to the dev mailing list for a vote. From my perspective, that's how a developer community should work. Until those steps are followed, you're going to have a lot of people asking the same questions I am - because they weren't involved and don't understand what you're doing. -Adrian --- On Fri, 5/1/09, Andrew Zeneski <[hidden email]> wrote: > From: Andrew Zeneski <[hidden email]> > Subject: Re: Authz API Discussion (was re: svn commit: r770084) > To: [hidden email] > Date: Friday, May 1, 2009, 2:30 PM > Don't worry, I expected some level of resistance to a > change of this magnitude, plus this requires a very > different way of thinking so I planned on having to explain > it, I tried to cover everything in the document, but > that's impossible to do :) > > This is VERY similar to the existing security > implementation, and very similar to other security APIs out > there (JSecurity, Spring Security, etc). The slight > differences are: > > Easier to understand and follow. Reading the new permission > string format, you can see what is being checked. Nothing is > hidden. The logic used to determine granular access control > it defined on the permission itself. No more guessing where > permission logic is located. > > It is much easier to extend, create seed data which > overwrites the default permission logic references and use > your own custom logic to determine access. No need to > override service definitions or patch code (well once the > migration is complete) or comment out ECAs. > > So, now my questions for you are: What is missing? What > does this new API NOT do, which you are looking for? > > > Andrew > > > On May 1, 2009, at 4:37 PM, Adrian Crum wrote: > > > > I read the Auto-Grant section. The question is, where > is the seed data shown in your code example located? If > it's it the SFA component, then the permissions are > still spread around. All that has changed is instead of > having permission-modifying SECAs in components, you have > permission-modifying seed data in components. How was > anything "centralized?" > > > > I don't mean to pour cold water on your > enthusiasm, it's just that I don't see where > anything is being added or improved. It looks basically the > same, only slightly different. > > > > -Adrian > > > > > > > > |
In reply to this post by Adrian Crum-2
Adrian,
> > I must be missing something. Still using the Example component as an > example: the service definition called a service permission, which > called a script, which ultimately called Security.hasPermission. > Your modification has the service definition use the <required- > permissions> which ultimately calls authz.hasPermission(). So, both > methods end up calling a single hasPermission() method. What changed? > > The only difference I see is that the permission string moved from a > script to the service definition. Is that the desired benefit? > It is indeed the designed benefit. Previously, we had this: 1. A service with a permission service attached. The permission service checked static permission, and possibly (not in the case of the example component, but honestly this component doesn't utilize the full potential of the new code) processed other logic which would determine of the user had the ability to perform that function. 2. A screen definition which checked permissions, okay again the example component doesn't utilize all the possibilities, but let's say we wanted to add a delete button to the screen to delete the example. Using the old method you would then call the has-permission screen operator and check for a static permission probably something like EXAMPLE_DELETE. Now, let's say we want to allow anyone to create examples, only the person who created the example and any admin can update or delete it. Using what we had in the old model, the permission service logic would need to be adjusted to grant permission to the owner of the example. However, the screen operator will still only pickup the static EXAMPLE_DELETE permission. We don't want to give everyone delete access, we only want them to delete the examples they created. So, only admins or users with EXAMPLE_DELETE would see the button. The new authz implementation handles all of this for us. First we define the permissions, access:example, update:example and delete:example as seed data. These are also attached to the example admin user's security group. We will give all users access:example permission so they can access the application, but only give admins the update and delete permissions. Next we define the Dynamic Access logic. Very little code need, check the example from the exampleId which is passed in the permissionContext and part of the permission string (which we will define in a moment) and if the owner is the userId return true, otherwise return false. This can be groovy or a simple method if desired. We then register this logic with the permissions in the seed data file. The same logic can be attached to both update:example as well as delete:example. Now we will configure the services to include permissions. The createExample will have no permission or set it to access:example to make sure only users who can access the app can create (I have other more complex ideas for this, but this is a simple example). The updateExample service should be set with "update:example:${exampleId}" as the permission, the deleteExample service set with "delete:example:$ {exampleId}" permission. Finally, we configure the screen definition and add the delete button (or update button whatever the case may be). But we do a permission check here as well for "delete:example:${exampleId}" (note: exampleId should be in the screen's context) to restrict the display of the button. Now, using the new API the button is displayed under two conditions: 1. the user is an admin and has delete:example permission 2. the user is the owner of the example The exact same logic is used by the service engine when submitting the request, so you can be sure that if the button was displayed then permission will be granted when submitting the form. Maybe later you want to change how this works. Maybe being the owner is not enough, you must the be owner and have been active in the last 5 days. So, you simply edit the logic in the groovy (or simple method) script and clear the cache. The new logic kicks in, effective in all places which check that permission. This is what I mean by 'centralized'. Instead of having security split up between the Security API and the Service Engine Permission API, everything is moved and centered around the permission. Andrew |
Free forum by Nabble | Edit this page |