Example #1
0
    def login(self):
        """Initializes an authentication, provided we have the credentials for
        it.

        :returns: The session. This is useful for jQuery-like command
            chaining::

                s = webuntis.Session(...).login()

        :raises: :py:class:`webuntis.errors.BadCredentialsError` --
            Username/Password missing or invalid.
        :raises: :py:class:`webuntis.errors.AuthError` -- Didn't recieve a
            session ID for unknown reasons.
        """

        try:
            username = self.config["username"]
            password = self.config["password"]
            useragent = self.config["useragent"]
        except KeyError as e:
            raise errors.BadCredentialsError("Missing config: " + str(e))

        res = self._request(
            "authenticate", {"user": username, "password": password, "client": useragent}, use_login_repeat=False
        )

        if "sessionId" in res:
            sid = self.config["jsessionid"] = res["sessionId"]
            log("debug", "Did get a jsessionid from the server: " + sid)
        else:
            raise errors.AuthError("Something went wrong while authenticating", res)

        return self
Example #2
0
    def _request(self, method, params=None, use_login_repeat=None):
        if not isinstance(method, unicode_string):
            method = method.decode('ascii')

        if use_login_repeat is None:
            use_login_repeat = (method not in ('logout', 'authenticate'))
        attempts_left = self.config['login_repeat'] if use_login_repeat else 0

        data = None

        while data is None:
            try:
                data = rpc_request(self.config, method, params or {})
            except errors.NotLoggedInError:
                if attempts_left > 0:
                    self.logout(suppress_errors=True)
                    self.login()
                else:
                    raise errors.NotLoggedInError(
                        'Tried to login several times, failed. Original method'
                        ' was ' + method)
            else:
                log('debug', "RETURN:" + str(data))
                return data

            attempts_left -= 1  # new round!
Example #3
0
    def _request(self, method, params=None, use_login_repeat=None):
        if not isinstance(method, unicode_string):
            method = method.decode("ascii")

        if use_login_repeat is None:
            use_login_repeat = method not in ("logout", "authenticate")
        attempts_left = self.config["login_repeat"] if use_login_repeat else 0

        data = None

        while data is None:
            try:
                data = rpc_request(self.config, method, params or {})
            except errors.NotLoggedInError:
                if attempts_left > 0:
                    self.logout(suppress_errors=True)
                    self.login()
                else:
                    raise errors.NotLoggedInError(
                        "Tried to login several times, failed. Original method" " was " + method
                    )
            else:
                log("debug", "RETURN:" + str(data))
                return data

            attempts_left -= 1  # new round!
Example #4
0
def _parse_error_code(request_body, result_body):
    '''A helper function for handling JSON error codes.'''
    log('error', result_body)
    try:
        error = result_body['error']
        exc = _errorcodes[error['code']](error['message'])
    except KeyError:
        exc = errors.RemoteError(
            ('Some JSON-RPC-ish error happened. Please report this to the '
                'developer so he can implement a proper handling.'),
            str(result_body),
            str(request_body)
        )

    raise exc
Example #5
0
def _parse_error_code(request_body, result_body):
    """A helper function for handling JSON error codes."""
    log("error", result_body)
    try:
        error = result_body[u"error"]
        code, message = error[u"code"], error[u"message"]
    except KeyError:
        code = None  # None doesn't exist in_errorcodes
        message = "Some error happened and there is no information provided " "what went wrong."

    exc = _errorcodes.get(code, errors.RemoteError)(message)
    exc.request = request_body
    exc.result = result_body
    exc.code = code
    raise exc
Example #6
0
def _parse_error_code(request_body, result_body):
    """A helper function for handling JSON error codes."""
    log('error', result_body)
    try:
        error = result_body[u'error']
        code, message = error[u'code'], error[u'message']
    except KeyError:
        code = None  # None doesn't exist in_errorcodes
        message = ('Some error happened and there is no information provided '
                   'what went wrong.')

    exc = _errorcodes.get(code, errors.RemoteError)(message)
    exc.request = request_body
    exc.result = result_body
    exc.code = code
    raise exc
Example #7
0
def _send_request(url, data, headers):
    '''Sends a POST request given the endpoint URL, JSON-encodable data and
    a dictionary with headers.
    '''

    request = urlrequest.Request(url, json.dumps(data).encode(), headers)
    # this will eventually raise errors, e.g. if there's an unexpected http
    # status code
    result_obj = urlrequest.urlopen(request)
    result = result_obj.read().decode('utf-8')

    try:
        result_data = json.loads(result)
        log('debug', 'Valid JSON found')
    except ValueError:
        raise errors.RemoteError('Invalid JSON', str(result))
    else:
        return result_data
Example #8
0
def _send_request(url, data, headers, http_session=None):
    """Sends a POST request given the endpoint URL, JSON-encodable data,
    a dictionary with headers and, optionally, a session object for requests.
    """

    if http_session is None:
        http_session = requests.session()

    r = http_session.post(url, data=json.dumps(data), headers=headers)
    result = r.text
    # this will eventually raise errors, e.g. on timeout

    try:
        result_data = json.loads(result)
        log("debug", "Valid JSON found")
    except ValueError:
        raise errors.RemoteError("Invalid JSON", result)
    else:
        return result_data
