Example #1
0
    def assert_access_token_response(self, r, expected):
        self.assertEqual(r.status_code, 200)
        try:
            data = json.loads(r.content)
        except:
            self.fail("Unexpected response content")

        self.assertTrue('access_token' in data)
        access_token = data['access_token']
        self.assertTrue('token_type' in data)
        token_type = data['token_type']
        self.assertTrue('expires_in' in data)
        expires_in = data['expires_in']

        try:
            token = Token.objects.get(code=access_token)
            self.assertEqual(
                token.expires_at,
                token.created_at + datetime.timedelta(seconds=expires_in))
            self.assertEqual(token.token_type, token_type)
            self.assertEqual(token.grant_type, 'authorization_code')
            #self.assertEqual(token.user, expected.get('user'))
            self.assertEqual(normalize(uenc(token.redirect_uri)),
                             normalize(uenc(expected.get('redirect_uri'))))
            self.assertEqual(normalize(uenc(token.scope)),
                             normalize(uenc(expected.get('scope'))))
            self.assertEqual(token.state, expected.get('state'))
        except Token.DoesNotExist:
            self.fail("Invalid access_token")
Example #2
0
 def _build_response(self, oa2response):
     response = http.HttpResponse()
     response.status_code = oa2response.status
     response.content = oa2response.body
     for key, value in oa2response.headers.iteritems():
         response[uenc(key)] = uenc(value)
     return response
Example #3
0
    def assert_access_token_response(self, r, expected):
        self.assertEqual(r.status_code, 200)
        try:
            data = json.loads(r.content)
        except:
            self.fail("Unexpected response content")

        self.assertTrue('access_token' in data)
        access_token = data['access_token']
        self.assertTrue('token_type' in data)
        token_type = data['token_type']
        self.assertTrue('expires_in' in data)
        expires_in = data['expires_in']

        try:
            token = Token.objects.get(code=access_token)
            self.assertEqual(token.expires_at,
                             token.created_at +
                             datetime.timedelta(seconds=expires_in))
            self.assertEqual(token.token_type, token_type)
            self.assertEqual(token.grant_type, 'authorization_code')
            #self.assertEqual(token.user, expected.get('user'))
            self.assertEqual(normalize(uenc(token.redirect_uri)),
                             normalize(uenc(expected.get('redirect_uri'))))
            self.assertEqual(normalize(uenc(token.scope)),
                             normalize(uenc(expected.get('scope'))))
            self.assertEqual(token.state, expected.get('state'))
        except Token.DoesNotExist:
            self.fail("Invalid access_token")
Example #4
0
def grapher(request, graph_type, hostname):
    hostname = decrypt(uenc(hostname))
    fname = uenc(os.path.join(settings.RRD_PREFIX, hostname))
    if not os.path.isdir(fname):
        raise faults.ItemNotFound("No such instance")

    outfname = uenc(os.path.join(settings.GRAPH_PREFIX, hostname))
    draw_func = available_graph_types[graph_type]

    response = HttpResponse(draw_func(fname, outfname), status=200, content_type="image/png")
    response.override_serialization = True

    return response
Example #5
0
def _create_image_response(image):
    response = HttpResponse()

    for key in DETAIL_FIELDS:
        if key == 'properties':
            for k, v in image.get('properties', {}).items():
                name = 'x-image-meta-property-' + k.replace('_', '-')
                response[name] = uenc(v)
        else:
            name = 'x-image-meta-' + key.replace('_', '-')
            response[name] = uenc(image.get(key, ''))

    return response
Example #6
0
def _create_image_response(image):
    response = HttpResponse()

    for key in DETAIL_FIELDS:
        if key == 'properties':
            for k, v in image.get('properties', {}).items():
                name = 'x-image-meta-property-' + k.replace('_', '-')
                response[name] = uenc(v)
        else:
            name = 'x-image-meta-' + key.replace('_', '-')
            response[name] = uenc(image.get(key, ''))

    return response
Example #7
0
def grapher(request, graph_type, hostname):
    hostname = decrypt(uenc(hostname))
    fname = uenc(os.path.join(settings.RRD_PREFIX, hostname))
    if not os.path.isdir(fname):
        raise faults.ItemNotFound('No such instance')

    outfname = uenc(os.path.join(settings.GRAPH_PREFIX, hostname))
    draw_func = available_graph_types[graph_type]

    response = HttpResponse(draw_func(fname, outfname),
                            status=200,
                            content_type="image/png")
    response.override_serialization = True

    return response
