示例#1
0
文件: dogtag.py 项目: Neetuj/barbican
    def _get_passphrase_for_a_private_key(self, secret_type, secret_metadata,
                                          key_spec):
        """Retrieve the passphrase for the private key stored in the KRA."""
        if secret_type is None:
            return None
        if key_spec.alg is None:
            return None

        passphrase = None
        if DogtagKRAPlugin.PASSPHRASE_KEY_ID in secret_metadata:
            if key_spec.alg.upper() == key.KeyClient.RSA_ALGORITHM:
                passphrase = self.keyclient.retrieve_key(
                    secret_metadata.get(DogtagKRAPlugin.PASSPHRASE_KEY_ID)
                ).data
            else:
                if key_spec.alg.upper() == key.KeyClient.DSA_ALGORITHM:
                    raise sstore.SecretGeneralException(
                        u._("DSA keys should not have a passphrase in the"
                            " database, for being used during retrieval.")
                    )
                raise sstore.SecretGeneralException(
                    u._("Secrets of type {secret_type} should not have a "
                        "passphrase in the database, for being used during "
                        "retrieval.").format(secret_type=secret_type)
                )

        # note that Barbican expects the passphrase to be base64 encoded when
        # stored, so we need to decode it.
        if passphrase:
            passphrase = base64.b64decode(passphrase)
        return passphrase
示例#2
0
    def _validate_content_parameters(self, content_type, content_encoding,
                                     schema_name):
        """Content parameter validator.

        Check that the content_type, content_encoding and the parameters
        that they affect are valid.
        """
        self._assert_validity(
            content_type is not None,
            schema_name,
            u._("If 'payload' is supplied, 'payload_content_type' must also "
                "be supplied."),
            "payload_content_type")

        self._assert_validity(
            mime_types.is_supported(content_type),
            schema_name,
            u._("payload_content_type {supplied} is not one of {supported}"
                ).format(supplied=content_type,
                         supported=mime_types.SUPPORTED),
            "payload_content_type")

        self._assert_validity(
            mime_types.is_content_type_with_encoding_supported(
                content_type,
                content_encoding),
            schema_name,
            u._("payload_content_encoding is not one of {supported}").format(
                supported=mime_types.get_supported_encodings(content_type)),
            "payload_content_encoding")
示例#3
0
文件: dogtag.py 项目: Banno/barbican
    def _create_dto(self, request_status, request_id, error_message, cert):
        dto = None
        if request_status == pki.cert.CertRequestStatus.COMPLETE:
            if cert is not None:
                dto = cm.ResultDTO(cm.CertificateStatus.CERTIFICATE_GENERATED,
                                   certificate=cert.encoded,
                                   intermediates=cert.pkcs7_cert_chain)
            else:
                raise cm.CertificateGeneralException(
                    u._("request_id {req_id} returns COMPLETE but no cert "
                        "returned").format(req_id=request_id))

        elif request_status == pki.cert.CertRequestStatus.REJECTED:
            dto = cm.ResultDTO(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN,
                               status_message=error_message)
        elif request_status == pki.cert.CertRequestStatus.CANCELED:
            dto = cm.ResultDTO(cm.CertificateStatus.REQUEST_CANCELED)
        elif request_status == pki.cert.CertRequestStatus.PENDING:
            dto = cm.ResultDTO(cm.CertificateStatus.WAITING_FOR_CA)
        else:
            raise cm.CertificateGeneralException(
                u._("Invalid request_status {status} for "
                    "request_id {request_id}").format(
                        status=request_status,
                        request_id=request_id)
            )

        return dto
示例#4
0
 def __init__(self, plugin_name=None):
     if plugin_name:
         message = u._('Secret store plugin "{name}"'
                       ' not found.').format(name=plugin_name)
     else:
         message = u._("Secret store plugin not found.")
     super(SecretStorePluginNotFound, self).__init__(message)
示例#5
0
    def on_delete(self, external_project_id, **kwargs):
        """Handles removing a secret reference from an existing container."""

        data = api.load_body(pecan.request, validator=self.validator)

        name = data.get('name')
        secret_ref = data.get('secret_ref')
        secret_id = hrefs.get_secret_id_from_ref(secret_ref)

        secret = self.secret_repo.get(
            entity_id=secret_id,
            external_project_id=external_project_id,
            suppress_exception=True)
        if not secret:
            pecan.abort(404, u._("Secret '{secret_name}' with reference "
                                 "'{secret_ref}' doesn't exist.").format(
                                     secret_name=name, secret_ref=secret_ref))

        found_container_secrets = list(
            filter(lambda cs: cs.secret_id == secret_id and cs.name == name,
                   self.container.container_secrets)
        )

        if not found_container_secrets:
            pecan.abort(404, u._('Secret provided is not in the container'))

        for container_secret in found_container_secrets:
            self.container_secret_repo.delete_entity_by_id(
                container_secret.id, external_project_id)

        pecan.response.status = 204
        LOG.info(u._LI('Deleted container secret for project: %s'),
                 external_project_id)
示例#6
0
    def _validate_pkcs10_data(self, request_data):
        """Confirm that the request_data is valid base64 encoded PKCS#10.

        Base64 decode the request, if it fails raise PayloadDecodingError.
        Then parse data into the ASN.1 structure defined by PKCS10 and
        verify the signing information.
        If parsing of verifying fails, raise InvalidPKCS10Data.
        """
        try:
            csr_pem = base64.b64decode(request_data)
        except Exception:
            raise exception.PayloadDecodingError()

        try:
            csr = crypto.load_certificate_request(crypto.FILETYPE_PEM,
                                                  csr_pem)
        except Exception:
            reason = u._("Bad format")
            raise exception.InvalidPKCS10Data(reason=reason)

        try:
            pubkey = csr.get_pubkey()
            csr.verify(pubkey)
        except Exception:
            reason = u._("Signing key incorrect")
            raise exception.InvalidPKCS10Data(reason=reason)
示例#7
0
 def test_should_have_expected_defaults(self):
     self.assertEqual(
         common.RetryTasks.NO_ACTION_REQUIRED, self.target.retry_task)
     self.assertEqual(u._('Unknown'), self.target.status)
     self.assertEqual(u._('Unknown'), self.target.status_message)
     self.assertEqual(common.RETRY_MSEC_DEFAULT, self.target.retry_msec)
     self.assertFalse(self.target.is_follow_on_needed())
示例#8
0
def validate_stored_key_rsa_container(project_id, container_ref, req):
        try:
            container_id = hrefs.get_container_id_from_ref(container_ref)
        except Exception:
            reason = u._("Bad Container Reference {ref}").format(
                ref=container_ref
            )
            raise exception.InvalidContainer(reason=reason)

        container_repo = repo.get_container_repository()

        container = container_repo.get_container_by_id(entity_id=container_id,
                                                       suppress_exception=True)
        if not container:
            reason = u._("Container Not Found")
            raise exception.InvalidContainer(reason=reason)

        if container.type != 'rsa':
            reason = u._("Container Wrong Type")
            raise exception.InvalidContainer(reason=reason)

        ctxt = controllers._get_barbican_context(req)
        inst = controllers.containers.ContainerController(container)
        controllers._do_enforce_rbac(inst, req,
                                     controllers.containers.CONTAINER_GET,
                                     ctxt)
示例#9
0
    def __init__(self, conf=CONF):
        self.username = conf.symantec_plugin.username
        self.password = conf.symantec_plugin.password
        self.partnercode = conf.symantec_plugin.partnercode
        self.testmode = conf.symantec_plugin.testmode

        if self.username == None:
            raise ValueError(u._("username is required"))

        if self.password == None:
            raise ValueError(u._("password is required"))

        if self.partnercode == None:
            raise ValueError(u._("partnercode is required"))

        if self.testmode == None:
            raise ValueError(u._("testmode is required"))

        # We can't read booleans off the config file.
        # This means we need to treat them as a string.
        testmode = False
        if self.testmode.lower() == 'true':
            testmode = True
        # Create and configure the Symantec API plugin
        self.api = SymAPI(useTestAPI = testmode, verbose=False)
        self.api.setCredentials(self.partnercode, self.username, self.password)
示例#10
0
def load_body(req, resp=None, validator=None):
    """Helper function for loading an HTTP request body from JSON.

    This body is placed into into a Python dictionary.

    :param req: The HTTP request instance to load the body from.
    :param resp: The HTTP response instance.
    :param validator: The JSON validator to enforce.
    :return: A dict of values from the JSON request.
    """
    try:
        body = req.body_file.read(CONF.max_allowed_request_size_in_bytes)
        req.body_file.seek(0)
    except IOError:
        LOG.exception(u._LE("Problem reading request JSON stream."))
        pecan.abort(500, u._('Read Error'))

    try:
        # TODO(jwood): Investigate how to get UTF8 format via openstack
        # jsonutils:
        #     parsed_body = json.loads(raw_json, 'utf-8')
        parsed_body = json.loads(body)
        strip_whitespace(parsed_body)
    except ValueError:
        LOG.exception(u._LE("Problem loading request JSON."))
        pecan.abort(400, u._('Malformed JSON'))

    if validator:
        try:
            parsed_body = validator.validate(parsed_body)
        except exception.BarbicanHTTPException as e:
            LOG.exception(e.message)
            pecan.abort(e.status_code, e.client_message)

    return parsed_body
