0

I want to use the Bitbucket API to get information of a private repository.

It works fine with curl:

curl -u username:apppassword https://api.bitbucket.org/2.0/repositories/company/repo

But not with Python (Unfortunately I have to use Python 3.4):

    #!/usr/bin/env python3

    from pybitbucket.auth import BasicAuthenticator
    from pybitbucket.bitbucket import Client
    from pybitbucket.repository import Repository
    from pybitbucket.user import User

    client = Client(BasicAuthenticator('username', 'apppassword ', 'usermail'))
    print(User.find_current_user(client).display_name)
    print(Repository.find_repository_by_full_name("company/repo"))

User name is printed correctly. But Repository.find_repository_by_full_name raises a 403 (forbidden).

Same thing, when I try to do it with urllib:

    import urllib.request

    base_url = 'https://api.bitbucket.org/2.0/'
    password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
    password_mgr.add_password(None, base_url, 'username', 'apppassword ')
    handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
    opener = urllib.request.build_opener(handler)

    with opener.open(base_url + 'user') as f:
        print(f.read())

    with opener.open(base_url + 'repositories/company/repo') as f:
        print(f.read())

Authentication must work, otherwise it could not return my user name correctly. Also, when I enter wrong credentials, I get a 401 (unauthorized) instead of a 403 (forbidden). On the other hand, it works perfectly fine when I use curl.

Oh, it doesn't work with wget either:

wget --http-user=username --http-passwd=apppassword https://api.bitbucket.org/2.0/repositories/company/repository

What is curl doing different than wget and Python?

Thomas Klier
  • 449
  • 4
  • 16

1 Answers1

0

The Bitbucket API doesn't answer with 401 Unauthorized when I call https://api.bitbucket.org/2.0/repositories/company/repository. This can easily tested with a browser. It doesn't ask for credentials but shows Access denied. You must have write or admin access. So no authentication will take place.

But when I open https://api.bitbucket.org/2.0/user, Bitbucket responses with 401 Unauthorized and the header www-authenticate: Basic realm="Bitbucket.org HTTP", so the browser knows to show the authentication dialog. That's why getting the user data works on Python.

To solve this, I have to enforce to send the authentication even when the server doesn't ask for it. I haven't found a way to do this with a urllib.request.HTTPBasicAuthHandler but by adding the Authorization header manually:

    import base64
    import urllib.request

    request = urllib.request.Request('https://api.bitbucket.org/2.0/repositories/company/repository')
    base64string = base64.b64encode('{}:{}'.format('username', 'apppassword').encode('ascii'))
    request.add_header('Authorization', 'Basic {}'.format(base64string.decode('ascii')))

    with urllib.request.urlopen(request) as response:
        print(response.read())
Thomas Klier
  • 449
  • 4
  • 16