Example #8
0
def grapher(request, graph_type, hostname):
    try:
        hostname = decrypt(uenc(hostname))
    except (ValueError, TypeError):
        raise faults.BadRequest("Invalid encrypted virtual server name")
    fname = uenc(os.path.join(settings.RRD_PREFIX, hostname))
    if not os.path.isdir(fname):
        raise faults.ItemNotFound('No such instance')

    outfname = uenc(os.path.join(settings.GRAPH_PREFIX, hostname))
    draw_func = available_graph_types[graph_type]

    response = HttpResponse(draw_func(fname, outfname),
                            status=200, content_type="image/png")
    response.override_serialization = True

    return response
Example #9
0
    def register(self, name, image_url, metadata):
        # Validate that metadata are allowed
        if "id" in metadata:
            raise ValueError("Passing an ID is not supported")
        store = metadata.pop("store", "pithos")
        if store != "pithos":
            raise ValueError("Invalid store '%s'. Only 'pithos' store is"
                             "supported" % store)
        disk_format = metadata.setdefault("disk_format",
                                          settings.DEFAULT_DISK_FORMAT)
        if disk_format not in settings.ALLOWED_DISK_FORMATS:
            raise ValueError("Invalid disk format '%s'" % disk_format)
        container_format =\
            metadata.setdefault("container_format",
                                settings.DEFAULT_CONTAINER_FORMAT)
        if container_format not in settings.ALLOWED_CONTAINER_FORMATS:
            raise ValueError("Invalid container format '%s'" %
                             container_format)

        # Validate that 'size' and 'checksum' are valid
        account, container, object = split_url(image_url)

        meta = self._get_meta(image_url)

        size = int(metadata.pop('size', meta['bytes']))
        if size != meta['bytes']:
            raise ValueError("Invalid size")

        checksum = metadata.pop('checksum', meta['hash'])
        if checksum != meta['hash']:
            raise ValueError("Invalid checksum")

        # Fix permissions
        is_public = metadata.pop('is_public', False)
        if is_public:
            permissions = {'read': ['*']}
        else:
            permissions = {'read': [self.user]}

        # Extract the properties dictionary from metadata, and store each
        # property as a separeted, prefixed metadata
        properties = metadata.pop("properties", {})
        meta = dict([(PROPERTY_PREFIX + k, v) for k, v in properties.items()])
        # Add creation(register) timestamp as a metadata, to avoid extra
        # queries when retrieving the list of images.
        meta['created_at'] = time()
        # Update rest metadata
        meta.update(name=name, status='available', **metadata)

        # Do the actualy update in the Pithos backend
        self._update_meta(image_url, meta)
        self._update_permissions(image_url, permissions)
        logger.debug("User '%s' created image '%s'('%s')", self.user,
                     image_url, uenc(name))
        return self._get_image(image_url)
Example #10
0
    def register(self, name, image_url, metadata):
        # Validate that metadata are allowed
        if "id" in metadata:
            raise ValueError("Passing an ID is not supported")
        store = metadata.pop("store", "pithos")
        if store != "pithos":
            raise ValueError("Invalid store '%s'. Only 'pithos' store is"
                             "supported" % store)
        disk_format = metadata.setdefault("disk_format",
                                          settings.DEFAULT_DISK_FORMAT)
        if disk_format not in settings.ALLOWED_DISK_FORMATS:
            raise ValueError("Invalid disk format '%s'" % disk_format)
        container_format =\
            metadata.setdefault("container_format",
                                settings.DEFAULT_CONTAINER_FORMAT)
        if container_format not in settings.ALLOWED_CONTAINER_FORMATS:
            raise ValueError("Invalid container format '%s'" %
                             container_format)

        # Validate that 'size' and 'checksum' are valid
        account, container, object = split_url(image_url)

        meta = self._get_meta(image_url)

        size = int(metadata.pop('size', meta['bytes']))
        if size != meta['bytes']:
            raise ValueError("Invalid size")

        checksum = metadata.pop('checksum', meta['hash'])
        if checksum != meta['hash']:
            raise ValueError("Invalid checksum")

        # Fix permissions
        is_public = metadata.pop('is_public', False)
        if is_public:
            permissions = {'read': ['*']}
        else:
            permissions = {'read': [self.user]}

        # Extract the properties dictionary from metadata, and store each
        # property as a separeted, prefixed metadata
        properties = metadata.pop("properties", {})
        meta = dict([(PROPERTY_PREFIX + k, v) for k, v in properties.items()])
        # Add creation(register) timestamp as a metadata, to avoid extra
        # queries when retrieving the list of images.
        meta['created_at'] = time()
        # Update rest metadata
        meta.update(name=name, status='available', **metadata)

        # Do the actualy update in the Pithos backend
        self._update_meta(image_url, meta)
        self._update_permissions(image_url, permissions)
        logger.debug("User '%s' created image '%s'('%s')", self.user,
                     image_url, uenc(name))
        return self._get_image(image_url)