Example #9
0
def _send_request(url, data, headers, http_session=None):
    """Sends a POST request given the endpoint URL, JSON-encodable data,
    a dictionary with headers and, optionally, a session object for requests.
    """

    if http_session is None:
        http_session = requests.session()

    r = http_session.post(url, data=json.dumps(data), headers=headers)
    result = r.text
    # this will eventually raise errors, e.g. on timeout

    try:
        result_data = json.loads(result)
        log('debug', 'Valid JSON found')
    except ValueError:
        raise errors.RemoteError('Invalid JSON', result)
    else:
        return result_data
Example #10
0
    def login(self):
        '''Initializes an authentication, provided we have the credentials for
        it.

        :returns: The session. This is useful for jQuery-like command
            chaining::

                s = webuntis.Session(...).login()

        :raises: :py:class:`webuntis.errors.BadCredentialsError` --
            Username/Password missing or invalid.
        :raises: :py:class:`webuntis.errors.AuthError` -- Didn't recieve a
            session ID for unknown reasons.
        '''

        if 'username' not in self.config \
                or 'password' not in self.config:
            raise errors.BadCredentialsError('No login data specified.')

        log('debug', 'Trying to authenticate with username/password...')
        log('debug', 'Username: %s Password: %s' %
           (self.config['username'], self.config['password']))
        res = self._request('authenticate', {
            'user': self.config['username'],
            'password': self.config['password'],
            'client': self.config['useragent']
        }, use_login_repeat=False)
        log('debug', res)
        if 'sessionId' in res:
            log('debug', 'Did get a jsessionid from the server:')
            self.config['jsessionid'] = res['sessionId']
            log('debug', self.config['jsessionid'])
        else:
            raise errors.AuthError(
                'Something went wrong while authenticating',
                res
            )

        return self
Example #11
0
def rpc_request(config, method, params):
    '''
    A method for sending a JSON-RPC request.

    :param config: A dictionary containing ``useragent``, ``server``,
        ``school``, ``username`` and ``password``
    :type config: dict

    :param method: The JSON-RPC method to be executed
    :type method: str

    :param params: JSON-RPC parameters to the method (should be JSON
        serializable)
    :type params: dict
    '''
    server = config['server']
    school = config['school']
    useragent = config['useragent']

    assert isinstance(method, unicode_string)
    assert isinstance(server, unicode_string)
    assert isinstance(school, unicode_string)
    assert isinstance(useragent, unicode_string)

    for v in params.values():
        assert not isinstance(v, bytestring)

    url = server + u'?school=' + school

    headers = {u'User-Agent': useragent, u'Content-Type': u'application/json'}

    request_body = {
        u'id': str(datetime.datetime.today()),
        u'method': method,
        u'params': params,
        u'jsonrpc': u'2.0'
    }

    if method != u'authenticate':
        if 'jsessionid' in config:
            assert isinstance(config['jsessionid'], unicode_string)
            headers['Cookie'] = u'JSESSIONID=' + config['jsessionid']
        else:
            raise errors.NotLoggedInError(
                'Don\'t have JSESSIONID. Did you already log out?')

    log('debug', 'Making new request:')
    log('debug', 'URL: ' + url)
    if method != u'authenticate':
        # user credentials will not be logged - fixing #14
        log('debug', 'DATA: ' + str(request_body))

    if '_http_session' not in config:
        config['_http_session'] = requests.session()
    http_session = config['_http_session']

    result_body = _send_request(url, request_body, headers, http_session)
    return _parse_result(request_body, result_body)
Example #12
0
    def login(self):
        """Initializes an authentication, provided we have the credentials for
        it.

        :returns: The session. This is useful for jQuery-like command
            chaining::

                s = webuntis.Session(...).login()

        :raises: :py:class:`webuntis.errors.BadCredentialsError` --
            Username/Password missing or invalid.
        :raises: :py:class:`webuntis.errors.AuthError` -- Didn't receive a
            session ID for unknown reasons.
        """

        try:
            username = self.config['username']
            password = self.config['password']
            useragent = self.config['useragent']
        except KeyError as e:
            raise errors.BadCredentialsError('Missing config: ' + str(e))

        res = self._request('authenticate', {
            'user': username,
            'password': password,
            'client': useragent
        },
                            use_login_repeat=False)

        if 'sessionId' in res:
            sid = self.config['jsessionid'] = res['sessionId']
            log('debug', 'Did get a jsessionid from the server: ' + sid)
        else:
            raise errors.AuthError('Something went wrong while authenticating',
                                   res)

        return self