示例#11
0
 def __init__(self, *args, **kwargs):
     self.invalid_property = kwargs.get('property')
     self.message = u._("Failed to validate JSON information: ")
     self.client_message = u._("Provided object does not match "
                               "schema '{schema}': "
                               "{reason}").format(*args, **kwargs)
     self.message = self.message + self.client_message
     super(InvalidObject, self).__init__(*args, **kwargs)
示例#12
0
 def __init__(self, plugin_name=None):
     if plugin_name:
         message = u._(
             'Certificate event plugin "{name}" '
             'not found.').format(name=plugin_name)
     else:
         message = u._("Certificate event plugin not found.")
     super(CertificateEventPluginNotFound, self).__init__(message)
示例#13
0
 def __init__(self, content_type):
     super(SecretContentTypeNotSupportedException, self).__init__(
         u._("A Content-Type of '{content_type}' for secrets is "
             "not supported").format(
                 content_type=content_type)
     )
     self.content_type = content_type
     self.client_message = u._(
         "content-type of '{content_type}' not supported").format(
             content_type=content_type)
示例#14
0
 def __init__(self, content_encoding):
     super(SecretContentEncodingNotSupportedException, self).__init__(
         u._("Secret Content-Encoding of '{content_encoding}' "
             "not supported").format(
                 content_encoding=content_encoding)
     )
     self.content_encoding = content_encoding
     self.client_message = u._(
         "content-encoding of '{content_encoding}' not supported").format(
             content_encoding=content_encoding)
示例#15
0
    def __init__(self, occurrence):
        msg = None
        if occurrence > 1:
            msg = u._("There are {count} plugins with global default as "
                      "True in service configuration. Only one plugin can have"
                      " this as True").format(count=occurrence)
        else:
            msg = u._("There is no plugin defined with global default as True."
                      " One of plugin must be identified as global default")

        super(MultipleStoreIncorrectGlobalDefault, self).__init__(msg)
示例#16
0
    def validate(self, json_data, parent_schema=None):
        schema_name = self._full_name(parent_schema)

        self._assert_schema_is_valid(json_data, schema_name)

        container_type = json_data.get('type')
        secret_refs = json_data.get('secret_refs')

        if not secret_refs:
            return json_data

        secret_refs_names = set(secret_ref.get('name', '')
                                for secret_ref in secret_refs)

        self._assert_validity(
            len(secret_refs_names) == len(secret_refs),
            schema_name,
            u._("Duplicate reference names are not allowed"),
            "secret_refs")

        # The combination of container_id and secret_id is expected to be
        # primary key for container_secret so same secret id (ref) cannot be
        # used within a container
        secret_ids = set(self._get_secret_id_from_ref(secret_ref)
                         for secret_ref in secret_refs)

        self._assert_validity(
            len(secret_ids) == len(secret_refs),
            schema_name,
            u._("Duplicate secret ids are not allowed"),
            "secret_refs")

        # Ensure that our secret refs are valid relative to our config, no
        # spoofing allowed!
        configured_host_href = CONF.host_href
        for secret_ref in secret_refs:
            if configured_host_href not in secret_ref.get('secret_ref'):
                raise exception.UnsupportedField(
                    field='secret_ref',
                    schema=schema_name,
                    reason=u._(
                        "Secret_ref does not match the configured hostname, "
                        "please try again"
                    )
                )

        if container_type == 'rsa':
            self._validate_rsa(secret_refs_names, schema_name)
        elif container_type == 'certificate':
            self._validate_certificate(secret_refs_names, schema_name)

        return json_data
示例#17
0
    def __init__(self, conf=CONF):
        self.username = conf.symantec_plugin.username
        self.password = conf.symantec_plugin.password
        self.url = conf.symantec_plugin.url

        if self.username == None:
            raise ValueError(u._("username is required"))

        if self.password == None:
            raise ValueError(u._("password is required"))

        if self.url == None:
            raise ValueError(u._("url is required"))
示例#18
0
    def _validate_meta_parameters(self, meta, order_type, schema_name):
        self._assert_validity(meta.get('algorithm'),
                              schema_name,
                              u._("'algorithm' is required field "
                                  "for {0} type order").format(order_type),
                              "meta")

        self._assert_validity(meta.get('bit_length'),
                              schema_name,
                              u._("'bit_length' is required field "
                                  "for {0} type order").format(order_type),
                              "meta")

        self._validate_bit_length(meta, schema_name)
示例#19
0
    def validate(self, json_data, parent_schema=None):
        schema_name = self._full_name(parent_schema)

        self._assert_schema_is_valid(json_data, schema_name)

        plugin_name = json_data.get("plugin_name", "").strip()
        self._assert_validity(plugin_name, schema_name, u._("plugin_name must be provided"), "plugin_name")
        json_data["plugin_name"] = plugin_name

        transport_key = json_data.get("transport_key", "").strip()
        self._assert_validity(transport_key, schema_name, u._("transport_key must be provided"), "transport_key")
        json_data["transport_key"] = transport_key

        return json_data
示例#20
0
    def _validate_bit_length(self, meta, schema_name):

        bit_length = int(meta.get("bit_length", 0))
        if bit_length <= 0:
            raise exception.UnsupportedField(
                field="bit_length",
                schema=schema_name,
                reason=u._("Must have " "non-zero positive" " bit_length to" " generate secret"),
            )
        if bit_length % 8 != 0:
            raise exception.UnsupportedField(
                field="bit_length",
                schema=schema_name,
                reason=u._("Must be a" " positive integer" " that is a" " multiple of 8"),
            )
示例#21
0
    def generate_asymmetric_key(self, key_spec):
        """Generate an asymmetric key pair.

        Creates KMIP attribute objects based on the given KeySpec to send to
        the server. The KMIP Secret Store currently does not support
        protecting the private key with a passphrase.

        :param key_spec: KeySpec with asymmetric algorithm and bit_length
        :returns: AsymmetricKeyMetadataDTO with the key UUIDs
        :raises: SecretGeneralException, SecretAlgorithmNotSupportedException
        """
        LOG.debug("Starting asymmetric key generation with KMIP plugin")
        if not self.generate_supports(key_spec):
            raise ss.SecretAlgorithmNotSupportedException(
                key_spec.alg)

        if key_spec.alg.lower() not in ss.KeyAlgorithm.ASYMMETRIC_ALGORITHMS:
            raise KMIPSecretStoreError(
                u._("An unsupported algorithm {algorithm} was passed to "
                    "the 'generate_asymmetric_key' method").format(
                        algorithm=key_spec.alg))

        if key_spec.passphrase:
            raise KMIPSecretStoreError(
                u._('KMIP plugin does not currently support protecting the '
                    'private key with a passphrase'))

        algorithm = self._get_kmip_algorithm(key_spec.alg.lower())
        length = key_spec.bit_length

        try:
            with self.client:
                LOG.debug("Opened connection to KMIP client for asymmetric " +
                          "secret generation")
                public_uuid, private_uuid = self.client.create_key_pair(
                    algorithm, length)
                LOG.debug("SUCCESS: Asymmetric key pair generated with "
                          "public key uuid: %s and private key uuid: %s",
                          public_uuid, private_uuid)
                private_key_metadata = {KMIPSecretStore.KEY_UUID: private_uuid}
                public_key_metadata = {KMIPSecretStore.KEY_UUID: public_uuid}
                passphrase_metadata = None
                return ss.AsymmetricKeyMetadataDTO(private_key_metadata,
                                                   public_key_metadata,
                                                   passphrase_metadata)
        except Exception as e:
            LOG.exception(u._LE("Error opening or writing to client"))
            raise ss.SecretGeneralException(str(e))
示例#22
0
    def issue_certificate_request(self, order_id, order_meta, plugin_meta,
                                  barbican_meta_dto):
        if barbican_meta_dto.generated_csr is not None:
            encoded_csr = barbican_meta_dto.generated_csr
        else:
            try:
                encoded_csr = base64.b64decode(order_meta['request_data'])
            except KeyError:
                return cert_manager.ResultDTO(
                    cert_manager.CertificateStatus.CLIENT_DATA_ISSUE_SEEN,
                    status_message=u._("No request_data specified"))
        csr = crypto.load_certificate_request(crypto.FILETYPE_PEM, encoded_csr)

        ca_id = barbican_meta_dto.plugin_ca_id
        if ca_id:
            ca = self.cas.get(ca_id)
            if ca is None:
                raise cert_manager.CertificateGeneralException(
                    "Invalid ca_id passed into snake oil plugin:" + ca_id)
        else:
            ca = self.ca

        cert_mgr = CertManager(ca)
        cert = cert_mgr.make_certificate(csr)
        cert_enc = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)

        return cert_manager.ResultDTO(
            cert_manager.CertificateStatus.CERTIFICATE_GENERATED,
            certificate=base64.b64encode(cert_enc),
            intermediates=base64.b64encode(ca.pkcs7))