Example #11
0
    def _update_meta(self, image_url, meta, replace=False):
        """Update object's metadata."""
        account, container, name = split_url(image_url)

        prefixed = [(PLANKTON_PREFIX + uenc(k), uenc(v))
                    for k, v in meta.items()
                    if k in PLANKTON_META or k.startswith(PROPERTY_PREFIX)]
        prefixed = dict(prefixed)

        for k, v in prefixed.items():
            if len(k) > 128:
                raise InvalidMetadata('Metadata keys should be less than %s '
                                      'characters' % MAX_META_KEY_LENGTH)
            if len(v) > 256:
                raise InvalidMetadata('Metadata values should be less than %s '
                                      'characters.' % MAX_META_VALUE_LENGTH)

        self.backend.update_object_meta(self.user, account, container, name,
                                        PLANKTON_DOMAIN, prefixed, replace)
        logger.debug("User '%s' updated image '%s', meta: '%s'", self.user,
                     image_url, prefixed)
Example #12
0
    def _update_meta(self, image_url, meta, replace=False):
        """Update object's metadata."""
        account, container, name = split_url(image_url)

        prefixed = [(PLANKTON_PREFIX + uenc(k), uenc(v))
                    for k, v in meta.items()
                    if k in PLANKTON_META or k.startswith(PROPERTY_PREFIX)]
        prefixed = dict(prefixed)

        for k, v in prefixed.items():
            if len(k) > 128:
                raise InvalidMetadata('Metadata keys should be less than %s '
                                      'characters' % MAX_META_KEY_LENGTH)
            if len(v) > 256:
                raise InvalidMetadata('Metadata values should be less than %s '
                                      'characters.' % MAX_META_VALUE_LENGTH)

        self.backend.update_object_meta(self.user, account, container, name,
                                        PLANKTON_DOMAIN, prefixed, replace)
        logger.debug("User '%s' updated image '%s', meta: '%s'", self.user,
                     image_url, prefixed)
Example #13
0
def add_image(request):
    """Add a new virtual machine image

    Described in:
    3.6. Adding a New Virtual Machine Image

    Implementation notes:
      * The implementation is very inefficient as it loads the whole image
        in memory.

    Limitations:
      * x-image-meta-id is not supported. Will always return 409 Conflict.

    Extensions:
      * An x-image-meta-location header can be passed with a link to file,
        instead of uploading the data.
    """

    params = _get_image_headers(request)
    log.debug('add_image %s', params)

    if not set(params.keys()).issubset(set(ADD_FIELDS)):
        raise faults.BadRequest("Invalid parameters")

    name = params.pop('name')
    if name is None:
        raise faults.BadRequest("Image 'name' parameter is required")
    elif len(uenc(name)) == 0:
        raise faults.BadRequest("Invalid image name")
    location = params.pop('location', None)
    if location is None:
        raise faults.BadRequest("'location' parameter is required")

    try:
        split_url(location)
    except InvalidLocation:
        raise faults.BadRequest("Invalid location '%s'" % location)

    validate_fields(params)

    if location:
        with image_backend(request.user_uniq) as backend:
            image = backend.register(name, location, params)
    else:
        #f = StringIO(request.body)
        #image = backend.put(name, f, params)
        return HttpResponse(status=501)  # Not Implemented

    if not image:
        return HttpResponse('Registration failed', status=500)

    return _create_image_response(image)
Example #14
0
def add_image(request):
    """Add a new virtual machine image

    Described in:
    3.6. Adding a New Virtual Machine Image

    Implementation notes:
      * The implementation is very inefficient as it loads the whole image
        in memory.

    Limitations:
      * x-image-meta-id is not supported. Will always return 409 Conflict.

    Extensions:
      * An x-image-meta-location header can be passed with a link to file,
        instead of uploading the data.
    """

    params = _get_image_headers(request)
    log.debug('add_image %s', params)

    if not set(params.keys()).issubset(set(ADD_FIELDS)):
        raise faults.BadRequest("Invalid parameters")

    name = params.pop('name', None)
    if name is None:
        raise faults.BadRequest("Image 'name' parameter is required")
    elif len(uenc(name)) == 0:
        raise faults.BadRequest("Invalid image name")
    location = params.pop('location', None)
    if location is None:
        raise faults.BadRequest("'location' parameter is required")

    try:
        split_url(location)
    except InvalidLocation:
        raise faults.BadRequest("Invalid location '%s'" % location)

    validate_fields(params)

    if location:
        with image_backend(request.user_uniq) as backend:
            image = backend.register(name, location, params)
    else:
        #f = StringIO(request.body)
        #image = backend.put(name, f, params)
        return HttpResponse(status=501)     # Not Implemented

    if not image:
        return HttpResponse('Registration failed', status=500)

    return _create_image_response(image)
