예제 #1
0
    def __call__(self):
        try:
            table_name = self.action_params.get(parser.Props.TABLE_NAME, None)

            # parse expected item conditions
            expected_item_conditions = (
                parser.Parser.parse_expected_attribute_conditions(
                    self.action_params.get(parser.Props.EXPECTED, {})
                )
            )

            # parse item
            item_attributes = parser.Parser.parse_item_attributes(
                self.action_params[parser.Props.ITEM]
            )

            # parse return_values param
            return_values_json = self.action_params.get(
                parser.Props.RETURN_VALUES, parser.Values.RETURN_VALUES_NONE
            )

            return_values = models.InsertReturnValuesType(return_values_json)

            # parse return_item_collection_metrics
            return_item_collection_metrics = self.action_params.get(
                parser.Props.RETURN_ITEM_COLLECTION_METRICS,
                parser.Values.RETURN_ITEM_COLLECTION_METRICS_NONE
            )

            return_consumed_capacity = self.action_params.get(
                parser.Props.RETURN_CONSUMED_CAPACITY,
                parser.Values.RETURN_CONSUMED_CAPACITY_NONE
            )
        except Exception:
            raise AWSValidationException()

        try:
            # put item
            result, old_item = storage.put_item(
                self.context,
                table_name,
                item_attributes,
                return_values,
                if_not_exist=False,
                expected_condition_map=expected_item_conditions
            )

            if not result:
                raise AWSErrorResponseException()

            # format response
            response = {}

            if old_item:
                response[parser.Props.ATTRIBUTES] = (
                    parser.Parser.format_item_attributes(item_attributes)
                )

            if (return_item_collection_metrics !=
                    parser.Values.RETURN_ITEM_COLLECTION_METRICS_NONE):
                response[parser.Props.ITEM_COLLECTION_METRICS] = {
                    parser.Props.ITEM_COLLECTION_KEY: {
                        parser.Parser.format_item_attributes(
                            models.AttributeValue("S", "key")
                        )
                    },
                    parser.Props.SIZE_ESTIMATED_RANGE_GB: [0]
                }

            if (return_consumed_capacity !=
                    parser.Values.RETURN_CONSUMED_CAPACITY_NONE):
                response[parser.Props.CONSUMED_CAPACITY] = (
                    parser.Parser.format_consumed_capacity(
                        return_consumed_capacity, None
                    )
                )

            return response
        except AWSErrorResponseException as e:
            raise e
        except Exception:
            raise AWSErrorResponseException()
예제 #2
0
    def __call__(self):
        try:
            table_name = self.action_params.get(parser.Props.TABLE_NAME, None)

            # get attributes_to_get
            attributes_to_get = self.action_params.get(
                parser.Props.ATTRIBUTES_TO_GET, None)

            select_type = (models.SelectType.all()
                           if attributes_to_get is None else
                           models.AttributeToGet.specified(attributes_to_get))

            # parse key_attributes
            key_attributes = parser.Parser.parse_item_attributes(
                self.action_params[parser.Props.KEY])

            # TODO(dukhlov):
            # it would be nice to validate given table_name, key_attributes and
            # attributes_to_get  to schema expectation

            consistent_read = self.action_params.get(
                parser.Props.CONSISTENT_READ, False)

            return_consumed_capacity = self.action_params.get(
                parser.Props.RETURN_CONSUMED_CAPACITY,
                parser.Values.RETURN_CONSUMED_CAPACITY_NONE)

            # format conditions to get item
            indexed_condition_map = {
                name: [models.IndexedCondition.eq(value)]
                for name, value in key_attributes.iteritems()
            }
        except Exception:
            raise AWSValidationException()

        try:
            # get item
            result = storage.select_item(self.context,
                                         table_name,
                                         indexed_condition_map,
                                         select_type=select_type,
                                         limit=2,
                                         consistent=consistent_read)

            # format response
            if result.count == 0:
                return {}

            assert result.count == 1

            response = {
                parser.Props.ITEM:
                parser.Parser.format_item_attributes(result.items[0])
            }

            if (return_consumed_capacity !=
                    parser.Values.RETURN_CONSUMED_CAPACITY_NONE):
                response[parser.Props.CONSUMED_CAPACITY] = (
                    parser.Parser.format_consumed_capacity(
                        return_consumed_capacity, None))

            return response
        except AWSErrorResponseException as e:
            raise e
        except Exception:
            raise AWSErrorResponseException()