示例#23
0
文件: dogtag.py 项目: Neetuj/barbican
    def _issue_custom_certificate_request(self, order_id, order_meta,
                                          plugin_meta, barbican_meta_dto):
        """Issue a custom certificate request to Dogtag CA

        :param order_id: ID of the order associated with this request
        :param order_meta: dict containing all the inputs required for a
            particular profile.  One of these must be the profile_id.
            The exact fields (both optional and mandatory) depend on the
            profile, but they will be exposed to the user in a method to
            expose syntax.  Depending on the profile, only the relevant fields
            will be populated in the request.  All others will be ignored.
        :param plugin_meta: Used to store data for status check.
        :param barbican_meta_dto: Extra data to aid in processing.
        :return: cm.ResultDTO
        """
        profile_id = order_meta.get(self.PROFILE_ID, None)
        if not profile_id:
            return cm.ResultDTO(
                cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN,
                status_message=u._("No profile_id specified"))

        # we expect the csr to be base64 encoded PEM data.  Dogtag CA expects
        # PEM data though so we need to decode it.
        updated_meta = copy.deepcopy(order_meta)
        if 'cert_request' in updated_meta:
            updated_meta['cert_request'] = base64.b64decode(
                updated_meta['cert_request'])

        return self._issue_certificate_request(
            profile_id, updated_meta, plugin_meta, barbican_meta_dto)
示例#24
0
文件: dogtag.py 项目: Neetuj/barbican
    def modify_certificate_request(self, order_id, order_meta, plugin_meta,
                                   barbican_meta_dto):
        """Modify a certificate request.

        Once a certificate request is generated, it cannot be modified.
        The only alternative is to cancel the request (if it has not already
        completed) and attempt a fresh enrolment.  That is what will be
        attempted here.
        :param order_id: ID for this order
        :param order_meta: order metadata.  It is assumed that the newly
            modified request data will be present here.
        :param plugin_meta: data stored on behalf of the plugin for further
            operations
        :param barbican_meta_dto: additional data needed to process order.
        :return: ResultDTO:
        """
        result_dto = self.cancel_certificate_request(
            order_id, order_meta, plugin_meta, barbican_meta_dto)

        if result_dto.status == cm.CertificateStatus.REQUEST_CANCELED:
            return self.issue_certificate_request(
                order_id, order_meta, plugin_meta, barbican_meta_dto)
        elif result_dto.status == cm.CertificateStatus.INVALID_OPERATION:
            return cm.ResultDTO(
                cm.CertificateStatus.INVALID_OPERATION,
                status_message=u._(
                    "Modify request: unable to cancel: "
                    "{message}").format(message=result_dto.status_message)
            )
        else:
            # other status (ca_unavailable, client_data_issue)
            # return result from cancel operation
            return result_dto
示例#25
0
文件: dogtag.py 项目: Neetuj/barbican
    def _process_auto_enrollment_results(self, enrollment_results,
                                         plugin_meta, barbican_meta_dto):
        """Process results received from Dogtag CA for auto-enrollment

        This processes data from enroll_cert, which submits, approves and
        gets the cert issued and returns as a list of CertEnrollment objects.

        :param enrollment_results: list of CertEnrollmentResult objects
        :param plugin_meta: metadata dict for storing plugin specific data
        :param barbican_meta_dto: object containing extra data to help process
               the request
        :return: cm.ResultDTO
        """

        # Although it is possible to create multiple certs in an invocation
        # of enroll_cert, Barbican cannot handle this case.  Assume
        # only once cert and request generated for now.
        enrollment_result = enrollment_results[0]
        request = enrollment_result.request
        if not request:
            raise cm.CertificateGeneralException(
                u._("No request returned in enrollment_results"))

        # store the request_id in the plugin metadata
        plugin_meta[self.REQUEST_ID] = request.request_id

        cert = enrollment_result.cert

        return self._create_dto(request.request_status,
                                request.request_id,
                                request.error_message,
                                cert)
示例#26
0
文件: dogtag.py 项目: Neetuj/barbican
    def cancel_certificate_request(self, order_id, order_meta, plugin_meta,
                                   barbican_meta_dto):
        """Cancel a certificate request.

        :param order_id: ID for the order associated with this request
        :param order_meta: order metadata fdr this request
        :param plugin_meta: data stored by plugin for further processing.
            In particular, the request_id
        :param barbican_meta_dto: additional data needed to process order.
        :return: cm.ResultDTO:
        """
        request_id = self._get_request_id(order_id, plugin_meta, "cancelling")

        try:
            review_response = self.certclient.review_request(request_id)
            self.certclient.cancel_request(request_id, review_response)

            return cm.ResultDTO(cm.CertificateStatus.REQUEST_CANCELED)
        except pki.RequestNotFoundException:
            return cm.ResultDTO(
                cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN,
                status_message=u._("no request found for this order"))
        except pki.ConflictingOperationException as e:
            return cm.ResultDTO(
                cm.CertificateStatus.INVALID_OPERATION,
                status_message=e.message)
示例#27
0
    def on_put(self, external_project_id, **kwargs):
        if (not pecan.request.content_type or
                pecan.request.content_type == 'application/json'):
            pecan.abort(
                415,
                u._("Content-Type of '{content_type}' is not supported for "
                    "PUT.").format(content_type=pecan.request.content_type)
            )

        transport_key_id = kwargs.get('transport_key_id')

        payload = pecan.request.body
        if not payload:
            raise exception.NoDataToProcess()
        if validators.secret_too_big(payload):
            raise exception.LimitExceeded()

        if self.secret.encrypted_data or self.secret.secret_store_metadata:
            _secret_already_has_data()

        project_model = res.get_or_create_project(external_project_id)
        content_type = pecan.request.content_type
        content_encoding = pecan.request.headers.get('Content-Encoding')

        plugin.store_secret(
            unencrypted_raw=payload,
            content_type_raw=content_type,
            content_encoding=content_encoding,
            secret_model=self.secret,
            project_model=project_model,
            transport_key_id=transport_key_id)
        LOG.info(u._LI('Updated secret for project: %s'), external_project_id)
示例#28
0
    def handle_order(self, order):
        """Handle checking the status of a certificate order.

        :param order: Order to process.
        :return: None if no follow on processing is needed for this task,
                 otherwise a :class:`FollowOnProcessingStatusDTO` instance
                 with information on how to process this task into the future.
        """
        result_follow_on = common.FollowOnProcessingStatusDTO()

        order_info = order.to_dict_fields()
        order_type = order_info.get('type')

        # Retrieve the project.
        project = self.project_repo.get(order.project_id)

        if order_type != models.OrderType.CERTIFICATE:
            raise NotImplementedError(
                u._('Order type "{order_type}" not supported.').format(
                    order_type=order_type))

        # Request a certificate
        new_container = cert.check_certificate_request(
            order, project, result_follow_on)
        if new_container:
            order.container_id = new_container.id
        LOG.debug("...done checking status of a certificate order.")

        return result_follow_on
示例#29
0
def _setup_nss_db_services(conf):
    """Sets up NSS Crypto functions

    This sets up the NSSCryptoProvider and the database it needs for it to
    store certificates. If the path specified in the configuration is already
    existent, it will assume that the database is already setup.

    This will also import the transport cert needed by the KRA if the NSS DB
    was created.
    """
    nss_db_path, nss_password = (conf.dogtag_plugin.nss_db_path,
                                 conf.dogtag_plugin.nss_password)
    if nss_db_path is None:
        LOG.warning(u._LW("nss_db_path was not provided so the crypto "
                          "provider functions were not initialized."))
        return None
    if nss_password is None:
        raise ValueError(u._("nss_password is required"))

    nss_db_created = _create_nss_db_if_needed(nss_db_path, nss_password)
    crypto = cryptoutil.NSSCryptoProvider(nss_db_path, nss_password)
    if nss_db_created:
        _import_kra_transport_cert_to_nss_db(conf, crypto)

    return crypto
示例#30
0
    def _build_attributes(self, attrs):
        attributes = self.ffi.new("CK_ATTRIBUTE[{0}]".format(len(attrs)))
        val_list = []
        for index, attr in enumerate(attrs):
            attributes[index].type = attr.type
            if isinstance(attr.value, bool):
                val_list.append(self.ffi.new("unsigned char *",
                                int(attr.value)))
                attributes[index].value_len = 1  # sizeof(char) is 1
            elif isinstance(attr.value, int):
                # second because bools are also considered ints
                val_list.append(self.ffi.new("CK_ULONG *", attr.value))
                attributes[index].value_len = 8
            elif isinstance(attr.value, str):
                buf = attr.value.encode('utf-8')
                val_list.append(self.ffi.new("char []", buf))
                attributes[index].value_len = len(buf)
            elif isinstance(attr.value, bytes):
                val_list.append(self.ffi.new("char []", attr.value))
                attributes[index].value_len = len(attr.value)
            else:
                raise TypeError(u._("Unknown attribute type provided."))

            attributes[index].value = val_list[-1]

        return CKAttributes(attributes, val_list)