Example #15
0
def astakos_user(user):
    """
    Context manager to mock astakos response.

    usage:
    with astakos_user("*****@*****.**"):
        .... make api calls ....

    """
    with patch("snf_django.lib.api.get_token") as get_token:
        get_token.return_value = "DummyToken"
        with patch('astakosclient.AstakosClient.get_user_info') as m:
            m.return_value = {"uuid": text.uenc(user, 'utf8')}
            with patch('astakosclient.AstakosClient.get_quotas') as m2:
                m2.return_value = {
                    "system": {
                        "pithos.diskspace": {
                            "usage": 0,
                            "limit": 1073741824,  # 1GB
                            "pending": 0
                        }
                    }
                }
                issue_fun = "astakosclient.AstakosClient.issue_one_commission"
                with patch(issue_fun) as m3:
                    serials = []
                    append = serials.append

                    def get_serial(*args, **kwargs):
                        global serial
                        serial += 1
                        append(serial)
                        return serial

                    m3.side_effect = get_serial
                    resolv_fun = \
                        'astakosclient.AstakosClient.resolve_commissions'
                    with patch(resolv_fun) as m4:
                        m4.return_value = {'accepted': serials,
                                           'rejected': [],
                                           'failed': []}
                        users_fun = 'astakosclient.AstakosClient.get_usernames'
                        with patch(users_fun) as m5:

                            def get_usernames(*args, **kwargs):
                                uuids = args[-1]
                                return dict((uuid, uuid) for uuid in uuids)

                            m5.side_effect = get_usernames
                            yield
Example #16
0
def check_name_length(name, max_length, message):
    """Check if a string is within acceptable value length"""
    if len(uenc(name)) > max_length:
        raise faults.BadRequest(message)
Example #17
0
        def wrapper(request, *args, **kwargs):
            if request.method not in ["GET", "HEAD"]:
                return HttpResponseNotAllowed(["GET", "HEAD"])

            try:
                access_token = request.GET.get("access_token")
                requested_resource = text.uenc(request.path.split(VIEW_PREFIX, 2)[-1])
                astakos = AstakosClient(SERVICE_TOKEN, ASTAKOS_AUTH_URL, retry=2, use_pool=True, logger=logger)
                if access_token is not None:
                    # authenticate using the short-term access token
                    try:
                        request.user = astakos.validate_token(access_token, requested_resource)
                    except AstakosClientException:
                        return HttpResponseRedirect(request.path)
                    request.user_uniq = request.user["access"]["user"]["id"]

                    _func = api_method(token_required=False, user_required=False)(func)
                    response = _func(request, *args, **kwargs)
                    if response.status_code == 404:
                        raise Http404
                    elif response.status_code == 403:
                        raise PermissionDenied
                    return response

                client_id, client_secret = OAUTH2_CLIENT_CREDENTIALS
                # TODO: check if client credentials are not set
                authorization_code = request.GET.get("code")
                redirect_uri = unquote(request.build_absolute_uri(request.get_full_path()))
                if authorization_code is None:
                    # request authorization code
                    params = {
                        "response_type": "code",
                        "client_id": client_id,
                        "redirect_uri": redirect_uri,
                        "state": "",  # TODO include state for security
                        "scope": requested_resource,
                    }
                    return HttpResponseRedirect("%s?%s" % (join_urls(astakos.oauth2_url, "auth"), urlencode(params)))
                else:
                    # request short-term access token
                    parts = list(urlsplit(redirect_uri))
                    params = dict(parse_qsl(parts[3], keep_blank_values=True))
                    if "code" in params:  # always True
                        del params["code"]
                    if "state" in params:
                        del params["state"]
                    parts[3] = urlencode(params)
                    redirect_uri = urlunsplit(parts)
                    data = astakos.get_token(
                        "authorization_code",
                        *OAUTH2_CLIENT_CREDENTIALS,
                        redirect_uri=redirect_uri,
                        scope=requested_resource,
                        code=authorization_code
                    )
                    params["access_token"] = data.get("access_token", "")
                    parts[3] = urlencode(params)
                    redirect_uri = urlunsplit(parts)
                    return HttpResponseRedirect(redirect_uri)
            except AstakosClientException, err:
                logger.exception(err)
                raise PermissionDenied
