diff --git a/getmystuph/epfl/__init__.py b/getmystuph/epfl/__init__.py new file mode 100644 index 0000000..19f48e3 --- /dev/null +++ b/getmystuph/epfl/__init__.py @@ -0,0 +1,5 @@ +# keep this file +__all__ = [] + +from . import git_repo +from . import directory diff --git a/getmystuph/epfl/directory.py b/getmystuph/epfl/directory.py new file mode 100644 index 0000000..bbfac79 --- /dev/null +++ b/getmystuph/epfl/directory.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +from .. import export +from .. import LDAPDirectory +import ldap3 + +__author__ = "Nicolas Richart" +__copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ + "de Lausanne) - SCITAS (Scientific IT and Application " \ + "Support)" +__credits__ = ["Nicolas Richart"] +__license__ = "BSD" +__version__ = "0.1" +__maintainer__ = "Nicolas Richart" +__email__ = "nicolas.richart@epfl.ch" + + +@export +class Directory(LDAPDirectory): + + def __init__(self): + args = { + 'basedn': 'o=epfl,c=ch', + 'scope': ldap3.SUBTREE, + 'uidNumber': 'uniqueIdentifier', + 'gecos': 'gecos', + 'uid': 'uid', + 'user_filter': '(&(objectClass=posixAccount)({attr}={value}))', + 'user_group_attrs': 'memberOf', + 'gidNumber': 'uniqueIdentifier', + 'gid': 'cn', + 'group_filter': '(&(objectClass=groupOfNames)({attr}={value}))', + 'group_member_filter': 'uniqueIdentifier', + 'group_user_attrs': 'memberUniqueId', + } + + super(Directory, self).__init__('ldaps://scoldap.epfl.ch', **args) diff --git a/getmystuph/epfl/git_repo.py b/getmystuph/epfl/git_repo.py new file mode 100644 index 0000000..f077244 --- /dev/null +++ b/getmystuph/epfl/git_repo.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +from .. import export +from ..repo import Repo +from .tequila import TequilaGet +from bs4 import BeautifulSoup +import copy +import re + +__author__ = "Nicolas Richart" +__copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ + "de Lausanne) - SCITAS (Scientific IT and Application " \ + "Support)" +__credits__ = ["Nicolas Richart"] +__license__ = "BSD" +__version__ = "0.1" +__maintainer__ = "Nicolas Richart" +__email__ = "nicolas.richart@epfl.ch" + + +@export +class GitRepo(Repo): + ''' + Description of a repostitory on git.epfl.ch + ''' + + __ROOT_URL = 'https://git.epfl.ch/polyrepo/private' + __LIST_REPOS = '{root}/repository/my.go' + __MANAGE_REPO = '{root}/repository/manage.go?id={id}' + __PERMISSION = '{root}/objectRole/list.go?objectId={id}' + __REPO_REGEX = '/polyrepo/private/repository/manage\.go\?id=([0-9]+)' + + def __init__(self, repo_name, repo_id=None, tequila_ctx=None, + *args, **kwargs): + super(GitRepo, self).__init__(repo_name, *args, **kwargs) + + option = copy.copy(kwargs) + _password = option.pop('password', None) + + if tequila_ctx is None: + self._tequila = TequilaGet( + self.__LIST_REPOS.format(root=self.__ROOT_URL), + username=self._username, + password=_password) + else: + self._tequila = tequila_ctx + + if repo_id is None: + (repo, info) = self.list_repositories(tequila_ctx=self._tequila) + if repo_name in repo: + self._id = info[repo_name]['id'] + else: + raise RuntimeError('The repo {0} was not found in your list\ + of repositories'.format(repo_name)) + else: + self._id = repo_id + + def get_permissions(self): + '''Get the group and user permissions on the repository''' + _html_resp = self._tequila.get( + self.__PERMISSION.format(root=self.__ROOT_URL, + id=self._id)) + _html_soup = BeautifulSoup(_html_resp.text, 'html.parser') + + _group_regex = re.compile('([US][0-9]+)') + _list_soup = _html_soup.find( + 'form', {'name': 'lister'}).find_all('td', + {'align': 'right'}) + for _td in _list_soup: + _ug_id = _td.text + _is_group = _group_regex.match(_ug_id) + if _is_group: + print('group: {0}'.format(_ug_id)) + else: + print('user: {0}'.format(_ug_id)) + + @classmethod + def list_repositories(cls, username=None, password=None, tequila_ctx=None): + _repos = [] + _extra_info = {} + + if tequila_ctx is None: + _tequila = TequilaGet( + cls.__LIST_REPOS.format(root=cls.__ROOT_URL), + username=username, + password=password) + else: + _tequila = tequila_ctx + + _html_resp = _tequila.get( + cls.__LIST_REPOS.format(root=cls.__ROOT_URL) + ) + + _html_soup = BeautifulSoup(_html_resp.text, 'html.parser') + _list_soup = _html_soup.find('tbody') + + _id_regex = re.compile(cls.__REPO_REGEX) + for _link in _list_soup.find_all('a'): + _repo = _link.get_text() + _repos.append(_repo) + + _repo_link = _link.get('href') + _match = _id_regex.match(_repo_link) + if _match: + _id = _match.group(1) + _extra_info[_repo] = {'id': _id} + + return (_repos, _extra_info) diff --git a/getmystuph/epfl/tequila.py b/getmystuph/epfl/tequila.py new file mode 100644 index 0000000..52935e7 --- /dev/null +++ b/getmystuph/epfl/tequila.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +''' + This code is adapted from the conde of Antoine Albertelli, found here: + https://github.com/antoinealb/python-tequila +''' + +import getpass +import requests +from bs4 import BeautifulSoup +try: + import urlparse +except ImportError: + import urllib.parse as urlparse + +__author__ = "Nicolas Richart" +__copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ + "de Lausanne) - SCITAS (Scientific IT and Application " \ + "Support) \n\n" \ + "Copyright (c) 2013, Antoine Albertelli" +__credits__ = ["Antoine Albertelli", "Nicolas Richart"] +__license__ = "BSD" +__version__ = "0.1" +__maintainer__ = "Nicolas Richart" +__email__ = "nicolas.richart@epfl.ch" + + +class TequilaGet(object): + """Get url that needs tequila authentiication""" + TEQUILA_LOGIN_POST = "https://tequila.epfl.ch/cgi-bin/tequila/login" + __session = None + + class TequilaError(RuntimeError): + """ + Exception thrown in case of Tequila error. + """ + pass + + def __init__(self, url, username, password=None): + """ + Explicitly login into the tequila service, this will create + a new tequila session. + :raise TequilaError: + """ + self.__session = requests.session() + + resp = self.__session.get(url) + if resp.status_code != 200: + raise TequilaGet.TequilaError('Cannot access {0}'.format(url)) + + parsed_url = urlparse.urlsplit(resp.url) + dict_query = urlparse.parse_qs(parsed_url.query) + sesskey = dict_query['requestkey'][0] + + if password is None: + password = getpass.getpass( + 'Tequilla password of user {0}: '.format(username)) + + payload = dict() + payload["requestkey"] = sesskey + payload["username"] = username + payload["password"] = password + + resp = self.__session.post(self.TEQUILA_LOGIN_POST, + verify=True, data=payload) + if resp.status_code != 200: + raise TequilaGet.TequilaError("Tequila didn't return a 200 code") + + soup = BeautifulSoup(resp.text, 'html.parser') + error = soup.find('font', color='red', size='+1') + if error: + # Grab the tequila error if any + raise TequilaGet.TequilaError(error.string) + + def get(self, url): + """Get an url in a authenticated session""" + resp = self.__session.get(url) + if resp.status_code != 200: + raise TequilaGet.TequilaError() + return resp