Skip to content

Credential-based login is broken after removal of /session endpoint #380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
GhostLyrics opened this issue Nov 24, 2017 · 14 comments
Closed
Labels

Comments

@GhostLyrics
Copy link
Contributor

GhostLyrics commented Nov 24, 2017

Remove Session API now that private tokens are removed from user API endpoints.

/api/v4/session has been removed and it is currently not possible to log in via email/password combination. [Deprecation notice, Changelog]

I use this to completely automate testing (e.g. create a GitLab instance, set a password for root, run some tests, tear everything down).

wget http://gitlab/api/v4/session
--2017-11-23 23:06:57--  http://gitlab/api/v4/session
Resolving gitlab (gitlab)... 192.168.34.151, 192.168.34.151
Connecting to gitlab (gitlab)|192.168.34.151|:80... connected.
HTTP request sent, awaiting response... 404 Not Found
2017-11-23 23:06:57 ERROR 404: Not Found.
import gitlab
s = gitlab.Gitlab('http://localhost',email='root',password='some_test_password',api_version=4)
s.auth()

Traceback (most recent call last):
  File "<input>", line 1, in <module>
    s.auth()
  File "/Users/ghostlyrics/.pyenv/versions/3.5.3/lib/python3.5/site-packages/gitlab/__init__
.py", line 197, in auth
    self._credentials_auth()
  File "/Users/ghostlyrics/.pyenv/versions/3.5.3/lib/python3.5/site-packages/gitlab/__init__
.py", line 216, in _credentials_auth
    r = self.http_post('/session', data)
  File "/Users/ghostlyrics/.pyenv/versions/3.5.3/lib/python3.5/site-packages/gitlab/__init__
.py", line 806, in http_post
    post_data=post_data, files=files, **kwargs)
  File "/Users/ghostlyrics/.pyenv/versions/3.5.3/lib/python3.5/site-packages/gitlab/__init__
.py", line 713, in http_request
    response_body=result.content)
gitlab.exceptions.GitlabHttpError: 404: b'{"error":"404 Not Found"}'

self = <gitlab.Gitlab object at 0x7f28dfd66da0>, verb = 'post', path = '/session', query_data = {'email': 'root', 'password': 'some_test_password'}, post_data = {}, streamed = False
files = None, kwargs = {}, sanitized_url = <function Gitlab.http_request.<locals>.sanitized_url at 0x7f28e17879d8>, url = 'http://localhost/api/v4/session'
params = {'email': 'root', 'password': 'some_test_password'}, opts = {'auth': None, 'headers': {'Content-type': 'application/json'}}, verify = True, timeout = None, req = <Request [post]>

    def http_request(self, verb, path, query_data={}, post_data={},
                     streamed=False, files=None, **kwargs):
        """Make an HTTP request to the Gitlab server.

            Args:
                verb (str): The HTTP method to call ('get', 'post', 'put',
                            'delete')
                path (str): Path or full URL to query ('/projects' or
                            'http://whatever/v4/api/projecs')
                query_data (dict): Data to send as query parameters
                post_data (dict): Data to send in the body (will be converted to
                                  json)
                streamed (bool): Whether the data should be streamed
                **kwargs: Extra data to make the query (e.g. sudo, per_page, page)

            Returns:
                A requests result object.

            Raises:
                GitlabHttpError: When the return code is not 2xx
            """

        def sanitized_url(url):
            parsed = six.moves.urllib.parse.urlparse(url)
            new_path = parsed.path.replace('.', '%2E')
            return parsed._replace(path=new_path).geturl()

        url = self._build_url(path)
        params = query_data.copy()
        params.update(kwargs)
        opts = self._get_session_opts(content_type='application/json')

        # don't set the content-type header when uploading files
        if files is not None:
            del opts["headers"]["Content-type"]

        verify = opts.pop('verify')
        timeout = opts.pop('timeout')

        # Requests assumes that `.` should not be encoded as %2E and will make
        # changes to urls using this encoding. Using a prepped request we can
        # get the desired behavior.
        # The Requests behavior is right but it seems that web servers don't
        # always agree with this decision (this is the case with a default
        # gitlab installation)
        req = requests.Request(verb, url, json=post_data, params=params,
                               files=files, **opts)
        prepped = self.session.prepare_request(req)
        prepped.url = sanitized_url(prepped.url)
        result = self.session.send(prepped, stream=streamed, verify=verify,
                                   timeout=timeout)

        if 200 <= result.status_code < 300:
            return result

        try:
            error_message = result.json()['message']
        except (KeyError, ValueError, TypeError):
            error_message = result.content

        if result.status_code == 401:
            raise GitlabAuthenticationError(response_code=result.status_code,
                                            error_message=error_message,
                                            response_body=result.content)

        raise GitlabHttpError(response_code=result.status_code,
                              error_message=error_message,
>                             response_body=result.content)
E       gitlab.exceptions.GitlabHttpError: 404: b'{"error":"404 Not Found"}'
@sslaven3
Copy link