Example #18
0
def normalize(url):
    return urltools.normalize(uenc(url))
Example #19
0
def urlencode(params):
    if hasattr(params, 'urlencode') and callable(getattr(params, 'urlencode')):
        return params.urlencode()
    for k in params:
        params[uenc(k)] = uenc(params.pop(k))
    return urllib.urlencode(params)
Example #20
0
    def test_code_authorization(self):
        # missing response_type
        r = self.client.get(self.client.get_url(self.client.auth_url))
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # invalid response_type
        r = self.client.get(self.client.get_url(self.client.auth_url,
                                                response_type='invalid'))
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # unsupported response_type
        r = self.client.get(self.client.get_url(self.client.auth_url,
                                                response_type='token'))
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # missing client_id
        r = self.client.get(self.client.get_url(self.client.auth_url,
                                                response_type='code'))
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # fake client
        r = self.client.authorize_code('client-fake')
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # mixed up credentials/client_id's
        self.client.set_credentials('client1', 'secret')
        r = self.client.authorize_code('client3')
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # invalid credentials
        self.client.set_credentials('client2', '')
        r = self.client.authorize_code('client2')
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # invalid redirect_uri: not absolute URI
        self.client.set_credentials()
        params = {'redirect_uri':
                  urlparse.urlparse(self.client1_redirect_uri).path}
        r = self.client.authorize_code('client1', urlparams=params)
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # mismatching redirect uri
        self.client.set_credentials()
        params = {'redirect_uri': self.client1_redirect_uri[1:]}
        r = self.client.authorize_code('client1', urlparams=params)
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # valid request: untrusted client
        params = {'redirect_uri': self.client1_redirect_uri,
                  'scope': self.client1_redirect_uri,
                  'extra_param': 'γιουνικοντ'}
        self.client.set_credentials('client1', 'secret')
        r = self.client.authorize_code('client1', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertTrue('Location' in r)
        self.assertHost(r['Location'], "testserver:80")
        self.assertPath(r['Location'], reverse('login'))

        self.client.set_credentials('client1', 'secret')
        self.client.login(username="******", password="******")
        r = self.client.authorize_code('client1', urlparams=params)
        self.assertEqual(r.status_code, 200)

        r = self.client.authorize_code('client1', urlparams=params,
                                       extraparams={'reject': 0})
        self.assertCount(AuthorizationCode, 1)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server.com")
        self.assertPath(redirect, "/handle_code")

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        #self.assertEqual(code.state, '')
        self.assertEqual(code.state, None)
        self.assertEqual(code.redirect_uri, self.client1_redirect_uri)

        params['state'] = 'csrfstate'
        params['scope'] = 'resource1'
        r = self.client.authorize_code('client1', urlparams=params)
        redirect = self.get_redirect_url(r)
        self.assertParamEqual(redirect, "state", 'csrfstate')
        self.assertCount(AuthorizationCode, 2)

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, 'csrfstate')
        self.assertEqual(code.redirect_uri, self.client1_redirect_uri)

        # valid request: trusted client
        params = {'redirect_uri': self.client3_redirect_uri,
                  'scope': self.client3_redirect_uri,
                  'extra_param': 'γιουνικοντ'}
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertCount(AuthorizationCode, 3)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertNoParam(redirect, "state")
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server3.com")
        self.assertPath(redirect, "/handle_code")

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, None)
        self.assertEqual(code.redirect_uri, self.client3_redirect_uri)

        # valid request: trusted client
        params['state'] = 'csrfstate'
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertCount(AuthorizationCode, 4)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertParamEqual(redirect, "state", 'csrfstate')
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server3.com")
        self.assertPath(redirect, "/handle_code")

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, 'csrfstate')
        self.assertEqual(code.redirect_uri, self.client3_redirect_uri)

        # redirect uri startswith the client's registered redirect url
        params['redirect_uri'] = '%sφωτογραφία.JPG' % self.client3_redirect_uri
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 400)

        # redirect uri descendant
        redirect_uri = '%s/' % self.client3_redirect_uri
        rest = settings.MAXIMUM_ALLOWED_REDIRECT_URI_LENGTH - len(redirect_uri)
        redirect_uri = '%s%s' % (redirect_uri, 'a'*rest)
        params['redirect_uri'] = redirect_uri
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertCount(AuthorizationCode, 5)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertParamEqual(redirect, "state", 'csrfstate')
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server3.com")
        self.assertPath(redirect, urlparse.urlparse(redirect_uri).path)

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, 'csrfstate')
        self.assertEqual(code.redirect_uri, redirect_uri)

        # too long redirect uri
        params['redirect_uri'] = '%sa' % redirect_uri
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 400)

        # redirect uri descendant
        redirect_uri = '%s/φωτογραφία.JPG?α=γιουνικοντ' % self.client3_redirect_uri
        params['redirect_uri'] = redirect_uri
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertCount(AuthorizationCode, 6)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertParamEqual(redirect, "state", 'csrfstate')
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server3.com")
        self.assertPath(redirect, urlparse.urlparse(redirect_uri).path)

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, 'csrfstate')
        self.assertEqual(normalize(uenc(code.redirect_uri)),
                         normalize(uenc(redirect_uri)))
