def update_roles(user, roles): """ Replaces the roles with new ones. This will detect when are roles added as well as when there are roles removed. :param user: :param roles: """ removed_roles = [] for ur in user.roles: for r in roles: if r.id == ur.id: break else: user.roles.remove(ur) removed_roles.append(ur.name) if removed_roles: log_service.audit_log("unassign_role", user.username, f"Un-assigning roles {removed_roles}") added_roles = [] for r in roles: for ur in user.roles: if r.id == ur.id: break else: user.roles.append(r) added_roles.append(r.name) if added_roles: log_service.audit_log("assign_role", user.username, f"Assigning roles {added_roles}")
def create(name, password=None, description=None, username=None, users=None, third_party=False): """ Create a new role :param name: :param users: :param description: :param username: :param password: :return: """ role = Role( name=name, description=description, username=username, password=password, third_party=third_party, ) if users: role.users = users log_service.audit_log("create_role", name, "Creating new role") return database.create(role)
def upload(pending_certificate_id, **kwargs): """ Uploads a (signed) pending certificate. The allowed fields are validated by PendingCertificateUploadInputSchema. The certificate is also validated to be signed by the correct authority. """ pending_cert = get(pending_certificate_id) partial_cert = kwargs uploaded_chain = partial_cert["chain"] authority = authorities_service.get(pending_cert.authority.id) # Construct the chain for cert validation if uploaded_chain: chain = uploaded_chain + "\n" + authority.authority_certificate.body else: chain = authority.authority_certificate.body parsed_chain = parse_cert_chain(chain) # Check that the certificate is actually signed by the CA to avoid incorrect cert pasting validators.verify_cert_chain([parse_certificate(partial_cert["body"])] + parsed_chain) final_cert = create_certificate(pending_cert, partial_cert, pending_cert.user) pending_cert_final_result = update(pending_cert.id, resolved_cert_id=final_cert.id) update(pending_cert.id, resolved=True) log_service.audit_log("resolve_pending_certificate", pending_cert.name, "Resolved the pending certificate") return pending_cert_final_result
def create(label, plugin_name, options, description=None): """ Creates a new destination, that can then be used as a destination for certificates. :param label: Destination common name :param description: :rtype: Destination :return: New destination """ # remove any sub-plugin objects before try to save the json options for option in options: if "plugin" in option["type"]: del option["value"]["plugin_object"] destination = Destination(label=label, options=options, plugin_name=plugin_name, description=description) current_app.logger.info("Destination: %s created", label) # add the destination as source, to avoid new destinations that are not in source, as long as an AWS destination if add_aws_destination_to_sources(destination): current_app.logger.info("Source: %s created", label) log_service.audit_log("create_destination", destination.label, "Creating new destination") return database.create(destination)
def update(destination_id, label, plugin_name, options, description): """ Updates an existing destination. :param destination_id: Lemur assigned ID :param label: Destination common name :param plugin_name: :param options: :param description: :rtype: Destination :return: """ destination = get(destination_id) destination.label = label destination.plugin_name = plugin_name # remove any sub-plugin objects before try to save the json options for option in options: if "plugin" in option["type"]: del option["value"]["plugin_object"] destination.options = options destination.description = description log_service.audit_log("update_destination", destination.label, "Updating destination") updated = database.update(destination) # add the destination as source, to avoid new destinations that are not in source, as long as an AWS destination if add_aws_destination_to_sources(updated): current_app.logger.info("Source: %s created", label) return updated
def update(destination_id, label, plugin_name, options, description): """ Updates an existing destination. :param destination_id: Lemur assigned ID :param label: Destination common name :param plugin_name: :param options: :param description: :rtype: Destination :return: """ destination = get(destination_id) destination.label = label destination.plugin_name = plugin_name # remove any sub-plugin objects before try to save the json options for option in options: if "plugin" in option["type"]: del option["value"]["plugin_object"] destination.options = options destination.description = description log_service.audit_log("update_destination", destination.label, "Updating destination") return database.update(destination)
def create_certificate(pending_certificate, certificate, user): """ Create and store a certificate with pending certificate's info :arg pending_certificate: PendingCertificate which will populate the certificate :arg certificate: dict from Authority, which contains the body, chain and external id :arg user: User that called this function, used as 'creator' of the certificate if it does not have an owner """ certificate["owner"] = pending_certificate.owner data, errors = CertificateUploadInputSchema().load(certificate) if errors: raise Exception( "Unable to create certificate: {reasons}".format(reasons=errors)) data.update(vars(pending_certificate)) # Copy relationships, vars doesn't copy this without explicit fields data["notifications"] = list(pending_certificate.notifications) data["destinations"] = list(pending_certificate.destinations) data["sources"] = list(pending_certificate.sources) data["roles"] = list(pending_certificate.roles) data["replaces"] = list(pending_certificate.replaces) data["rotation_policy"] = pending_certificate.rotation_policy # Replace external id and chain with the one fetched from source data["external_id"] = certificate["external_id"] data["chain"] = certificate["chain"] creator = user_service.get_by_email(pending_certificate.owner) if not creator: # Owner of the pending certificate is not the creator, so use the current user who called # this as the creator (usually lemur) creator = user if pending_certificate.rename: # If generating name from certificate, remove the one from pending certificate del data["name"] data["creator"] = creator cert = certificate_service.import_certificate(**data) database.update(cert) metrics.send("certificate_issued", "counter", 1, metric_tags=dict(owner=cert.owner, issuer=cert.issuer)) log_service.audit_log( "certificate_from_pending_certificate", cert.name, f"Created from the pending certificate {pending_certificate.name}") log_data = { "function": "lemur.certificates.service.create", "owner": cert.owner, "name": cert.name, "serial": cert.serial, "issuer": cert.issuer, "not_after": cert.not_after.format('YYYY-MM-DD HH:mm:ss'), "not_before": cert.not_before.format('YYYY-MM-DD HH:mm:ss'), "sans": cert.san, } current_app.logger.info(log_data) return cert
def delete(access_key): """ Delete an access key. This is one way to remove a key, though you probably should just set revoked. :param access_key: :return: """ log_service.audit_log("delete_api_key", access_key.name, "Deleting the API key") database.delete(access_key)
def delete(dns_provider_id): """ Deletes a DNS provider. :param dns_provider_id: Lemur assigned ID """ dns_provider = get(dns_provider_id) if dns_provider: log_service.audit_log("delete_dns_provider", dns_provider.name, "Deleting the DNS provider") database.delete(dns_provider)
def delete(source_id): """ Deletes an source. :param source_id: Lemur assigned ID """ source = get(source_id) if source: log_service.audit_log("delete_source", source.label, "Deleting source") database.delete(source)
def delete(notification_id): """ Deletes an notification. :param notification_id: Lemur assigned ID """ notification = get(notification_id) if notification: log_service.audit_log("delete_notification", notification.label, "Deleting notification") database.delete(notification)
def revoke(aid): """ Revokes an api key. :param aid: :return: """ api_key = get(aid) setattr(api_key, "revoked", True) log_service.audit_log("revoke_api_key", api_key.name, "Revoking API key") return database.update(api_key)
def delete(destination_id): """ Deletes an destination. :param destination_id: Lemur assigned ID """ destination = get(destination_id) if destination: log_service.audit_log("delete_destination", destination.label, "Deleting destination") database.delete(destination)
def increment_attempt(pending_certificate): """ Increments pending certificate attempt counter and updates it in the database. """ pending_certificate.number_attempts += 1 database.update(pending_certificate) log_service.audit_log("increment_attempt_pending_certificate", pending_certificate.name, "Incremented attempts for the pending certificate") return pending_certificate.number_attempts
def delete(role_id): """ Remove a role :param role_id: :return: """ role = get(role_id) log_service.audit_log("delete_role", role.name, "Deleting role") return database.delete(role)
def update(pending_cert_id, **kwargs): """ Updates a pending certificate. The allowed fields are validated by PendingCertificateEditInputSchema. """ pending_cert = get(pending_cert_id) for key, value in kwargs.items(): setattr(pending_cert, key, value) log_service.audit_log("update_pending_certificate", pending_cert.name, f"Update summary - {kwargs}") return database.update(pending_cert)
def update(api_key, **kwargs): """ Updates an api key. :param api_key: :param kwargs: :return: """ for key, value in kwargs.items(): setattr(api_key, key, value) log_service.audit_log("update_api_key", api_key.name, f"Update summary - {kwargs}") return database.update(api_key)
def create(**kwargs): """ Creates a new authority. """ ca_name = kwargs.get("name") if get_by_name(ca_name): raise Exception(f"Authority with name {ca_name} already exists") if role_service.get_by_name( f"{ca_name}_admin") or role_service.get_by_name( f"{ca_name}_operator"): raise Exception( f"Admin and/or operator roles for authority {ca_name} already exist" ) body, private_key, chain, roles = mint(**kwargs) kwargs["creator"].roles = list(set(list(kwargs["creator"].roles) + roles)) kwargs["body"] = body kwargs["private_key"] = private_key kwargs["chain"] = chain if kwargs.get("roles"): kwargs["roles"] += roles else: kwargs["roles"] = roles cert = upload(**kwargs) kwargs["authority_certificate"] = cert if kwargs.get("plugin", {}).get("plugin_options", []): # encrypt the private key before persisting in DB for option in kwargs.get("plugin").get("plugin_options"): if option["name"] == "acme_private_key" and option["value"]: option["value"] = data_encrypt(option["value"]) kwargs["options"] = json.dumps(kwargs["plugin"]["plugin_options"]) authority = Authority(**kwargs) authority = database.create(authority) kwargs["creator"].authorities.append(authority) log_service.audit_log("create_authority", ca_name, "Created new authority") issuer = kwargs["plugin"]["plugin_object"] current_app.logger.warning( f"Created new authority {ca_name} with issuer {issuer.title}") metrics.send("authority_created", "counter", 1, metric_tags=dict(owner=authority.owner)) return authority
def create(**kwargs): """ Creates a new API Key. :param kwargs: :return: """ api_key = ApiKey(**kwargs) # this logs only metadata about the api key log_service.audit_log("create_api_key", api_key.name, f"Creating the API key {api_key}") database.create(api_key) return api_key
def get(self, pending_certificate_id): """ .. http:get:: /pending_certificates/1/key Retrieves the private key for a given pneding certificate **Example request**: .. sourcecode:: http GET /pending_certificates/1/key HTTP/1.1 Host: example.com Accept: application/json, text/javascript **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: text/javascript { "key": "-----BEGIN ..." } :reqheader Authorization: OAuth token to authenticate :statuscode 200: no error :statuscode 403: unauthenticated """ cert = service.get(pending_certificate_id) if not cert: return dict(message="Cannot find specified pending certificate"), 404 # allow creators if g.current_user != cert.user: owner_role = role_service.get_by_name(cert.owner) permission = CertificatePermission(owner_role, [x.name for x in cert.roles]) if not permission.can(): return dict(message="You are not authorized to view this key"), 403 response = make_response(jsonify(key=cert.private_key), 200) response.headers["cache-control"] = "private, max-age=0, no-cache, no-store" response.headers["pragma"] = "no-cache" log_service.audit_log("export_private_key_pending_certificate", cert.name, "Exported Private key for the pending certificate") return response
def get(self, role_id): """ .. http:get:: /roles/1/credentials View a roles credentials **Example request**: .. sourcecode:: http GET /users/1 HTTP/1.1 Host: example.com Accept: application/json, text/javascript **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: text/javascript { "username": "******", "password": "******" } :reqheader Authorization: OAuth token to authenticate :statuscode 200: no error :statuscode 403: unauthenticated """ permission = RoleMemberPermission(role_id) if permission.can(): role = service.get(role_id) response = make_response( jsonify(username=role.username, password=role.password), 200 ) response.headers["cache-control"] = "private, max-age=0, no-cache, no-store" response.headers["pragma"] = "no-cache" log_service.audit_log("view_role_credentials", role.name, "View role username and password") return response return ( dict( message="You are not authorized to view the credentials for this role." ), 403, )
def set_third_party(role_id, third_party_status=False): """ Sets a role to be a third party role. A user should pretty much never call this directly. :param role_id: :param third_party_status: :return: """ role = get(role_id) role.third_party = third_party_status database.update(role) log_service.audit_log("update_role", role.name, f"Updated third_party_status={third_party_status}") return role
def create(data): provider_name = data.get("name") credentials = {} for item in data.get("provider_type", {}).get("requirements", []): credentials[item["name"]] = item["value"] dns_provider = DnsProvider( name=provider_name, description=data.get("description"), provider_type=data.get("provider_type").get("name"), credentials=json.dumps(credentials), ) created = database.create(dns_provider) log_service.audit_log("create_dns_provider", provider_name, "Created new DNS provider") return created.id
def cancel(pending_certificate, **kwargs): """ Cancel a pending certificate. A check should be done prior to this function to decide to revoke the certificate or just abort cancelling. :arg pending_certificate: PendingCertificate to be cancelled :return: the pending certificate if successful, raises Exception if there was an issue """ plugin = plugins.get(pending_certificate.authority.plugin_name) plugin.cancel_ordered_certificate(pending_certificate, **kwargs) pending_certificate.status = "Cancelled" database.update(pending_certificate) log_service.audit_log("cancel_pending_certificate", pending_certificate.name, "Cancelled the pending certificate") return pending_certificate
def create(label, plugin_name, options, description=None): """ Creates a new source, that can then be used as a source for certificates. :param label: Source common name :param plugin_name: :param options: :param description: :rtype: Source :return: New source """ source = Source(label=label, options=options, plugin_name=plugin_name, description=description) log_service.audit_log("create_source", source.label, "Creating new source") return database.create(source)
def update(authority_id, description, owner, active, roles): """ Update an authority with new values. :param authority_id: :param roles: roles that are allowed to use this authority :return: """ authority = get(authority_id) authority.roles = roles authority.active = active authority.description = description authority.owner = owner log_service.audit_log("update_authority", authority.name, "Updating authority") # check ui what can be updated return database.update(authority)
def update(role_id, name, description, users): """ Update a role :param role_id: :param name: :param description: :param users: :return: """ role = get(role_id) role.name = name role.description = description role.users = users database.update(role) log_service.audit_log("update_role", name, f"Role with id {role_id} updated") return role
def update_user(user, profile, roles): """Updates user with current profile information and associated roles. :param user: :param profile: :param roles: """ # if we get an sso user create them an account if not user: user = user_service.create( profile["email"], get_psuedo_random_string(), profile["email"], True, profile.get("thumbnailPhotoUrl"), roles, ) else: # we add 'lemur' specific roles, so they do not get marked as removed removed_roles = [] for ur in user.roles: if not ur.third_party: roles.append(ur) elif ur not in roles: # This is a role assigned in lemur, but not returned by sso during current login removed_roles.append(ur.name) if removed_roles: log_service.audit_log("unassign_role", user.username, f"Un-assigning roles {removed_roles}") # update any changes to the user user_service.update( user.id, profile["email"], profile["email"], True, profile.get("thumbnailPhotoUrl"), # profile isn't google+ enabled roles, ) return user
def create(**kwargs): """ Creates a new authority. """ ca_name = kwargs.get("name") if get_by_name(ca_name): raise Exception(f"Authority with name {ca_name} already exists") if role_service.get_by_name( f"{ca_name}_admin") or role_service.get_by_name( f"{ca_name}_operator"): raise Exception( f"Admin and/or operator roles for authority {ca_name} already exist" ) body, private_key, chain, roles = mint(**kwargs) kwargs["creator"].roles = list(set(list(kwargs["creator"].roles) + roles)) kwargs["body"] = body kwargs["private_key"] = private_key kwargs["chain"] = chain if kwargs.get("roles"): kwargs["roles"] += roles else: kwargs["roles"] = roles cert = upload(**kwargs) kwargs["authority_certificate"] = cert if kwargs.get("plugin", {}).get("plugin_options", []): kwargs["options"] = json.dumps(kwargs["plugin"]["plugin_options"]) authority = Authority(**kwargs) authority = database.create(authority) kwargs["creator"].authorities.append(authority) log_service.audit_log("create_authority", ca_name, "Created new authority") metrics.send("authority_created", "counter", 1, metric_tags=dict(owner=authority.owner)) return authority
def delete(source_id): """ Deletes an source. :param source_id: Lemur assigned ID """ source = get(source_id) if source: # remove association of this source from all valid certificates certificates = certificate_service.get_all_valid_certificates_with_source( source_id) for certificate in certificates: certificate_service.remove_source_association(certificate, source) current_app.logger.warning( f"Removed source {source.label} for {certificate.name} during source delete" ) # proceed with source delete log_service.audit_log("delete_source", source.label, "Deleting source") database.delete(source)