/3.0/addresses/cris@example.com/user' - multi purpose REST API method

TLDR - This API methods does multiple things and depends on information apart from the URL to define its behaviour mode, making it hard to give a clear authentication scope to. I wonder if it should be broken out into individual REST API methods, each with a single purpose and a clear authentication scope.
As background information, from the documentation:
“”"To link an address to a user, a POST request can be sent to the /user
sub-resource of the address. If the user does not exist, it will be created.””"
>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user',
... {'display_name': 'Cris X. Person’})
My question is - I am interested to understand the thinking behind this REST method.
It is effectively a multi purpose method.
In one case it *creates an email address* and *creates a new user* and which are linked to each other.
In one case it *creates an email address* and links that address to an existing user, when given a POSTed user_id.
In one case it *creates an email address* and does not link it to any user, if the auto_create POST option is False.
In terms of building an authentication system this REST method is problematic. All (I think at this stage anyway) other methods in the REST API can be given a clear authentication scope/role based only on the URL. This REST API method, dual to its multi purpose, mode options-in-the-POST-data behaviour, cannot be given an authentication scope based only on the URL.
Each of the above behaviours have a different authentication scope/role. For example:
(permitted by superuser only) In one case it *creates an email address* and *creates a new user* and which are linked to each other.
(permitted by superuser only, permitted by existing user) In one case it *creates an email address* and links that address to an existing user, when given a POSTed user_id.
(permitted by superuser only) In one case it *creates an email address* and does not link it to any user, if the auto_create POST option is False.
I’m interested to hear thoughts on this. It would be good if the authentication scope of every REST API URL could be defined based only on the URL, without the need to know either options provided in the form data, or whether or not other records such as user records exist.
In summary - This API methods does too many things and depends on information apart from the URL to define its behaviour, making it hard to give a clear authentication scope to. I wonder if it should be broken out into individual REST API methods, each with a single purpose and a clear authentication scope.

Actually I meant authorization not authentication.
On 8 Feb 2015, at 12:28 am, Andrew Stuart <andrew.stuart@supercoders.com.au> wrote:
TLDR - This API methods does multiple things and depends on information apart from the URL to define its behaviour mode, making it hard to give a clear authentication scope to. I wonder if it should be broken out into individual REST API methods, each with a single purpose and a clear authentication scope.
As background information, from the documentation:
“”"To link an address to a user, a POST request can be sent to the /user
sub-resource of the address. If the user does not exist, it will be created.””"
dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user', ... {'display_name': 'Cris X. Person’})
My question is - I am interested to understand the thinking behind this REST method.
It is effectively a multi purpose method.
In one case it *creates an email address* and *creates a new user* and which are linked to each other.
In one case it *creates an email address* and links that address to an existing user, when given a POSTed user_id.
In one case it *creates an email address* and does not link it to any user, if the auto_create POST option is False.
In terms of building an authentication system this REST method is problematic. All (I think at this stage anyway) other methods in the REST API can be given a clear authentication scope/role based only on the URL. This REST API method, dual to its multi purpose, mode options-in-the-POST-data behaviour, cannot be given an authentication scope based only on the URL.
Each of the above behaviours have a different authentication scope/role. For example:
(permitted by superuser only) In one case it *creates an email address* and *creates a new user* and which are linked to each other.
(permitted by superuser only, permitted by existing user) In one case it *creates an email address* and links that address to an existing user, when given a POSTed user_id.
(permitted by superuser only) In one case it *creates an email address* and does not link it to any user, if the auto_create POST option is False.
I’m interested to hear thoughts on this. It would be good if the authentication scope of every REST API URL could be defined based only on the URL, without the need to know either options provided in the form data, or whether or not other records such as user records exist.
In summary - This API methods does too many things and depends on information apart from the URL to define its behaviour, making it hard to give a clear authentication scope to. I wonder if it should be broken out into individual REST API methods, each with a single purpose and a clear authentication scope.
Mailman-Developers mailing list Mailman-Developers@python.org https://mail.python.org/mailman/listinfo/mailman-developers Mailman FAQ: http://wiki.list.org/x/AgA3 Searchable Archives: http://www.mail-archive.com/mailman-developers%40python.org/ Unsubscribe: https://mail.python.org/mailman/options/mailman-developers/andrew.stuart%40s...
Security Policy: http://wiki.list.org/x/QIA9