I'm experiencing this as well. Our GitLab CE was just updated to 10.2.1 this last weekend and now gl.auth throws a 404. I'm using the latest version of python-gitlab.

@gpocentek
Copy link
Contributor

Without the /session endpoint python-gitlab cannot do password authentication.

One possible solution is to use cookie authentication:

  1. use python-requests to authenticate on the web UI (POST on /users/sign_in)
  2. get the cookie from the answer
  3. create a requests.Session object and setup the cookies
  4. use the session object to create a Gitlab connexion
  5. create/get a token from the API
  6. create a new gitlab object with token authentication

I have not tested this solution but according to Gitlab docs cookie authentication is supposed to work.

@ViachaslauKabak
Copy link

Experiencing this too as soon as upgraded to 10.2

@melissaulaval
Copy link

I am experiencing the same problem even I didn't upgrade gitlab. It seems the commands:

s = gitlab.Gitlab('https://gitlab.com',email='my_username',password='my_password')
s.auth()

not working.

Thank you for the response!

@ahsobhi
Copy link

ahsobhi commented Dec 12, 2017

im experiencing the same issue with our updated Gitlab instance to 10.2

@gpocentek
Copy link
Contributor

GitLab has decided to remove the /session endpoint so there is nothing much I can do.

I've successfully used cookie authentication on gitlab.com with the following code: https://gist.github.com/gpocentek/bd4c3fbf8a6ce226ebddc4aad6b46c0a

I'll add some documentation to python-gitlab.

@ViachaslauKabak
Copy link

@gpocentek , do you mean that there will be only token authentication since GL10.2?

@ViachaslauKabak
Copy link

found in GL changelog 10.2
Remove Session API now that private tokens are removed from user API endpoints.

@GhostLyrics
Copy link
Contributor Author

@gpocentek Do you plan on integrating this workaround into python-gitlab?

@gpocentek
Copy link
Contributor

@GhostLyrics I'm afraid not, because there are multiple ways to authenticate using the web UI (LDAP and DB authentication use different endpoints for instance), and I'm not really sure that things will not change and break.

GitLab devs clearly want to make personal token authentication the default. This makes full automation more complicated (functional testing for python-gitlab needs to be updated as well), but it also makes sense.

My plan to resolve this issue is to update the documentation with code examples, to make initial setup of tokens easier.

@gpocentek gpocentek added the docs label Dec 13, 2017
@ahsobhi
Copy link

ahsobhi commented Dec 13, 2017

@gpocentek Thank you for your efforts and the code sample, it works like a charm, now i do agree with you that things might change and break, GitLab undergoes major changes every few months, adding new features and functionality, we've been using it since it was v4 and it has come a long long way

@sslaven3
Copy link

@gpocentek - Thanks for the update Gauvain. I see now that it's just a change in GitLab's code, and nothing you can do about it. The module is great though, and I appreciate your work. I've converted to using a private token, which I programmatically pull from a password management system using my credentials. For others, if you don't have a secure password system, you can use a token of an account with less privileges on your GitLab projects, and generate a token for that account to pull code. It's not perfect, but it's an option.

@slonopotamus
Copy link

Hi! We've also hit this problem in git-as-svn/git-as-svn#154. Did anyone try to file a bugreport to GitLab so they would consider returning back password-based authentication API? I'm also interested in GitLab ticket that triggered removal of /session API.

@slonopotamus
Copy link

slonopotamus commented Dec 19, 2017

Okay, it is possible to perform login/password -> token authentication even with GitLab 10.2: https://docs.gitlab.com/ce/api/oauth2.html#resource-owner-password-credentials

That's how it was done in git-as-svn (Java): slonopotamus/git-as-svn@8a4d067

So I think you should reopen this issue and reimplement login/password authentication via OAuth2 too.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

7 participants