示例#31
0
def _cant_remove_preferred_ca_from_project():
    pecan.abort(
        409,
        u._('Please change the preferred CA to a different project CA '
            'before removing it.'))
示例#32
0
class CertificateAuthorityController(controllers.ACLMixin):
    """Handles certificate authority retrieval requests."""
    def __init__(self, ca):
        LOG.debug('=== Creating CertificateAuthorityController ===')
        self.ca = ca
        self.ca_repo = repo.get_ca_repository()
        self.project_ca_repo = repo.get_project_ca_repository()
        self.preferred_ca_repo = repo.get_preferred_ca_repository()
        self.project_repo = repo.get_project_repository()

    def __getattr__(self, name):
        route_table = {
            'add-to-project': self.add_to_project,
            'remove-from-project': self.remove_from_project,
            'set-global-preferred': self.set_global_preferred,
            'set-preferred': self.set_preferred,
        }
        if name in route_table:
            return route_table[name]
        raise AttributeError

    @pecan.expose()
    def _lookup(self, attribute, *remainder):
        _certificate_authority_attribute_not_found()

    @pecan.expose(generic=True)
    def index(self, **kwargs):
        pecan.abort(405)  # HTTP 405 Method Not Allowed as default

    @index.when(method='GET', template='json')
    @controllers.handle_exceptions(u._('Certificate Authority retrieval'))
    @controllers.enforce_rbac('certificate_authority:get')
    def on_get(self, external_project_id):
        LOG.debug("== Getting certificate authority for %s", self.ca.id)
        return self.ca.to_dict_fields()

    @pecan.expose()
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('CA Signing Cert retrieval'))
    @controllers.enforce_rbac('certificate_authority:get_cacert')
    def cacert(self, external_project_id):
        LOG.debug("== Getting signing cert for %s", self.ca.id)
        cacert = self.ca.ca_meta['ca_signing_certificate'].value
        return cacert

    @pecan.expose()
    @controllers.handle_exceptions(u._('CA Cert Chain retrieval'))
    @controllers.enforce_rbac('certificate_authority:get_ca_cert_chain')
    def intermediates(self, external_project_id):
        LOG.debug("== Getting CA Cert Chain for %s", self.ca.id)
        cert_chain = self.ca.ca_meta['intermediates'].value
        return cert_chain

    @pecan.expose(template='json')
    @controllers.handle_exceptions(u._('CA projects retrieval'))
    @controllers.enforce_rbac('certificate_authority:get_projects')
    def projects(self, external_project_id):
        LOG.debug("== Getting Projects for %s", self.ca.id)
        project_cas = self.ca.project_cas
        if not project_cas:
            ca_projects_resp = {'projects': []}
        else:
            project_list = []
            for p in project_cas:
                project_list.append(p.project.external_id)

            ca_projects_resp = {'projects': project_list}

        return ca_projects_resp

    @pecan.expose()
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('Add CA to project'))
    @controllers.enforce_rbac('certificate_authority:add_to_project')
    def add_to_project(self, external_project_id):
        if pecan.request.method != 'POST':
            pecan.abort(405)

        LOG.debug("== Saving CA %s to external_project_id %s", self.ca.id,
                  external_project_id)
        project_model = res.get_or_create_project(external_project_id)

        # CA must be a base CA or a subCA owned by this project
        if (self.ca.project_id is not None
                and self.ca.project_id != project_model.id):
            raise excep.UnauthorizedSubCA()

        project_cas = project_model.cas
        num_cas = len(project_cas)
        for project_ca in project_cas:
            if project_ca.ca_id == self.ca.id:
                # project already added
                return

        project_ca = models.ProjectCertificateAuthority(
            project_model.id, self.ca.id)
        self.project_ca_repo.create_from(project_ca)

        if num_cas == 0:
            # set first project CA to be the preferred one
            preferred_ca = models.PreferredCertificateAuthority(
                project_model.id, self.ca.id)
            self.preferred_ca_repo.create_from(preferred_ca)

    @pecan.expose()
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('Remove CA from project'))
    @controllers.enforce_rbac('certificate_authority:remove_from_project')
    def remove_from_project(self, external_project_id):
        if pecan.request.method != 'POST':
            pecan.abort(405)

        LOG.debug("== Removing CA %s from project_external_id %s", self.ca.id,
                  external_project_id)

        project_model = res.get_or_create_project(external_project_id)
        (project_ca, __offset, __limit,
         __total) = (self.project_ca_repo.get_by_create_date(
             project_id=project_model.id,
             ca_id=self.ca.id,
             suppress_exception=True))

        if project_ca:
            self._do_remove_from_project(project_ca[0])
        else:
            _ca_not_in_project()

    def _do_remove_from_project(self, project_ca):
        project_id = project_ca.project_id
        ca_id = project_ca.ca_id
        preferred_ca = self.preferred_ca_repo.get_project_entities(
            project_id)[0]
        if cert_resources.is_last_project_ca(project_id):
            self.preferred_ca_repo.delete_entity_by_id(preferred_ca.id, None)
        else:
            self._assert_is_not_preferred_ca(preferred_ca.ca_id, ca_id)

        self.project_ca_repo.delete_entity_by_id(project_ca.id, None)

    def _assert_is_not_preferred_ca(self, preferred_ca_id, ca_id):
        if preferred_ca_id == ca_id:
            _cant_remove_preferred_ca_from_project()

    @pecan.expose()
    @controllers.handle_exceptions(u._('Set preferred project CA'))
    @controllers.enforce_rbac('certificate_authority:set_preferred')
    def set_preferred(self, external_project_id):
        if pecan.request.method != 'POST':
            pecan.abort(405)

        LOG.debug("== Setting preferred CA %s for project %s", self.ca.id,
                  external_project_id)

        project_model = res.get_or_create_project(external_project_id)

        (project_ca, __offset, __limit,
         __total) = (self.project_ca_repo.get_by_create_date(
             project_id=project_model.id,
             ca_id=self.ca.id,
             suppress_exception=True))
        if not project_ca:
            _requested_preferred_ca_not_a_project_ca()

        self.preferred_ca_repo.create_or_update_by_project_id(
            project_model.id, self.ca.id)

    @pecan.expose()
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('Set global preferred CA'))
    @controllers.enforce_rbac('certificate_authority:set_global_preferred')
    def set_global_preferred(self, external_project_id):
        if pecan.request.method != 'POST':
            pecan.abort(405)

        LOG.debug("== Set global preferred CA %s", self.ca.id)
        project = res.get_or_create_global_preferred_project()
        self.preferred_ca_repo.create_or_update_by_project_id(
            project.id, self.ca.id)

    @index.when(method='DELETE')
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('CA deletion'))
    @controllers.enforce_rbac('certificate_authority:delete')
    def on_delete(self, external_project_id, **kwargs):
        cert_resources.delete_subordinate_ca(external_project_id, self.ca)
        LOG.info(u._LI('Deleted CA for project: %s'), external_project_id)
示例#33
0
def _secret_not_in_order():
    """Throw exception that secret info is not available in the order."""
    pecan.abort(400, u._("Secret metadata expected but not received."))
示例#34
0
def order_cannot_modify_order_type():
    """Throw exception that order type cannot be modified."""
    pecan.abort(400, u._("Cannot modify order type."))
示例#35
0
 def __init__(self):
     super(SecretNoPayloadProvidedException, self).__init__(
         u._('No secret information provided to encrypt.')
     )
示例#36
0
def _certificate_authority_attribute_not_found():
    """Throw exception indicating CA attribute was not found."""
    pecan.abort(404, u._('Not Found. CA attribute not found.'))
示例#37
0
def _secret_metadata_not_found():
    """Throw exception indicating secret metadata not found."""
    pecan.abort(404, u._('Not Found. Sorry but your secret metadata is in '
                         'another castle.'))