예제 #3
0
    def __call__(self):
        try:
            table_name = self.action_params.get(parser.Props.TABLE_NAME, None)

            # parse expected item conditions
            expected_item_conditions = (
                parser.Parser.parse_expected_attribute_conditions(
                    self.action_params.get(parser.Props.EXPECTED, {})))

            # parse item
            key_attributes = parser.Parser.parse_item_attributes(
                self.action_params[parser.Props.KEY])

            # parse return_values param
            return_values = self.action_params.get(
                parser.Props.RETURN_VALUES, parser.Values.RETURN_VALUES_NONE)

            # parse return_item_collection_metrics
            return_item_collection_metrics = self.action_params.get(
                parser.Props.RETURN_ITEM_COLLECTION_METRICS,
                parser.Values.RETURN_ITEM_COLLECTION_METRICS_NONE)

            return_consumed_capacity = self.action_params.get(
                parser.Props.RETURN_CONSUMED_CAPACITY,
                parser.Values.RETURN_CONSUMED_CAPACITY_NONE)
        except Exception:
            raise AWSValidationException()

        try:
            # put item
            result = storage.delete_item(
                self.context,
                table_name,
                key_attributes,
                expected_condition_map=expected_item_conditions)
        except AWSErrorResponseException as e:
            raise e
        except Exception:
            raise AWSErrorResponseException()

        if not result:
            raise AWSErrorResponseException()

        # format response
        response = {}

        try:
            if return_values != parser.Values.RETURN_VALUES_NONE:
                # TODO(dukhlov):
                # It is needed to return all deleted item attributes
                #
                response[parser.Props.ATTRIBUTES] = (
                    parser.Parser.format_item_attributes(key_attributes))

            if (return_item_collection_metrics !=
                    parser.Values.RETURN_ITEM_COLLECTION_METRICS_NONE):
                response[parser.Props.ITEM_COLLECTION_METRICS] = {
                    parser.Props.ITEM_COLLECTION_KEY: {
                        parser.Parser.format_item_attributes(
                            models.AttributeValue(models.ATTRIBUTE_TYPE_STRING,
                                                  "key"))
                    },
                    parser.Props.SIZE_ESTIMATED_RANGE_GB: [0]
                }

            if (return_consumed_capacity !=
                    parser.Values.RETURN_CONSUMED_CAPACITY_NONE):
                response[parser.Props.CONSUMED_CAPACITY] = (
                    parser.Parser.format_consumed_capacity(
                        return_consumed_capacity, None))

            return response
        except Exception:
            raise exception.AWSErrorResponseException()