Example #21
0
    def test_code_authorization(self):
        # missing response_type
        r = self.client.get(self.client.get_url(self.client.auth_url))
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # invalid response_type
        r = self.client.get(
            self.client.get_url(self.client.auth_url, response_type='invalid'))
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # unsupported response_type
        r = self.client.get(
            self.client.get_url(self.client.auth_url, response_type='token'))
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # missing client_id
        r = self.client.get(
            self.client.get_url(self.client.auth_url, response_type='code'))
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # fake client
        r = self.client.authorize_code('client-fake')
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # mixed up credentials/client_id's
        self.client.set_credentials('client1', 'secret')
        r = self.client.authorize_code('client3')
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # invalid credentials
        self.client.set_credentials('client2', '')
        r = self.client.authorize_code('client2')
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # invalid redirect_uri: not absolute URI
        self.client.set_credentials()
        params = {
            'redirect_uri': urlparse.urlparse(self.client1_redirect_uri).path
        }
        r = self.client.authorize_code('client1', urlparams=params)
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # mismatching redirect uri
        self.client.set_credentials()
        params = {'redirect_uri': self.client1_redirect_uri[1:]}
        r = self.client.authorize_code('client1', urlparams=params)
        self.assertEqual(r.status_code, 400)
        self.assertCount(AuthorizationCode, 0)

        # valid request: untrusted client
        params = {
            'redirect_uri': self.client1_redirect_uri,
            'scope': self.client1_redirect_uri,
            'extra_param': 'γιουνικοντ'
        }
        self.client.set_credentials('client1', 'secret')
        r = self.client.authorize_code('client1', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertTrue('Location' in r)
        self.assertHost(r['Location'], "testserver:80")
        self.assertPath(r['Location'], reverse('login'))

        self.client.set_credentials('client1', 'secret')
        self.client.login(username="******", password="******")
        r = self.client.authorize_code('client1', urlparams=params)
        self.assertEqual(r.status_code, 200)

        r = self.client.authorize_code('client1',
                                       urlparams=params,
                                       extraparams={'reject': 0})
        self.assertCount(AuthorizationCode, 1)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server.com")
        self.assertPath(redirect, "/handle_code")

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        #self.assertEqual(code.state, '')
        self.assertEqual(code.state, None)
        self.assertEqual(code.redirect_uri, self.client1_redirect_uri)

        params['state'] = 'csrfstate'
        params['scope'] = 'resource1'
        r = self.client.authorize_code('client1', urlparams=params)
        redirect = self.get_redirect_url(r)
        self.assertParamEqual(redirect, "state", 'csrfstate')
        self.assertCount(AuthorizationCode, 2)

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, 'csrfstate')
        self.assertEqual(code.redirect_uri, self.client1_redirect_uri)

        # valid request: trusted client
        params = {
            'redirect_uri': self.client3_redirect_uri,
            'scope': self.client3_redirect_uri,
            'extra_param': 'γιουνικοντ'
        }
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertCount(AuthorizationCode, 3)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertNoParam(redirect, "state")
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server3.com")
        self.assertPath(redirect, "/handle_code")

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, None)
        self.assertEqual(code.redirect_uri, self.client3_redirect_uri)

        # valid request: trusted client
        params['state'] = 'csrfstate'
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertCount(AuthorizationCode, 4)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertParamEqual(redirect, "state", 'csrfstate')
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server3.com")
        self.assertPath(redirect, "/handle_code")

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, 'csrfstate')
        self.assertEqual(code.redirect_uri, self.client3_redirect_uri)

        # redirect uri startswith the client's registered redirect url
        params['redirect_uri'] = '%sφωτογραφία.JPG' % self.client3_redirect_uri
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 400)

        # redirect uri descendant
        redirect_uri = '%s/' % self.client3_redirect_uri
        rest = settings.MAXIMUM_ALLOWED_REDIRECT_URI_LENGTH - len(redirect_uri)
        redirect_uri = '%s%s' % (redirect_uri, 'a' * rest)
        params['redirect_uri'] = redirect_uri
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertCount(AuthorizationCode, 5)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertParamEqual(redirect, "state", 'csrfstate')
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server3.com")
        self.assertPath(redirect, urlparse.urlparse(redirect_uri).path)

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, 'csrfstate')
        self.assertEqual(code.redirect_uri, redirect_uri)

        # too long redirect uri
        params['redirect_uri'] = '%sa' % redirect_uri
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 400)

        # redirect uri descendant
        redirect_uri = '%s/φωτογραφία.JPG?α=γιουνικοντ' % self.client3_redirect_uri
        params['redirect_uri'] = redirect_uri
        self.client.set_credentials('client3', 'secret')
        r = self.client.authorize_code('client3', urlparams=params)
        self.assertEqual(r.status_code, 302)
        self.assertCount(AuthorizationCode, 6)

        # redirect is valid
        redirect = self.get_redirect_url(r)
        self.assertParam(redirect, "code")
        self.assertParamEqual(redirect, "state", 'csrfstate')
        self.assertNoParam(redirect, "extra_param")
        self.assertHost(redirect, "server3.com")
        self.assertPath(redirect, urlparse.urlparse(redirect_uri).path)

        code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
        self.assertEqual(code.state, 'csrfstate')
        self.assertEqual(normalize(uenc(code.redirect_uri)),
                         normalize(uenc(redirect_uri)))