示例#38
0
class SecretMetadataController(controllers.ACLMixin):
    """Handles SecretMetadata requests by a given secret id."""

    def __init__(self, secret):
        LOG.debug('=== Creating SecretMetadataController ===')
        self.secret = secret
        self.secret_project_id = self.secret.project.external_id
        self.secret_repo = repo.get_secret_repository()
        self.user_meta_repo = repo.get_secret_user_meta_repository()
        self.metadata_validator = validators.NewSecretMetadataValidator()
        self.metadatum_validator = validators.NewSecretMetadatumValidator()

    @pecan.expose(generic=True)
    def index(self, **kwargs):
        pecan.abort(405)  # HTTP 405 Method Not Allowed as default

    @index.when(method='GET', template='json')
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('Secret metadata retrieval'))
    @controllers.enforce_rbac('secret_meta:get')
    def on_get(self, external_project_id, **kwargs):
        """Handles retrieval of existing secret metadata requests."""

        LOG.debug(u._('Start secret metadata on_get '
                      'for secret-ID %s:'), self.secret.id)

        resp = self.user_meta_repo.get_metadata_for_secret(self.secret.id)
        pecan.response.status = 200

        return {"metadata": resp}

    @index.when(method='PUT', template='json')
    @controllers.handle_exceptions(u._('Secret metadata creation'))
    @controllers.enforce_rbac('secret_meta:put')
    @controllers.enforce_content_types(['application/json'])
    def on_put(self, external_project_id, **kwargs):
        """Handles creation/update of secret metadata."""
        data = api.load_body(pecan.request, validator=self.metadata_validator)
        LOG.debug(u._('Start secret metadata on_put...%s'), data)

        self.user_meta_repo.create_replace_user_metadata(self.secret.id,
                                                         data)

        url = hrefs.convert_user_meta_to_href(self.secret.id)
        LOG.debug(u._('URI to secret metadata is %s'), url)

        pecan.response.status = 201
        return {'metadata_ref': url}

    @index.when(method='POST', template='json')
    @controllers.handle_exceptions(u._('Secret metadatum creation'))
    @controllers.enforce_rbac('secret_meta:post')
    @controllers.enforce_content_types(['application/json'])
    def on_post(self, external_project_id, **kwargs):
        """Handles creation of secret metadatum."""

        data = api.load_body(pecan.request, validator=self.metadatum_validator)

        key = data.get('key')
        value = data.get('value')

        metadata = self.user_meta_repo.get_metadata_for_secret(self.secret.id)
        if key in metadata:
            pecan.abort(409, u._('Conflict. Key in request is already in the '
                                 'secret metadata'))

        LOG.debug(u._('Start secret metadatum on_post...%s'), metadata)
        self.user_meta_repo.create_replace_user_metadatum(self.secret.id,
                                                          key, value)

        url = hrefs.convert_user_meta_to_href(self.secret.id)
        LOG.debug(u._('URI to secret metadata is %s'), url)

        pecan.response.status = 201
        return {'metadata_ref': url + "/%s {key: %s, value:%s}" % (key,
                                                                   key,
                                                                   value)}
示例#39
0
from requests import exceptions as request_exceptions
from symantecssl.core import Symantec
from symantecssl import exceptions as symantec_exceptions

from barbican.common import config
from barbican import i18n as u
from barbican.plugin.interface import certificate_manager as cert

CONF = config.new_config()

symantec_plugin_group = cfg.OptGroup(name='symantec_plugin',
                                     title='Symantec Plugin Options')

symantec_plugin_opts = [
    cfg.StrOpt('username',
               help=u._('Symantec username for authentication')),
    cfg.StrOpt('password',
               help=u._('Symantec password for authentication'),
               secret=True),
    cfg.StrOpt('url',
               help=u._('Domain of Symantec API'))
]

CONF.register_group(symantec_plugin_group)
CONF.register_opts(symantec_plugin_opts, group=symantec_plugin_group)
config.parse_args(CONF)


class SymantecCertificatePlugin(cert.CertificatePluginBase):
    """Symantec certificate plugin."""
示例#40
0
from oslo_config import cfg
from requests import exceptions as request_exceptions
from symantecssl.core import Symantec
from symantecssl import exceptions as symantec_exceptions

from barbican.common import config
from barbican import i18n as u
from barbican.plugin.interface import certificate_manager as cert

CONF = config.new_config()

symantec_plugin_group = cfg.OptGroup(name='symantec_plugin',
                                     title='Symantec Plugin Options')

symantec_plugin_opts = [
    cfg.StrOpt('username', help=u._('Symantec username for authentication')),
    cfg.StrOpt('password', help=u._('Symantec password for authentication')),
    cfg.StrOpt('url', help=u._('Domain of Symantec API'))
]

CONF.register_group(symantec_plugin_group)
CONF.register_opts(symantec_plugin_opts, group=symantec_plugin_group)
config.parse_args(CONF)


class SymantecCertificatePlugin(cert.CertificatePluginBase):
    """Symantec certificate plugin."""
    def __init__(self, conf=CONF):
        self.username = conf.symantec_plugin.username
        self.password = conf.symantec_plugin.password
        self.url = conf.symantec_plugin.url
示例#41
0
def modify_certificate_request(order_model, updated_meta):
    """Update the order with CA."""
    # TODO(chellygel): Add the modify certificate request logic.
    LOG.debug(u._('in modify_certificate_request'))
    raise NotImplementedError  # pragma: no cover
示例#42
0
class OrdersController(controllers.ACLMixin):
    """Handles Order requests for Secret creation."""
    def __init__(self, queue_resource=None):

        LOG.debug('Creating OrdersController')
        self.order_repo = repo.get_order_repository()
        self.queue = queue_resource or async_client.TaskClient()
        self.type_order_validator = validators.TypeOrderValidator()
        self.quota_enforcer = quota.QuotaEnforcer('orders', self.order_repo)

    @pecan.expose()
    def _lookup(self, order_id, *remainder):
        # NOTE(jaosorior): It's worth noting that even though this section
        # actually does a lookup in the database regardless of the RBAC policy
        # check, the execution only gets here if authentication of the user was
        # previously successful.

        ctx = controllers._get_barbican_context(pecan.request)

        order = self.order_repo.get(entity_id=order_id,
                                    external_project_id=ctx.project,
                                    suppress_exception=True)
        if not order:
            _order_not_found()

        return OrderController(order, self.order_repo), remainder

    @pecan.expose(generic=True)
    def index(self, **kwargs):
        pecan.abort(405)  # HTTP 405 Method Not Allowed as default

    @index.when(method='GET', template='json')
    @controllers.handle_exceptions(u._('Order(s) retrieval'))
    @controllers.enforce_rbac('orders:get')
    def on_get(self, external_project_id, **kw):
        LOG.debug('Start orders on_get '
                  'for project-ID %s:', external_project_id)

        result = self.order_repo.get_by_create_date(
            external_project_id,
            offset_arg=kw.get('offset', 0),
            limit_arg=kw.get('limit', None),
            meta_arg=kw.get('meta', None),
            suppress_exception=True)
        orders, offset, limit, total = result

        if not orders:
            orders_resp_overall = {'orders': [], 'total': total}
        else:
            orders_resp = [
                hrefs.convert_to_hrefs(o.to_dict_fields()) for o in orders
            ]
            orders_resp_overall = hrefs.add_nav_hrefs('orders', offset, limit,
                                                      total,
                                                      {'orders': orders_resp})
            orders_resp_overall.update({'total': total})

        return orders_resp_overall

    @index.when(method='PUT', template='json')
    @controllers.handle_exceptions(u._('Order update'))
    @controllers.enforce_rbac('orders:put')
    def on_put(self, external_project_id, **kwargs):
        _order_update_not_supported()

    @index.when(method='POST', template='json')
    @controllers.handle_exceptions(u._('Order creation'))
    @controllers.enforce_rbac('orders:post')
    @controllers.enforce_content_types(['application/json'])
    def on_post(self, external_project_id, **kwargs):
        project = res.get_or_create_project(external_project_id)

        body = api.load_body(pecan.request,
                             validator=self.type_order_validator)

        order_type = body.get('type')
        order_meta = body.get('meta')
        request_type = order_meta.get('request_type')

        LOG.debug('Processing order type %(order_type)s,'
                  ' request type %(request_type)s' % {
                      'order_type': order_type,
                      'request_type': request_type
                  })

        if order_type == models.OrderType.CERTIFICATE:
            msg = _DEPRECATION_MSG % "Certificate Order Resource"
            versionutils.report_deprecated_feature(LOG, msg)
            validators.validate_ca_id(project.id, body.get('meta'))
            if request_type == 'stored-key':
                container_ref = order_meta.get('container_ref')
                validators.validate_stored_key_rsa_container(
                    external_project_id, container_ref, pecan.request)

        self.quota_enforcer.enforce(project)

        new_order = models.Order()
        new_order.meta = body.get('meta')
        new_order.type = order_type
        new_order.project_id = project.id

        request_id = None
        ctxt = controllers._get_barbican_context(pecan.request)
        if ctxt:
            new_order.creator_id = ctxt.user
            request_id = ctxt.request_id

        self.order_repo.create_from(new_order)

        # Grab our id before commit due to obj expiration from sqlalchemy
        order_id = new_order.id

        # Force commit to avoid async issues with the workers
        repo.commit()

        self.queue.process_type_order(order_id=order_id,
                                      project_id=external_project_id,
                                      request_id=request_id)

        url = hrefs.convert_order_to_href(order_id)

        pecan.response.status = 202
        pecan.response.headers['Location'] = url

        return {'order_ref': url}
