You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@couchdb.apache.org by Gowtham Tamizharasan <go...@inmobi.com> on 2014/02/19 07:54:49 UTC

Capturing UserCtx automatically

Hi all,

We want to capture the user details of the person who creates or modifies a
document. Now, I understand that in couch context, even a replication job
is a 'user' that is modifying the DB.

I'd ideally like to just use Changes API. It is almost perfect - except -
we don't see the 'user' in the changes API output.

So, I'm thinking of modifying validate_doc_update erlang function such that
it will extract username from UserCtx and set a "_user" field in the
document. However, this will surely interfere with replication. Am I
correct?

While we can "work around" this problem by putting some convention in the
users db (if "replication user" role then don't modify _user). Is this
approach good enough and will this work?

So the modification will have be here, correct?

In couch_db.erl:469: (
https://github.com/apache/couchdb/blob/master/src/couchdb/couch_db.erl )

validate_doc_update(Db, Doc, GetDiskDocFun) ->
    DiskDoc = GetDiskDocFun(),
    JsonCtx = couch_util:json_user_ctx(Db),
    SecObj = get_security(Db),
    try [case Fun(Doc, DiskDoc, JsonCtx, SecObj) of
            % INSERT HACK HERE
            ok -> ok;
            Error -> throw(Error)
        end || Fun <- Db#db.validate_doc_funs],
        ok
    catch

        throw:Error ->

            Error
    end.


Another question: Can we use an _ field (like "_user") and will it just
work? Or do I have to modify elsewhere too?

In other words, do I have to explicitly do a transfer_fields? How do I now
ensure _user value gets stored? From what we see, _id is written back like
this:

transfer_fields([{<<"_id">>, Id} | Rest], Doc) ->
    validate_docid(Id),
    transfer_fields(Rest, Doc#doc{id=Id});

That means, I must invent a way to store the user also? like :

*transfer_fields([{<<"_user">>, User} | Rest], Doc) ->*
*    %My falidation for _User field, *
*    transfer_fields(Rest, Doc#doc{user=User});*


 what about retrieval? how ll my *"_user"* field get stored, and how can i
retrieve it?


Regards,
Gowtham.

-- 
_____________________________________________________________
The information contained in this communication is intended solely for the 
use of the individual or entity to whom it is addressed and others 
authorized to receive it. It may contain confidential or legally privileged 
information. If you are not the intended recipient you are hereby notified 
that any disclosure, copying, distribution or taking any action in reliance 
on the contents of this information is strictly prohibited and may be 
unlawful. If you have received this communication in error, please notify 
us immediately by responding to this email and then delete it from your 
system. The firm is neither liable for the proper and complete transmission 
of the information contained in this communication nor for any delay in its 
receipt.

Re: Capturing UserCtx automatically

Posted by Robert Samuel Newson <rn...@apache.org>.
You could ensure all replications use a userCtx that has a role you don’t grant to any other user. if userCtx.roles contains it, you just "return;"

Conversely, you could give all your users a particular role that you test for. if userCtx.roles contains it, you apply all the auditing checks.

B.


On 19 Feb 2014, at 10:42, Alexander Shorin <kx...@gmail.com> wrote:

> On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
> <rn...@apache.org> wrote:
>> validate_doc_update(oldDoc, newDoc, userCtx) {
>> 
>>  if (newDoc.audit_trail[0].user != userCtx.name) {
>>    throw({forbidden: "You didn’t add your name to the audit trail!"});
>>  }
>>  …
>> }
> 
> There is one issue with such approach: replications. You will not be
> able to replicate documents which has different username in
> audit_trail from those one who runs the replication. Or, to be more
> detailed, you'll replicate fine all documents till the design document
> which brings this validation function to your database and after that
> you'll only able to store documents which matches replication's user.
> 
> --
> ,,,^..^,,,


Re: Capturing UserCtx automatically

Posted by Alexander Shorin <kx...@gmail.com>.
On Wed, Feb 19, 2014 at 5:25 PM, Jan Lehnardt <ja...@apache.org> wrote:
> No, I mean in my scenario the person who could make a local change to a doc
> they didn’t create would *NOT* have the replicator user’s credentials, so
> they could NOT replicate things back elsewhere.
>

Aaa! I see your point. Sorry, I found the flaw in my story. So, I have
to instruct people to setup some special username _at the local
instance_  or set  some special role to user they preferred to use for
store data onto local instance which bypasses validate function
restrictions upon userCtx.name. Good point! I'd already used the same
assumption for users with _admin role, but never thought about having
some magical role for regular users on the other side. Thanks, I see
the solution now (:

--
,,,^..^,,,

Re: Capturing UserCtx automatically

Posted by Jan Lehnardt <ja...@apache.org>.
On 19 Feb 2014, at 14:19 , Alexander Shorin <kx...@gmail.com> wrote:

> On Wed, Feb 19, 2014 at 5:15 PM, Jan Lehnardt <ja...@apache.org> wrote:
>> On 19 Feb 2014, at 13:27 , Alexander Shorin <kx...@gmail.com> wrote:
>> 
>>> On Wed, Feb 19, 2014 at 4:17 PM, Jan Lehnardt <ja...@apache.org> wrote:
>>>> On 19 Feb 2014, at 13:02 , Alexander Shorin <kx...@gmail.com> wrote:
>>>> 
>>>>> On Wed, Feb 19, 2014 at 3:59 PM, Jan Lehnardt <ja...@apache.org> wrote:
>>>>>> On 19 Feb 2014, at 11:42 , Alexander Shorin <kx...@gmail.com> wrote:
>>>>>> 
>>>>>>> On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
>>>>>>> <rn...@apache.org> wrote:
>>>>>>>> validate_doc_update(oldDoc, newDoc, userCtx) {
>>>>>>>> 
>>>>>>>> if (newDoc.audit_trail[0].user != userCtx.name) {
>>>>>>>> throw({forbidden: "You didn’t add your name to the audit trail!"});
>>>>>>>> }
>>>>>>>> …
>>>>>>>> }
>>>>>>> 
>>>>>>> There is one issue with such approach: replications. You will not be
>>>>>>> able to replicate documents which has different username in
>>>>>>> audit_trail from those one who runs the replication. Or, to be more
>>>>>>> detailed, you'll replicate fine all documents till the design document
>>>>>>> which brings this validation function to your database and after that
>>>>>>> you'll only able to store documents which matches replication's user.
>>>>>> 
>>>>>> You could add the replication user to the validation function and keep
>>>>>> the original author.
>>>>> 
>>>>> Sure, I could. But this would be tricky and unclear for other users
>>>>> that just wanted to grab the data from CouchDB.
>>>> 
>>>> how so?
>>> 
>>> Let's say we have some database where multiple users are collaborating
>>> upon some stuff. Let it be image hosting service based on CouchDB
>>> where friends shares images between. Your users allowed to post new
>>> docs with images, but they don't wanted to see how others users
>>> changes docs that they owned. We forbidden such actions via
>>> validate_doc_update function by checking if doc.author matches
>>> userCtx.name. So, that's the case: you allowed to update own documents
>>> and only allow to read the others.
>>> 
>>> Now some user wanted to replicate this database to local CouchDB. He
>>> already has his own personal credentials. And he'll use them in
>>> replication and I wonder if he's able to recall another account to use
>>> for replications. Also, if I create special username which is able to
>>> bypass validation function ... well, that's a bug in the system -
>>> what's the reason left to use restricted accounts when you have access
>>> to more powerful ones?
>> 
>> In this scenario, the other user would not be able to invoke a replication
>> with the replication-user credentials.
> 
> Which bypassed validation rules, right? And what stops him to use the
> same credentials to push data back from local instance to public one?
> If it workarounds validation rules, he'll be able to rewrite docs that
> he shouldn't be able to. That's the problem.

No, I mean in my scenario the person who could make a local change to a doc
they didn’t create would *NOT* have the replicator user’s credentials, so
they could NOT replicate things back elsewhere.

You point is important though: you need to set these things up carefully :)

Best
Jan
-- 




Re: Capturing UserCtx automatically

Posted by Alexander Shorin <kx...@gmail.com>.
On Wed, Feb 19, 2014 at 5:15 PM, Jan Lehnardt <ja...@apache.org> wrote:
> On 19 Feb 2014, at 13:27 , Alexander Shorin <kx...@gmail.com> wrote:
>
>> On Wed, Feb 19, 2014 at 4:17 PM, Jan Lehnardt <ja...@apache.org> wrote:
>>> On 19 Feb 2014, at 13:02 , Alexander Shorin <kx...@gmail.com> wrote:
>>>
>>>> On Wed, Feb 19, 2014 at 3:59 PM, Jan Lehnardt <ja...@apache.org> wrote:
>>>>> On 19 Feb 2014, at 11:42 , Alexander Shorin <kx...@gmail.com> wrote:
>>>>>
>>>>>> On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
>>>>>> <rn...@apache.org> wrote:
>>>>>>> validate_doc_update(oldDoc, newDoc, userCtx) {
>>>>>>>
>>>>>>> if (newDoc.audit_trail[0].user != userCtx.name) {
>>>>>>> throw({forbidden: "You didn’t add your name to the audit trail!"});
>>>>>>> }
>>>>>>> …
>>>>>>> }
>>>>>>
>>>>>> There is one issue with such approach: replications. You will not be
>>>>>> able to replicate documents which has different username in
>>>>>> audit_trail from those one who runs the replication. Or, to be more
>>>>>> detailed, you'll replicate fine all documents till the design document
>>>>>> which brings this validation function to your database and after that
>>>>>> you'll only able to store documents which matches replication's user.
>>>>>
>>>>> You could add the replication user to the validation function and keep
>>>>> the original author.
>>>>
>>>> Sure, I could. But this would be tricky and unclear for other users
>>>> that just wanted to grab the data from CouchDB.
>>>
>>> how so?
>>
>> Let's say we have some database where multiple users are collaborating
>> upon some stuff. Let it be image hosting service based on CouchDB
>> where friends shares images between. Your users allowed to post new
>> docs with images, but they don't wanted to see how others users
>> changes docs that they owned. We forbidden such actions via
>> validate_doc_update function by checking if doc.author matches
>> userCtx.name. So, that's the case: you allowed to update own documents
>> and only allow to read the others.
>>
>> Now some user wanted to replicate this database to local CouchDB. He
>> already has his own personal credentials. And he'll use them in
>> replication and I wonder if he's able to recall another account to use
>> for replications. Also, if I create special username which is able to
>> bypass validation function ... well, that's a bug in the system -
>> what's the reason left to use restricted accounts when you have access
>> to more powerful ones?
>
> In this scenario, the other user would not be able to invoke a replication
> with the replication-user credentials.

Which bypassed validation rules, right? And what stops him to use the
same credentials to push data back from local instance to public one?
If it workarounds validation rules, he'll be able to rewrite docs that
he shouldn't be able to. That's the problem.

--
,,,^..^,,,

Re: Capturing UserCtx automatically

Posted by Jan Lehnardt <ja...@apache.org>.
On 19 Feb 2014, at 13:27 , Alexander Shorin <kx...@gmail.com> wrote:

> On Wed, Feb 19, 2014 at 4:17 PM, Jan Lehnardt <ja...@apache.org> wrote:
>> On 19 Feb 2014, at 13:02 , Alexander Shorin <kx...@gmail.com> wrote:
>> 
>>> On Wed, Feb 19, 2014 at 3:59 PM, Jan Lehnardt <ja...@apache.org> wrote:
>>>> On 19 Feb 2014, at 11:42 , Alexander Shorin <kx...@gmail.com> wrote:
>>>> 
>>>>> On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
>>>>> <rn...@apache.org> wrote:
>>>>>> validate_doc_update(oldDoc, newDoc, userCtx) {
>>>>>> 
>>>>>> if (newDoc.audit_trail[0].user != userCtx.name) {
>>>>>> throw({forbidden: "You didn’t add your name to the audit trail!"});
>>>>>> }
>>>>>> …
>>>>>> }
>>>>> 
>>>>> There is one issue with such approach: replications. You will not be
>>>>> able to replicate documents which has different username in
>>>>> audit_trail from those one who runs the replication. Or, to be more
>>>>> detailed, you'll replicate fine all documents till the design document
>>>>> which brings this validation function to your database and after that
>>>>> you'll only able to store documents which matches replication's user.
>>>> 
>>>> You could add the replication user to the validation function and keep
>>>> the original author.
>>> 
>>> Sure, I could. But this would be tricky and unclear for other users
>>> that just wanted to grab the data from CouchDB.
>> 
>> how so?
> 
> Let's say we have some database where multiple users are collaborating
> upon some stuff. Let it be image hosting service based on CouchDB
> where friends shares images between. Your users allowed to post new
> docs with images, but they don't wanted to see how others users
> changes docs that they owned. We forbidden such actions via
> validate_doc_update function by checking if doc.author matches
> userCtx.name. So, that's the case: you allowed to update own documents
> and only allow to read the others.
> 
> Now some user wanted to replicate this database to local CouchDB. He
> already has his own personal credentials. And he'll use them in
> replication and I wonder if he's able to recall another account to use
> for replications. Also, if I create special username which is able to
> bypass validation function ... well, that's a bug in the system -
> what's the reason left to use restricted accounts when you have access
> to more powerful ones?

In this scenario, the other user would not be able to invoke a replication
with the replication-user credentials.


Re: Capturing UserCtx automatically

Posted by Alexander Shorin <kx...@gmail.com>.
On Wed, Feb 19, 2014 at 4:17 PM, Jan Lehnardt <ja...@apache.org> wrote:
> On 19 Feb 2014, at 13:02 , Alexander Shorin <kx...@gmail.com> wrote:
>
>> On Wed, Feb 19, 2014 at 3:59 PM, Jan Lehnardt <ja...@apache.org> wrote:
>>> On 19 Feb 2014, at 11:42 , Alexander Shorin <kx...@gmail.com> wrote:
>>>
>>>> On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
>>>> <rn...@apache.org> wrote:
>>>>> validate_doc_update(oldDoc, newDoc, userCtx) {
>>>>>
>>>>> if (newDoc.audit_trail[0].user != userCtx.name) {
>>>>>  throw({forbidden: "You didn’t add your name to the audit trail!"});
>>>>> }
>>>>> …
>>>>> }
>>>>
>>>> There is one issue with such approach: replications. You will not be
>>>> able to replicate documents which has different username in
>>>> audit_trail from those one who runs the replication. Or, to be more
>>>> detailed, you'll replicate fine all documents till the design document
>>>> which brings this validation function to your database and after that
>>>> you'll only able to store documents which matches replication's user.
>>>
>>> You could add the replication user to the validation function and keep
>>> the original author.
>>
>> Sure, I could. But this would be tricky and unclear for other users
>> that just wanted to grab the data from CouchDB.
>
> how so?

Let's say we have some database where multiple users are collaborating
upon some stuff. Let it be image hosting service based on CouchDB
where friends shares images between. Your users allowed to post new
docs with images, but they don't wanted to see how others users
changes docs that they owned. We forbidden such actions via
validate_doc_update function by checking if doc.author matches
userCtx.name. So, that's the case: you allowed to update own documents
and only allow to read the others.

Now some user wanted to replicate this database to local CouchDB. He
already has his own personal credentials. And he'll use them in
replication and I wonder if he's able to recall another account to use
for replications. Also, if I create special username which is able to
bypass validation function ... well, that's a bug in the system -
what's the reason left to use restricted accounts when you have access
to more powerful ones?

--
,,,^..^,,,

Re: Capturing UserCtx automatically

Posted by Jan Lehnardt <ja...@apache.org>.
On 19 Feb 2014, at 13:02 , Alexander Shorin <kx...@gmail.com> wrote:

> On Wed, Feb 19, 2014 at 3:59 PM, Jan Lehnardt <ja...@apache.org> wrote:
>> On 19 Feb 2014, at 11:42 , Alexander Shorin <kx...@gmail.com> wrote:
>> 
>>> On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
>>> <rn...@apache.org> wrote:
>>>> validate_doc_update(oldDoc, newDoc, userCtx) {
>>>> 
>>>> if (newDoc.audit_trail[0].user != userCtx.name) {
>>>>  throw({forbidden: "You didn’t add your name to the audit trail!"});
>>>> }
>>>> …
>>>> }
>>> 
>>> There is one issue with such approach: replications. You will not be
>>> able to replicate documents which has different username in
>>> audit_trail from those one who runs the replication. Or, to be more
>>> detailed, you'll replicate fine all documents till the design document
>>> which brings this validation function to your database and after that
>>> you'll only able to store documents which matches replication's user.
>> 
>> You could add the replication user to the validation function and keep
>> the original author.
> 
> Sure, I could. But this would be tricky and unclear for other users
> that just wanted to grab the data from CouchDB.

how so?

Re: Capturing UserCtx automatically

Posted by Alexander Shorin <kx...@gmail.com>.
On Wed, Feb 19, 2014 at 3:59 PM, Jan Lehnardt <ja...@apache.org> wrote:
> On 19 Feb 2014, at 11:42 , Alexander Shorin <kx...@gmail.com> wrote:
>
>> On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
>> <rn...@apache.org> wrote:
>>> validate_doc_update(oldDoc, newDoc, userCtx) {
>>>
>>>  if (newDoc.audit_trail[0].user != userCtx.name) {
>>>    throw({forbidden: "You didn’t add your name to the audit trail!"});
>>>  }
>>>  …
>>> }
>>
>> There is one issue with such approach: replications. You will not be
>> able to replicate documents which has different username in
>> audit_trail from those one who runs the replication. Or, to be more
>> detailed, you'll replicate fine all documents till the design document
>> which brings this validation function to your database and after that
>> you'll only able to store documents which matches replication's user.
>
> You could add the replication user to the validation function and keep
> the original author.

Sure, I could. But this would be tricky and unclear for other users
that just wanted to grab the data from CouchDB.

--
,,,^..^,,,

Re: Capturing UserCtx automatically

Posted by Jan Lehnardt <ja...@apache.org>.
On 19 Feb 2014, at 11:42 , Alexander Shorin <kx...@gmail.com> wrote:

> On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
> <rn...@apache.org> wrote:
>> validate_doc_update(oldDoc, newDoc, userCtx) {
>> 
>>  if (newDoc.audit_trail[0].user != userCtx.name) {
>>    throw({forbidden: "You didn’t add your name to the audit trail!"});
>>  }
>>  …
>> }
> 
> There is one issue with such approach: replications. You will not be
> able to replicate documents which has different username in
> audit_trail from those one who runs the replication. Or, to be more
> detailed, you'll replicate fine all documents till the design document
> which brings this validation function to your database and after that
> you'll only able to store documents which matches replication's user.

You could add the replication user to the validation function and keep
the original author.

Jan
--


Re: Capturing UserCtx automatically

Posted by Alexander Shorin <kx...@gmail.com>.
On Wed, Feb 19, 2014 at 2:24 PM, Robert Samuel Newson
<rn...@apache.org> wrote:
> validate_doc_update(oldDoc, newDoc, userCtx) {
>
>   if (newDoc.audit_trail[0].user != userCtx.name) {
>     throw({forbidden: "You didn’t add your name to the audit trail!"});
>   }
>   …
> }

There is one issue with such approach: replications. You will not be
able to replicate documents which has different username in
audit_trail from those one who runs the replication. Or, to be more
detailed, you'll replicate fine all documents till the design document
which brings this validation function to your database and after that
you'll only able to store documents which matches replication's user.

--
,,,^..^,,,

Re: Capturing UserCtx automatically

Posted by Robert Samuel Newson <rn...@apache.org>.
validate_doc_update cannot modify the document for the reasons you state.

As I said when you asked on IRC, you can write a validate_doc_update function that refuses any update to a document that doesn’t also add information to that document about the change being made. That is, you can insist that users include an accurate audit trail when they update documents, and couchdb will reject any write that doesn’t do so. A rough sketch;

validate_doc_update(oldDoc, newDoc, userCtx) {

  if (newDoc.audit_trail[0].user != userCtx.name) {
    throw({forbidden: "You didn’t add your name to the audit trail!"});
  }
  …
}

You’d obviously need to verify that the other items in doc.audit_trail are identical to the ones in oldDoc, etc, but it’s possible.

To make adhering to these constraints easier for users, you can write a document update handler that automatically generates an audit entry and adds it to the start or end of the audit_trail array.

B.

On 19 Feb 2014, at 06:54, Gowtham Tamizharasan <go...@inmobi.com> wrote:

> Hi all,
> 
> We want to capture the user details of the person who creates or modifies a
> document. Now, I understand that in couch context, even a replication job
> is a 'user' that is modifying the DB.
> 
> I'd ideally like to just use Changes API. It is almost perfect - except -
> we don't see the 'user' in the changes API output.
> 
> So, I'm thinking of modifying validate_doc_update erlang function such that
> it will extract username from UserCtx and set a "_user" field in the
> document. However, this will surely interfere with replication. Am I
> correct?
> 
> While we can "work around" this problem by putting some convention in the
> users db (if "replication user" role then don't modify _user). Is this
> approach good enough and will this work?
> 
> So the modification will have be here, correct?
> 
> In couch_db.erl:469: (
> https://github.com/apache/couchdb/blob/master/src/couchdb/couch_db.erl )
> 
> validate_doc_update(Db, Doc, GetDiskDocFun) ->
>    DiskDoc = GetDiskDocFun(),
>    JsonCtx = couch_util:json_user_ctx(Db),
>    SecObj = get_security(Db),
>    try [case Fun(Doc, DiskDoc, JsonCtx, SecObj) of
>            % INSERT HACK HERE
>            ok -> ok;
>            Error -> throw(Error)
>        end || Fun <- Db#db.validate_doc_funs],
>        ok
>    catch
> 
>        throw:Error ->
> 
>            Error
>    end.
> 
> 
> Another question: Can we use an _ field (like "_user") and will it just
> work? Or do I have to modify elsewhere too?
> 
> In other words, do I have to explicitly do a transfer_fields? How do I now
> ensure _user value gets stored? From what we see, _id is written back like
> this:
> 
> transfer_fields([{<<"_id">>, Id} | Rest], Doc) ->
>    validate_docid(Id),
>    transfer_fields(Rest, Doc#doc{id=Id});
> 
> That means, I must invent a way to store the user also? like :
> 
> *transfer_fields([{<<"_user">>, User} | Rest], Doc) ->*
> *    %My falidation for _User field, *
> *    transfer_fields(Rest, Doc#doc{user=User});*
> 
> 
> what about retrieval? how ll my *"_user"* field get stored, and how can i
> retrieve it?
> 
> 
> Regards,
> Gowtham.
> 
> -- 
> _____________________________________________________________
> The information contained in this communication is intended solely for the 
> use of the individual or entity to whom it is addressed and others 
> authorized to receive it. It may contain confidential or legally privileged 
> information. If you are not the intended recipient you are hereby notified 
> that any disclosure, copying, distribution or taking any action in reliance 
> on the contents of this information is strictly prohibited and may be 
> unlawful. If you have received this communication in error, please notify 
> us immediately by responding to this email and then delete it from your 
> system. The firm is neither liable for the proper and complete transmission 
> of the information contained in this communication nor for any delay in its 
> receipt.