Example #22
0
def normalize(url):
    return urltools.normalize(uenc(url))
Example #23
0
        def wrapper(request, *args, **kwargs):
            if request.method not in ['GET', 'HEAD']:
                return HttpResponseNotAllowed(['GET', 'HEAD'])

            try:
                access_token = request.GET.get('access_token')
                requested_resource = text.uenc(request.path.split(VIEW_PREFIX,
                                                                  2)[-1])
                astakos = AstakosClient(SERVICE_TOKEN, ASTAKOS_AUTH_URL,
                                        retry=2, use_pool=True,
                                        logger=logger)
                if access_token is not None:
                    # authenticate using the short-term access token
                    try:
                        request.user = astakos.validate_token(
                            access_token, requested_resource)
                    except AstakosClientException:
                        return HttpResponseRedirect(request.path)
                    request.user_uniq = request.user["access"]["user"]["id"]

                    _func = api_method(token_required=False,
                                       user_required=False)(func)
                    response = _func(request, *args, **kwargs)
                    if response.status_code == 404:
                        raise Http404
                    elif response.status_code == 403:
                        raise PermissionDenied
                    return response

                client_id, client_secret = OAUTH2_CLIENT_CREDENTIALS
                # TODO: check if client credentials are not set
                authorization_code = request.GET.get('code')
                redirect_uri = unquote(request.build_absolute_uri(
                    request.get_full_path()))
                if authorization_code is None:
                    # request authorization code
                    params = {'response_type': 'code',
                              'client_id': client_id,
                              'redirect_uri': redirect_uri,
                              'state': '',  # TODO include state for security
                              'scope': requested_resource}
                    return HttpResponseRedirect('%s?%s' %
                                                (join_urls(astakos.oauth2_url,
                                                           'auth'),
                                                 urlencode(params)))
                else:
                    # request short-term access token
                    parts = list(urlsplit(redirect_uri))
                    params = dict(parse_qsl(parts[3], keep_blank_values=True))
                    if 'code' in params:  # always True
                        del params['code']
                    if 'state' in params:
                        del params['state']
                    parts[3] = urlencode(params)
                    redirect_uri = urlunsplit(parts)
                    data = astakos.get_token('authorization_code',
                                             *OAUTH2_CLIENT_CREDENTIALS,
                                             redirect_uri=redirect_uri,
                                             scope=requested_resource,
                                             code=authorization_code)
                    params['access_token'] = data.get('access_token', '')
                    parts[3] = urlencode(params)
                    redirect_uri = urlunsplit(parts)
                    return HttpResponseRedirect(redirect_uri)
            except AstakosClientException, err:
                logger.exception(err)
                raise PermissionDenied
Example #24
0
def urlencode(params):
    if hasattr(params, 'urlencode') and callable(getattr(params, 'urlencode')):
        return params.urlencode()
    for k in params:
        params[uenc(k)] = uenc(params.pop(k))
    return urllib.urlencode(params)
