GithubHelp home page GithubHelp logo

Comments (24)

alfinkel avatar alfinkel commented on August 26, 2024 1

The call needs to be with cloudant not with Cloudant. cloudant is the name of the context manager defined in the init.py. Cloudant is the name of the Cloudant client in the account module. See https://github.com/cloudant/python-cloudant/blob/master/src/cloudant/__init__.py#L24 and http://python-cloudant.readthedocs.org/en/latest/cloudant.html#cloudant.cloudant

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

Are you looking for share_database, unshare_database?

from python-cloudant.

bradwbonn avatar bradwbonn commented on August 26, 2024

No, that's sharing databases with another Cloudant user. The idea is to create an API key using generate_api_key() and then assign permissions to a specific database, or give the API key permission to create a new database itself. Particularly helpful for temporal, per-user, or per-device database use cases.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

I may be misunderstanding what you are looking for but you can use share_database from the database module (It uses the /_api/v2/db/$DB/_security endpoint) and pass it the API Key as the username and then set permissions for reader, writer, admin and this would grant permissions to a specific database for that API key. As for giving permission to create databases, what endpoint would that be?

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

Also a little confused on your first question re: the base64 auth token. Are you looking to do basic authentication or are you looking to base64.urlsafe_b64encode your passcode and authenticate using the encoded value? Can you provide a curl statement that gives an example of what you mean here? That might help me uderstand a bit better.

from python-cloudant.

bradwbonn avatar bradwbonn commented on August 26, 2024

Basically, there are two things I'm trying to here, yes, so I'll separate them out and describe with examples.
Number one is to increase the security profile for a script which is meant to run via cron and utilize Cloudant as its database. Having it run as a script without a security gateway means that (like any local program that utilizes a cloud resource) it will have to store its authentication data somewhere. I'd prefer to store the configuration file using hashed credentials so they can't be human-read.

An example using curl would be: curl -s --proto '=https' -g -H 'Authorization: Basic <BASE64HASHOFUSERPASSWORDCREDS>'�
This is easy to do with the python requests library with code such as:

import requests
response = requests.get(
    url="https://bradwbonn.cloudant.com/_all_dbs",
    headers = {"Content-Type": "application/json", "Authorization": "Basic <BASE64HASHOFUSERPASSWORDCREDS>"}
)
print r.json()

Number two is to use API keys as the stored credentials instead of a Cloudant username, but now I'm thinking this may be moot. I'm planning to use a rolling database model, which means whatever stored credentials are used will need to be able to create and delete databases, and I'm fairly certain API keys only exist on a per-database basis. It's good to know that share_database() can interact with the _security endpoint though.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

Thanks for the clarification. Currently we are set up for cookie authentication only when using the connect(...) method on a client. But fortunately with Python there is usually a workaround. For this case the work around to use Basic authentication you basically would need to "roll your own" connection routine as in the following:

from cloudant import Cloudant
import requests

# Construct a client object but don't provide it with your password.
# However, the password (auth_token) argument must be set to something.
client = Cloudant('bradwbonn', 'not-giving-you-my-password', account='bradwbonn')
# Roll your own connect() routine...
client.r_session = requests.Session()
client.r_session.headers.update({'Authorization': 'Basic <BASE64HASHOFUSERPASSWORDCREDS>'})
client._cloudant_session = client.session()
# Done ...

Unfortunately, you cannot use the Cloudant with context manager using this work around as in your original example. Also, if you were using the url kwarg along with the x_cloudant_user kwarg you would need to account for an additional User-Agent header but you get the gist...

I hope that works out for you.

I'll open a new "Enhancement" Issue for adding Basic authentication and reference this one.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

For added context: take a look at client.connect() to see what exactly you would be overriding. Hopefully seeing that would add a bit more context around the proposed the work around.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

Now that I've had more time to think about it, there's no reason why you could not create your own context manager to replicate what the cloudant context manager does and then you could do all this via with as well. ref: https://github.com/cloudant/python-cloudant/blob/master/src/cloudant/__init__.py#L59

I hope some of this helps you along... I'll stop beating this horse now. :)

from python-cloudant.

bradwbonn avatar bradwbonn commented on August 26, 2024

This is really helpful, thank you! I've actually never extended a library in Python before, so this will end up being yet another learning experience for me. ;)