예제 #4
0
    def __call__(self):
        try:
            table_name = self.action_params.get(parser.Props.TABLE_NAME, None)

            # parse table attributes
            attribute_definitions = parser.Parser.parse_attribute_definitions(
                self.action_params.get(parser.Props.ATTRIBUTE_DEFINITIONS, {})
            )

            # parse table key schema
            key_attrs = parser.Parser.parse_key_schema(
                self.action_params.get(parser.Props.KEY_SCHEMA, [])
            )

            # parse table indexed field list
            indexed_def_map = parser.Parser.parse_local_secondary_indexes(
                self.action_params.get(
                    parser.Props.LOCAL_SECONDARY_INDEXES, [])
            )

            # prepare table_schema structure
            table_schema = models.TableSchema(
                attribute_definitions, key_attrs, indexed_def_map
            )

        except Exception:
            raise AWSValidationException()

        try:
            # creating table
            table_meta = storage.create_table(
                self.context, table_name, table_schema
            )

            result = {
                parser.Props.TABLE_DESCRIPTION: {
                    parser.Props.ATTRIBUTE_DEFINITIONS: (
                        parser.Parser.format_attribute_definitions(
                            table_meta.schema.attribute_type_map
                        )
                    ),
                    parser.Props.CREATION_DATE_TIME: 0,
                    parser.Props.ITEM_COUNT: 0,
                    parser.Props.KEY_SCHEMA: (
                        parser.Parser.format_key_schema(
                            table_meta.schema.key_attributes
                        )
                    ),
                    parser.Props.PROVISIONED_THROUGHPUT: (
                        parser.Values.PROVISIONED_THROUGHPUT_DUMMY
                    ),
                    parser.Props.TABLE_NAME: table_name,
                    parser.Props.TABLE_STATUS: (
                        parser.Parser.format_table_status(table_meta.status)
                    ),
                    parser.Props.TABLE_SIZE_BYTES: 0
                }
            }

            if table_meta.schema.index_def_map:
                table_def = result[parser.Props.TABLE_DESCRIPTION]
                table_def[parser.Props.LOCAL_SECONDARY_INDEXES] = (
                    parser.Parser.format_local_secondary_indexes(
                        table_meta.schema.key_attributes[0],
                        table_meta.schema.index_def_map
                    )
                )

            return result
        except TableAlreadyExistsException:
            raise AWSDuplicateTableError(table_name)
        except AWSErrorResponseException as e:
            raise e
        except Exception:
            raise AWSErrorResponseException()
예제 #5
0
    def _authorize(self, req, auth_uri):
        # Read request signature and access id.
        # If we find X-Auth-User in the headers we ignore a key error
        # here so that we can use both authentication methods.
        # Returning here just means the user didn't supply AWS
        # authentication and we'll let the app try native keystone next.
        LOG.info(_("Checking AWS credentials.."))

        signature = self._get_signature(req)
        if not signature:
            if 'X-Auth-User' in req.headers:
                return self.application
            elif 'X-Auth-Token' in req.headers:
                return self.application
            else:
                LOG.info(_("No AWS Signature found."))
                raise AWSIncompleteSignatureError()

        access = self._get_access(req)
        if not access:
            if 'X-Auth-User' in req.headers:
                return self.application
            else:
                LOG.info(_("No AWSAccessKeyId/Authorization Credential"))
                raise AWSIncompleteSignatureError()

        LOG.info(_("AWS credentials found, checking against keystone."))

        if not auth_uri:
            LOG.error(
                _("Ec2Token authorization failed, no auth_uri "
                  "specified in config file"))
            raise AWSErrorResponseException(_('Service misconfigured'))
        # Make a copy of args for authentication and signature verification.
        auth_params = dict(req.params)
        # 'Signature' param Not part of authentication args
        auth_params.pop('Signature', None)

        # Authenticate the request.
        # AWS v4 authentication requires a hash of the body
        body_hash = hashlib.sha256(req.body).hexdigest()
        creds = {
            'ec2Credentials': {
                'access': access,
                'signature': signature,
                'host': req.host,
                'verb': req.method,
                'path': req.path,
                'params': auth_params,
                'headers': req.headers,
                'body_hash': body_hash
            }
        }
        creds_json = json.dumps(creds)
        headers = {'Content-Type': 'application/json'}

        keystone_ec2_uri = self._conf_get_keystone_ec2_uri(auth_uri)
        LOG.info(_('Authenticating with %s'), keystone_ec2_uri)
        response = requests.post(keystone_ec2_uri,
                                 data=creds_json,
                                 headers=headers)
        result = response.json()
        try:
            if self._is_v2_token(result):
                token_id = result['access']['token']['id']
                tenant = result['access']['token']['tenant']['name']
                tenant_id = result['access']['token']['tenant']['id']
                metadata = result['access'].get('metadata', {})
                roles = metadata.get('roles', [])
            elif self._is_v3_token(result):
                token_id = response.headers['X-Subject-Token']
                tenant = result['token']['project']['name']
                tenant_id = result['token']['project']['id']
                metadata = result['token']['roles']
                roles = [r['name'] for r in metadata]
            else:
                raise AWSInvalidClientTokenIdError()
            LOG.info(_("AWS authentication successful."))
        except (AttributeError, KeyError):
            LOG.info(_("AWS authentication failure."))
            # Try to extract the reason for failure so we can return the
            # appropriate AWS error via raising an exception
            try:
                reason = result['error']['message']
            except KeyError:
                reason = None

            if reason == "EC2 access key not found.":
                raise AWSInvalidClientTokenIdError()
            elif reason == "EC2 signature not supplied.":
                raise AWSSignatureError()
            else:
                raise AWSAccessDeniedError()

        # Authenticated!
        ec2_creds = {
            'ec2Credentials': {
                'access': access,
                'signature': signature
            }
        }
        req.headers['X-Auth-EC2-Creds'] = json.dumps(ec2_creds)
        req.headers['X-Auth-Token'] = token_id
        req.headers['X-Tenant-Name'] = tenant
        req.headers['X-Tenant-Id'] = tenant_id
        req.headers['X-Auth-URL'] = auth_uri

        req.headers['X-Roles'] = ','.join(roles)

        return self.application