Example #13
0
    def login(self):
        '''Initializes an authentication, provided we have the credentials for
        it.

        :returns: The session. This is useful for jQuery-like command
            chaining::

                s = webuntis.Session(...).login()

        :raises: :py:class:`webuntis.errors.BadCredentialsError` --
            Username/Password missing or invalid.
        :raises: :py:class:`webuntis.errors.AuthError` -- Didn't recieve a
            session ID for unknown reasons.
        '''

        try:
            username = self.config['username']
            password = self.config['password']
            useragent = self.config['useragent']
        except KeyError as e:
            raise errors.BadCredentialsError('Missing config: ' + str(e))

        res = self._request('authenticate', {
            'user': username,
            'password': password,
            'client': useragent
        }, use_login_repeat=False)

        if 'sessionId' in res:
            sid = self.config['jsessionid'] = res['sessionId']
            log('debug', 'Did get a jsessionid from the server: ' + sid)
        else:
            raise errors.AuthError('Something went wrong while authenticating',
                                   res)

        return self
Example #14
0
def rpc_request(config, method, params):
    '''
    A method for sending a JSON-RPC request.

    :param config: A dictionary containing ``useragent``, ``server``,
        ``school``, ``username`` and ``password``
    :type config: dict

    :param method: The JSON-RPC method to be executed
    :type method: str

    :param params: JSON-RPC parameters to the method (should be JSON
        serializable)
    :type params: dict
    '''

    url = config['server'] + \
        '?school=' + \
        config['school']

    headers = {
        'User-Agent': config['useragent'],
        'Content-Type': 'application/json'
    }

    request_body = {
        'id': str(datetime.datetime.today()),
        'method': method,
        'params': params,
        'jsonrpc': '2.0'
    }

    if method != 'authenticate':
        if 'jsessionid' not in config:
            raise errors.NotLoggedInError(
                'Don\'t have JSESSIONID. Did you already log out?')
        else:
            headers['Cookie'] = 'JSESSIONID=' + \
                config['jsessionid']

    log('debug', 'Making new request:')
    log('debug', 'URL: ' + url)
    log('debug', 'DATA: ' + str(request_body))

    result_body = _send_request(
        url,
        request_body,
        headers
    )
    return _parse_result(request_body, result_body)
Example #15
0
def rpc_request(config, method, params):
    """
    A method for sending a JSON-RPC request.

    :param config: A dictionary containing ``useragent``, ``server``,
        ``school``, ``username`` and ``password``
    :type config: dict

    :param method: The JSON-RPC method to be executed
    :type method: str

    :param params: JSON-RPC parameters to the method (should be JSON
        serializable)
    :type params: dict
    """
    server = config["server"]
    school = config["school"]
    useragent = config["useragent"]

    assert isinstance(method, unicode_string)
    assert isinstance(server, unicode_string)
    assert isinstance(school, unicode_string)
    assert isinstance(useragent, unicode_string)

    for v in params.values():
        assert not isinstance(v, bytestring)

    url = server + u"?school=" + school

    headers = {u"User-Agent": useragent, u"Content-Type": u"application/json"}

    request_body = {u"id": str(datetime.datetime.today()), u"method": method, u"params": params, u"jsonrpc": u"2.0"}

    if method != u"authenticate":
        if "jsessionid" in config:
            assert isinstance(config["jsessionid"], unicode_string)
            headers["Cookie"] = u"JSESSIONID=" + config["jsessionid"]
        else:
            raise errors.NotLoggedInError("Don't have JSESSIONID. Did you already log out?")

    log("debug", "Making new request:")
    log("debug", "URL: " + url)
    log("debug", "DATA: " + str(request_body))

    if "_http_session" not in config:
        config["_http_session"] = requests.session()
    http_session = config["_http_session"]

    result_body = _send_request(url, request_body, headers, http_session)
    return _parse_result(request_body, result_body)
Example #16
0
def rpc_request(config, method, params):
    """
    A method for sending a JSON-RPC request.

    :param config: A dictionary containing ``useragent``, ``server``,
        ``school``, ``username`` and ``password``
    :type config: dict or FilterDict

    :param method: The JSON-RPC method to be executed
    :type method: str

    :param params: JSON-RPC parameters to the method (should be JSON
        serializable)
    :type params: dict
    """
    server = config['server']
    school = config['school']
    useragent = config['useragent']

    assert isinstance(method, unicode_string)
    assert isinstance(server, unicode_string)
    assert isinstance(school, unicode_string)
    assert isinstance(useragent, unicode_string)

    for v in params.values():
        assert not isinstance(v, bytestring)

    url = server + u'?school=' + school

    headers = {
        u'User-Agent': useragent,
        u'Content-Type': u'application/json'
    }

    request_body = {
        u'id': _request_getid(),
        u'method': method,
        u'params': params,
        u'jsonrpc': u'2.0'
    }

    if method != u'authenticate':
        if 'jsessionid' in config:
            assert isinstance(config['jsessionid'], unicode_string)
            headers['Cookie'] = u'JSESSIONID=' + config['jsessionid']
        else:
            raise errors.NotLoggedInError(
                'Don\'t have JSESSIONID. Did you already log out?')

    log('debug', 'Making new request:')
    log('debug', 'URL: ' + url)
    if method != u'authenticate':
        # user credentials will not be logged - fixing #14
        log('debug', 'DATA: ' + str(request_body))

    if '_http_session' not in config:
        config['_http_session'] = requests.session()
    http_session = config['_http_session']

    result_body = _send_request(
        url,
        request_body,
        headers,
        http_session
    )
    return _parse_result(request_body, result_body)