from python-cloudant.

bradwbonn avatar bradwbonn commented on August 26, 2024

In your example above: client._cloudant_session = c.session() I'm not sure I understand what the c refers to. Is it supposed to be client.session()?

from python-cloudant.

vinomaster avatar vinomaster commented on August 26, 2024

not much luck using

from cloudant import Cloudant
import requests

# Construct a client object but don't provide it with your password.
# However, the password (auth_token) argument must be set to something.
client = Cloudant(USERNAME, PASSWORD, account=USERNAME)

Error using Python 3 notebook is after a !pip install --pre cloudant


NameError Traceback (most recent call last)
in ()
----> 1 from cloudant import Cloudant
2 import requests
3
4 # Construct a client object but don't provide it with your password.
5 # However, the password (auth_token) argument must be set to something.

/opt/conda/lib/python3.4/site-packages/cloudant/init.py in ()
20 import contextlib
21
---> 22 from .account import Cloudant, CouchDB
23
24 @contextlib.contextmanager

/opt/conda/lib/python3.4/site-packages/cloudant/account.py in ()
23 import sys
24
---> 25 from .database import CloudantDatabase, CouchDatabase
26 from .changes import Feed
27 from .errors import CloudantException

/opt/conda/lib/python3.4/site-packages/cloudant/database.py in ()
23
24 from .document import Document
---> 25 from .design_document import DesignDocument
26 from .views import View
27 from .errors import CloudantException