示例#43
0
class ContainerConsumersController(controllers.ACLMixin):
    """Handles Consumer creation requests."""

    def __init__(self, container_id):
        self.container_id = container_id
        self.consumer_repo = repo.get_container_consumer_repository()
        self.container_repo = repo.get_container_repository()
        self.validator = validators.ContainerConsumerValidator()
        self.quota_enforcer = quota.QuotaEnforcer('consumers',
                                                  self.consumer_repo)

    @pecan.expose()
    def _lookup(self, consumer_id, *remainder):
        return ContainerConsumerController(consumer_id), remainder

    @pecan.expose(generic=True)
    def index(self, **kwargs):
        pecan.abort(405)  # HTTP 405 Method Not Allowed as default

    @index.when(method='GET', template='json')
    @controllers.handle_exceptions(u._('ContainerConsumers(s) retrieval'))
    @controllers.enforce_rbac('consumers:get')
    def on_get(self, external_project_id, **kw):
        LOG.debug('Start consumers on_get '
                  'for container-ID %s:', self.container_id)

        try:
            self.container_repo.get(self.container_id, external_project_id)
        except exception.NotFound:
            controllers.containers.container_not_found()

        result = self.consumer_repo.get_by_container_id(
            self.container_id,
            offset_arg=kw.get('offset', 0),
            limit_arg=kw.get('limit', None),
            suppress_exception=True
        )

        consumers, offset, limit, total = result

        if not consumers:
            resp_ctrs_overall = {'consumers': [], 'total': total}
        else:
            resp_ctrs = [
                hrefs.convert_to_hrefs(c.to_dict_fields())
                for c in consumers
            ]
            resp_ctrs_overall = hrefs.add_nav_hrefs(
                'consumers',
                offset,
                limit,
                total,
                {'consumers': resp_ctrs}
            )
            resp_ctrs_overall.update({'total': total})

        LOG.info(u._LI('Retrieved a consumer list for project: %s'),
                 external_project_id)
        return resp_ctrs_overall

    @index.when(method='POST', template='json')
    @controllers.handle_exceptions(u._('ContainerConsumer creation'))
    @controllers.enforce_rbac('consumers:post')
    @controllers.enforce_content_types(['application/json'])
    def on_post(self, external_project_id, **kwargs):

        project = res.get_or_create_project(external_project_id)
        data = api.load_body(pecan.request, validator=self.validator)
        LOG.debug('Start on_post...%s', data)

        try:
            container = self.container_repo.get(self.container_id,
                                                external_project_id)
        except exception.NotFound:
            controllers.containers.container_not_found()

        self.quota_enforcer.enforce(project)

        new_consumer = models.ContainerConsumerMetadatum(self.container_id,
                                                         project.id,
                                                         data)
        new_consumer.project_id = project.id
        self.consumer_repo.create_or_update_from(new_consumer, container)

        url = hrefs.convert_consumer_to_href(new_consumer.container_id)
        pecan.response.headers['Location'] = url

        LOG.info(u._LI('Created a consumer for project: %s'),
                 external_project_id)

        return self._return_container_data(self.container_id,
                                           external_project_id)

    @index.when(method='DELETE', template='json')
    @controllers.handle_exceptions(u._('ContainerConsumer deletion'))
    @controllers.enforce_rbac('consumers:delete')
    @controllers.enforce_content_types(['application/json'])
    def on_delete(self, external_project_id, **kwargs):
        data = api.load_body(pecan.request, validator=self.validator)
        LOG.debug(data)
        consumer = self.consumer_repo.get_by_values(
            self.container_id,
            data["name"],
            data["URL"],
            suppress_exception=True
        )
        if not consumer:
            _consumer_not_found()
        LOG.debug("Found consumer: %s", consumer)

        try:
            self.consumer_repo.delete_entity_by_id(consumer.id,
                                                   external_project_id)
        except exception.NotFound:
            LOG.exception(u._LE('Problem deleting consumer'))
            _consumer_not_found()

        ret_data = self._return_container_data(
            self.container_id,
            external_project_id
        )
        LOG.info(u._LI('Deleted a consumer for project: %s'),
                 external_project_id)
        return ret_data

    def _return_container_data(self, container_id, external_project_id):
        try:
            container = self.container_repo.get(container_id,
                                                external_project_id)
            dict_fields = container.to_dict_fields()
        except Exception:
            controllers.containers.container_not_found()

        for secret_ref in dict_fields['secret_refs']:
            hrefs.convert_to_hrefs(secret_ref)

        # TODO(john-wood-w) Why two calls to convert_to_hrefs()?
        return hrefs.convert_to_hrefs(
            hrefs.convert_to_hrefs(dict_fields)
        )
示例#44
0
def _requested_preferred_ca_not_a_project_ca():
    """Throw exception indicating that preferred CA is not a project CA."""
    pecan.abort(
        400, u._('Cannot set CA as a preferred CA as it is not a project CA.'))
示例#45
0
def _ca_not_in_project():
    """Throw exception certificate authority is not in project."""
    pecan.abort(404, u._('Not Found. CA not in project.'))
示例#46
0
class SecretMetadatumController(controllers.ACLMixin):

    def __init__(self, secret):
        LOG.debug('=== Creating SecretMetadatumController ===')
        self.user_meta_repo = repo.get_secret_user_meta_repository()
        self.secret = secret
        self.metadatum_validator = validators.NewSecretMetadatumValidator()

    @pecan.expose(generic=True)
    def index(self, **kwargs):
        pecan.abort(405)  # HTTP 405 Method Not Allowed as default

    @index.when(method='GET', template='json')
    @controllers.handle_exceptions(u._('Secret metadatum retrieval'))
    @controllers.enforce_rbac('secret_meta:get')
    def on_get(self, external_project_id, remainder, **kwargs):
        """Handles retrieval of existing secret metadatum."""

        LOG.debug(u._('Start secret metadatum on_get '
                      'for secret-ID %s:'), self.secret.id)

        metadata = self.user_meta_repo.get_metadata_for_secret(self.secret.id)
        if remainder in metadata:
            pecan.response.status = 200
            pair = {'key': remainder, 'value': metadata[remainder]}
            return collections.OrderedDict(sorted(pair.items()))
        else:
            _secret_metadata_not_found()

    @index.when(method='PUT', template='json')
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('Secret metadatum update'))
    @controllers.enforce_rbac('secret_meta:put')
    @controllers.enforce_content_types(['application/json'])
    def on_put(self, external_project_id, remainder, **kwargs):
        """Handles update of existing secret metadatum."""
        metadata = self.user_meta_repo.get_metadata_for_secret(self.secret.id)
        data = api.load_body(pecan.request, validator=self.metadatum_validator)

        key = data.get('key')
        value = data.get('value')

        if remainder not in metadata:
            _secret_metadata_not_found()
        elif remainder != key:
            msg = 'Key in request data does not match key in the '
            'request url.'
            pecan.abort(409, msg)
        else:
            LOG.debug(u._('Start secret metadatum on_put...%s'), metadata)

            self.user_meta_repo.create_replace_user_metadatum(self.secret.id,
                                                              key, value)

            pecan.response.status = 200
            pair = {'key': key, 'value': value}
            return collections.OrderedDict(sorted(pair.items()))

    @index.when(method='DELETE', template='json')
    @controllers.handle_exceptions(u._('Secret metadatum removal'))
    @controllers.enforce_rbac('secret_meta:delete')
    def on_delete(self, external_project_id, remainder, **kwargs):
        """Handles removal of existing secret metadatum."""

        self.user_meta_repo.delete_metadatum(self.secret.id,
                                             remainder)
        msg = 'Deleted secret metadatum: %s for secret %s' % (remainder,
                                                              self.secret.id)
        pecan.response.status = 204
        LOG.info(msg)
示例#47
0
def _certificate_authority_not_found():
    """Throw exception indicating certificate authority not found."""
    pecan.abort(404, u._('Not Found. CA not found.'))