예제 #6
0
    def __call__(self):
        try:
            table_name = self.action_params.get(parser.Props.TABLE_NAME, None)

            # parse select_type
            attributes_to_get = self.action_params.get(
                parser.Props.ATTRIBUTES_TO_GET, None
            )
            if attributes_to_get is not None:
                attributes_to_get = frozenset(attributes_to_get)

            select = self.action_params.get(
                parser.Props.SELECT, None
            )

            index_name = self.action_params.get(parser.Props.INDEX_NAME, None)

            select_type = parser.Parser.parse_select_type(select,
                                                          attributes_to_get,
                                                          index_name)

            # parse exclusive_start_key_attributes
            exclusive_start_key_attributes = self.action_params.get(
                parser.Props.EXCLUSIVE_START_KEY, None
            )
            if exclusive_start_key_attributes is not None:
                exclusive_start_key_attributes = (
                    parser.Parser.parse_item_attributes(
                        exclusive_start_key_attributes
                    )
                )

            # parse indexed_condition_map
            indexed_condition_map = parser.Parser.parse_attribute_conditions(
                self.action_params.get(parser.Props.KEY_CONDITIONS, None)
            )

            # TODO(dukhlov):
            # it would be nice to validate given table_name, key_attributes and
            # attributes_to_get to schema expectation

            consistent_read = self.action_params.get(
                parser.Props.CONSISTENT_READ, False
            )

            limit = self.action_params.get(parser.Props.LIMIT, None)

            return_consumed_capacity = self.action_params.get(
                parser.Props.RETURN_CONSUMED_CAPACITY,
                parser.Values.RETURN_CONSUMED_CAPACITY_NONE
            )

            order_asc = self.action_params.get(
                parser.Props.SCAN_INDEX_FORWARD, None
            )

            order_type = (
                None if order_asc is None else
                models.ORDER_TYPE_ASC if order_asc else
                models.ORDER_TYPE_DESC
            )
        except Exception:
            raise AWSValidationException()

        try:
            # select item
            result = storage.query(
                self.context, table_name, indexed_condition_map,
                select_type=select_type, index_name=index_name, limit=limit,
                consistent=consistent_read, order_type=order_type,
                exclusive_start_key=exclusive_start_key_attributes
            )

            # format response
            if select_type.type == models.SelectType.SELECT_TYPE_COUNT:
                response = {
                    parser.Props.COUNT: result.count
                }
            else:
                response = {
                    parser.Props.COUNT: result.count,
                    parser.Props.ITEMS: [
                        parser.Parser.format_item_attributes(row)
                        for row in result.items
                    ]
                }

            if (return_consumed_capacity !=
                    parser.Values.RETURN_CONSUMED_CAPACITY_NONE):
                response[parser.Props.CONSUMED_CAPACITY] = (
                    parser.Parser.format_consumed_capacity(
                        return_consumed_capacity, None
                    )
                )

            if limit == result.count:
                response[parser.Props.LAST_EVALUATED_KEY] = (
                    parser.Parser.format_item_attributes(
                        result.last_evaluated_key)
                )
            return response
        except AWSErrorResponseException as e:
            raise e
        except Exception:
            raise AWSErrorResponseException()