/opt/conda/lib/python3.4/site-packages/cloudant/design_document.py in ()
17 """
18 from .document import Document
---> 19 from .views import View
20 from .errors import CloudantArgumentError
21

/opt/conda/lib/python3.4/site-packages/cloudant/views.py in ()
19 import posixpath
20
---> 21 from .result import Result, python_to_couch
22
23 class Code(str):

/opt/conda/lib/python3.4/site-packages/cloudant/result.py in ()
24 ARG_TYPES = {
25 "descending": bool,
---> 26 "endkey": (basestring, Sequence),
27 "endkey_docid": basestring,
28 "group": bool,

NameError: name 'basestring' is not defined

from python-cloudant.

vinomaster avatar vinomaster commented on August 26, 2024

Ideally, I would like to avoid UID/PW credentials and leverage this type of approach for Cloudant:

import couchdb
couch = couchdb.Server("https://%s.cloudant.com" % USERNAME)
couch.resource.credentials = (USERNAME, auth=(API_KEY, API_SECRET))

Any plans for enabling this approach?

from python-cloudant.

mikerhodes avatar mikerhodes commented on August 26, 2024

There appear to be a few questions and misconceptions here around API keys and security.

base64

Firstly, @bradwbonn remember base64 doesn't make any difference to security. I suggest storing the plain credentials, because it's easier for others and your future self to understand what the security properties of the script are (if the server's insecure, you've bigger issues anyway :) )

I think this negates the need for accessing the authorization header in your case; but clearly it could be useful for other scenarios, such as authenticating against a proxy server rather than Cloudant itself. I think our workaround works for now, but I do quite like @vinomaster's suggestion -- though it appears requests-specific (though I can't imagine changing!).

Setting permissions

To set the security on a database from an API key and password, you'll need to set up the _security document. However, looks like you can't do that yet from issue #52.

Using API keys with python-cloudant

@vinomaster I think your question is around using API keys; let me know if I misunderstood, there's a bunch of issues here :)

To use an API key and password, it's important to note that they are just username and password pairs, so you use them as follows (feel free to try it as-is, the key is a valid read key for that db at least for the next few days):

USERNAME = "bouninamendouldnimendepa"
PASSWORD = "e6fda548ce40d21ae675d03068bb0f913f2d99f1"
ACCOUNT_NAME = "mikerhodes"
DATABASE_NAME = "animaldb"
DOC_NAME = "badger"

from cloudant.account import Cloudant

client = Cloudant(USERNAME, PASSWORD, account=ACCOUNT_NAME)

# Connect to the account and establish a session cookie
client.connect()
session = client.session()

database = client[DATABASE_NAME]

document = database[DOC_NAME]
print "Got document: ", document

client.disconnect()

As @bradwbonn said, this appears to not be working with the context manager, that is, this fails:

# With context manager
with Cloudant(USERNAME, PASSWORD, account=ACCOUNT_NAME) as client:
    session = client.session()
    database = client[DATABASE_NAME]
    document = database[DOC_NAME]
    print "Got document from context manager: ", document

I filed this as issue #53.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

@bradwbonn, I'm not sure where we are at with this conversation. Apparently a lot has happened while I was sleeping. I'll be sure never to sleep again :). But yes you found a typo in #49 (comment). The line in question should read client._cloudant_session = client.session(). I apologize for that, in my testing I was using c as the client but wanted to make it more readible in my comments to you so I changed it to client. Unfortunately I did not change it everywhere.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

@vinomaster, this library is not yet supported in Python3. See http://python-cloudant.readthedocs.org/en/latest/compatibility.html. The problem you are seeing is because of the use of basestring which was removed in Python3. We have plans to make the library Python3 compatible in the near future. See #23.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

Below is a summary of "where we are" with this issue, since it seems that we have diverged in a few directions.

@bradwbonn, setting permissions can be done for users as well as API keys by using the database module's share_database and unshare_database methods. On the topic of using Basic authentication with this library, you can still follow the work around that I presented but I think I was negligent before in not stating that extending the library is done at your risk. On a somewhat related note, relating to the work around that I presented: I am sure that you are aware that the _ prefix in Python denotes a "private" variable so it is not best practice to access these variables. However in Python you can pretty much do what you want so there are no mechanisms in place to keep you from doing so. I guess the point that I am trying to make here is keep letting us know about gaps in functionality. This will help us bridge those gaps but any work around should be treated as an exception rather than normal practice.

@vinomaster, the problem you are experiencing is simple. This library has not yet been scrubbed to be used with Python3. Unfortunately, I'm not sure that will help you much. Sorry for that.

@mikerhodes, on the topic of the main context manager, I believe the problem you encountered was simply a spelling mistake. Cloudant should have been cloudant. So I am pretty sure we can close #53. As far as the _security document goes, database level security is currently managed via the share_database and unshare_database methods found in the database module as I mentioned earlier. So we have means to update the security document. We can use #52 to add functionality that will allow us to manipulate the _security document directly since it seems as though this is a requirement now.

A lot of this along with other good stuff can be found in our docs.

from python-cloudant.

bradwbonn avatar bradwbonn commented on August 26, 2024

This whole conversation has been super-insightful, thank you!

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

@bradwbonn: I have an update on the whole setting of permissions question. See #52 (comment)

from python-cloudant.

vinomaster avatar vinomaster commented on August 26, 2024

So to summarize:

  1. The python-cloudant is not yet supported on Python 3. This should be in-your-face on the readme.
  2. We are using Cloudant on Bluemix which does support API Keys. I seek only an simple pythonic way to authenticate to a db using an API key. Based on this thread, it seems this functionality is available but it is not intuitive that APIKey and USERNAME can be interchanged. Maybe two simple constructors would be more intuitive: UID/PW credentials, APIKey/Passcode credentials.

Remaining questions:

  1. When will Python3 support be available?

from python-cloudant.

vinomaster avatar vinomaster commented on August 26, 2024

So after further testing... using Python 2 under Project Jupyter we are unable to pip install Cloudant.

!pip install --pre cloudant
Collecting cloudant
  Retrying (Retry(total=4, connect=None, read=None, redirect=None)) after connection broken by 'ProtocolError('Connection aborted.', gaierror(-2, 'Name or service not known'))': /simple/cloudant/

To be clear this Python 2 kernel functionality is provided via conda

!python --version
Python 3.4.3 :: Continuum Analytics, Inc.

To test try here.

At this juncture, until Python3 support it seems Project Jupyter integration with Cloudant is a non-starter.

from python-cloudant.

mikerhodes avatar mikerhodes commented on August 26, 2024

@vinomaster Could you file a separate bug for Project Jupyter support? This bug is overloaded.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

@vinomaster, I've moved your issue with the pip install on Project Jupyter to #54.

from python-cloudant.

alfinkel avatar alfinkel commented on August 26, 2024

I think that all issues here have been either answered or moved off to their own separate issue.

from python-cloudant.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.