Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thoughts about a "register to newsletter" plugin #2050

Closed
magopian opened this issue Feb 18, 2019 · 18 comments
Closed

Thoughts about a "register to newsletter" plugin #2050

magopian opened this issue Feb 18, 2019 · 18 comments

Comments

@magopian
Copy link
Contributor

The idea is that sometimes a new record has to be created from a front-end, with the "admin" rights, but we obviously don't want the admin credentials to be available on the front-end.

Such a case is when you want to allow a user to register to a newsletter on your website: if you create all the records with the same user, that same user can view the list of all the registered emails for the newsletter (even if the permissions don't include read : system.Everyone, as an owner it has the read permission).

So this plugin would add an endpoint that would allow an anonymous POST to create a record as a different registered user, transferring the ownership.

Example configuration:

kinto.newsletter.bucket = myproject
kinto.newsletter.collection = newsletter
kinto.newsletter.owner = account:admin

Example usage:

echo '{"data": {"email": "foo@bar.com", "name": "test name"}}' | http POST https://kinto.server/v1/newsletter

Propositions:

  • instead of adding a /newsletter root endpoint it could be a "leaf" endpoint like the kinto-attachment plugin does: http POST https://..../v1/buckets/foo/collections/bar/newsletter
  • this plugin could be more generic and be "create-for-owner" or "create-as-account", and you could be able to create a record and pass in the owner as metadata: echo '{"data": {...}, "owner": "account:admin"} | http POST ....
    In this case, we might want to discuss the security and configuration implications (provide a list of allowed owners? A list of allowed resources to create with a different owner?)

As a heads up: the same "newsletter" use case could be fixed by having finer grained permissions (eg a "read-only" permission that would not give read access to the owner/creator).

@Natim
Copy link
Member

Natim commented Feb 19, 2019

Can you elaborate on why the record:create permission on the collection doesn't meet your requirements?

@magopian
Copy link
Contributor Author

Whenever a user creates or modifies a record, the write permission is automatically added to the record's permission. So unless you create a new random user for each creation (what I'm doing right now for the newsletter registration, but which requires enabling unlimited "account creation" using the basicauth policy), the user used to create the records will have access to all the records created.

Is that clearer @Natim ?

@Natim
Copy link
Member

Natim commented Feb 19, 2019

Actually what you said is not entirely true. The write permission will be added only to records that the user created, is that an issue that a user can delete its registration?

@leplatrem
Copy link
Contributor

leplatrem commented Feb 19, 2019

I don't think we'll add newsletter features to kinto, but using this use-case to rethink permissions or options makes sense ;)

I would like to have finer-grained permissions :) see #1550 and #368 for example.

Something like...

{
   "write": ["admin"]
   "record:create": ["system.Everyone"],
   "record:read: [],
   "record:write": [],
}

@magopian
Copy link
Contributor Author

I was going to create a plugin for that feature, not modify kinto itself obviously.

As I said above:

As a heads up: the same "newsletter" use case could be fixed by having finer grained permissions (eg a "read-only" permission that would not give read access to the owner/creator).

Which is probably the best solution. It might be a lot more involved and a lot more work though, so I might spend some time on the "newsletter" plugin in the meanwhile, I'll see.

Closing this now.

@Natim
Copy link
Member

Natim commented Feb 19, 2019

For instance:

newsletter.py
from kinto_http import Client

KINTO_SERVICE = "https://kinto.dev.mozaws.net/v1"
ADMIN_AUTH = ("admin", "p4ssw0rd")
ALEXIS_AUTH = ("alexis", "p4ssw0rd")
EMILIE_AUTH = ("emilie", "p4ssw0rd")

admin_client = Client(server_url=KINTO_SERVICE, bucket="newsletter",
                      collection="registration", auth=ADMIN_AUTH)

alexis_client = Client(server_url=KINTO_SERVICE, bucket="newsletter",
                       collection="registration", auth=ALEXIS_AUTH)

emilie_client = Client(server_url=KINTO_SERVICE, bucket="newsletter",
                       collection="registration", auth=EMILIE_AUTH)

admin_client.create_bucket(safe=False)
admin_client.create_collection(permissions={"record:create": ["system.Authenticated"]}, safe=False)

# Alexis register
alexis_client.create_record(data={"email": "alexis@domain.tld"})

# Emilie register
emilie_client.create_record(data={"email": "emilie@domain.tld"})


# Alexis registrations
print("Alexis records", alexis_client.get_records())

# Emilie registrations
print("Emilie records", emilie_client.get_records())

# Admin registrations
print("Admin records", admin_client.get_records())
$ python newsletter.py 

