Getting Forbidden when trying to access a view from public URL of sync_gateway

.net

#1

Hello,

I have created a View via Sync Gateway admin REST API and got 201 Created. I try to GET the view from Admin API and I get the result from the view fine.

But when I try to access the same view from Public API (Port: 4984), I get error:

curl --cookie "SyncGatewaySession=d619c14cef3c2959eaca00c1d192a8fc53161199" http://mysyncgatewayurl:4984/mycbcluster/_design/all_lists/_view/all_lists {"error":"Forbidden","reason":"forbidden"}

This public api has GUEST disabled TRUE and the Session token was generated for one of the user via Admin port.
Couchbase Community - 4.0
Couchbase SyncGatway - 1.2.0


User_views causes Sync Gateway crash on Linux
#2

Actually this might be something as silly as not putting a trailing slash on the URL. I get 403 when I put in the URL without a slash at the end, but a different response with the slash on the end.


#3

@borrrden I am pretty sure it is not a trialing slash issue.

By adding a slash to the end i get different error:

curl --cookie "SyncGatewaySession=5fa812b8a76a8095ff3a87d3085e29f86d1196d3" http://mysyncgatewayurl:4984/mycbcluster/_design/all_lists/_view/all_lists/ <a href="/mycbcluster/_design/all_lists/_view/all_lists">Moved Permanently</a>.


#4

the path should not have a slash at the end, so if you add one the server will redirect you to the correct path. (I don’t know why curl doesn’t follow redirects by default…)


#5

In SG 1.2 access to views vie the user REST API is disabled by default.

To enable add the following entry to your database config:

"unsupported": {
          "user_views": {
            "enabled":true
          }
        },

You must then delete and recreate your custom views via the ADMIN REST API, to add the channel mapper code to the view map function.


#6

Can you explain more on how can I add above snippet in “database config”, sorry I am still very new to the couchbase world.

@andy Thanks!


#7

It’s the JSON file used to configure Sync Gateway, usually called config.json. There’s an object in that which contains an entry for every database to serve; you would add the above snippet inside the entry for the database(s) you want to enable this feature for.

The SG docs have more info on the config file, if you want to learn more.


How to exclude '_sync:rev' documents
#8

Can yo confirm that your solution works? I’ve tried it - create the view via the admin port with the unsupported config in my sync-gateway config file, and then query via the users port… I simply can’t get the view to return any documents.


#9

@nick-couchbase

To validate that your view is created correctly and that it is processing documents you can do the following:

First look at the view via the Couchbase Server Admin Console, if it was created after the ‘unsupported’ property was added to the database config it will contain additional channel processing.

e.g. A view created in SG 1.2 without the ‘unsupported’ configuration:

{
	"views":{
		"all_lists":{
			"map":"function(doc,meta) {
				var sync = doc._sync;
				if (sync === undefined || meta.id.substring(0,6) == \"_sync:\") return;
				if ((sync.flags \u0026 1) || sync.deleted) return;
				delete doc._sync;
				meta.rev = sync.rev;
					(
					function (doc, meta) { 
						if (doc.type != \"list\") { return; } 
						emit(doc.title, doc.owner); 
					}
					) 
					(doc, meta);
					doc._sync = sync;
			}"
		}
	}
}

The same view created in SG 1.2 after the ‘unsupported’ property was added to the SG config:

{
	"views":{
		"all_lists":{
			"map":"function(doc,meta) {
				var sync = doc._sync;
				if (sync === undefined || meta.id.substring(0,6) == \"_sync:\") return;
				if ((sync.flags \u0026 1) || sync.deleted) return;
				var channels = [];
				var channelMap = sync.channels;
				if (channelMap) {
					for (var name in channelMap) {
						removed = channelMap[name];
						if (!removed)
						 channels.push(name);
					}
				}
				delete doc._sync;
				meta.rev = sync.rev;
				meta.channels = channels;
				var _emit = emit;
				(function(){
					var emit = function(key,value) {
						_emit(key,[channels, value]);
					};
				(function (doc, meta) { 
					if (doc.type != \"list\") { return; } 
					emit(doc.title, doc.owner); 
				}) 
				(doc, meta);
			}());
			doc._sync = sync;
			}"
		}
	}
}

If the channel processing is present then you can use the CBS Admin Console to process some documents by clicking on the “Show Results” Button. You should see results similar to:

"docID" [ [ "list--9swubvIT19JnxLT28todis" ], "p:10153954222643362" ]

If this is working and you are not seeing any rows when you query a view via the REST API then it is most likely that your user does not have any documents (for which rows are emitted by the view) tagged with any channels the user is assigned.

You can validate that by calling _all_docs on the User REST API (with user authentication) and check to see if any of the documents should be emitted by the view e.g…

curl -X GET http://localhost:4984/db/_all_docs

#10

@andy @jens @nick-couchbase Thank you guys for the support and replies. I was travelling so could not check it any earlier.

Now i did, here is the outcome.

I added “unsupported” node as provided to the database node for which I want to enable the same. Re-created the query / view via Admin API and try to access the same view from Public API using a user’s session.

This time I do not get any forbidden error anymore, this is progress. I see list of rows based on the channels to which the user was granted access to.

Now if (as) you mentioned, on querying the view from Public API with user’s session the result will only show the documents where the user have access to those channels then it does not serve my purpose.

I need to explain the case here so someone can follow through and suggest the right way to solve this problem:
I have user document containing basic info (name, profile pic url, designation), this gets created on the users couchbase lite and syncs to server with doc.type = “user-account” where I see this doc type on sync gateway function and add to two channel - “user specific channel” and common channel “ua-list”.

Every user are added to “ua-list” channel, so that everyone can see the basic user info doc (because that channel will sync). But now I have concern, if I keep adding all users to “ua-list” channel and all user sync’s those documents then what will happen on the day when I have 2 million user (example, please don’t panic). If that happens each user will have 2 million basic user info document synced (takes time to sync on initial run) plus if one of the document owner updates their info, it would sync to 2 million user’s local couchbase lite DB.

I want that basic user info of other users available to a user so that he can add him as a friend / contact to do further app related stuffs in combination to that user reference. But what I am going forward with or implementing does not seems to be a good approach or a long term solution.

So I turn to Rest API (public / admin) to see if I can call a view / query and get x amount of basic user info and then subsequent (paging) and by some mechanism only query or view them and not sync them to local db.

Sorry guys it seems to be hard to explain when I am writing this but I need some good help on this.
Thank you all for the replies and future conversation.


#11

My view code after enabling the “unsupported” node in sync gateway config.

function(doc, meta) { var sync = doc._sync; if (sync === undefined || meta.id.substring(0, 6) == "_sync:") return; if ((sync.flags & 1) || sync.deleted) return; var channels = []; var channelMap = sync.channels; if (channelMap) { for (var name in channelMap) { removed = channelMap[name]; if (!removed) channels.push(name); } } delete doc._sync; meta.rev = sync.rev; meta.channels = channels; var _emit = emit; (function() { var emit = function(key, value) { _emit(key, [channels, value]); }; (function(doc, meta) { emit(doc.account-id, doc.account-id); })(doc, meta); }()); doc._sync = sync; }


#12
"unsupported": {
      "user_views": {
        "enabled":true
      }
    },

I’m wondering why I cannot find any reference to this object in the sg config-file docs? Is this still necessary on sg 2.1?