Last active
April 26, 2024 05:02
-
-
Save vitalyisaev2/215f890e75252cd36794221c2debf365 to your computer and use it in GitHub Desktop.
Script for obtaining Gitlab API Personal Access Token
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
""" | |
Script that creates Personal Access Token for Gitlab API; | |
Tested with: | |
- Gitlab Community Edition 10.1.4 | |
- Gitlab Enterprise Edition 12.6.2 | |
- Gitlab Enterprise Edition 13.4.4 | |
""" | |
import sys | |
import requests | |
from urllib.parse import urljoin | |
from bs4 import BeautifulSoup | |
endpoint = "http://localhost:10080" | |
root_route = urljoin(endpoint, "/") | |
sign_in_route = urljoin(endpoint, "/users/sign_in") | |
pat_route = urljoin(endpoint, "/profile/personal_access_tokens") | |
login = "root" | |
password = "password" | |
def find_csrf_token(text): | |
soup = BeautifulSoup(text, "lxml") | |
token = soup.find(attrs={"name": "csrf-token"}) | |
param = soup.find(attrs={"name": "csrf-param"}) | |
data = {param.get("content"): token.get("content")} | |
return data | |
def obtain_csrf_token(): | |
r = requests.get(root_route) | |
token = find_csrf_token(r.text) | |
return token, r.cookies | |
def sign_in(csrf, cookies): | |
data = { | |
"user[login]": login, | |
"user[password]": password, | |
"user[remember_me]": 0, | |
"utf8": "✓" | |
} | |
data.update(csrf) | |
r = requests.post(sign_in_route, data=data, cookies=cookies) | |
token = find_csrf_token(r.text) | |
return token, r.history[0].cookies | |
def obtain_personal_access_token(name, expires_at, csrf, cookies): | |
data = { | |
"personal_access_token[expires_at]": expires_at, | |
"personal_access_token[name]": name, | |
"personal_access_token[scopes][]": "api", | |
"utf8": "✓" | |
} | |
data.update(csrf) | |
r = requests.post(pat_route, data=data, cookies=cookies) | |
soup = BeautifulSoup(r.text, "lxml") | |
token = soup.find('input', id='created-personal-access-token').get('value') | |
return token | |
def main(): | |
csrf1, cookies1 = obtain_csrf_token() | |
print("root", csrf1, cookies1) | |
csrf2, cookies2 = sign_in(csrf1, cookies1) | |
print("sign_in", csrf2, cookies2) | |
name = sys.argv[1] | |
expires_at = sys.argv[2] | |
token = obtain_personal_access_token(name, expires_at, csrf2, cookies2) | |
print(token) | |
if __name__ == "__main__": | |
main() |
I experienced the same issue. I extended this script with an authenticity_token and a change in the url.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Import Modules
import os
import sys
import requests
import argparse
from urllib.parse import urljoin
from bs4 import BeautifulSoup
# Variables
endpoint = os.environ['GITLAB_URL']
if 'ssh://' in endpoint:
endpoint = "http://" + endpoint.split("@")[1]
login = os.environ['GITLAB_ADMIN_USER']
password = os.environ['GITLAB_ADMIN_PASSWD']
scopes = {'personal_access_token[scopes][]': [
'api', 'sudo', 'read_user', 'read_repository']}
root_route = urljoin(endpoint, "/")
sign_in_route = urljoin(endpoint, "/users/sign_in")
pat_route = urljoin(endpoint, "/-/profile/personal_access_tokens")
# Methods
def find_csrf_token(text):
soup = BeautifulSoup(text, "lxml")
token = soup.find(attrs={"name": "csrf-token"})
param = soup.find(attrs={"name": "csrf-param"})
data = {param.get("content"): token.get("content")}
return data
def obtain_csrf_token():
r = requests.get(root_route)
token = find_csrf_token(r.text)
return token, r.cookies
def obtain_authenticity_token(cookies):
r = requests.get(pat_route, cookies=cookies)
soup = BeautifulSoup(r.text, "lxml")
token = soup.find('input', attrs={'name':'authenticity_token', 'type':'hidden'}).get('value')
return token
def sign_in(csrf, cookies):
data = {
"user[login]": login,
"user[password]": password,
"user[remember_me]": 0,
"utf8": "✓"
}
data.update(csrf)
r = requests.post(sign_in_route, data=data, cookies=cookies)
token = find_csrf_token(r.text)
return token, r.history[0].cookies
def obtain_personal_access_token(name, expires_at, csrf, cookies, authenticity_token):
data = {
"personal_access_token[expires_at]": expires_at,
"personal_access_token[name]": name,
"authenticity_token": authenticity_token,
"utf8": "✓"
}
data.update(scopes)
data.update(csrf)
r = requests.post(pat_route, data=data, cookies=cookies)
soup = BeautifulSoup(r.text, "lxml")
token = soup.find('input', id='created-personal-access-token').get('value')
return token
def main():
csrf1, cookies1 = obtain_csrf_token()
csrf2, cookies2 = sign_in(csrf1, cookies1)
name = sys.argv[1]
expires_at = sys.argv[2]
authenticity_token = obtain_authenticity_token(cookies2)
token = obtain_personal_access_token(name, expires_at, csrf2, cookies2, authenticity_token)
print(token)
if __name__ == "__main__":
main()
I still have the same error, @MiVents
data = {param.get("content"): token.get("content")} AttributeError: 'NoneType object has no attribute' get'
Hi guys, thank you for discussion. I see that the problem is still relevant in more recent versions of Gitlab, so I decided to create a full-fledged repository to give developers opportunity to contribute and maintain newer versions of this script. I think that we need to develop a little library that will provide simple API to obtain tokens.
https://github.com/vitalyisaev2/gitlab_token
If anybody wants to be a maintainer, please drop me a line.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello,
I just tested the code with Python 3.8.3 and 3.9.1, GitLab Enterprise Edition version 12.7.5, and it doesn't not work for me. I get an AttributeError:
data = {param.get("content"): token.get("content")} AttributeError: 'NoneType' object has no attribute 'get'
Do you have an idea of where it comes from?
Thank you much for your excellent work.
Good day to you.