-
Tim Knapp <duffyd@...> writes: > I've been searching through the remember/membrane tests to try and work > out how the member subscription expiry functionality works? Is this > based on the last logon time? Also, how do I reset the expiration date > for a user? I know that members are not authenticated if their workflow state but I've never confirmed if remember honors the effective and expiration dates. I've done quick look through the code and I can't see anything that looks like it is intended to honor those dates. I'll look more thoroughly later. If it's not currently supported, it seems like we should honor those dates. Anyone have any objections or other thoughts? Ross
-
On May 21, 2009, at 12:31 PM, Ross Patterson wrote: > Tim Knapp <duffyd@...> writes: > >> I've been searching through the remember/membrane tests to try and >> work >> out how the member subscription expiry functionality works? Is this >> based on the last logon time? Also, how do I reset the expiration >> date >> for a user? > > I know that members are not authenticated if their workflow state but > I've never confirmed if remember honors the effective and expiration > dates. I've done quick look through the code and I can't see anything > that looks like it is intended to honor those dates. I'll look more > thoroughly later. > > If it's not currently supported, it seems like we should honor those > dates. Anyone have any objections or other thoughts? That seems perfectly reasonable to me and would probably help the cause of any subscription based memberships :) Clayton -- S i x F e e t U p , I n c . | http://www.sixfeetup.com Phone: +1 (317) 861-5948 x603 clayton@... ANNOUNCING the first Plone Immersive Training Experience | Sept. 10-11-12, 2009 http://www.sixfeetup.com/immerse
-
Ross Patterson wrote: > Tim Knapp <duffyd@...> writes: > >> I've been searching through the remember/membrane tests to try and work >> out how the member subscription expiry functionality works? Is this >> based on the last logon time? Also, how do I reset the expiration date >> for a user? > > I know that members are not authenticated if their workflow state but > I've never confirmed if remember honors the effective and expiration > dates. I've done quick look through the code and I can't see anything > that looks like it is intended to honor those dates. I'll look more > thoroughly later. no, you're right. currently, the MembraneUserManager plugin (which provides the IAuthenticationPlugin interface) checks to make sure a member object is in an "active" workflow state before delegating actual authentication to the member object, but it does not check the effective or expiration dates at all. > If it's not currently supported, it seems like we should honor those > dates. Anyone have any objections or other thoughts? it'd be tempting to put support for this in the MembraneUserManager plugin, but i'd recommend against doing that, since we want Membrane to be making fewer assumptions about the member objects, not more. it seems reasonable to me for membrane to assume that a member object has a workflow. it seems less reasonable for membrane to assume that a member object will always support effective and expire dates in the same way, if at all. given that, then, if it's decided that the out-of-box products should support this functionality, i'd recommend any code to support this land in Remember, not in Membrane. frankly, though, if i needed this functionality, i'd probably just do it in custom code, outside of Remember itself. it'd look something like this: - when someone confirms registration for a specific duration of time (via payment or some other means), i'd set the expiration date on their member object. - i'd set up a nightly clockserver job to query for members who are in an active workflow state but whose expiration date is in the past. - this clockserver job would fire a transition for those member objects, putting them into an inactive state designed specifically for this purpose (i.e. i'd use 'inactive' or 'expired', i wouldn't try to overload 'pending'). - i'd have an event listener subscribed to that workflow transition event, which would send an email to notify the user that their account has expired and that they won't be able to log in again until they reactivate their account. the change of the workflow state would already prevent the user from logging in, so there wouldn't need to be any changes to the MembraneUserManager plugin, nor would it be necessary to override the member object's authenticateCredentials method. there are other details to be worked out here, of course. probably you'd want the clockserver job to also look for folks whose expiration dates are coming soon, to send out warnings, to give them a chance to renew their account before the actual deactivation occurs. another slightly tricky bit could be handling reactivation after their account has been expired. at this point, the user can't log in... which means you'll be interacting w/ anonymous users, who of course have no privileges. this still isn't that bad, though. it's not like some nefarious attacker is going to go around paying subscription fees on expired accounts. it's similar to a bank; you don't need to prove who you are to make a deposit to an account, only to withdraw. if you really want to be careful, to prevent people from accidentally paying for someone else's subscription, you could require users to enter their password at some point in the renewal process. even though the account is inactive, the password is still there, you should be able to call authenticateCredentials directly on the member object to make sure the entered password is correct. the main thing to be careful of here is to make sure you don't expose any of the member's personal information (email address, etc.) to anonymous users. of course, if account renewal is triggered by some external mechanism (i.e. a paypal payment triggering a message of some sort to be sent to your system), then you don't really have to worry about that, you just need to make sure you reset both the workflow state AND the expiration date if the renewal trigger happens after the previous expiry. hth, -r
-
Hi Rob, This is *very* helpful and was what I was planning on implementing too. Gracias and thanks, Tim On Thu, 2009-05-21 at 11:35 -0700, Rob Miller wrote: > Ross Patterson wrote: > > Tim Knapp <duffyd@...> writes: > > > >> I've been searching through the remember/membrane tests to try and work > >> out how the member subscription expiry functionality works? Is this > >> based on the last logon time? Also, how do I reset the expiration date > >> for a user? > > > > I know that members are not authenticated if their workflow state but > > I've never confirmed if remember honors the effective and expiration > > dates. I've done quick look through the code and I can't see anything > > that looks like it is intended to honor those dates. I'll look more > > thoroughly later. > > no, you're right. currently, the MembraneUserManager plugin (which provides > the IAuthenticationPlugin interface) checks to make sure a member object is in > an "active" workflow state before delegating actual authentication to the > member object, but it does not check the effective or expiration dates at all. > > > If it's not currently supported, it seems like we should honor those > > dates. Anyone have any objections or other thoughts? > > it'd be tempting to put support for this in the MembraneUserManager plugin, > but i'd recommend against doing that, since we want Membrane to be making > fewer assumptions about the member objects, not more. it seems reasonable to > me for membrane to assume that a member object has a workflow. it seems less > reasonable for membrane to assume that a member object will always support > effective and expire dates in the same way, if at all. > > given that, then, if it's decided that the out-of-box products should support > this functionality, i'd recommend any code to support this land in Remember, > not in Membrane. > > frankly, though, if i needed this functionality, i'd probably just do it in > custom code, outside of Remember itself. it'd look something like this: > > - when someone confirms registration for a specific duration of time (via > payment or some other means), i'd set the expiration date on their member object. > > - i'd set up a nightly clockserver job to query for members who are in an > active workflow state but whose expiration date is in the past. > > - this clockserver job would fire a transition for those member objects, > putting them into an inactive state designed specifically for this purpose > (i.e. i'd use 'inactive' or 'expired', i wouldn't try to overload 'pending'). > > - i'd have an event listener subscribed to that workflow transition event, > which would send an email to notify the user that their account has expired > and that they won't be able to log in again until they reactivate their account. > > the change of the workflow state would already prevent the user from logging > in, so there wouldn't need to be any changes to the MembraneUserManager > plugin, nor would it be necessary to override the member object's > authenticateCredentials method. > > there are other details to be worked out here, of course. probably you'd want > the clockserver job to also look for folks whose expiration dates are coming > soon, to send out warnings, to give them a chance to renew their account > before the actual deactivation occurs. > > another slightly tricky bit could be handling reactivation after their account > has been expired. at this point, the user can't log in... which means you'll > be interacting w/ anonymous users, who of course have no privileges. this > still isn't that bad, though. it's not like some nefarious attacker is going > to go around paying subscription fees on expired accounts. it's similar to a > bank; you don't need to prove who you are to make a deposit to an account, > only to withdraw. if you really want to be careful, to prevent people from > accidentally paying for someone else's subscription, you could require users > to enter their password at some point in the renewal process. even though the > account is inactive, the password is still there, you should be able to call > authenticateCredentials directly on the member object to make sure the entered > password is correct. the main thing to be careful of here is to make sure you > don't expose any of the member's personal information (email address, etc.) to > anonymous users. > > of course, if account renewal is triggered by some external mechanism (i.e. a > paypal payment triggering a message of some sort to be sent to your system), > then you don't really have to worry about that, you just need to make sure you > reset both the workflow state AND the expiration date if the renewal trigger > happens after the previous expiry. > > hth, > > -r > > > -- > Archive: http://www.openplans.org/projects/remember/lists/remember/archive/2009/05/1242930958306 > To unsubscribe send an email with subject "unsubscribe" to remember@.... Please contact remember-manager@... for questions. >
-
Hello again Rob, On Thu, 2009-05-21 at 11:35 -0700, Rob Miller wrote: > Ross Patterson wrote: <snip /> > > another slightly tricky bit could be handling reactivation after their account > has been expired. at this point, the user can't log in... which means you'll > be interacting w/ anonymous users, who of course have no privileges. this > still isn't that bad, though. it's not like some nefarious attacker is going > to go around paying subscription fees on expired accounts. it's similar to a > bank; you don't need to prove who you are to make a deposit to an account, > only to withdraw. if you really want to be careful, to prevent people from > accidentally paying for someone else's subscription, you could require users > to enter their password at some point in the renewal process. even though the > account is inactive, the password is still there, you should be able to call > authenticateCredentials directly on the member object to make sure the entered > password is correct. the main thing to be careful of here is to make sure you > don't expose any of the member's personal information (email address, etc.) to > anonymous users. I've implemented this solution as per your recommendations and I ended up having to create a browser view that the expired member opens up (with the memberid supplied via query string) and enters their password and selects their subscription period and the authenticateCredentials method is run against the member object and if this is successful the user is 'enabled' and redirected off to the payment processor and subsequently their expiry date is updated. This all works fine and dandy but I had to take away the transition guards from the 'enable_private' transition and I'm unsure what kind of security holes this opens up? Thanks, Tim
-
Tim Knapp wrote: > Hello again Rob, > > On Thu, 2009-05-21 at 11:35 -0700, Rob Miller wrote: >> Ross Patterson wrote: > > <snip /> > >> another slightly tricky bit could be handling reactivation after their account >> has been expired. at this point, the user can't log in... which means you'll >> be interacting w/ anonymous users, who of course have no privileges. this >> still isn't that bad, though. it's not like some nefarious attacker is going >> to go around paying subscription fees on expired accounts. it's similar to a >> bank; you don't need to prove who you are to make a deposit to an account, >> only to withdraw. if you really want to be careful, to prevent people from >> accidentally paying for someone else's subscription, you could require users >> to enter their password at some point in the renewal process. even though the >> account is inactive, the password is still there, you should be able to call >> authenticateCredentials directly on the member object to make sure the entered >> password is correct. the main thing to be careful of here is to make sure you >> don't expose any of the member's personal information (email address, etc.) to >> anonymous users. > > I've implemented this solution as per your recommendations and I ended > up having to create a browser view that the expired member opens up > (with the memberid supplied via query string) and enters their password > and selects their subscription period and the authenticateCredentials > method is run against the member object and if this is successful the > user is 'enabled' and redirected off to the payment processor and > subsequently their expiry date is updated. This all works fine and dandy > but I had to take away the transition guards from the 'enable_private' > transition and I'm unsure what kind of security holes this opens up? well, the security holes that this opens up are what you might expect based on what you changed: it's now possible for any user to reactivate a disabled user, whereas before it was only possible for someone w/ the "Manage users" permission (assuming the guards you removed were still the default as provided in the member_approval_workflow). i wouldn't remove the guards, myself; instead i'd probably escalate the user privileges by changing to the "system" user before triggering the protected code, something like this: from AccessControl.SecurityManagement import getSecurityManager from AccessControl.SecurityManagement import newSecurityManager from AccessControl.SecurityManagement import setSecurityManager from AccessControl.SpecialUsers import system sm = getSecurityManager() try: newSecurityManager(None, system) ### INSERT CODE REQUIRING EXTRA PRIVS HERE finally: setSecurityManager(sm) i haven't tested this, so it may need a bit of tweaking, but the idea is sound; i've used this technique successfully a number of times. -r-
Hi, On Tue, 2009-05-26 at 11:47 -0700, Rob Miller wrote: > Tim Knapp wrote: > > Hello again Rob, > > > > On Thu, 2009-05-21 at 11:35 -0700, Rob Miller wrote: > >> Ross Patterson wrote: > > > > <snip /> > > > >> another slightly tricky bit could be handling reactivation after their account > >> has been expired. at this point, the user can't log in... which means you'll > >> be interacting w/ anonymous users, who of course have no privileges. this > >> still isn't that bad, though. it's not like some nefarious attacker is going > >> to go around paying subscription fees on expired accounts. it's similar to a > >> bank; you don't need to prove who you are to make a deposit to an account, > >> only to withdraw. if you really want to be careful, to prevent people from > >> accidentally paying for someone else's subscription, you could require users > >> to enter their password at some point in the renewal process. even though the > >> account is inactive, the password is still there, you should be able to call > >> authenticateCredentials directly on the member object to make sure the entered > >> password is correct. the main thing to be careful of here is to make sure you > >> don't expose any of the member's personal information (email address, etc.) to > >> anonymous users. > > > > I've implemented this solution as per your recommendations and I ended > > up having to create a browser view that the expired member opens up > > (with the memberid supplied via query string) and enters their password > > and selects their subscription period and the authenticateCredentials > > method is run against the member object and if this is successful the > > user is 'enabled' and redirected off to the payment processor and > > subsequently their expiry date is updated. This all works fine and dandy > > but I had to take away the transition guards from the 'enable_private' > > transition and I'm unsure what kind of security holes this opens up? > > well, the security holes that this opens up are what you might expect based on > what you changed: it's now possible for any user to reactivate a disabled > user, whereas before it was only possible for someone w/ the "Manage users" > permission (assuming the guards you removed were still the default as provided > in the member_approval_workflow). > > i wouldn't remove the guards, myself; instead i'd probably escalate the user > privileges by changing to the "system" user before triggering the protected > code, something like this: > > > from AccessControl.SecurityManagement import getSecurityManager > from AccessControl.SecurityManagement import newSecurityManager > from AccessControl.SecurityManagement import setSecurityManager > from AccessControl.SpecialUsers import system > > sm = getSecurityManager() > try: > newSecurityManager(None, system) > ### INSERT CODE REQUIRING EXTRA PRIVS HERE > finally: > setSecurityManager(sm) > > > i haven't tested this, so it may need a bit of tweaking, but the idea is > sound; i've used this technique successfully a number of times. Thanks a lot, as always 'on the money'. I did try to use a similar approach to this but got errors but didn't try the 'system' user. I'll give it another go and report back. Thanks again, Tim > > -r > > > -- > Archive: http://www.openplans.org/projects/remember/lists/remember/archive/2009/05/1243363709686 > To unsubscribe send an email with subject "unsubscribe" to remember@.... Please contact remember-manager@... for questions. >
-
Hi Rob et al, On Tue, 2009-05-26 at 11:47 -0700, Rob Miller wrote: > Tim Knapp wrote: <snip /> > > well, the security holes that this opens up are what you might expect based on > what you changed: it's now possible for any user to reactivate a disabled > user, whereas before it was only possible for someone w/ the "Manage users" > permission (assuming the guards you removed were still the default as provided > in the member_approval_workflow). > > i wouldn't remove the guards, myself; instead i'd probably escalate the user > privileges by changing to the "system" user before triggering the protected > code, something like this: > > > from AccessControl.SecurityManagement import getSecurityManager > from AccessControl.SecurityManagement import newSecurityManager > from AccessControl.SecurityManagement import setSecurityManager > from AccessControl.SpecialUsers import system > > sm = getSecurityManager() > try: > newSecurityManager(None, system) > ### INSERT CODE REQUIRING EXTRA PRIVS HERE > finally: > setSecurityManager(sm) > > > i haven't tested this, so it may need a bit of tweaking, but the idea is > sound; i've used this technique successfully a number of times. Just an update re. this thread that this code did in fact resolve 'most' of my problems. I did also have to just do a check to see what the 'old_state' was (which I should've done at the outset) as follows (as there's a guard transition that checks this): if getattr(member, 'old_state', None) == 'public': workflow.doActionFor(member, 'enable_public') else: workflow.doActionFor(member, 'enable_private') Thanks again, Tim > > -r > > > -- > Archive: http://www.openplans.org/projects/remember/lists/remember/archive/2009/05/1243363709686 > To unsubscribe send an email with subject "unsubscribe" to remember@.... Please contact remember-manager@... for questions. >
-
-
Re: Re: Confirming expiration functionality in remember
from Jeremy McMillanon May 26, 2009 10:04 PM I've been researching how to approach this, and I think this problem stems from confusion about workflow state and active/expiration state. The path I'm starting to go down is workflow that hooks a Zope event which is set on changes to an object's expiration. This way I can use workflow state transitions to change things like group memberships and permissions on user object fields. I haven't gotten much further than that, and I'd appreciate any advice on whether that's a bad idea or how to implement it. On May 25, 2009, at 7:02 AM, Tim Knapp wrote: > Hello again Rob, > > On Thu, 2009-05-21 at 11:35 -0700, Rob Miller wrote: >> Ross Patterson wrote: > > <snip /> > >> >> another slightly tricky bit could be handling reactivation after >> their account >> has been expired. at this point, the user can't log in... which >> means you'll >> be interacting w/ anonymous users, who of course have no >> privileges. this >> still isn't that bad, though. it's not like some nefarious >> attacker is going >> to go around paying subscription fees on expired accounts. it's >> similar to a >> bank; you don't need to prove who you are to make a deposit to an >> account, >> only to withdraw. if you really want to be careful, to prevent >> people from >> accidentally paying for someone else's subscription, you could >> require users >> to enter their password at some point in the renewal process. >> even though the >> account is inactive, the password is still there, you should be >> able to call >> authenticateCredentials directly on the member object to make sure >> the entered >> password is correct. the main thing to be careful of here is to >> make sure you >> don't expose any of the member's personal information (email >> address, etc.) to >> anonymous users. > > I've implemented this solution as per your recommendations and I ended > up having to create a browser view that the expired member opens up > (with the memberid supplied via query string) and enters their > password > and selects their subscription period and the authenticateCredentials > method is run against the member object and if this is successful the > user is 'enabled' and redirected off to the payment processor and > subsequently their expiry date is updated. This all works fine and > dandy > but I had to take away the transition guards from the 'enable_private' > transition and I'm unsure what kind of security holes this opens up? > > Thanks, > Tim
-
Jeremy McMillan wrote: > I've been researching how to approach this, and I think this problem > stems from confusion about workflow state and active/expiration state. > The path I'm starting to go down is workflow that hooks a Zope event > which is set on changes to an object's expiration. does the CMF already fire and event when an object's expiration date passes? if so, then great, we don't need the clockserver job that goes through and finds the recently expired users, we can just register an event subscriber instead. i've not seen such an event, however... > This way I can use > workflow state transitions to change things like group memberships and > permissions on user object fields. > > I haven't gotten much further than that, and I'd appreciate any advice > on whether that's a bad idea or how to implement it. well, your description is a wee bit vague, but it sounds like you're basically describing the solution that i've already gone over in some detail in this thread. is there something specific that you don't understand? or are you suggesting a different approach and i'm misunderstanding you? -r > > On May 25, 2009, at 7:02 AM, Tim Knapp wrote: > >> Hello again Rob, >> >> On Thu, 2009-05-21 at 11:35 -0700, Rob Miller wrote: >>> Ross Patterson wrote: >> >> <snip /> >> >>> >>> another slightly tricky bit could be handling reactivation after >>> their account >>> has been expired. at this point, the user can't log in... which >>> means you'll >>> be interacting w/ anonymous users, who of course have no privileges. >>> this >>> still isn't that bad, though. it's not like some nefarious attacker >>> is going >>> to go around paying subscription fees on expired accounts. it's >>> similar to a >>> bank; you don't need to prove who you are to make a deposit to an >>> account, >>> only to withdraw. if you really want to be careful, to prevent >>> people from >>> accidentally paying for someone else's subscription, you could >>> require users >>> to enter their password at some point in the renewal process. even >>> though the >>> account is inactive, the password is still there, you should be able >>> to call >>> authenticateCredentials directly on the member object to make sure >>> the entered >>> password is correct. the main thing to be careful of here is to make >>> sure you >>> don't expose any of the member's personal information (email address, >>> etc.) to >>> anonymous users. >> >> I've implemented this solution as per your recommendations and I ended >> up having to create a browser view that the expired member opens up >> (with the memberid supplied via query string) and enters their password >> and selects their subscription period and the authenticateCredentials >> method is run against the member object and if this is successful the >> user is 'enabled' and redirected off to the payment processor and >> subsequently their expiry date is updated. This all works fine and dandy >> but I had to take away the transition guards from the 'enable_private' >> transition and I'm unsure what kind of security holes this opens up? >> >> Thanks, >> Tim > > > -- > Archive: > http://www.openplans.org/projects/remember/lists/remember/archive/2009/05/1243389890653 > > To unsubscribe send an email with subject "unsubscribe" to > remember@.... Please contact > remember-manager@... for questions. >
-
-
-