示例#48
0
class CertificateAuthoritiesController(controllers.ACLMixin):
    """Handles certificate authority list requests."""
    def __init__(self):
        LOG.debug('Creating CertificateAuthoritiesController')
        self.ca_repo = repo.get_ca_repository()
        self.project_ca_repo = repo.get_project_ca_repository()
        self.preferred_ca_repo = repo.get_preferred_ca_repository()
        self.project_repo = repo.get_project_repository()
        self.validator = validators.NewCAValidator()
        self.quota_enforcer = quota.QuotaEnforcer('cas', self.ca_repo)
        # Populate the CA table at start up
        cert_resources.refresh_certificate_resources()

    def __getattr__(self, name):
        route_table = {
            'all': self.get_all,
            'global-preferred': self.get_global_preferred,
            'preferred': self.preferred,
            'unset-global-preferred': self.unset_global_preferred,
        }
        if name in route_table:
            return route_table[name]
        raise AttributeError

    @pecan.expose()
    def _lookup(self, ca_id, *remainder):
        ca = self.ca_repo.get(entity_id=ca_id, suppress_exception=True)
        if not ca:
            _certificate_authority_not_found()
        return CertificateAuthorityController(ca), remainder

    @pecan.expose(generic=True)
    def index(self, **kwargs):
        pecan.abort(405)  # HTTP 405 Method Not Allowed as default

    @index.when(method='GET', template='json')
    @controllers.handle_exceptions(
        u._('Certificate Authorities retrieval (limited)'))
    @controllers.enforce_rbac('certificate_authorities:get_limited')
    def on_get(self, external_project_id, **kw):
        LOG.debug('Start certificate_authorities on_get (limited)')

        plugin_name = kw.get('plugin_name')
        if plugin_name is not None:
            plugin_name = parse.unquote_plus(plugin_name)

        plugin_ca_id = kw.get('plugin_ca_id', None)
        if plugin_ca_id is not None:
            plugin_ca_id = parse.unquote_plus(plugin_ca_id)

        # refresh CA table, in case plugin entries have expired
        cert_resources.refresh_certificate_resources()

        project_model = res.get_or_create_project(external_project_id)

        if self._project_cas_defined(project_model.id):
            cas, offset, limit, total = self._get_subcas_and_project_cas(
                offset=kw.get('offset', 0),
                limit=kw.get('limit', None),
                plugin_name=plugin_name,
                plugin_ca_id=plugin_ca_id,
                project_id=project_model.id)
        else:
            cas, offset, limit, total = self._get_subcas_and_root_cas(
                offset=kw.get('offset', 0),
                limit=kw.get('limit', None),
                plugin_name=plugin_name,
                plugin_ca_id=plugin_ca_id,
                project_id=project_model.id)

        return self._display_cas(cas, offset, limit, total)

    @pecan.expose(generic=True, template='json')
    @controllers.handle_exceptions(u._('Certificate Authorities retrieval'))
    @controllers.enforce_rbac('certificate_authorities:get')
    def get_all(self, external_project_id, **kw):
        LOG.debug('Start certificate_authorities on_get')

        plugin_name = kw.get('plugin_name')
        if plugin_name is not None:
            plugin_name = parse.unquote_plus(plugin_name)

        plugin_ca_id = kw.get('plugin_ca_id', None)
        if plugin_ca_id is not None:
            plugin_ca_id = parse.unquote_plus(plugin_ca_id)

        # refresh CA table, in case plugin entries have expired
        cert_resources.refresh_certificate_resources()

        project_model = res.get_or_create_project(external_project_id)

        cas, offset, limit, total = self._get_subcas_and_root_cas(
            offset=kw.get('offset', 0),
            limit=kw.get('limit', None),
            plugin_name=plugin_name,
            plugin_ca_id=plugin_ca_id,
            project_id=project_model.id)

        return self._display_cas(cas, offset, limit, total)

    def _get_project_cas(self, project_id, query_filters):
        cas, offset, limit, total = self.project_ca_repo.get_by_create_date(
            offset_arg=query_filters.get('offset', 0),
            limit_arg=query_filters.get('limit', None),
            project_id=project_id,
            suppress_exception=True)
        return cas, offset, limit, total

    def _project_cas_defined(self, project_id):
        _cas, _offset, _limit, total = self._get_project_cas(project_id, {})
        return total > 0

    def _get_subcas_and_project_cas(self, offset, limit, plugin_name,
                                    plugin_ca_id, project_id):
        return self.ca_repo.get_by_create_date(offset_arg=offset,
                                               limit_arg=limit,
                                               plugin_name=plugin_name,
                                               plugin_ca_id=plugin_ca_id,
                                               project_id=project_id,
                                               restrict_to_project_cas=True,
                                               suppress_exception=True)

    def _get_subcas_and_root_cas(self, offset, limit, plugin_name,
                                 plugin_ca_id, project_id):
        return self.ca_repo.get_by_create_date(offset_arg=offset,
                                               limit_arg=limit,
                                               plugin_name=plugin_name,
                                               plugin_ca_id=plugin_ca_id,
                                               project_id=project_id,
                                               restrict_to_project_cas=False,
                                               suppress_exception=True)

    def _display_cas(self, cas, offset, limit, total):
        if not cas:
            cas_resp_overall = {'cas': [], 'total': total}
        else:
            cas_resp = [
                hrefs.convert_certificate_authority_to_href(ca.id)
                for ca in cas
            ]
            cas_resp_overall = hrefs.add_nav_hrefs('cas', offset, limit, total,
                                                   {'cas': cas_resp})
            cas_resp_overall.update({'total': total})

        return cas_resp_overall

    @pecan.expose(generic=True, template='json')
    @controllers.handle_exceptions(u._('Retrieve global preferred CA'))
    @controllers.enforce_rbac('certificate_authorities:get_global_preferred_ca'
                              )
    def get_global_preferred(self, external_project_id, **kw):
        LOG.debug('Start certificate_authorities get_global_preferred CA')

        pref_ca = cert_resources.get_global_preferred_ca()
        if not pref_ca:
            pecan.abort(404, u._("No global preferred CA defined"))

        return {
            'ca_ref':
            hrefs.convert_certificate_authority_to_href(pref_ca.ca_id)
        }

    @pecan.expose()
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('Unset global preferred CA'))
    @controllers.enforce_rbac('certificate_authorities:unset_global_preferred')
    def unset_global_preferred(self, external_project_id):
        if pecan.request.method != 'POST':
            pecan.abort(405)
        LOG.debug("== Unsetting global preferred CA")
        self._remove_global_preferred_ca(external_project_id)

    def _remove_global_preferred_ca(self, external_project_id):
        global_preferred_ca = cert_resources.get_global_preferred_ca()
        if global_preferred_ca:
            self.preferred_ca_repo.delete_entity_by_id(global_preferred_ca.id,
                                                       external_project_id)

    @pecan.expose(generic=True, template='json')
    @utils.allow_all_content_types
    @controllers.handle_exceptions(u._('Retrieve project preferred CA'))
    @controllers.enforce_rbac('certificate_authorities:get_preferred_ca')
    def preferred(self, external_project_id, **kw):
        LOG.debug('Start certificate_authorities get project preferred CA')

        project = res.get_or_create_project(external_project_id)

        pref_ca_id = cert_resources.get_project_preferred_ca_id(project.id)
        if not pref_ca_id:
            pecan.abort(404, u._("No preferred CA defined for this project"))

        return {
            'ca_ref': hrefs.convert_certificate_authority_to_href(pref_ca_id)
        }

    @index.when(method='POST', template='json')
    @controllers.handle_exceptions(u._('CA creation'))
    @controllers.enforce_rbac('certificate_authorities:post')
    @controllers.enforce_content_types(['application/json'])
    def on_post(self, external_project_id, **kwargs):
        LOG.debug('Start on_post for project-ID %s:...', external_project_id)

        data = api.load_body(pecan.request, validator=self.validator)
        project = res.get_or_create_project(external_project_id)

        ctxt = controllers._get_barbican_context(pecan.request)
        if ctxt:  # in authenticated pipeline case, always use auth token user
            creator_id = ctxt.user

        self.quota_enforcer.enforce(project)

        new_ca = cert_resources.create_subordinate_ca(
            project_model=project,
            name=data.get('name'),
            description=data.get('description'),
            subject_dn=data.get('subject_dn'),
            parent_ca_ref=data.get('parent_ca_ref'),
            creator_id=creator_id)

        url = hrefs.convert_certificate_authority_to_href(new_ca.id)
        LOG.debug('URI to sub-CA is %s', url)

        pecan.response.status = 201
        pecan.response.headers['Location'] = url

        LOG.info(u._LI('Created a sub CA for project: %s'),
                 external_project_id)

        return {'ca_ref': url}
示例#49
0
 def generate_asymmetric(self, generate_dto, kek_meta_dto, project_id):
     raise NotImplementedError(u._("Feature not implemented for PKCS11"))
示例#50
0
from barbican.plugin.util import multiple_backends
from barbican.plugin.util import utils as plugin_utils


_SECRET_STORE = None

CONF = config.new_config()
DEFAULT_PLUGIN_NAMESPACE = 'barbican.secretstore.plugin'
DEFAULT_PLUGINS = ['store_crypto']

store_opt_group = cfg.OptGroup(name='secretstore',
                               title='Secret Store Plugin Options')
store_opts = [
    cfg.StrOpt('namespace',
               default=DEFAULT_PLUGIN_NAMESPACE,
               help=u._('Extension namespace to search for plugins.')
               ),
    cfg.MultiStrOpt('enabled_secretstore_plugins',
                    default=DEFAULT_PLUGINS,
                    help=u._('List of secret store plugins to load.')
                    ),
    cfg.BoolOpt('enable_multiple_secret_stores',
                default=False,
                help=u._('Flag to enable multiple secret store plugin'
                         ' backend support. Default is False')
                ),
    cfg.ListOpt('stores_lookup_suffix',
                help=u._('List of suffix to use for looking up plugins which '
                         'are supported with multiple backend support.')
                )
]
示例#51
0
from barbican.common import config
from barbican.common import utils
from barbican import i18n as u
from barbican.plugin.crypto import base as c


CONF = config.new_config()
LOG = utils.getLogger(__name__)

simple_crypto_plugin_group = cfg.OptGroup(name='simple_crypto_plugin',
                                          title="Simple Crypto Plugin Options")
simple_crypto_plugin_opts = [
    cfg.StrOpt('kek',
               default='dGhpcnR5X3R3b19ieXRlX2tleWJsYWhibGFoYmxhaGg=',
               help=u._('Key encryption key to be used by Simple Crypto '
                        'Plugin'), secret=True),
    cfg.StrOpt('plugin_name',
               help=u._('User friendly plugin name'),
               default='Software Only Crypto'),
]
CONF.register_group(simple_crypto_plugin_group)
CONF.register_opts(simple_crypto_plugin_opts, group=simple_crypto_plugin_group)
config.parse_args(CONF)