Example #25
0
def pprint_table(out, table, headers=None, output_format='pretty',
                 separator=None, vertical=False, title=None):
    """Print a pretty, aligned string representation of table.

    Works by finding out the max width of each column and padding to data
    to this value.
    """

    assert(isinstance(table, (list, tuple))), "Invalid table type"
    if headers:
        assert(isinstance(headers, (list, tuple))), "Invalid headers type"

    sep = separator if separator else "  "

    def stringnify(obj):
        if isinstance(obj, (unicode, str)):
            return udec(obj)
        else:
            return str(obj)

    if headers:
        headers = map(stringnify, headers)
    table = [map(stringnify, row) for row in table]

    if output_format == "json":
        assert(headers is not None), "json output format requires headers"
        table = [dict(zip(headers, row)) for row in table]
        out.write(json.dumps(table, indent=4))
        out.write("\n")
    elif output_format == "csv":
        cw = csv.writer(out)
        if headers:
            table.insert(0, headers)
        table = map(functools.partial(map, uenc), table)
        cw.writerows(table)
    elif output_format == "pretty":
        if vertical:
            assert(len(table) == 1)
            row = table[0]
            max_key = max(map(len, headers))
            for row in table:
                for (k, v) in zip(headers, row):
                    k = uenc(k.ljust(max_key))
                    v = uenc(v)
                    out.write("%s: %s\n" % (k, v))
        else:
            # Find out the max width of each column
            columns = [headers] + table if headers else table
            widths = [max(map(len, col)) for col in zip(*(columns))]

            t_length = sum(widths) + len(sep) * (len(widths) - 1)
            if title is not None:
                out.write(title.center(t_length) + "\n")
            if headers:
                # pretty print the headers
                line = sep.join(uenc(v.rjust(w))\
                                for v, w in zip(headers, widths))
                out.write(line + "\n")
                out.write("-" * t_length + "\n")

            # print the rest table
            for row in table:
                line = sep.join(uenc(v.rjust(w)) for v, w in zip(row, widths))
                out.write(line + "\n")
    else:
        raise ValueError("Unknown output format '%s'" % output_format)
Example #26
0
def pprint_table(out,
                 table,
                 headers=None,
                 output_format='pretty',
                 separator=None,
                 vertical=False,
                 title=None):
    """Print a pretty, aligned string representation of table.

    Works by finding out the max width of each column and padding to data
    to this value.
    """

    assert (isinstance(table, (list, tuple))), "Invalid table type"
    if headers:
        assert (isinstance(headers, (list, tuple))), "Invalid headers type"

    sep = separator if separator else "  "

    def stringnify(obj):
        if isinstance(obj, (unicode, str)):
            return udec(obj)
        else:
            return str(obj)

    if headers:
        headers = map(stringnify, headers)
    table = [map(stringnify, row) for row in table]

    if output_format == "json":
        assert (headers is not None), "json output format requires headers"
        table = [dict(zip(headers, row)) for row in table]
        out.write(json.dumps(table, indent=4))
        out.write("\n")
    elif output_format == "csv":
        cw = csv.writer(out)
        if headers:
            table.insert(0, headers)
        table = map(functools.partial(map, uenc), table)
        cw.writerows(table)
    elif output_format == "pretty":
        if vertical:
            assert (len(table) == 1)
            row = table[0]
            max_key = max(map(len, headers))
            for row in table:
                for (k, v) in zip(headers, row):
                    k = uenc(k.ljust(max_key))
                    v = uenc(v)
                    out.write("%s: %s\n" % (k, v))
        else:
            # Find out the max width of each column
            columns = [headers] + table if headers else table
            widths = [max(map(len, col)) for col in zip(*(columns))]

            t_length = sum(widths) + len(sep) * (len(widths) - 1)
            if title is not None:
                t_length = max(t_length, len(title))
                out.write("-" * t_length + "\n")
                out.write(title.center(t_length) + "\n")
                out.write("-" * t_length + "\n")
            if headers:
                # pretty print the headers
                line = sep.join(
                    uenc(v.rjust(w)) for v, w in zip(headers, widths))
                out.write(line + "\n")
                out.write("-" * t_length + "\n")

            # print the rest table
            for row in table:
                line = sep.join(uenc(v.rjust(w)) for v, w in zip(row, widths))
                out.write(line + "\n")
    else:
        raise ValueError("Unknown output format '%s'" % output_format)
Example #27
0
def check_name_length(name, max_length, message):
    """Check if a string is within acceptable value length"""
    if len(uenc(name)) > max_length:
        raise faults.BadRequest(message)