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
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")
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
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)
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)
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)
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())
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)
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)
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
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)
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)
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)
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)
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)
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
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"))
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)
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
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"), )
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))
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))
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)
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
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)
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)
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)
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
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
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)
def _cant_remove_preferred_ca_from_project(): pecan.abort( 409, u._('Please change the preferred CA to a different project CA ' 'before removing it.'))
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)
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."))
def order_cannot_modify_order_type(): """Throw exception that order type cannot be modified.""" pecan.abort(400, u._("Cannot modify order type."))
def __init__(self): super(SecretNoPayloadProvidedException, self).__init__( u._('No secret information provided to encrypt.') )
def _certificate_authority_attribute_not_found(): """Throw exception indicating CA attribute was not found.""" pecan.abort(404, u._('Not Found. CA attribute not found.'))
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.'))
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)}
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."""
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
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
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}
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) )
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.'))
def _ca_not_in_project(): """Throw exception certificate authority is not in project.""" pecan.abort(404, u._('Not Found. CA not in project.'))
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)
def _certificate_authority_not_found(): """Throw exception indicating certificate authority not found.""" pecan.abort(404, u._('Not Found. CA not found.'))
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}
def generate_asymmetric(self, generate_dto, kek_meta_dto, project_id): raise NotImplementedError(u._("Feature not implemented for PKCS11"))
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.') ) ]
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."""
def _order_not_found(): """Throw exception indicating order not found.""" pecan.abort(404, u._('Order not found.'))
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))
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))
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'),
def _order_update_not_supported(): """Throw exception that PUT operation is not supported for orders.""" pecan.abort(405, u._("Order update is not supported."))
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
def _project_quotas_not_found(): """Throw exception indicating project quotas not found.""" pecan.abort(404, u._('Project quotas not found.'))
def __init__(self): super(SecretStorePluginsNotConfigured, self).__init__( u._('No secret store plugins have been configured') )
def _order_not_found(): """Throw exception indicating order not found.""" pecan.abort( 404, u._('Not Found. Sorry but your order is in ' 'another castle.'))