Alexis records [{'id': '5090b563-6b88-4d2c-9f92-89111d751043', 'email': 'alexis@domain.tld', 'last_modified': 1550565644103}]

Emilie records [{'id': '22b8615c-7de7-4569-9208-69b3a4d549cd', 'email': 'emilie@domain.tld', 'last_modified': 1550565644955}]

Admin records [{'id': '22b8615c-7de7-4569-9208-69b3a4d549cd', 'email': 'emilie@domain.tld', 'last_modified': 1550565644955}, {'id': '5090b563-6b88-4d2c-9f92-89111d751043', 'email': 'alexis@domain.tld', 'last_modified': 1550565644103}]

@Natim
Copy link
Member

Natim commented Feb 19, 2019

I missed the fact that people are not authenticated at this stage. I agree that we need to fix that somehow.

I think what is missing too is a way to give access to authenticated people with a given authentication policy: system.Authenticated:accounts

Why? Because if you allow both accounts and basicauth with some collections with system.Authenticated you will allow anyone to use this system.Authenticated permission (with unauthorized basicauth accounts). While if you allow only the one with the accounts policy, then you restrict access to those with basicauth.

This allow throw away sessions that will meet this use case.

@revolunet
Copy link

Is there a way to configure kinto so system.Everyone can only create records in some specific collection ?
Without read rights on the collection.

Useful for newsletter or contact forms

@Natim
Copy link
Member

Natim commented Nov 14, 2020

You can use the create:record permission on the collection for that.

What we used in the past is to derivate the email address from the form to generate a api key so that the user can manager their subscription.

@revolunet
Copy link

Looks like create:record implies read on the collection. Is it correct or did i miss something ?

@Natim
Copy link
Member

Natim commented Nov 14, 2020 via email

@revolunet
Copy link

Thanks for the confirmation, will try again !

@magopian
Copy link
Contributor Author

magopian commented Nov 14, 2020 via email

@revolunet
Copy link

if i set "record:create": ["system.Everyone"] on a collection permissions

then when i create a record as some random user (or anonymous), the records always ends up having "write": ["system.Everyone"] in the permissions 🤔 . If i specify the permission in the record payload, its also adds system.Everyone in the write list.

The record read permission are correctly scoped to the user, but not the write. hence, the read is possible if you query the collection anonymously.

record :

{
  "data": {
    "pouet": 44
  },
  "permissions": {
    "read": ["account:userY2", "account:userY3"],
    "write": ["account:userY2", "account:userY3"]
  }
}

PUT result as userY2 :
Capture d’écran 2020-11-21 à 00 47 57

i must doing something wrong

@Natim
Copy link
Member

Natim commented Nov 21, 2020

As @magopian said 👍

The trick is to have a different random user for each and every newsletter subscription

You shall use "record:create": ["system.Authenticated"] and then generate a random and unique user for each record using the BasicAuthAuthenticationPolicy

To activate the BasicAuthAuthenticationPolicy you need to add multiauth.policies = basicauth in your config.

Be careful that then people will be able to create throw away accounts that are unique by login:password couples.

Usually we generate 32 bytes string as a login with an empty password such as e4736b12e2271b4eae9fbb702f90d57a:

@Natim
Copy link
Member

Natim commented Nov 21, 2020

@leplatrem do you know if since Kinto 14.1 we could rely on kinto.explicit_permissions = false to allow to create records without inheriting the write permissions for system.Everyone?

@revolunet
Copy link

Ok, it worked, thanks !!

create-collection :

{
  "data": { "id": "form" },
  "permissions": {
    "record:create": ["system.Authenticated"],
    "read": [],
    "write": []
  }
}

create-record with some user:pass in a basic auth Authorization header :

{
  "data": {
    "pouet": 42
  }
}

environment variables :

KINTO_STORAGE_BACKEND: kinto.core.storage.postgresql
KINTO_STORAGE_URL: postgresql://postgres:postgres@postgres/postgres
KINTO_PERMISSION_BACKEND: kinto.core.permission.postgresql
KINTO_PERMISSION_URL: postgresql://postgres:postgres@postgres/postgres
KINTO_MULTIAUTH_POLICIES: account basicauth

result :

{
  "permissions": {
    "write": [
      "basicauth:dcd85f608b7d5cfdf2d0957d9c47966956d767745ff6511c4b0cf85b8d"
    ]
  },
  "data": {
    "pouet": 42,
    "id": "3e473dc0-3d8f-4d18-91b9-5bf162a985db",
    "last_modified": 1606086609299
  }
}

Is there a trick to make the newly created record not alterable by the creator ?

@magopian
Copy link
Contributor Author

magopian commented Nov 23, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants