One db per user and security - security

I'm trying to implement an app which uses couchdb as backend, But the problem is,
When installing couchdb , couchdb allows anyone to enter couchdb and create/delete/update databases, so we configure admin(super admin) for the couchdb server to prevent anonymous And if we configure superadmin while installing couchdb server, then normal users can't create databases, so userdb for the user isn't created. Only super admin has privilege to create database in couchdb. Even users with 'admins' role can't create db in couchdb.

I just dealt with all of this myself and couldn't find hardly anything about it...
From the documentation:
Users may only access (GET /_users/org.couchdb.user:Jan) or modify (PUT /_users/org.couchdb.user:Jan) documents that they own
This means that users can add themselves to the _users db. Thus, if you have couch_peruser turned on, running the following curl command will create the user jan along with the userdb-6a616e database.
curl -X PUT http://localhost:5984/_users/org.couchdb.user:jan \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "jan", "password": "apple", "roles": [], "type": "user"}'
You can use the db.signUp() function from the PouchDB Authentication plugin to effectively do the same thing. Also, I had to manually encode the username when initially creating my db var for the new remote PouchDB instance:
function encode (str) {
return unescape(encodeURIComponent(str))
.split('').map(function (v) {
return v.charCodeAt(0).toString(16)
}).join('')
}
var db = new PouchDB('http://localhost:5984/userdb-' + encode(username), {
auth: {
username: username,
password: username
},
skip_setup: true // Because the DB won't exist initially
})

Related

creating new user in couchdb 3 without admin password

I just downloaded and installed CouchDB v3.
On first start, it prompted me to set an admin password which I did.
For the web app that I'm building, I want to use the CouchDB user authentication feature, so I created a new _users database using the Fauxton UI.
After creating the _users database I made a call to the REST API to insert a new user (this is the example code taken from the documentation):
$ curl -X PUT http://localhost:5984/_users/org.couchdb.user:jan \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "jan", "password": "apple", "roles": [], "type": "user"}'
Instead of the expected response
{"ok":true,"id":"org.couchdb.user:jan","rev":..."}
I'm getting
{"error":"unauthorized","reason":"You are not authorized to access this db."}
When adding the admin credentials to the API call, it works as expected:
$ curl -X PUT http://admin:____#localhost:5984/_users/org.couchdb.user:jan \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "jan", "password": "apple", "roles": [], "type": "user"}'
{"ok":true,"id":"org.couchdb.user:jan","rev":"..."}
My question:
Are there any settings or permissions I can set to make the request work without having to add the admin credentials? (AFAIK this worked fine in v2.x)
You are missing the fun of the good old Admin Party, which for many years was the default setting for CouchDB, meaning it was installed with zero security as everyone was effectively an admin.
From The Road to CouchDB 3.0: Security[1]
One of the aspects of getting started easily was a 1.x-era choice to
make it easy to use CouchDB: the Admin Party. Admin Party means that,
by default, any request made against CouchDB was done in the context
of an admin user, i.e. you were allowed to do anything.
3.0 changed all of that by shutting down the Admin Party - what a bunch of buzz kills!
I suspect there are more sophisticated solutions, but for those that want to party on[2] quickly, minor changes to etc/local.ini and any permissions on _users will satisfy.
The key is the configuration property require_valid_user[3].
In etc/local.ini, modify the chttpd and couch_httpd_auth sections
[chttpd]
require_valid_user = false
[couch_httpd_auth]
require_valid_user = false
That's all that is needed unless there are members and/or roles defined for the _users database. If there are, they must be deleted (easily with Fauxton).
After cleaning up members/roles and altering the etc/local.ini restart CouchDB and you should be able to create users without a problem. Party on! 👍
Just be sure to consider the ramifications of such changes.
Disclaimer - I don't recommend running CouchDB in any security context resembling Admin Party!
1 The Road to CouchDB 3.0: Security
2 Party On
3 require_valid_user

How to get only specific fields in Gitlab API response?

For example I want to receive only project names:
https://gitlab.com/api/v4/groups/:id/projects?fields=name
Is that possible?
That's not possible in the REST API. But, GitLab is working on GraphQL support, and you'd be able to express that in GraphQL.
https://docs.gitlab.com/ee/api/graphql/
To iterate on Vonc & King Chung Huang 's answers, using the following GraphQL query, you can get only the name field of the projects inside your group :
{
group(fullPath: "your_group_name") {
projects {
nodes {
name
}
}
}
}
You can go to the following URL : https://$gitlab_url/-/graphql-explorer and past the above query
Using curl & jq :
gitlab_url=<your gitlab host>
access_token=<your access token>
group_name=<your group name>
curl -s -H "Authorization: Bearer $access_token" \
-H "Content-Type:application/json" \
-d '{
"query": "{ group(fullPath: \"'$group_name'\") { projects { nodes { name }}}}"
}' "https://$gitlab_url/api/graphql" | jq '.'
GitLab 1.11 (May 2019) has now introduced a "basic support for group GraphQL queries "
GraphQL APIs allows users to request exactly the data they need, making it possible to get all required data in a limited number of requests.
In this release, GitLab is now supporting basic group information support in the GraphQL API.
See Issue 60786 and documentation: "Available queries"
A first iteration of a GraphQL API includes the following queries
project : Within a project it is also possible to fetch a mergeRequest by IID.
group : Only basic group information is currently supported.

Authentication always failing when connecting to MongoDB

I am using node/express
node_modules =
"mongodb": "2.0.33",
"mongoose": "3.8.15",
mongo shell version: 3.0, and mongo 3.0
I'm able to connect to my mongoDB just fine, but if I pass in any authentication parameters, it will fail:
connection error: { [MongoError: auth failed] name: 'MongoError', ok: 0, errmsg: 'auth failed', code: 18 }
The following shows up in the logs when this happens:
2015-06-13T15:10:09.863-0400 I ACCESS [conn8] authenticate db: mydatabase { authenticate: 1, user: "user", nonce: "xxx", key: "xxx" } 2015-06-13T15:10:09.863-0400 I ACCESS [conn8] Failed to authenticate user#mydatabase with mechanism MONGODB-CR: AuthenticationFailed UserNotFound Could not find user user#mydatabase
I've done quite a few patterns to try to get this to work.
Here's what happens when I do the show users command in the mongo shell while on the appropriate database:
{
"_id" : "mydatabase.user",
"user" : "user",
"db" : "mydatabase",
"roles" : [
{
"role" : "readWrite",
"db" : "mydatabase"
}
]
}
Here's my attempt to connect to this particular database while passing in the correct parameters:
mongoose.connect('mongodb://user:password#host:port/mydatabase');
For good measure I also tried passing in an options hash instead of passing the params via uri:
mongoose.connect('mongodb://host:port/mydatabase',{user: 'user',pass: 'password'});
Strangely enough, this works when done from the shell:
mongo mydatabase -u user -p password
so clearly, the credentials are right, and it's lining them up to the correct database, but something about the connection with Mongoose is not working...
Here is the shell command I passed in when creating that user:
db.createUser({
user: "user",
pwd: "password",
roles: [
{ role: "readWrite", db: "mydatabase" }
]
});
I got a success message with this, and I confirmed by calling the show users command when using the mydatabase set
I'm at a real loss here.... Here's some of the prior research I have done that hasn't yet given me success:
Cannot authenticate into mongo, "auth fails"
This answer suggests that it wouldn't be working because authentication happens at a database level, so I'm missing some sort of config option for my mongo instance, however the docs now say that such level authentication is disabled by default, and the docs the answer links to are since deprecated.
MongoDB & Mongoose accessing one database while authenticating against another (NodeJS, Mongoose)
uses older version of Mongo that still have addUser
On top of that, I don't see why that would work given it suggests I add a parameter to the 'auth' options that isn't listed in the documentation:
http://mongodb.github.io/node-mongodb-native/api-generated/db.html#authenticate
http://mongoosejs.com/docs/connections.html
Basically what I'm trying now, but isn't working.
authenticate user with mongoose + express.js
I've tried a number of answers that involved doing something of this sort, that gave me the same error. Also, I'd rather avoid these type of solutions that require +80 lines of code to authenticate for now. I just want to get basic authentication down first.
You mentioned that you are using MongoDB 3.0. In MongoDB 3.0, it now supports multiple authentication mechanisms.
MongoDB Challenge and Response (SCRAM-SHA-1) - default in 3.0
MongoDB Challenge and Response (MONGODB-CR) - previous default (< 3.0)
If you started with a new 3.0 database with new users created, they would have been created using SCRAM-SHA-1.
So you will need a driver capable of that authentication:
http://docs.mongodb.org/manual/release-notes/3.0-scram/#considerations-scram-sha-1-drivers
If you had a database upgraded from 2.x with existing user data, they would still be using MONGODB-CR, and the user authentication database would have to be upgraded:
http://docs.mongodb.org/manual/release-notes/3.0-scram/#upgrade-mongodb-cr-to-scram
Specific to your particular environment Mongoose compatibility for that version doesn't appear to support 3.0 due to the MongoDB Node.js driver that is in use (see the compatibility page on the Mongoose site--sorry, can't post more than 2 links currently).
I would suggest you update Mongoose.
Mongo v3.0+:
The db field (outside of the role object) matters here. That is not settable bby passing it into the createUser command afaict.
The way to set it is to type 'use ' before issuing the creatUser command.
Unless you do it that way, the db object inside role may have he correct and intended value, but the auth will still not work.

CouchDB and PouchDB plain users can create Databases

I don't want normal users to be able to create Databases.
In the Futon Screen /_utils, when logged in as a plain user, everything functions as expected. Only Admins can create Databases.
But when I sync my pouchDB with couchDB, plain users can also create (replicate?) Database. I want the adding of new Databases only to be restricted to Admin users.
Also I just noticed that existing DB also get edited even when user is restricted.
How can I fix this?
var remoteCouch = http://testuser:testuser#{domain}.iriscouch.com/testdb;
PouchDB.debug.disable();
if (remoteCouch) {
sync();
} else {
console.log("No remote server.");
}
function sync() {
var opts = {live: true};
db.replicate.to(remoteCouch, opts, syncError);
db.replicate.from(remoteCouch, opts, syncError);
}
EDIT
Testuser is also not in /_config/admins
Testuser:
{
"_id": "org.couchdb.user:testuser",
"_rev": "1-7d28b3388a62cfca103cbe3642549bee",
"password_scheme": "pbkdf2",
"iterations": 10,
"type": "user",
"name": "testuser",
"roles": [
"testuser"
],
"derived_key": "2181a44141d6d6aa2061bb2c5c057451acc6461e",
"salt": "2184888b099f37605feca0a22e5b6bb9"
}
Is your CouchDB in admin party mode? If it's not, then only admins should be able to create databases, whether it's via Futon or PouchDB.
PouchDB isn't doing anything special; you can simulate what PouchDB is doing by using curl:
curl -X PUT http://someuser:somepassword#path.to.couchdb.com:5984/somedatabase
Are you sure your testuser isn't an admin? If the user that you give to PouchDB is an admin, then yes, users will be able to create their own databases.
More info on authentication can be found here: https://github.com/nolanlawson/pouchdb-authentication#couchdb-authentication-recipes

CouchDB Authorization on a Per-Database Basis