def list_opts():
    yield simple_crypto_plugin_group, simple_crypto_plugin_opts


class SimpleCryptoPlugin(c.CryptoPluginBase):
    """Insecure implementation of the crypto plugin."""
示例#52
0
def _order_not_found():
    """Throw exception indicating order not found."""
    pecan.abort(404, u._('Order not found.'))
示例#53
0
def _order_update_not_supported_for_type(order_type):
    """Throw exception that update is not supported."""
    pecan.abort(
        400,
        u._("Updates are not supported for order type "
            "{0}.").format(order_type))
示例#54
0
def _order_cannot_be_updated_if_not_pending(order_status):
    """Throw exception that order cannot be updated if not PENDING."""
    pecan.abort(
        400,
        u._("Only PENDING orders can be updated. Order is in the"
            "{0} state.").format(order_status))
示例#55
0
from barbican.common import config
from barbican.common import exception
from barbican.common import utils
from barbican import i18n as u
from barbican.plugin.crypto import base as plugin
from barbican.plugin.crypto import pkcs11

CONF = config.new_config()
LOG = utils.getLogger(__name__)

CachedKEK = collections.namedtuple("CachedKEK", ["kek", "expires"])

p11_crypto_plugin_group = cfg.OptGroup(name='p11_crypto_plugin',
                                       title="PKCS11 Crypto Plugin Options")
p11_crypto_plugin_opts = [
    cfg.StrOpt('library_path', help=u._('Path to vendor PKCS11 library')),
    cfg.StrOpt('token_serial_number',
               help=u._('Token serial number used to identify the token to be '
                        'used.')),
    cfg.StrOpt('token_label',
               deprecated_for_removal=True,
               help=u._('DEPRECATED: Use token_labels instead. '
                        'Token label used to identify the token to '
                        'be used.')),
    cfg.ListOpt('token_labels',
                help=u._('List of labels for one or more tokens to be used. '
                         'Typically this is a single label, but some HSM '
                         'devices may require more than one label for Load '
                         'Balancing or High Availability configurations.')),
    cfg.StrOpt('login',
               help=u._('Password to login to PKCS11 session'),
示例#56
0
def _order_update_not_supported():
    """Throw exception that PUT operation is not supported for orders."""
    pecan.abort(405, u._("Order update is not supported."))
示例#57
0
class SecretACLsController(controllers.ACLMixin):
    """Handles SecretACL requests by a given secret id."""
    def __init__(self, secret):
        super().__init__()
        self.secret = secret
        self.secret_project_id = self.secret.project.external_id
        self.acl_repo = repo.get_secret_acl_repository()
        self.validator = validators.ACLValidator()

    def get_acl_tuple(self, req, **kwargs):
        d = {
            'project_id': self.secret_project_id,
            'creator_id': self.secret.creator_id
        }
        return 'secret', d

    @pecan.expose(generic=True)
    def index(self, **kwargs):
        pecan.abort(405)  # HTTP 405 Method Not Allowed as default

    @index.when(method='GET', template='json')
    @controllers.handle_exceptions(u._('SecretACL(s) retrieval'))
    @controllers.enforce_rbac('secret_acls:get')
    def on_get(self, external_project_id, **kw):
        LOG.debug('Start secret ACL on_get '
                  'for secret-ID %s:', self.secret.id)

        return self._return_acl_list_response(self.secret.id)

    @index.when(method='PATCH', template='json')
    @controllers.handle_exceptions(u._('SecretACL(s) Update'))
    @controllers.enforce_rbac('secret_acls:put_patch')
    @controllers.enforce_content_types(['application/json'])
    def on_patch(self, external_project_id, **kwargs):
        """Handles update of existing secret acl requests.

        At least one secret ACL needs to exist for update to proceed.
        In update, multiple operation ACL payload can be specified as
        mentioned in sample below. A specific ACL can be updated by its
        own id via SecretACLController patch request.

        {
          "read":{
            "users":[
              "5ecb18f341894e94baca9e8c7b6a824a",
              "20b63d71f90848cf827ee48074f213b7",
              "c7753f8da8dc4fbea75730ab0b6e0ef4"
            ]
          },
          "write":{
            "users":[
              "5ecb18f341894e94baca9e8c7b6a824a"
            ],
            "project-access":true
          }
        }
        """
        data = api.load_body(pecan.request, validator=self.validator)
        LOG.debug('Start on_patch...%s', data)

        existing_acls_map = {
            acl.operation: acl
            for acl in self.secret.secret_acls
        }
        for operation in six.moves.filter(lambda x: data.get(x),
                                          validators.ACL_OPERATIONS):
            project_access = data[operation].get('project-access')
            user_ids = data[operation].get('users')
            s_acl = None
            if operation in existing_acls_map:  # update if matching acl exists
                s_acl = existing_acls_map[operation]
                if project_access is not None:
                    s_acl.project_access = project_access
            else:
                s_acl = models.SecretACL(self.secret.id,
                                         operation=operation,
                                         project_access=project_access)
            self.acl_repo.create_or_replace_from(self.secret,
                                                 secret_acl=s_acl,
                                                 user_ids=user_ids)

        acl_ref = '{0}/acl'.format(hrefs.convert_secret_to_href(
            self.secret.id))
        return {'acl_ref': acl_ref}

    @index.when(method='PUT', template='json')
    @controllers.handle_exceptions(u._('SecretACL(s) Update'))
    @controllers.enforce_rbac('secret_acls:put_patch')
    @controllers.enforce_content_types(['application/json'])
    def on_put(self, external_project_id, **kwargs):
        """Handles update of existing secret acl requests.

        Replaces existing secret ACL(s) with input ACL(s) data. Existing
        ACL operation not specified in input are removed as part of update.
        For missing project-access in ACL, true is used as default.
        In update, multiple operation ACL payload can be specified as
        mentioned in sample below. A specific ACL can be updated by its
        own id via SecretACLController patch request.

        {
          "read":{
            "users":[
              "5ecb18f341894e94baca9e8c7b6a824a",
              "20b63d71f90848cf827ee48074f213b7",
              "c7753f8da8dc4fbea75730ab0b6e0ef4"
            ]
          },
          "write":{
            "users":[
              "5ecb18f341894e94baca9e8c7b6a824a"
            ],
            "project-access":false
          }
        }

        Every secret, by default, has an implicit ACL in case client has not
        defined an explicit ACL. That default ACL definition, DEFAULT_ACL,
        signifies that a secret by default has project based access i.e. client
        with necessary roles on secret project can access the secret. That's
        why when ACL is added to a secret, it always returns 200 (and not 201)
        indicating existence of implicit ACL on a secret.
        """
        data = api.load_body(pecan.request, validator=self.validator)
        LOG.debug('Start on_put...%s', data)

        existing_acls_map = {
            acl.operation: acl
            for acl in self.secret.secret_acls
        }
        for operation in six.moves.filter(lambda x: data.get(x),
                                          validators.ACL_OPERATIONS):
            project_access = data[operation].get('project-access', True)
            user_ids = data[operation].get('users', [])
            s_acl = None
            if operation in existing_acls_map:  # update if matching acl exists
                s_acl = existing_acls_map.pop(operation)
                s_acl.project_access = project_access
            else:
                s_acl = models.SecretACL(self.secret.id,
                                         operation=operation,
                                         project_access=project_access)
            self.acl_repo.create_or_replace_from(self.secret,
                                                 secret_acl=s_acl,
                                                 user_ids=user_ids)
        # delete remaining existing acls as they are not present in input.
        for acl in existing_acls_map.values():
            self.acl_repo.delete_entity_by_id(entity_id=acl.id,
                                              external_project_id=None)
        acl_ref = '{0}/acl'.format(hrefs.convert_secret_to_href(
            self.secret.id))
        return {'acl_ref': acl_ref}

    @index.when(method='DELETE', template='json')
    @controllers.handle_exceptions(u._('SecretACL(s) deletion'))
    @controllers.enforce_rbac('secret_acls:delete')
    def on_delete(self, external_project_id, **kwargs):

        count = self.acl_repo.get_count(self.secret.id)
        if count > 0:
            self.acl_repo.delete_acls_for_secret(self.secret)

    def _return_acl_list_response(self, secret_id):
        result = self.acl_repo.get_by_secret_id(secret_id)

        acls_data = {}
        if result:
            for acl in result:
                _convert_acl_to_response_format(acl, acls_data)
        if not acls_data:
            acls_data = DEFAULT_ACL.copy()
        return acls_data
示例#58
0
def _project_quotas_not_found():
    """Throw exception indicating project quotas not found."""
    pecan.abort(404, u._('Project quotas not found.'))
示例#59
0
 def __init__(self):
     super(SecretStorePluginsNotConfigured, self).__init__(
         u._('No secret store plugins have been configured')
     )
示例#60
0
def _order_not_found():
    """Throw exception indicating order not found."""
    pecan.abort(
        404, u._('Not Found. Sorry but your order is in '
                 'another castle.'))