def test_Backend(self): """ Test using the ldap2 Backend directly (ala ipa-server-install) """ # Create our own api because the one generated for the tests is # a client-only api. Then we register in the commands and objects # we need for the test. myapi = create_api(mode=None) myapi.bootstrap(context='cli', in_server=True, in_tree=True) myapi.register(ldap2) myapi.register(host) myapi.register(service) myapi.register(service_show) myapi.finalize() pwfile = api.env.dot_ipa + os.sep + ".dmpw" if ipautil.file_exists(pwfile): fp = open(pwfile, "r") dm_password = fp.read().rstrip() fp.close() else: raise nose.SkipTest("No directory manager password in %s" % pwfile) myapi.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password) result = myapi.Command['service_show']('ldap/%s@%s' % ( api.env.host, api.env.realm, )) entry_attrs = result['result'] cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) # In the case of services we don't want IPA master services to be # deleted. This is a limited few though. If the user has their own # custom services allow them to manage them. (service, hostname, realm) = split_principal(keys[-1]) check_required_principal(ldap, hostname, service) if self.api.Command.ca_is_enabled()['result']: try: entry_attrs = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) cert = entry_attrs.get('usercertificate') if cert: cert = cert[0] try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # removing the service. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr
def test_Backend(self): """ Test using the ldap2 Backend directly (ala ipa-server-install) """ # Create our own api because the one generated for the tests is # a client-only api. Then we register in the commands and objects # we need for the test. myapi = create_api(mode=None) myapi.bootstrap(context='cli', in_server=True, in_tree=True) myapi.register(ldap2) myapi.register(host) myapi.register(service) myapi.register(service_show) myapi.finalize() pwfile = api.env.dot_ipa + os.sep + ".dmpw" if ipautil.file_exists(pwfile): fp = open(pwfile, "r") dm_password = fp.read().rstrip() fp.close() else: raise nose.SkipTest("No directory manager password in %s" % pwfile) myapi.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password) result = myapi.Command['service_show']('ldap/%s@%s' % (api.env.host, api.env.realm,)) entry_attrs = result['result'] cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def revoke_certs(certs, logger=None): """ revoke the certificates removed from host/service entry """ for cert in certs: try: cert = x509.normalize_certificate(cert) except errors.CertificateFormatError as e: if logger is not None: logger.info("Problem decoding certificate: %s" % e) serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result'] except errors.CertificateOperationError: continue if 'revocation_reason' in result: continue if x509.normalize_certificate(result['certificate']) != cert: continue try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass
def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) # In the case of services we don't want IPA master services to be # deleted. This is a limited few though. If the user has their own # custom services allow them to manage them. (service, hostname, realm) = split_principal(keys[-1]) check_required_principal(ldap, hostname, service) if self.api.env.enable_ra: try: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) cert = entry_attrs.get('usercertificate') if cert: cert = cert[0] try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # removing the service. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) self.obj.validate_ipakrbauthzdata(entry_attrs) if 'usercertificate' in options: (service, hostname, realm) = split_principal(keys[-1]) cert = options.get('usercertificate') if cert: dercert = x509.normalize_certificate(cert) x509.verify_cert_subject(ldap, hostname, dercert) try: (dn, entry_attrs_old) = ldap.get_entry( dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) if 'usercertificate' in entry_attrs_old: # FIXME: what to do here? do we revoke the old cert? fmt = 'entry already has a certificate, serial number: %s' % ( x509.get_serial_number(entry_attrs_old['usercertificate'][0], x509.DER) ) raise errors.GenericError(format=fmt) entry_attrs['usercertificate'] = dercert else: entry_attrs['usercertificate'] = None update_krbticketflags(ldap, entry_attrs, attrs_list, options, True) return dn
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.validate_ipakrbauthzdata(entry_attrs) if 'usercertificate' in options: (service, hostname, realm) = split_principal(keys[-1]) cert = options.get('usercertificate') if cert: dercert = x509.normalize_certificate(cert) x509.verify_cert_subject(ldap, hostname, dercert) try: (dn, entry_attrs_old) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) if 'usercertificate' in entry_attrs_old: # FIXME: what to do here? do we revoke the old cert? fmt = 'entry already has a certificate, serial number: %s' % ( x509.get_serial_number( entry_attrs_old['usercertificate'][0], x509.DER)) raise errors.GenericError(format=fmt) entry_attrs['usercertificate'] = dercert else: entry_attrs['usercertificate'] = None return dn
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # Allow an existing OTP to be reset but don't allow a OTP to be # added to an enrolled host. if options.get('userpassword') or options.get('random'): entry = {} self.obj.get_password_attributes(ldap, dn, entry) if not entry['has_password'] and entry['has_keytab']: raise errors.ValidationError(name='password', error=_('Password cannot be set on enrolled host.')) # Once a principal name is set it cannot be changed if 'cn' in entry_attrs: raise errors.ACIError(info=_('cn is immutable')) if 'locality' in entry_attrs: entry_attrs['l'] = entry_attrs['locality'] if 'krbprincipalname' in entry_attrs: (dn, entry_attrs_old) = ldap.get_entry( dn, ['objectclass', 'krbprincipalname'] ) if 'krbprincipalname' in entry_attrs_old: msg = 'Principal name already set, it is unchangeable.' raise errors.ACIError(info=msg) obj_classes = entry_attrs_old['objectclass'] if 'krbprincipalaux' not in obj_classes: obj_classes.append('krbprincipalaux') entry_attrs['objectclass'] = obj_classes cert = x509.normalize_certificate(entry_attrs.get('usercertificate')) if cert: if self.api.env.enable_ra: x509.verify_cert_subject(ldap, keys[-1], cert) (dn, entry_attrs_old) = ldap.get_entry(dn, ['usercertificate']) oldcert = entry_attrs_old.single_value.get('usercertificate') if oldcert: oldcert = x509.normalize_certificate(oldcert) try: serial = x509.get_serial_number(oldcert, x509.DER) serial = unicode(serial) try: result = api.Command['cert_show'](serial)['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke']( serial, revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # modifying the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr entry_attrs['usercertificate'] = cert
def _parse_cert(dercert): try: subject = x509.get_subject(dercert, x509.DER) issuer = x509.get_issuer(dercert, x509.DER) serial_number = x509.get_serial_number(dercert, x509.DER) public_key_info = x509.get_der_public_key_info(dercert, x509.DER) except (NSPRError, PyAsn1Error), e: raise ValueError("failed to decode certificate: %s" % e)
def test_2_get_serial_number(self): """ Test retrieving the serial number """ serial = x509.get_serial_number(goodcert) assert serial == 1093 der = base64.b64decode(goodcert) serial = x509.get_serial_number(der, x509.DER) assert serial == 1093 # We should be able to pass in a tuple/list of certs too serial = x509.get_serial_number((goodcert)) assert serial == 1093 serial = x509.get_serial_number([goodcert]) assert serial == 1093
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # Allow an existing OTP to be reset but don't allow a OTP to be # added to an enrolled host. if options.get('userpassword') or options.get('random'): entry = {} self.obj.get_password_attributes(ldap, dn, entry) if not entry['has_password'] and entry['has_keytab']: raise errors.ValidationError(name='password', error=_('Password cannot be set on enrolled host.')) # Once a principal name is set it cannot be changed if 'cn' in entry_attrs: raise errors.ACIError(info=_('cn is immutable')) if 'locality' in entry_attrs: entry_attrs['l'] = entry_attrs['locality'] del entry_attrs['locality'] if 'krbprincipalname' in entry_attrs: (dn, entry_attrs_old) = ldap.get_entry( dn, ['objectclass', 'krbprincipalname'] ) if 'krbprincipalname' in entry_attrs_old: msg = 'Principal name already set, it is unchangeable.' raise errors.ACIError(info=msg) obj_classes = entry_attrs_old['objectclass'] if 'krbprincipalaux' not in obj_classes: obj_classes.append('krbprincipalaux') entry_attrs['objectclass'] = obj_classes cert = x509.normalize_certificate(entry_attrs.get('usercertificate')) if cert: x509.verify_cert_subject(ldap, keys[-1], cert) (dn, entry_attrs_old) = ldap.get_entry(dn, ['usercertificate']) if 'usercertificate' in entry_attrs_old: oldcert = x509.normalize_certificate(entry_attrs_old.get('usercertificate')[0]) try: serial = unicode(x509.get_serial_number(oldcert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # modifying the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr entry_attrs['usercertificate'] = cert
def test_GSSAPI(self): """ Test a GSSAPI LDAP bind using ldap2 """ self.conn = ldap2(api, ldap_uri=self.ldapuri) self.conn.connect() entry_attrs = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def test_anonymous(self): """ Test an anonymous LDAP bind using ldap2 """ self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri) self.conn.connect() (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def test_GSSAPI(self): """ Test a GSSAPI LDAP bind using ldap2 """ if not ipautil.file_exists(self.ccache): raise nose.SkipTest('Missing ccache %s' % self.ccache) self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri) self.conn.connect(ccache='FILE:%s' % self.ccache) (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def test_GSSAPI(self): """ Test a GSSAPI LDAP bind using ldap2 """ if not ipautil.file_exists(self.ccache): raise nose.SkipTest('Missing ccache %s' % self.ccache) self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri) self.conn.connect(ccache='FILE:%s' % self.ccache) entry_attrs = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def test_GSSAPI(self): """ Test a GSSAPI LDAP bind using ldap2 """ if not ipautil.file_exists(self.ccache): raise nose.SkipTest("Missing ccache %s" % self.ccache) self.conn = ldap2(api, ldap_uri=self.ldapuri) self.conn.connect(ccache="FILE:%s" % self.ccache) entry_attrs = self.conn.get_entry(self.dn, ["usercertificate"]) cert = entry_attrs.get("usercertificate") cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def _parse_cert(dercert): try: subject = x509.get_subject(dercert, x509.DER) issuer = x509.get_issuer(dercert, x509.DER) serial_number = x509.get_serial_number(dercert, x509.DER) public_key_info = x509.get_der_public_key_info(dercert, x509.DER) except (NSPRError, PyAsn1Error) as e: raise ValueError("failed to decode certificate: %s" % e) subject = str(subject).replace('\\;', '\\3b') issuer = str(issuer).replace('\\;', '\\3b') issuer_serial = '%s;%s' % (issuer, serial_number) return subject, issuer_serial, public_key_info
def test_autobind(self): """ Test an autobind LDAP bind using ldap2 """ ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % api.env.realm.replace('.','-') self.conn = ldap2(api, ldap_uri=ldapuri) try: self.conn.connect(autobind=True) except errors.ACIError: raise nose.SkipTest("Only executed as root") entry_attrs = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def test_autobind(self): """ Test an autobind LDAP bind using ldap2 """ ldapuri = "ldapi://%%2fvar%%2frun%%2fslapd-%s.socket" % api.env.realm.replace(".", "-") self.conn = ldap2(api, ldap_uri=ldapuri) try: self.conn.connect(autobind=True) except errors.ACIError: raise nose.SkipTest("Only executed as root") entry_attrs = self.conn.get_entry(self.dn, ["usercertificate"]) cert = entry_attrs.get("usercertificate") cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def test_autobind(self): """ Test an autobind LDAP bind using ldap2 """ ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % api.env.realm.replace('.','-') self.conn = ldap2(shared_instance=False, ldap_uri=ldapuri) try: self.conn.connect(autobind=True) except errors.ACIError: raise nose.SkipTest("Only executed as root") (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def test_simple(self): """ Test a simple LDAP bind using ldap2 """ pwfile = api.env.dot_ipa + os.sep + ".dmpw" if ipautil.file_exists(pwfile): fp = open(pwfile, "r") dm_password = fp.read().rstrip() fp.close() else: raise nose.SkipTest("No directory manager password in %s" % pwfile) self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri) self.conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password) (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) self.obj.validate_ipakrbauthzdata(entry_attrs) (service, hostname, realm) = split_principal(keys[-1]) # verify certificates certs = entry_attrs.get('usercertificate') or [] certs_der = map(x509.normalize_certificate, certs) for dercert in certs_der: x509.verify_cert_subject(ldap, hostname, dercert) # revoke removed certificates if certs and self.api.Command.ca_is_enabled()['result']: try: entry_attrs_old = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) old_certs = entry_attrs_old.get('usercertificate', []) old_certs_der = map(x509.normalize_certificate, old_certs) removed_certs_der = set(old_certs_der) - set(certs_der) for cert in removed_certs_der: try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](serial)['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke']( serial, revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # modifying the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr
def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) (service, hostname, realm) = split_principal(keys[-1]) check_required_principal(ldap, hostname, service) # See if we do any work at all here and if not raise an exception done_work = False if 'usercertificate' in entry_attrs: cert = x509.normalize_certificate( entry_attrs.get('usercertificate')[0]) try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show']( unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # disabling the service self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr # Remove the usercertificate altogether ldap.update_entry(dn, {'usercertificate': None}) done_work = True
def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) entry_attrs = ldap.get_entry(dn, ['usercertificate']) (service, hostname, realm) = split_principal(keys[-1]) check_required_principal(ldap, hostname, service) # See if we do any work at all here and if not raise an exception done_work = False if self.api.Command.ca_is_enabled()['result']: certs = entry_attrs.get('usercertificate', []) for cert in map(x509.normalize_certificate, certs): try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # disabling the service self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr if len(certs) > 0: # Remove the usercertificate altogether entry_attrs['usercertificate'] = None ldap.update_entry(entry_attrs) done_work = True
pass try: cert_fd = open(cert_name) cert = cert_fd.read() cert_fd.close() finally: try: os.remove(cert_name) except: pass try: subject = x509.get_subject(cert) serial = x509.get_serial_number(cert) except NSPRError, e: self.log.error('Unable to decode certificate in entry: %s' % str(e)) raise errors.CertificateOperationError( error=_('Unable to decode certificate in entry: %s') % str(e)) # To make it look like dogtag return just the base64 data. cert = cert.replace('\n','') cert = cert.replace('\r','') s = cert.find('-----BEGIN CERTIFICATE-----') e = cert.find('-----END CERTIFICATE-----') s = s + 27 cert = cert[s:e] cmd_result = {} cmd_result['serial_number'] = unicode(serial) # convert long to decimal unicode string
raise errors.ACIError(info=_( "Insufficient privilege to create a certificate with " "subject alt name '%s'.") % name) elif name_type in (pkcs10.SAN_OTHERNAME_KRB5PRINCIPALNAME, pkcs10.SAN_OTHERNAME_UPN): if name != principal: raise errors.ACIError( info=_("Principal '%s' in subject alt name does not " "match requested service principal") % name) else: raise errors.ACIError( info=_("Subject alt name type %s is forbidden") % name_type) if 'usercertificate' in service: serial = x509.get_serial_number(service['usercertificate'][0], datatype=x509.DER) # revoke the certificate and remove it from the service # entry before proceeding. First we retrieve the certificate to # see if it is already revoked, if not then we revoke it. try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement get pass
class cert_request(VirtualCommand): __doc__ = _('Submit a certificate signing request.') takes_args = (File( 'csr', validate_csr, label=_('CSR'), cli_name='csr_file', normalizer=normalize_csr, ), ) operation = "request certificate" takes_options = ( Str( 'principal', label=_('Principal'), doc= _('Service principal for this certificate (e.g. HTTP/test.example.com)' ), ), Str( 'request_type', default=u'pkcs10', autofill=True, ), Flag('add', doc=_("automatically add the principal if it doesn't exist"), default=False, autofill=True), ) has_output_params = ( Str( 'certificate', label=_('Certificate'), ), Str( 'subject', label=_('Subject'), ), Str( 'issuer', label=_('Issuer'), ), Str( 'valid_not_before', label=_('Not Before'), ), Str( 'valid_not_after', label=_('Not After'), ), Str( 'md5_fingerprint', label=_('Fingerprint (MD5)'), ), Str( 'sha1_fingerprint', label=_('Fingerprint (SHA1)'), ), Str( 'serial_number', label=_('Serial number'), ), Str( 'serial_number_hex', label=_('Serial number (hex)'), ), ) has_output = (Output( 'result', type=dict, doc=_('Dictionary mapping variable name to value'), ), ) def execute(self, csr, **kw): ldap = self.api.Backend.ldap2 principal = kw.get('principal') add = kw.get('add') del kw['principal'] del kw['add'] service = None """ Access control is partially handled by the ACI titled 'Hosts can modify service userCertificate'. This is for the case where a machine binds using a host/ prinicpal. It can only do the request if the target hostname is in the managedBy attribute which is managed using the add/del member commands. Binding with a user principal one needs to be in the request_certs taskgroup (directly or indirectly via role membership). """ bind_principal = getattr(context, 'principal') # Can this user request certs? if not bind_principal.startswith('host/'): self.check_access() # FIXME: add support for subject alt name # Ensure that the hostname in the CSR matches the principal subject_host = get_csr_hostname(csr) (servicename, hostname, realm) = split_principal(principal) if subject_host.lower() != hostname.lower(): raise errors.ACIError( info=_("hostname in subject of request '%(subject_host)s' " "does not match principal hostname '%(hostname)s'") % dict(subject_host=subject_host, hostname=hostname)) dn = None service = None # See if the service exists and punt if it doesn't and we aren't # going to add it try: if not principal.startswith('host/'): service = api.Command['service_show'](principal, all=True, raw=True)['result'] dn = service['dn'] else: hostname = get_host_from_principal(principal) service = api.Command['host_show'](hostname, all=True, raw=True)['result'] dn = service['dn'] except errors.NotFound, e: if not add: raise errors.NotFound(reason=_("The service principal for " "this request doesn't exist.")) try: service = api.Command['service_add'](principal, **{ 'force': True })['result'] dn = service['dn'] except errors.ACIError: raise errors.ACIError( info=_('You need to be a member of ' 'the serviceadmin role to add services')) # We got this far so the service entry exists, can we write it? if not ldap.can_write(dn, "usercertificate"): raise errors.ACIError( info=_("Insufficient 'write' privilege " "to the 'userCertificate' attribute of entry '%s'.") % dn) # Validate the subject alt name, if any request = pkcs10.load_certificate_request(csr) subjectaltname = pkcs10.get_subjectaltname(request) if subjectaltname is not None: for name in subjectaltname: name = unicode(name) try: hostentry = api.Command['host_show'](name, all=True, raw=True)['result'] hostdn = hostentry['dn'] except errors.NotFound: # We don't want to issue any certificates referencing # machines we don't know about. Nothing is stored in this # host record related to this certificate. raise errors.NotFound(reason=_( 'no host record for ' 'subject alt name %s in certificate request') % name) authprincipal = getattr(context, 'principal') if authprincipal.startswith("host/"): if not hostdn in service.get('managedby', []): raise errors.ACIError(info=_( "Insufficient privilege to create a certificate " "with subject alt name '%s'.") % name) if 'usercertificate' in service: serial = x509.get_serial_number(service['usercertificate'][0], datatype=x509.DER) # revoke the certificate and remove it from the service # entry before proceeding. First we retrieve the certificate to # see if it is already revoked, if not then we revoke it. try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement get pass if not principal.startswith('host/'): api.Command['service_mod'](principal, usercertificate=None) else: hostname = get_host_from_principal(principal) api.Command['host_mod'](hostname, usercertificate=None) # Request the certificate result = self.Backend.ra.request_certificate(csr, **kw) cert = x509.load_certificate(result['certificate']) result['issuer'] = unicode(cert.issuer) result['valid_not_before'] = unicode(cert.valid_not_before_str) result['valid_not_after'] = unicode(cert.valid_not_after_str) result['md5_fingerprint'] = unicode( nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0]) result['sha1_fingerprint'] = unicode( nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0]) # Success? Then add it to the service entry. if 'certificate' in result: if not principal.startswith('host/'): skw = {"usercertificate": str(result.get('certificate'))} api.Command['service_mod'](principal, **skw) else: hostname = get_host_from_principal(principal) skw = {"usercertificate": str(result.get('certificate'))} api.Command['host_mod'](hostname, **skw) return dict(result=result)
def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) # If we aren't given a fqdn, find it if _hostname_validator(None, keys[-1]) is not None: hostentry = api.Command['host_show'](keys[-1])['result'] fqdn = hostentry['fqdn'][0] else: fqdn = keys[-1] host_is_master(ldap, fqdn) # Remove all service records for this host truncated = True while truncated: try: ret = api.Command['service_find'](fqdn) truncated = ret['truncated'] services = ret['result'] except errors.NotFound: break else: for entry_attrs in services: principal = entry_attrs['krbprincipalname'][0] (service, hostname, realm) = split_principal(principal) if hostname.lower() == fqdn: api.Command['service_del'](principal) updatedns = options.get('updatedns', False) if updatedns: try: updatedns = dns_container_exists(ldap) except errors.NotFound: updatedns = False if updatedns: # Remove DNS entries parts = fqdn.split('.') domain = unicode('.'.join(parts[1:])) try: result = api.Command['dnszone_show'](domain)['result'] domain = result['idnsname'][0] except errors.NotFound: self.obj.handle_not_found(*keys) # Get all forward resources for this host records = api.Command['dnsrecord_find'](domain, idnsname=parts[0])['result'] for record in records: if 'arecord' in record: remove_fwd_ptr(record['arecord'][0], parts[0], domain, 'arecord') if 'aaaarecord' in record: remove_fwd_ptr(record['aaaarecord'][0], parts[0], domain, 'aaaarecord') else: # Try to delete all other record types too _attribute_types = [str('%srecord' % t.lower()) for t in _record_types] for attr in _attribute_types: if attr not in ['arecord', 'aaaarecord'] and attr in record: for i in xrange(len(record[attr])): if (record[attr][i].endswith(parts[0]) or record[attr][i].endswith(fqdn+'.')): delkw = { unicode(attr) : record[attr][i] } api.Command['dnsrecord_del'](domain, record['idnsname'][0], **delkw) break try: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) if 'usercertificate' in entry_attrs: cert = x509.normalize_certificate(entry_attrs.get('usercertificate')[0]) try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result' ] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # removing the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr
def execute(self, *keys, **options): ldap = self.obj.backend # If we aren't given a fqdn, find it if _hostname_validator(None, keys[-1]) is not None: hostentry = api.Command['host_show'](keys[-1])['result'] fqdn = hostentry['fqdn'][0] else: fqdn = keys[-1] host_is_master(ldap, fqdn) # See if we actually do anthing here, and if not raise an exception done_work = False dn = self.obj.get_dn(*keys, **options) try: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) truncated = True while truncated: try: ret = api.Command['service_find'](fqdn) truncated = ret['truncated'] services = ret['result'] except errors.NotFound: break else: for entry_attrs in services: principal = entry_attrs['krbprincipalname'][0] (service, hostname, realm) = split_principal(principal) if hostname.lower() == fqdn: try: api.Command['service_disable'](principal) done_work = True except errors.AlreadyInactive: pass if 'usercertificate' in entry_attrs: cert = x509.normalize_certificate(entry_attrs.get('usercertificate')[0]) try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # disabling the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr # Remove the usercertificate altogether ldap.update_entry(dn, {'usercertificate': None}) done_work = True
class test_ldap(object): """ Test various LDAP client bind methods. """ def setUp(self): self.conn = None self.ldapuri = 'ldap://%s' % ipautil.format_netloc(api.env.host) self.ccache = '/tmp/krb5cc_%d' % os.getuid() nss.nss_init_nodb() self.dn = DN(('krbprincipalname','ldap/%s@%s' % (api.env.host, api.env.realm)), ('cn','services'),('cn','accounts'),api.env.basedn) def tearDown(self): if self.conn and self.conn.isconnected(): self.conn.disconnect() def test_anonymous(self): """ Test an anonymous LDAP bind using ldap2 """ self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri) self.conn.connect() (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None def test_GSSAPI(self): """ Test a GSSAPI LDAP bind using ldap2 """ if not ipautil.file_exists(self.ccache): raise nose.SkipTest('Missing ccache %s' % self.ccache) self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri) self.conn.connect(ccache='FILE:%s' % self.ccache) (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None def test_simple(self): """ Test a simple LDAP bind using ldap2 """ pwfile = api.env.dot_ipa + os.sep + ".dmpw" if ipautil.file_exists(pwfile): fp = open(pwfile, "r") dm_password = fp.read().rstrip() fp.close() else: raise nose.SkipTest("No directory manager password in %s" % pwfile) self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri) self.conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password) (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None def test_Backend(self): """ Test using the ldap2 Backend directly (ala ipa-server-install) """ # Create our own api because the one generated for the tests is # a client-only api. Then we register in the commands and objects # we need for the test. myapi = create_api(mode=None) myapi.bootstrap(context='cli', in_server=True, in_tree=True) myapi.register(ldap2) myapi.register(host) myapi.register(service) myapi.register(service_show) myapi.finalize() pwfile = api.env.dot_ipa + os.sep + ".dmpw" if ipautil.file_exists(pwfile): fp = open(pwfile, "r") dm_password = fp.read().rstrip() fp.close() else: raise nose.SkipTest("No directory manager password in %s" % pwfile) myapi.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password) result = myapi.Command['service_show']('ldap/%s@%s' % (api.env.host, api.env.realm,)) entry_attrs = result['result'] cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None def test_autobind(self): """ Test an autobind LDAP bind using ldap2 """ ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % api.env.realm.replace('.','-') self.conn = ldap2(shared_instance=False, ldap_uri=ldapuri) try: self.conn.connect(autobind=True) except errors.DatabaseError, e: if e.desc == 'Inappropriate authentication': raise nose.SkipTest("Only executed as root") (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') cert = cert[0] serial = unicode(x509.get_serial_number(cert, x509.DER)) assert serial is not None
def execute(self, *keys, **options): ldap = self.obj.backend # If we aren't given a fqdn, find it if _hostname_validator(None, keys[-1]) is not None: hostentry = api.Command['host_show'](keys[-1])['result'] fqdn = hostentry['fqdn'][0] else: fqdn = keys[-1] host_is_master(ldap, fqdn) # See if we actually do anthing here, and if not raise an exception done_work = False truncated = True while truncated: try: ret = api.Command['service_find'](fqdn) truncated = ret['truncated'] services = ret['result'] except errors.NotFound: break else: for entry_attrs in services: principal = entry_attrs['krbprincipalname'][0] (service, hostname, realm) = split_principal(principal) if hostname.lower() == fqdn: try: api.Command['service_disable'](principal) done_work = True except errors.AlreadyInactive: pass dn = self.obj.get_dn(*keys, **options) try: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) cert = entry_attrs.single_value.get('usercertificate') if cert: if self.api.env.enable_ra: cert = x509.normalize_certificate(cert) try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](serial)['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](serial, revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # disabling the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr # Remove the usercertificate altogether ldap.update_entry(dn, {'usercertificate': None}) done_work = True
def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) # If we aren't given a fqdn, find it if _hostname_validator(None, keys[-1]) is not None: hostentry = api.Command['host_show'](keys[-1])['result'] fqdn = hostentry['fqdn'][0] else: fqdn = keys[-1] host_is_master(ldap, fqdn) # Remove all service records for this host truncated = True while truncated: try: ret = api.Command['service_find'](fqdn) truncated = ret['truncated'] services = ret['result'] except errors.NotFound: break else: for entry_attrs in services: principal = entry_attrs['krbprincipalname'][0] (service, hostname, realm) = split_principal(principal) if hostname.lower() == fqdn: api.Command['service_del'](principal) updatedns = options.get('updatedns', False) if updatedns: try: updatedns = dns_container_exists(ldap) except errors.NotFound: updatedns = False if updatedns: # Remove DNS entries parts = fqdn.split('.') domain = unicode('.'.join(parts[1:])) try: result = api.Command['dnszone_show'](domain)['result'] domain = result['idnsname'][0] except errors.NotFound: self.obj.handle_not_found(*keys) # Get all forward resources for this host records = api.Command['dnsrecord_find'](domain, idnsname=parts[0])['result'] for record in records: if 'arecord' in record: remove_fwd_ptr(record['arecord'][0], parts[0], domain, 'arecord') if 'aaaarecord' in record: remove_fwd_ptr(record['aaaarecord'][0], parts[0], domain, 'aaaarecord') else: # Try to delete all other record types too _attribute_types = [str('%srecord' % t.lower()) for t in _record_types] for attr in _attribute_types: if attr not in ['arecord', 'aaaarecord'] and attr in record: for i in xrange(len(record[attr])): if (record[attr][i].endswith(parts[0]) or record[attr][i].endswith(fqdn+'.')): delkw = { unicode(attr) : record[attr][i] } api.Command['dnsrecord_del'](domain, record['idnsname'][0], **delkw) break if self.api.env.enable_ra: try: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) cert = entry_attrs.single_value.get('usercertificate') if cert: cert = x509.normalize_certificate(cert) try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](serial)['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](serial, revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # removing the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr
raise errors.ACIError(info=_( "Insufficient privilege to create a certificate with " "subject alt name '%s'.") % name) elif name_type in (pkcs10.SAN_OTHERNAME_KRB5PRINCIPALNAME, pkcs10.SAN_OTHERNAME_UPN): if name != principal: raise errors.ACIError( info=_("Principal '%s' in subject alt name does not " "match requested service principal") % name) else: raise errors.ACIError( info=_("Subject alt name type %s is forbidden") % name_type) if 'usercertificate' in service: serial = x509.get_serial_number(service['usercertificate'][0], datatype=x509.DER) # revoke the certificate and remove it from the service # entry before proceeding. First we retrieve the certificate to # see if it is already revoked, if not then we revoke it. try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement get pass if not principal.startswith('host/'):