I'm working on an application supported by CouchDB. Essentially, I want to create a database for each individual user of my app. To accomplish this, the admin user will create the database, but going forward, the user will need to access their database (using HTTP Auth over SSL). I've been having a hell of a time figuring this out.
The best resource I have found is in the CouchDB wiki, at this link:
http://wiki.apache.org/couchdb/Security_Features_Overview#Authorization
It suggests that you can set per-database authorization by creating a document called "_security" to which you add a hash of admins and readers. When I attempt to create that document, the message I get back is "Bad special document member: _security".
$ curl -X GET http://localhost:5984
{"couchdb":"Welcome","version":"1.0.1"}
Any help would be appreciated!
Cheers,
Aaron.
There should be no problem with that aproach.
Let's say you have a database "test", and have an admin account already:
curl -X PUT http://localhost:5984/test -u "admin:123"
Now you can create a _security document for it:
curl -X PUT http://localhost:5984/test/_security -u "admin:123" -d '{"admins":{"names":[], "roles":[]}, "readers":{"names":["joe"],"roles":[]}}'
Them only the user "joe" will be able to read the database. To create the user you must have already the sha1 hashed password:
curl -X POST http://localhost:5984/_users -d '{"_id":"org.couchdb.user:joe","type":"user","name":"joe","roles":[],"password_sha":"c348c1794df04a0473a11234389e74a236833822", "salt":"1"}' -H "Content-Type: application/json"
This user have the password "123" hashed using sha1 with salt "1" (sha1("123"+"1")), so he can read the database:
curl -X GET http://localhost:5984/test -u "joe:123"
He can read any document now on that database, and no other user (but him and admin) can.
UPDATED: Writer security
The above method issues the reader problem, but the reader permission here actually mean "read/write common docs", so it allows to write docs except for design-docs. The "admin"s in the _security doc are allowed to write do design-docs in this database.
The other approach, as taken from your own answer, is the "validate_doc_update", you can have a validate_doc_update as follow in a file:
function(new_doc, old_doc, userCtx) {
if(!userCtx || userCtx.name != "joe") {
throw({forbidden: "Bad user"});
}
}
And push it into a couchdb design:
curl -X PUT http://localhost:5984/test/_design/security -d "{ \"validate_doc_update\": \"function(new_doc,doc,userCtx) { if(userCtx || userCtx.name != 'joe') {throw({forbidden: 'Bad user'})}}\"}" --user 'admin:123'
Them "joe" can write to the database using Basic Authentication:
curl -X PUT http://localhost:5984/test/foobar -d '{"foo":"bar"}' -u 'joe:123'
As you also addressed you can use the _session api to get a cookie for authentication:
curl http://localhost:5984/_session -v -X POST -d 'name=joe&password=123' -H "Content-Type: application/x-www-form-urlencodeddata"
This will return a header like:
Set-Cookie: AuthSession=am9lOjRDRDE1NzQ1Oj_xIexerFtLI6EWrBN8IWYWoDRz; Version=1; Path=/; HttpOnly
So you can include the cookie "AuthSession=am9lOjRDRDE1NzQ1Oj_xIexerFtLI6EWrBN8IWYWoDRz" in your next requests and they will be authenticated.
I've been doing more research and testing, and I want to summarize where I've gotten to, and what still isn't working for me.
First off, apologies for those who read this question: I was looking for ways to set permissions for people to write, not read, the database. It turns out be be a big difference: the techniques for creating a "reader" are entirely different from creating a "writer" (that term actually doesn't exist, though I wonder why).
In brief: you have to add a user to the _users database, which is a list of the users that have access to any database in your CouchDB instance. I was able to do that by issuing a command similar to:
curl -X PUT http://admin:password#localhost:5984/_users/org.couchdb.user:username -d '{"type":"user", "hashed_password":"2bf184a2d152aad139dc4facd7710ee848c2af27", "name":"username", "roles":[]}'
Note you need to apparently namespace the user name with the "org.couchdb.user" prefix. I used a Ruby hashing method to get the hashed_password value:
require 'digest/sha1'
pass_hash = Digest::SHA1.hexdigest(password)
This gets an apparently valid user into the database. The next step is to assign that user as a "writer" (ha, there it is again!) for the new database that I created. So I might do something like:
curl -X PUT http://admin:password#localhost:5984/newdatabase
and then
curl -X PUT http://admin:password#localhost:5984/newdatabase/_design/security -d #security.json
That .json file contains a Javascript function for the "validate_doc_update" key, and that function looks like this:
function(new_doc, old_doc, userCtx) {
if(userCtx.name != username) {
throw({forbidden: "Please log in first."});
}
}
It's roundabout, but it makes sense. However, I now am running into a problem: apparently the userCtx variable doesn't get populated until the user is authenticated. This article suggests that all you have to do is pass the credentials through an HTTP request to a special _session database, like so:
curl -X POST http://username:password#localhost:5984/_session
I can do that for my admin user, and the userCtx var will be populated. But for my newly-created user, it fails:
$ curl http://org.couchdb.user:username:password#localhost:5984/_session
{"ok":true,"userCtx":{"name":null,"roles":[]},"info":{"authentication_db":"_users","authentication_handlers":["cookie","oauth","default"]}}
Note the userCtx hash is null. I wonder if that namespace thing is causing the problem? It's got a freakin' colon in it, so maybe there's some confusion about the password? I've tried making it without the namespace, and it doesn't work at all; at least here my request appears to be hitting the database and getting a response.
I'm stuck at this point. If anyone can check my assumptions and progress thus far, I hope we can all figure out how to make this work.
Thanks!
Aaron.
You may want to check out Matt Woodward's - The Definitive Guide to CouchDB Authentication and Security http://blog.mattwoodward.com/2012/03/definitive-guide-to-couchdb.html

Resources