On Feb 08, 2015, at 12:28 AM, Andrew Stuart wrote:
Yes, that makes sense as a general principle.
It's not really that deep. ;) As it turns out, the REST method is a thin layer on top of IUserManager.create_user() which itself has been around for quite a while. In the model, the behavior is pretty convenient.
(I'll also note that create_user() is used when POSTing to the <api>/users resource.)
Another guiding principle is that the edges should not have too much logic. In MM2, there was a lot of logic ingrained in the cgi scripts, and that causes a lot of problems if you want the same behavior in some other edge. Therefore I try to keep the REST API limited to parsing arguments, handling responses, and reporting error conditions while the actual core logic is implemented in the model or the app directory.
The use case here is when someone walks up to Postorious and creates an account for the first time. They'd enter their email address and Postorious would direct the core to create a user for them *and* an email address for them. It then makes sense to link the two together. Of course, the new address begins unverified.
The use case here is that someone already has a login to Postorious, and now they want to associate a new email address with their existing one. They log in (establishing their ownership of an existing user), enter their email address and if needed, that's created.
Now, it's questionable whether that address should be linked to the user until they verify the address. I think that happens now, but probably shouldn't, otherwise it could be hijacked.
Another use case is where a list administrator wants to add a bunch of addresses to their mailing list. There may be reasons to opt-out (e.g. a corporate list of employees, or a physical sign-up sheet that by its nature implies opt-in).
Maybe one way to look at it is that any operation that links an address to a user has to be a privileged url. A user creating an account on Postorious, or trying to add an address to an existing user are both operations where the address being created will not be verified (until they do a mail-back or confirmation click). In those cases, maybe we need an entirely separate resource (url) for the user operations, which would ensure the proper confirmation dance were performed.
Thoughts?
Cheers, -Barry

Is this command meant to create the email address 1@example.org , create a user and link them?
POST http://localhost:8001/3.0/addresses/1@example.org/user
It returns 404
this bit of code in rest/addresses.py appears to be what is being executed and seems to be returning a 404 if the address does not already exist.
@child() def user(self, request, segments): """/addresses/<email>/user""" if self._address is None: return NotFound(), [] # Avoid circular imports. from mailman.rest.users import AddressUser return AddressUser(self._address)
thanks
as
On 10 Feb 2015, at 1:53 pm, Barry Warsaw <barry@list.org> wrote:
On Feb 08, 2015, at 12:28 AM, Andrew Stuart wrote:
Yes, that makes sense as a general principle.
It's not really that deep. ;) As it turns out, the REST method is a thin layer on top of IUserManager.create_user() which itself has been around for quite a while. In the model, the behavior is pretty convenient.
(I'll also note that create_user() is used when POSTing to the <api>/users resource.)
Another guiding principle is that the edges should not have too much logic. In MM2, there was a lot of logic ingrained in the cgi scripts, and that causes a lot of problems if you want the same behavior in some other edge. Therefore I try to keep the REST API limited to parsing arguments, handling responses, and reporting error conditions while the actual core logic is implemented in the model or the app directory.
The use case here is when someone walks up to Postorious and creates an account for the first time. They'd enter their email address and Postorious would direct the core to create a user for them *and* an email address for them. It then makes sense to link the two together. Of course, the new address begins unverified.
The use case here is that someone already has a login to Postorious, and now they want to associate a new email address with their existing one. They log in (establishing their ownership of an existing user), enter their email address and if needed, that's created.
Now, it's questionable whether that address should be linked to the user until they verify the address. I think that happens now, but probably shouldn't, otherwise it could be hijacked.
Another use case is where a list administrator wants to add a bunch of addresses to their mailing list. There may be reasons to opt-out (e.g. a corporate list of employees, or a physical sign-up sheet that by its nature implies opt-in).
Maybe one way to look at it is that any operation that links an address to a user has to be a privileged url. A user creating an account on Postorious, or trying to add an address to an existing user are both operations where the address being created will not be verified (until they do a mail-back or confirmation click). In those cases, maybe we need an entirely separate resource (url) for the user operations, which would ensure the proper confirmation dance were performed.
Thoughts?
Cheers, -Barry
Mailman-Developers mailing list Mailman-Developers@python.org https://mail.python.org/mailman/listinfo/mailman-developers Mailman FAQ: http://wiki.list.org/x/AgA3 Searchable Archives: http://www.mail-archive.com/mailman-developers%40python.org/ Unsubscribe: https://mail.python.org/mailman/options/mailman-developers/andrew.stuart%40s...
Security Policy: http://wiki.list.org/x/QIA9

Barry just a prod on this one - if you have a moment to comment that would be great. thanks
Begin forwarded message:
Subject: Re: [Mailman-Developers] /3.0/addresses/cris@example.com/user' - multi purpose REST API method From: Andrew Stuart <andrew.stuart@supercoders.com.au> Date: 20 February 2015 12:29:17 pm AEDT To: Mailman Developers <Mailman-Developers@python.org>
Is this command meant to create the email address 1@example.org , create a user and link them?
POST http://localhost:8001/3.0/addresses/1@example.org/user
It returns 404
this bit of code in rest/addresses.py appears to be what is being executed and seems to be returning a 404 if the address does not already exist.
@child() def user(self, request, segments): """/addresses/<email>/user""" if self._address is None: return NotFound(), [] # Avoid circular imports. from mailman.rest.users import AddressUser return AddressUser(self._address)
thanks
as
On 10 Feb 2015, at 1:53 pm, Barry Warsaw <barry@list.org> wrote:
On Feb 08, 2015, at 12:28 AM, Andrew Stuart wrote:
Yes, that makes sense as a general principle.
It's not really that deep. ;) As it turns out, the REST method is a thin layer on top of IUserManager.create_user() which itself has been around for quite a while. In the model, the behavior is pretty convenient.
(I'll also note that create_user() is used when POSTing to the <api>/users resource.)
Another guiding principle is that the edges should not have too much logic. In MM2, there was a lot of logic ingrained in the cgi scripts, and that causes a lot of problems if you want the same behavior in some other edge. Therefore I try to keep the REST API limited to parsing arguments, handling responses, and reporting error conditions while the actual core logic is implemented in the model or the app directory.
The use case here is when someone walks up to Postorious and creates an account for the first time. They'd enter their email address and Postorious would direct the core to create a user for them *and* an email address for them. It then makes sense to link the two together. Of course, the new address begins unverified.
The use case here is that someone already has a login to Postorious, and now they want to associate a new email address with their existing one. They log in (establishing their ownership of an existing user), enter their email address and if needed, that's created.
Now, it's questionable whether that address should be linked to the user until they verify the address. I think that happens now, but probably shouldn't, otherwise it could be hijacked.
Another use case is where a list administrator wants to add a bunch of addresses to their mailing list. There may be reasons to opt-out (e.g. a corporate list of employees, or a physical sign-up sheet that by its nature implies opt-in).
Maybe one way to look at it is that any operation that links an address to a user has to be a privileged url. A user creating an account on Postorious, or trying to add an address to an existing user are both operations where the address being created will not be verified (until they do a mail-back or confirmation click). In those cases, maybe we need an entirely separate resource (url) for the user operations, which would ensure the proper confirmation dance were performed.
Thoughts?
Cheers, -Barry
Mailman-Developers mailing list Mailman-Developers@python.org https://mail.python.org/mailman/listinfo/mailman-developers Mailman FAQ: http://wiki.list.org/x/AgA3 Searchable Archives: http://www.mail-archive.com/mailman-developers%40python.org/ Unsubscribe: https://mail.python.org/mailman/options/mailman-developers/andrew.stuart%40s...
Security Policy: http://wiki.list.org/x/QIA9

Actually I meant authorization not authentication.
On 8 Feb 2015, at 12:28 am, Andrew Stuart <andrew.stuart@supercoders.com.au> wrote:
TLDR - This API methods does multiple things and depends on information apart from the URL to define its behaviour mode, making it hard to give a clear authentication scope to. I wonder if it should be broken out into individual REST API methods, each with a single purpose and a clear authentication scope.
As background information, from the documentation:
“”"To link an address to a user, a POST request can be sent to the /user
sub-resource of the address. If the user does not exist, it will be created.””"
dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user', ... {'display_name': 'Cris X. Person’})
My question is - I am interested to understand the thinking behind this REST method.
It is effectively a multi purpose method.
In one case it *creates an email address* and *creates a new user* and which are linked to each other.
In one case it *creates an email address* and links that address to an existing user, when given a POSTed user_id.
In one case it *creates an email address* and does not link it to any user, if the auto_create POST option is False.
In terms of building an authentication system this REST method is problematic. All (I think at this stage anyway) other methods in the REST API can be given a clear authentication scope/role based only on the URL. This REST API method, dual to its multi purpose, mode options-in-the-POST-data behaviour, cannot be given an authentication scope based only on the URL.
Each of the above behaviours have a different authentication scope/role. For example:
(permitted by superuser only) In one case it *creates an email address* and *creates a new user* and which are linked to each other.
(permitted by superuser only, permitted by existing user) In one case it *creates an email address* and links that address to an existing user, when given a POSTed user_id.
(permitted by superuser only) In one case it *creates an email address* and does not link it to any user, if the auto_create POST option is False.
I’m interested to hear thoughts on this. It would be good if the authentication scope of every REST API URL could be defined based only on the URL, without the need to know either options provided in the form data, or whether or not other records such as user records exist.
In summary - This API methods does too many things and depends on information apart from the URL to define its behaviour, making it hard to give a clear authentication scope to. I wonder if it should be broken out into individual REST API methods, each with a single purpose and a clear authentication scope.
Mailman-Developers mailing list Mailman-Developers@python.org https://mail.python.org/mailman/listinfo/mailman-developers Mailman FAQ: http://wiki.list.org/x/AgA3 Searchable Archives: http://www.mail-archive.com/mailman-developers%40python.org/ Unsubscribe: https://mail.python.org/mailman/options/mailman-developers/andrew.stuart%40s...
Security Policy: http://wiki.list.org/x/QIA9

On Feb 08, 2015, at 12:28 AM, Andrew Stuart wrote:
Yes, that makes sense as a general principle.
It's not really that deep. ;) As it turns out, the REST method is a thin layer on top of IUserManager.create_user() which itself has been around for quite a while. In the model, the behavior is pretty convenient.
(I'll also note that create_user() is used when POSTing to the <api>/users resource.)
Another guiding principle is that the edges should not have too much logic. In MM2, there was a lot of logic ingrained in the cgi scripts, and that causes a lot of problems if you want the same behavior in some other edge. Therefore I try to keep the REST API limited to parsing arguments, handling responses, and reporting error conditions while the actual core logic is implemented in the model or the app directory.
The use case here is when someone walks up to Postorious and creates an account for the first time. They'd enter their email address and Postorious would direct the core to create a user for them *and* an email address for them. It then makes sense to link the two together. Of course, the new address begins unverified.
The use case here is that someone already has a login to Postorious, and now they want to associate a new email address with their existing one. They log in (establishing their ownership of an existing user), enter their email address and if needed, that's created.
Now, it's questionable whether that address should be linked to the user until they verify the address. I think that happens now, but probably shouldn't, otherwise it could be hijacked.
Another use case is where a list administrator wants to add a bunch of addresses to their mailing list. There may be reasons to opt-out (e.g. a corporate list of employees, or a physical sign-up sheet that by its nature implies opt-in).
Maybe one way to look at it is that any operation that links an address to a user has to be a privileged url. A user creating an account on Postorious, or trying to add an address to an existing user are both operations where the address being created will not be verified (until they do a mail-back or confirmation click). In those cases, maybe we need an entirely separate resource (url) for the user operations, which would ensure the proper confirmation dance were performed.
Thoughts?
Cheers, -Barry

Is this command meant to create the email address 1@example.org , create a user and link them?
POST http://localhost:8001/3.0/addresses/1@example.org/user
It returns 404
this bit of code in rest/addresses.py appears to be what is being executed and seems to be returning a 404 if the address does not already exist.
@child() def user(self, request, segments): """/addresses/<email>/user""" if self._address is None: return NotFound(), [] # Avoid circular imports. from mailman.rest.users import AddressUser return AddressUser(self._address)
thanks
as
On 10 Feb 2015, at 1:53 pm, Barry Warsaw <barry@list.org> wrote:
On Feb 08, 2015, at 12:28 AM, Andrew Stuart wrote:
Yes, that makes sense as a general principle.
It's not really that deep. ;) As it turns out, the REST method is a thin layer on top of IUserManager.create_user() which itself has been around for quite a while. In the model, the behavior is pretty convenient.
(I'll also note that create_user() is used when POSTing to the <api>/users resource.)
Another guiding principle is that the edges should not have too much logic. In MM2, there was a lot of logic ingrained in the cgi scripts, and that causes a lot of problems if you want the same behavior in some other edge. Therefore I try to keep the REST API limited to parsing arguments, handling responses, and reporting error conditions while the actual core logic is implemented in the model or the app directory.
The use case here is when someone walks up to Postorious and creates an account for the first time. They'd enter their email address and Postorious would direct the core to create a user for them *and* an email address for them. It then makes sense to link the two together. Of course, the new address begins unverified.
The use case here is that someone already has a login to Postorious, and now they want to associate a new email address with their existing one. They log in (establishing their ownership of an existing user), enter their email address and if needed, that's created.
Now, it's questionable whether that address should be linked to the user until they verify the address. I think that happens now, but probably shouldn't, otherwise it could be hijacked.
Another use case is where a list administrator wants to add a bunch of addresses to their mailing list. There may be reasons to opt-out (e.g. a corporate list of employees, or a physical sign-up sheet that by its nature implies opt-in).
Maybe one way to look at it is that any operation that links an address to a user has to be a privileged url. A user creating an account on Postorious, or trying to add an address to an existing user are both operations where the address being created will not be verified (until they do a mail-back or confirmation click). In those cases, maybe we need an entirely separate resource (url) for the user operations, which would ensure the proper confirmation dance were performed.
Thoughts?
Cheers, -Barry
Mailman-Developers mailing list Mailman-Developers@python.org https://mail.python.org/mailman/listinfo/mailman-developers Mailman FAQ: http://wiki.list.org/x/AgA3 Searchable Archives: http://www.mail-archive.com/mailman-developers%40python.org/ Unsubscribe: https://mail.python.org/mailman/options/mailman-developers/andrew.stuart%40s...
Security Policy: http://wiki.list.org/x/QIA9

Barry just a prod on this one - if you have a moment to comment that would be great. thanks
Begin forwarded message:
Subject: Re: [Mailman-Developers] /3.0/addresses/cris@example.com/user' - multi purpose REST API method From: Andrew Stuart <andrew.stuart@supercoders.com.au> Date: 20 February 2015 12:29:17 pm AEDT To: Mailman Developers <Mailman-Developers@python.org>
Is this command meant to create the email address 1@example.org , create a user and link them?
POST http://localhost:8001/3.0/addresses/1@example.org/user
It returns 404
this bit of code in rest/addresses.py appears to be what is being executed and seems to be returning a 404 if the address does not already exist.
@child() def user(self, request, segments): """/addresses/<email>/user""" if self._address is None: return NotFound(), [] # Avoid circular imports. from mailman.rest.users import AddressUser return AddressUser(self._address)
thanks
as
On 10 Feb 2015, at 1:53 pm, Barry Warsaw <barry@list.org> wrote:
On Feb 08, 2015, at 12:28 AM, Andrew Stuart wrote:
Yes, that makes sense as a general principle.
It's not really that deep. ;) As it turns out, the REST method is a thin layer on top of IUserManager.create_user() which itself has been around for quite a while. In the model, the behavior is pretty convenient.
(I'll also note that create_user() is used when POSTing to the <api>/users resource.)
Another guiding principle is that the edges should not have too much logic. In MM2, there was a lot of logic ingrained in the cgi scripts, and that causes a lot of problems if you want the same behavior in some other edge. Therefore I try to keep the REST API limited to parsing arguments, handling responses, and reporting error conditions while the actual core logic is implemented in the model or the app directory.
The use case here is when someone walks up to Postorious and creates an account for the first time. They'd enter their email address and Postorious would direct the core to create a user for them *and* an email address for them. It then makes sense to link the two together. Of course, the new address begins unverified.
The use case here is that someone already has a login to Postorious, and now they want to associate a new email address with their existing one. They log in (establishing their ownership of an existing user), enter their email address and if needed, that's created.
Now, it's questionable whether that address should be linked to the user until they verify the address. I think that happens now, but probably shouldn't, otherwise it could be hijacked.
Another use case is where a list administrator wants to add a bunch of addresses to their mailing list. There may be reasons to opt-out (e.g. a corporate list of employees, or a physical sign-up sheet that by its nature implies opt-in).
Maybe one way to look at it is that any operation that links an address to a user has to be a privileged url. A user creating an account on Postorious, or trying to add an address to an existing user are both operations where the address being created will not be verified (until they do a mail-back or confirmation click). In those cases, maybe we need an entirely separate resource (url) for the user operations, which would ensure the proper confirmation dance were performed.
Thoughts?
Cheers, -Barry
Mailman-Developers mailing list Mailman-Developers@python.org https://mail.python.org/mailman/listinfo/mailman-developers Mailman FAQ: http://wiki.list.org/x/AgA3 Searchable Archives: http://www.mail-archive.com/mailman-developers%40python.org/ Unsubscribe: https://mail.python.org/mailman/options/mailman-developers/andrew.stuart%40s...
Security Policy: http://wiki.list.org/x/QIA9
participants (2)
-
Andrew Stuart
-
Barry Warsaw