def get_crl(request): pki = PKI() pki.ensure_crl() # noinspection PyTypeChecker with open(pki.cacrl_path, 'rb') as fd: content = fd.read() return HttpResponse(content, content_type='text/plain')
def setUpClass(cls): TestCase.setUpClass() pki = PKI() pki.initialize() entry = CertificateEntry(cls.domain_name, organizationalUnitName='certificates', emailAddress=settings.PENATES_EMAIL_ADDRESS, localityName=settings.PENATES_LOCALITY, countryName=settings.PENATES_COUNTRY, stateOrProvinceName=settings.PENATES_STATE, altNames=[], role=CA) pki.ensure_ca(entry)
def set_service(request, scheme, hostname, port): encryption = request.GET.get('encryption', 'none') srv_field = request.GET.get('srv', None) kerberos_service = request.GET.get('keytab', None) role = request.GET.get('role', SERVICE) protocol = request.GET.get('protocol', 'tcp') if encryption not in ('none', 'tls', 'starttls'): return HttpResponse('valid encryption levels are none, tls, or starttls') port = int(port) if not (0 <= port <= 65536): return HttpResponse('Invalid port: %s' % port, status=403, content_type='text/plain') if protocol not in ('tcp', 'udp', 'socket'): return HttpResponse('Invalid protocol: %s' % protocol, status=403, content_type='text/plain') description = request.body fqdn = hostname_from_principal(request.user.username) # a few checks if Service.objects.filter(hostname=hostname).exclude(fqdn=fqdn).count() > 0: return HttpResponse(status=401, content='%s is already registered' % hostname) if role not in (SERVICE, KERBEROS_DC, PRINTER, TIME_SERVER, SERVICE_1024): return HttpResponse(status=401, content='Role %s is not allowed' % role) if kerberos_service and kerberos_service not in ('HTTP', 'XMPP', 'smtp', 'IPP', 'ldap', 'cifs', 'imap', 'postgres', 'host'): return HttpResponse(status=401, content='Kerberos service %s is not allowed' % role) hosts = list(Host.objects.filter(fqdn=fqdn)[0:1]) if not hosts: return HttpResponse(status=401, content='Unknown host %s is not allowed' % fqdn) host = hosts[0] if scheme == 'ssh' and host.admin_ip_address != host.main_ip_address: fqdn = '%s.%s%s' % (fqdn.partition('.')[0], settings.PDNS_ADMIN_PREFIX, settings.PENATES_DOMAIN) # Penates service service, created = Service.objects.get_or_create(fqdn=fqdn, scheme=scheme, hostname=hostname, port=port, protocol=protocol) Service.objects.filter(pk=service.pk).update(kerberos_service=kerberos_service, description=description, dns_srv=srv_field, encryption=encryption) # certificates entry = CertificateEntry(hostname, organizationName=settings.PENATES_ORGANIZATION, organizationalUnitName=_('Services'), emailAddress=settings.PENATES_EMAIL_ADDRESS, localityName=settings.PENATES_LOCALITY, countryName=settings.PENATES_COUNTRY, stateOrProvinceName=settings.PENATES_STATE, altNames=[], role=role) pki = PKI() pki.ensure_certificate(entry) if kerberos_service: principal_name = '%s/%s@%s' % (kerberos_service, fqdn, settings.PENATES_REALM) add_principal(principal_name) # DNS part record_name, sep, domain_name = hostname.partition('.') if sep == '.': domains = list(Domain.objects.filter(name=domain_name)[0:1]) if domains: domain = domains[0] domain.ensure_record(fqdn, hostname) domain.set_extra_records(scheme, hostname, port, fqdn, srv_field, entry=entry) domain.update_soa() return HttpResponse(status=201, content='%s://%s:%s/ created' % (scheme, hostname, port))
def handle(self, *args, **options): role = options['role'] if role not in ROLES: self.stdout.write(self.style.ERROR('Invalid role: %s' % role)) self.stdout.write('Valid roles: %s' % ', '.join(ROLES)) return alt_names = [] for alt_name in options['altNames']: kind, sep, value = alt_name.partition(':') if sep != ':' or kind not in dict(ALT_TYPES): self.stdout.write( self.style.ERROR( 'Altname %s must be of form KIND:VALUE with KIND one of %s' % (alt_name, ', '.join(ALT_TYPES)))) return alt_names.append((kind, value)) for key in 'cert', 'key', 'ssh', 'ca', 'pubssh', 'pubkey': if not options[key]: continue try: with open(options[key], 'wb') as fd: fd.write(b'') except OSError: self.stdout.write( self.style.ERROR('Unable to write file: %s' % options[key])) return entry = CertificateEntry( options['commonName'], organizationalUnitName=options['organizationalUnitName'], emailAddress=options['emailAddress'], localityName=options['localityName'], countryName=options['countryName'], stateOrProvinceName=options['stateOrProvinceName'], altNames=alt_names, role=role) pki = PKI() pki.initialize() if options['initialize']: pki.ensure_ca(entry) else: pki.ensure_certificate(entry) ca_crt_path, ca_key_path = pki.get_subca_infos(entry) for key, attr in ( ('cert', 'crt_filename'), ('key', 'key_filename'), ('ssh', 'key_filename'), ('ca', 'ca_filename'), ('pubssh', 'ssh_filename'), ('pubkey', 'pub_filename'), ): dst_filename = options[key] if not dst_filename: continue if key == 'ca': open(dst_filename, 'ab').write(open(ca_crt_path, 'rb').read()) src_filename = getattr(entry, attr) open(dst_filename, 'ab').write(open(src_filename, 'rb').read()) self.stdout.write('File %s written' % dst_filename)
def get_host_keytab(request, hostname): """Register a computer: - create Kerberos principal - create private key - create public SSH key - create x509 certificate - create PTR DNS record - create A or AAAA DNS record - create SSHFP DNS record - return keytab :param request: :type request: :param hostname: :type hostname: :return: :rtype: """ admin_ip_address = request.GET.get('ip_address') ip_address = request.META.get('HTTP_X_FORWARDED_FOR') short_hostname = hostname.partition('.')[0] domain_name = settings.PENATES_DOMAIN fqdn = '%s.%s%s' % (short_hostname, settings.PDNS_INFRA_PREFIX, domain_name) # valid FQDN # create Kerberos principal principal = principal_from_hostname(fqdn, settings.PENATES_REALM) if principal_exists(principal): return HttpResponse('', status=403) else: add_principal(principal) Host.objects.get_or_create(fqdn=fqdn) # create private key, public key, public certificate, public SSH key entry = entry_from_hostname(fqdn) pki = PKI() pki.ensure_certificate(entry) # create DNS records if ip_address: Domain.ensure_auto_record(ip_address, fqdn, unique=True, override_reverse=True) Host.objects.filter(fqdn=fqdn).update(main_ip_address=ip_address) if admin_ip_address: admin_fqdn = '%s.%s%s' % (short_hostname, settings.PDNS_ADMIN_PREFIX, domain_name) Domain.ensure_auto_record(admin_ip_address, admin_fqdn, unique=True, override_reverse=False) Host.objects.filter(fqdn=fqdn).update(admin_ip_address=admin_ip_address) if settings.OFFER_HOST_KEYTABS: return KeytabResponse(principal) return HttpResponse('', content_type='text/plain', status=201)
def register_host(short_hostname, main_ip_address=None, admin_ip_address=None): fqdn = '%s.%s%s' % (short_hostname, settings.PDNS_INFRA_PREFIX, settings.PENATES_DOMAIN) principal = principal_from_hostname(fqdn, settings.PENATES_REALM) add_principal(principal) Host.objects.get_or_create(fqdn=fqdn) # create private key, public key, public certificate, public SSH key entry = entry_from_hostname(fqdn) pki = PKI() pki.ensure_certificate(entry) # create DNS records if main_ip_address: Domain.ensure_auto_record(main_ip_address, fqdn, unique=True, override_reverse=True) Host.objects.filter(fqdn=fqdn).update(main_ip_address=main_ip_address) if admin_ip_address: admin_fqdn = '%s.%s%s' % (short_hostname, settings.PDNS_ADMIN_PREFIX, settings.PENATES_DOMAIN) Domain.ensure_auto_record(admin_ip_address, admin_fqdn, unique=True, override_reverse=False) Host.objects.filter(fqdn=fqdn).update(admin_ip_address=admin_ip_address) return principal
def __init__(self, entry, ensure_entry=True, **kwargs): pki = PKI() if ensure_entry: pki.ensure_certificate(entry) content = b'' # noinspection PyTypeChecker with open(entry.key_filename, 'rb') as fd: content += fd.read() # noinspection PyTypeChecker with open(entry.crt_filename, 'rb') as fd: content += fd.read() ca_crt_path, ca_key_path = pki.get_subca_infos(entry) # noinspection PyTypeChecker with open(ca_crt_path, 'rb') as fd: content += fd.read() # noinspection PyTypeChecker with open(entry.ca_filename, 'rb') as fd: content += fd.read() super(CertificateEntryResponse, self).__init__(content=content, content_type='text/plain', **kwargs)
def get_service_certificate(request, scheme, hostname, port): fqdn = hostname_from_principal(request.user.username) role = request.GET.get('role', SERVICE) protocol = request.GET.get('protocol', 'tcp') port = int(port) services = list(Service.objects.filter(fqdn=fqdn, scheme=scheme, hostname=hostname, port=port, protocol=protocol)[0:1]) if not services: return HttpResponse(status=404, content='%s://%s:%s/ unknown' % (scheme, hostname, port)) if role not in (SERVICE, KERBEROS_DC, PRINTER, TIME_SERVER, SERVICE_1024): return HttpResponse(status=401, content='Role %s is not allowed' % role) entry = CertificateEntry(hostname, organizationName=settings.PENATES_ORGANIZATION, organizationalUnitName=_('Services'), emailAddress=settings.PENATES_EMAIL_ADDRESS, localityName=settings.PENATES_LOCALITY, countryName=settings.PENATES_COUNTRY, stateOrProvinceName=settings.PENATES_STATE, altNames=[], role=role) pki = PKI() pki.ensure_certificate(entry) record_name, sep, domain_name = hostname.partition('.') domain = Domain.objects.get(name=domain_name) domain.set_certificate_records(entry, protocol, hostname, port) return CertificateEntryResponse(entry)
def get_service_certificate(request, scheme, hostname, port): try: fqdn = hostname_from_principal(request.user.username) except ValueError: return HttpResponse( status=401, content='Unable to get service certificate: invalid username') role = request.GET.get('role', SERVICE) protocol = request.GET.get('protocol', 'tcp') port = int(port) query = Service.objects.filter(fqdn=fqdn, scheme=scheme, hostname=hostname, port=port, protocol=protocol) services = list(query[0:1]) if not services: return HttpResponse(status=404, content='%s://%s:%s/ unknown' % (scheme, hostname, port)) if role not in (SERVICE, KERBEROS_DC, PRINTER, TIME_SERVER, SERVICE_1024): return HttpResponse(status=401, content='Role %s is not allowed' % role) entry = CertificateEntry(hostname, organizationName=settings.PENATES_ORGANIZATION, organizationalUnitName=_('Services'), emailAddress=settings.PENATES_EMAIL_ADDRESS, localityName=settings.PENATES_LOCALITY, countryName=settings.PENATES_COUNTRY, stateOrProvinceName=settings.PENATES_STATE, altNames=[], role=role) pki = PKI() pki.ensure_certificate(entry) record_name, sep, domain_name = hostname.partition('.') domain = Domain.objects.get(name=domain_name) domain.set_certificate_records(entry, protocol, hostname, port) return CertificateEntryResponse(entry)
def setUpClass(cls): TestCase.setUpClass() cls.dirname = tempfile.mkdtemp() cls.pki = PKI(dirname=cls.dirname) cls.ca_entry = CertificateEntry('test_CA', organizationName='test_org', organizationalUnitName='test_unit', emailAddress='*****@*****.**', localityName='City', countryName='FR', stateOrProvinceName='Province', altNames=[], role=CA_TEST, dirname=cls.dirname)
def handle(self, *args, **options): role = options['role'] if role not in ROLES: self.stdout.write(self.style.ERROR('Invalid role: %s' % role)) self.stdout.write('Valid roles: %s' % ', '.join(ROLES)) return alt_names = [] for alt_name in options['altNames']: kind, sep, value = alt_name.partition(':') if sep != ':' or kind not in dict(ALT_TYPES): self.stdout.write(self.style.ERROR('Altname %s must be of form KIND:VALUE with KIND one of %s' % (alt_name, ', '.join(ALT_TYPES)))) return alt_names.append((kind, value)) for key in 'cert', 'key', 'ssh', 'ca', 'pubssh', 'pubkey': if not options[key]: continue try: with open(options[key], 'wb') as fd: fd.write(b'') except OSError: self.stdout.write(self.style.ERROR('Unable to write file: %s' % options[key])) return entry = CertificateEntry(options['commonName'], organizationalUnitName=options['organizationalUnitName'], emailAddress=options['emailAddress'], localityName=options['localityName'], countryName=options['countryName'], stateOrProvinceName=options['stateOrProvinceName'], altNames=alt_names, role=role) pki = PKI() pki.initialize() if options['initialize']: pki.ensure_ca(entry) else: pki.ensure_certificate(entry) ca_crt_path, ca_key_path = pki.get_subca_infos(entry) for key, attr in (('cert', 'crt_filename'), ('key', 'key_filename'), ('ssh', 'key_filename'), ('ca', 'ca_filename'), ('pubssh', 'ssh_filename'), ('pubkey', 'pub_filename'), ): dst_filename = options[key] if not dst_filename: continue if key == 'ca': open(dst_filename, 'ab').write(open(ca_crt_path, 'rb').read()) src_filename = getattr(entry, attr) open(dst_filename, 'ab').write(open(src_filename, 'rb').read()) self.stdout.write('File %s written' % dst_filename)
def get_ca_certificate(request, kind='ca'): pki = PKI() if kind == 'ca': path = pki.cacrt_path elif kind == 'users': path = pki.users_crt_path elif kind == 'hosts': path = pki.hosts_crt_path elif kind == 'services': path = pki.services_crt_path else: raise PermissionDenied # noinspection PyTypeChecker with open(path, 'rb') as fd: content = fd.read() return HttpResponse(content, content_type='text/plain')
def get_user_mobileconfig(request): user = get_object_or_404(User, name=request.user.username) password = request.GET.get('password', '') if not password: password = user.read_password() password = password or 'password' pki = PKI() p12_certificates = [] for (entry, title) in ( (user.user_certificate_entry, _('User certificate')), (user.encipherment_certificate_entry, _('Encipherment certificate')), (user.email_certificate_entry, _('Email certificate')), (user.signature_certificate_entry, _('Signature certificate')), ): with tempfile.NamedTemporaryFile() as fd: filename = fd.name pki.ensure_certificate(entry) pki.gen_pkcs12(entry, filename, password=password) p12_certificates.append((filename, title)) def f_scheme(y): if y in ('caldav', 'carddav'): return 'http' return y kerberos_prefixes = [ '%s%s://%s/' % (f_scheme(x[0]), 's' if x[2] == 'tls' else '', x[1]) for x in Service.objects.filter( scheme__in=['http', 'smtp', 'imap', 'ldap', 'caldav', 'carddav' ]).exclude(kerberos_service=None).values_list( 'scheme', 'hostname', 'encryption') ] domain_components = settings.PENATES_DOMAIN.split('.') domain_components.reverse() inverted_domain = '.'.join(domain_components) template_values = { 'domain': settings.PENATES_DOMAIN, 'inverted_domain': inverted_domain, 'organization': settings.PENATES_ORGANIZATION, 'realm': settings.PENATES_REALM, 'ldap_servers': [], 'carddav_servers': [], 'caldav_servers': [], 'email_servers': [], 'kerberos_prefixes': kerberos_prefixes, 'vpn_servers': [], 'http_proxies': [], 'password': password, 'username': user.name, 'user': user, 'ldap_base_dn': settings.LDAP_BASE_DN, 'ca_cert_path': pki.cacrt_path, 'hosts_crt_path': pki.hosts_crt_path, 'users_crt_path': pki.users_crt_path, 'services_crt_path': pki.services_crt_path, 'p12_certificates': p12_certificates, } mail_services = {} for service in Service.objects.all(): if service.scheme == 'ldap': template_values['ldap_servers'].append(service) elif service.scheme == 'carddav': template_values['carddav_servers'].append(service) elif service.scheme == 'caldav': template_values['caldav_servers'].append(service) elif service.scheme == 'imap': mail_services.setdefault(service.hostname, {})['imap'] = service elif service.scheme == 'smtp': mail_services.setdefault(service.hostname, {})['smtp'] = service elif service.scheme == 'proxy_http': template_values['http_proxies'].append(service) template_values['email_servers'] = list(mail_services.values()) response = render_to_response('penatesserver/mobileconfig.xml', template_values, content_type='application/xml') for filename, title in p12_certificates: os.remove(filename) response[ 'Content-Disposition'] = 'attachment; filename=%s.mobileconfig' % request.user.username return response
def set_service(request, scheme, hostname, port): try: fqdn = hostname_from_principal(request.user.username) except ValueError: return HttpResponse( status=401, content='Unable to create %s://%s:%s/: invalid username' % (scheme, hostname, port)) encryption = request.GET.get('encryption', 'none') srv_field = request.GET.get('srv', None) kerberos_service = request.GET.get('keytab', None) role = request.GET.get('role', SERVICE) protocol = request.GET.get('protocol', 'tcp') if encryption not in ('none', 'tls', 'starttls'): return HttpResponse( 'valid encryption levels are none, tls, or starttls') port = int(port) if not (0 <= port <= 65536): return HttpResponse('Invalid port: %s' % port, status=403, content_type='text/plain') if protocol not in ('tcp', 'udp', 'socket'): return HttpResponse('Invalid protocol: %s' % protocol, status=403, content_type='text/plain') description = request.body # a few checks if Service.objects.filter(hostname=hostname).exclude( fqdn=fqdn).count() > 0: return HttpResponse(status=401, content='%s is already registered' % hostname) if role not in (SERVICE, KERBEROS_DC, PRINTER, TIME_SERVER, SERVICE_1024): return HttpResponse(status=401, content='Role %s is not allowed' % role) if kerberos_service and kerberos_service not in settings.KERBEROS_SERVICES: return HttpResponse(status=401, content='Kerberos service %s is not allowed' % role) hosts = list(Host.objects.filter(fqdn=fqdn)[0:1]) if not hosts: return HttpResponse(status=401, content='Unknown host %s is not allowed' % fqdn) host = hosts[0] if scheme == 'ssh' and host.admin_ip_address != host.main_ip_address: fqdn = '%s.%s%s' % (fqdn.partition('.')[0], settings.PDNS_ADMIN_PREFIX, settings.PENATES_DOMAIN) # Penates service service, created = Service.objects.get_or_create(fqdn=fqdn, scheme=scheme, hostname=hostname, port=port, protocol=protocol, defaults={ 'kerberos_service': kerberos_service, 'dns_srv': srv_field, 'encryption': encryption, 'description': description }) Service.objects.filter(pk=service.pk).update( kerberos_service=kerberos_service, description=description, dns_srv=srv_field, encryption=encryption) # certificates entry = CertificateEntry(hostname, organizationName=settings.PENATES_ORGANIZATION, organizationalUnitName=_('Services'), emailAddress=settings.PENATES_EMAIL_ADDRESS, localityName=settings.PENATES_LOCALITY, countryName=settings.PENATES_COUNTRY, stateOrProvinceName=settings.PENATES_STATE, altNames=[], role=role) pki = PKI() pki.ensure_certificate(entry) if kerberos_service: add_principal(service.principal_name) # DNS part record_name, sep, domain_name = hostname.partition('.') if sep == '.': domains = list(Domain.objects.filter(name=domain_name)[0:1]) if domains: domain = domains[0] domain.ensure_record(fqdn, hostname) domain.set_extra_records(scheme, hostname, port, fqdn, srv_field, entry=entry) domain.update_soa() return HttpResponse(status=201, content='%s://%s:%s/ created' % (scheme, hostname, port))
def get_user_mobileconfig(request): user = get_object_or_404(User, name=request.user.username) password = request.GET.get('password', '') if not password: password = user.read_password() password = password or 'password' pki = PKI() p12_certificates = [] for (entry, title) in ( (user.user_certificate_entry, _('User certificate')), (user.encipherment_certificate_entry, _('Encipherment certificate')), (user.email_certificate_entry, _('Email certificate')), (user.signature_certificate_entry, _('Signature certificate')), ): with tempfile.NamedTemporaryFile() as fd: filename = fd.name pki.ensure_certificate(entry) pki.gen_pkcs12(entry, filename, password=password) p12_certificates.append((filename, title)) def f_scheme(y): if y in ('caldav', 'carddav'): return 'http' return y kerberos_prefixes = ['%s%s://%s/' % (f_scheme(x[0]), 's' if x[2] == 'tls' else '', x[1]) for x in Service.objects.filter(scheme__in=['http', 'smtp', 'imap', 'ldap', 'caldav', 'carddav']) .exclude(kerberos_service=None).values_list('scheme', 'hostname', 'encryption')] domain_components = settings.PENATES_DOMAIN.split('.') domain_components.reverse() inverted_domain = '.'.join(domain_components) template_values = { 'domain': settings.PENATES_DOMAIN, 'inverted_domain': inverted_domain, 'organization': settings.PENATES_ORGANIZATION, 'realm': settings.PENATES_REALM, 'ldap_servers': [], 'carddav_servers': [], 'caldav_servers': [], 'email_servers': [], 'kerberos_prefixes': kerberos_prefixes, 'vpn_servers': [], 'http_proxies': [], 'password': password, 'username': user.name, 'user': user, 'ldap_base_dn': settings.LDAP_BASE_DN, 'ca_cert_path': pki.cacrt_path, 'hosts_crt_path': pki.hosts_crt_path, 'users_crt_path': pki.users_crt_path, 'services_crt_path': pki.services_crt_path, 'p12_certificates': p12_certificates, } mail_services = {} for service in Service.objects.all(): if service.scheme == 'ldap': template_values['ldap_servers'].append(service) elif service.scheme == 'carddav': template_values['carddav_servers'].append(service) elif service.scheme == 'caldav': template_values['caldav_servers'].append(service) elif service.scheme == 'imap': mail_services.setdefault(service.hostname, {})['imap'] = service elif service.scheme == 'smtp': mail_services.setdefault(service.hostname, {})['smtp'] = service elif service.scheme == 'proxy_http': template_values['http_proxies'].append(service) template_values['email_servers'] = list(mail_services.values()) response = render_to_response('penatesserver/mobileconfig.xml', template_values, content_type='application/xml') for filename, title in p12_certificates: os.remove(filename) response['Content-Disposition'] = 'attachment; filename=%s.mobileconfig' % request.user.username return response