def bcrypt_hash(password): # type: (str) -> str """ Return bcrypt hash. :param password: password string. :returns: the hashed password string. """ cost_factor = int( configRegistry.get('password/hashing/bcrypt/cost_factor', '12')) prefix = configRegistry.get('password/hashing/bcrypt/prefix', '2b').encode('utf8') salt = bcrypt.gensalt(rounds=cost_factor, prefix=prefix) return bcrypt.hashpw(password.encode('utf-8'), salt).decode('ASCII')
def modify_text(text, commands): # type: (str, List[str]) -> str # apply all string commands for iCmd in commands: if iCmd == 'lower': text = text.lower() elif iCmd == 'upper': text = text.upper() elif iCmd == 'umlauts': if isinstance(text, bytes): # Python 2 text = text.decode('UTF-8') # We need this to handle german umlauts, e.g. รค -> ae for umlaut, code in property.UMLAUTS.items(): text = text.replace(umlaut, code) text = unidecode.unidecode(text) elif iCmd == 'alphanum': whitelist = configRegistry.get('directory/manager/templates/alphanum/whitelist', '') if isinstance(whitelist, bytes): # Python 2 whitelist = whitelist.decode('UTF-8') if isinstance(text, bytes): text = text.decode('UTF-8') text = u''.join([c for c in text if (c.isalnum() or c in whitelist)]) elif iCmd in ('trim', 'strip'): text = text.strip() return text
def getBaseDN(host='localhost', port=None, uri=None): # type: (str, Optional[int], Optional[str]) -> str """ Return the naming context of the LDAP server. :param str host: The hostname of the LDAP server. :param int port: The TCP port number of the LDAP server. :param str uri: A complete LDAP URI. :returns: The distinguished name of the LDAP root. :rtype: str """ if not uri: if not port: port = int(configRegistry.get('ldap/server/port', 7389)) uri = "ldap://%s:%s" % (host, port) try: lo = ldap.ldapobject.ReconnectLDAPObject(uri, trace_stack_limit=None) result = lo.search_s('', ldap.SCOPE_BASE, 'objectClass=*', ['NamingContexts']) return result[0][1]['namingContexts'][0].decode('utf-8') except ldap.SERVER_DOWN: time.sleep(60) lo = ldap.ldapobject.ReconnectLDAPObject(uri, trace_stack_limit=None) result = lo.search_s('', ldap.SCOPE_BASE, 'objectClass=*', ['NamingContexts']) return result[0][1]['namingContexts'][0].decode('utf-8')
def modify_text(text, commands): # apply all string commands for iCmd in commands: if iCmd == 'lower': text = text.lower() elif iCmd == 'upper': text = text.upper() elif iCmd == 'umlauts': if isinstance(text, bytes): text = text.decode('UTF-8') for umlaut, code in property.UMLAUTS.items(): text = text.replace(umlaut, code) text = unicodedata.normalize('NFKD', text).encode( 'ascii', 'ignore').decode('ascii') elif iCmd == 'alphanum': whitelist = configRegistry.get( 'directory/manager/templates/alphanum/whitelist', '') if isinstance(whitelist, bytes): # Python 2 whitelist = whitelist.decode('UTF-8') if isinstance(text, bytes): text = text.decode('UTF-8') text = u''.join( [c for c in text if (c.isalnum() or c in whitelist)]) elif iCmd in ('trim', 'strip'): text = text.strip() return text
def password_is_auth_saslpassthrough(password): # type: (str) -> bool """ Check if the password hash indicates the use of |SASL|. :param apssword: password hash. :returns: `True` is |SASL| shall be used, `False` otherwise. """ return password.startswith('{SASL}') and configRegistry.get( 'directory/manager/web/modules/users/user/auth/saslpassthrough', 'no').lower() == 'keep'
def crypt(password, method_id=None, salt=None): # type: (str, Optional[str], Optional[str]) -> str """ Return crypt hash. :param password: password string. :param method_id: optional hash type, MD5, SHA256/SHA-256, SHA512/SHA-512. :param salt: salt for randomize the hashing. :returns: the hashed password string. """ hashing_method = configRegistry.get('password/hashing/method', 'sha-512').upper() if salt is None: salt = '' valid = [ '.', '/', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ] urandom = open("/dev/urandom", "rb") for i in range( 0, 16 ): # up to 16 bytes of salt are evaluated by crypt(3), overhead is ignored o = ord(urandom.read(1)) while not o < 256 // len(valid) * len( valid ): # make sure not to skew the distribution when using modulo o = ord(urandom.read(1)) salt = salt + valid[(o % len(valid))] urandom.close() if method_id is None: method_id = { 'MD5': '1', 'SHA256': '5', 'SHA-256': '5', 'SHA512': '6', 'SHA-512': '6', }.get(hashing_method, '6') from crypt import crypt as _crypt return _crypt(password, '$%s$%s$' % ( method_id, salt, ))
def __init__(self, host='localhost', port=None, base=u'', binddn=u'', bindpw=u'', start_tls=2, lo=None, follow_referral=False): # type: (str, int, str, str, str, int, univention.uldap.access, bool) -> None """ :param str host: The hostname of the |LDAP| server. :param int port: The |TCP| port number of the |LDAP| server. :param str base: The base distinguished name. :param str binddn: The distinguished name of the account. :param str bindpw: The user password for simple authentication. :param int start_tls: Negotiate |TLS| with server. If `2` is given, the command will require the operation to be successful. :param univention.uldap.access lo: |LDAP| connection. :param:bool follow_referral: Follow |LDAP| referrals. """ if lo: self.lo = lo else: if not port: port = int(configRegistry.get('ldap/server/port', 7389)) try: self.lo = univention.uldap.access( host, port, base, binddn, bindpw, start_tls, follow_referral=follow_referral) except ldap.INVALID_CREDENTIALS: raise univention.admin.uexceptions.authFail( _("Authentication failed")) except ldap.UNWILLING_TO_PERFORM: raise univention.admin.uexceptions.authFail( _("Authentication failed")) self.require_license = False self.allow_modify = True self.licensetypes = ['UCS']
def ucr_overwrite_layout(module, ucr_property, tab): """ Overwrite the advanced setting in the layout """ desc = tab['name'] if hasattr(tab['name'], 'data'): desc = tab.tab['name'].data # replace invalid characters by underscores desc = re.sub(univention.config_registry.invalid_key_chars, '_', desc).replace('/', '_') p_v = configRegistry.get( 'directory/manager/web/modules/%s/layout/%s/%s' % (module, desc, ucr_property), None) if not p_v: return None if p_v.lower() in ['0', 'false', 'no', 'off']: return False else: return True
def ucr_overwrite_module_layout(module): # type: (Any) -> None """ Overwrite the tab layout through |UCR| variables. """ ud.debug(ud.ADMIN, ud.INFO, "layout overwrite") # there are modules without a layout definition if not hasattr(module, 'layout'): return new_layout = [] for tab in module.layout[:]: desc = tab.label if hasattr(tab.label, 'data'): desc = tab.label.data # replace invalid characters by underscores desc = re.sub(univention.config_registry.invalid_key_chars, '_', desc).replace('/', '_') tab_layout = configRegistry.get('directory/manager/web/modules/%s/layout/%s' % (module.module, desc)) ud.debug(ud.ADMIN, ud.INFO, "layout overwrite: tab_layout='%s'" % tab_layout) tab_name = configRegistry.get('directory/manager/web/modules/%s/layout/%s/name' % (module.module, desc)) ud.debug(ud.ADMIN, ud.INFO, "layout overwrite: tab_name='%s'" % tab_name) tab_descr = configRegistry.get('directory/manager/web/modules/%s/layout/%s/description' % (module.module, desc)) ud.debug(ud.ADMIN, ud.INFO, "layout overwrite: tab_descr='%s'" % tab_descr) if tab_name: tab['name'] = tab_name if tab_descr: tab['description'] = tab_descr # for now the layout modification from UCS 2.4 is disabled (see Bug #26673) # (this piece of code does not respect the tab-group-hierarchie of UCS 3.0) # if tab_layout and tab_layout.lower() != 'none': # layout = [] # for row in tab_layout.split( ';' ): # line = [] # for col in row.split( ',' ): # col = col.strip() # if not col: # continue # if col in module.property_descriptions: # line.append( col ) # else: # ud.debug( ud.ADMIN, ud.ERROR, "layout overwrite: unknown property: %s" % col ) # layout.append( line ) # tab[ 'layout' ] = { 'label' : _( 'General' ), 'layout' : layout } if not tab_layout or tab_layout.lower() != 'none': # disable specified properties via UCR ud.debug(ud.ADMIN, ud.INFO, 'ucr_overwrite_module_layout: trying to hide properties on tab %s' % (desc)) ucr_prefix = ucr_property_prefix % module.module for var in configRegistry.keys(): if not var.startswith(ucr_prefix): continue prop, attr = var[len(ucr_prefix):].split('/', 1) # ignore invalid/unknown UCR variables if '/' in attr: continue if attr in ('__hidden') and configRegistry.is_true(var): removed, layout = tab.remove(prop) ud.debug(ud.ADMIN, ud.INFO, 'ucr_overwrite_module_layout: tried to hide property: %s (found=%s)' % (prop, removed)) new_layout.append(tab) del module.layout module.layout = new_layout # sort tabs: All apps occur alphabetical after the "Apps" / "Options" tab app_tabs = [x for x in module.layout if x.is_app_tab] app_tabs.sort(key=lambda x: x.label.lower()) layout = [x for x in module.layout if not x.is_app_tab] pos = ([i for i, x in enumerate(layout, 1) if x.label == 'Apps'] or [len(layout)])[0] layout[pos:pos] = app_tabs module.layout = layout
def __init__( self, short_description='', # type: str long_description='', # type: str syntax=None, # type: Union[Type, Any] module_search=None, # type: None multivalue=False, # type: bool one_only=False, # type: bool parent=None, # type: str options=[], # type: List[str] license=[], # type: List[str] required=False, # type: bool may_change=True, # type: bool identifies=False, # type: bool unique=False, # type: bool default=None, # type: Any prevent_umc_default_popup=False, # type: bool dontsearch=False, # type: bool show_in_lists=False, # type: bool editable=True, # type: bool configObjectPosition=None, # type: None configAttributeName=None, # type: None include_in_default_search=False, # type: bool nonempty_is_default=False, # type: bool readonly_when_synced=False, # type: bool size=None, # type: str copyable=False, # type: bool type_class=None, # type: type # univention.admin.types.TypeHint ): # type: (...) -> None """ |UDM| property. :param short_description: a short descriptive text - shown below the input filed in |UMC| by default. :param long_description: a long descriptive text - shown only on demand in |UMC|. :param syntax: a syntax class or instance to validate the value. :param module_search: UNUSED? :param multivalue: allow only a single value (`False`) or multiple values (`True`) . :param one_only: UNUSED? :param parent: UNUSED? :param options: List of options, which enable this property. :param license: List of license strings, which are required to use this property. :param required: `True` for a required property, `False` for an optional property. :param may_change: `True` if the property can be changed after the object has been created, `False` when the property can only be specified when the object is created. :param identifies: `True` if the property is part of the set of properties, which are required to uniquely identify the object. The properties are used by default to build |RDN| for a new object. :param unique: `True` if the property must be unique for all object instances. :param default: The default value for the property when a new object is created. :param prevent_umc_default_popup: `True` to prevent a pop-up dialog in |UMC| when the default value is not set. :param dontsearch: `True` to prevent searches using the property. :param show_in_lists: UNUSED? :param editable: `False` prevents the property from being modified by the user; it still can be modified by code. :param configObjectPosition: UNUSED? :param configAttributeName: UNUSED? :param include_in_default_search: The default search searches this property when set to `True`. :param nonempty_is_default: `True` selects the first non-empty value as the default. `False` always selects the first default value, even if it is empty. :param readonly_when_synced: `True` only shows the value as read-only when synchronized from some upstream database. :param size: The |UMC| widget size; one of :py:data:`univention.admin.syntax.SIZES`. :param copyable: With `True` the property is copied when the object is cloned; with `False` the new object will use the default value. :param type_class: An optional Typing class which overwrites the syntax class specific type. """ self.short_description = short_description self.long_description = long_description if isinstance(syntax, type): self.syntax = syntax() else: self.syntax = syntax self.module_search = module_search self.multivalue = multivalue self.one_only = one_only self.parent = parent self.options = options or [] self.license = license or [] self.required = required self.may_change = may_change self.identifies = identifies self.unique = unique self.base_default = default self.prevent_umc_default_popup = prevent_umc_default_popup self.dontsearch = dontsearch self.show_in_lists = show_in_lists self.editable = editable self.configObjectPosition = configObjectPosition self.configAttributeName = configAttributeName self.templates = [] # type: List # univention.admin.handlers.simpleLdap self.include_in_default_search = include_in_default_search self.threshold = int(configRegistry.get('directory/manager/web/sizelimit', '2000') or 2000) self.nonempty_is_default = nonempty_is_default self.readonly_when_synced = readonly_when_synced self.size = size self.copyable = copyable self.type_class = type_class
def __init__(self): if _license: raise Exception('never create this object directly') self.new_license = False self.disable_add = 0 self._expired = False self.endDate = None self.oemProductTypes = [] self.licenseBase = None self.types = [] self.version = '1' self.searchResult = None self.sysAccountNames = ( custom_username('Administrator'), 'ucs-sso', 'join-backup', 'join-slave', 'spam', 'oxadmin', 'krbtgt', 'pcpatch', # opsi app 'opsiconfd', # opsi app custom_username('Guest'), 'dns-*', 'http-%s' % configRegistry.get('hostname'), 'http-proxy-%s' % configRegistry.get('hostname'), 'zarafa-%s' % configRegistry.get('hostname'), custom_username('SBSMonAcct'), # SBS account custom_username('Network Administrator'), # SBS role custom_username('Standard User'), # SBS role custom_username( 'WebWorkplaceTools' ), # SBS role "Standard User with administration links" 'IUSR_WIN-*', # IIS account ) self.sysAccountsFound = 0 self.licenses = { '1': { # Version 1 till UCS 3.1 License.ACCOUNT: None, License.CLIENT: None, License.DESKTOP: None, License.GROUPWARE: None, }, '2': { # Version 2 since UCS 3.1 License.USERS: None, License.SERVERS: None, License.MANAGEDCLIENTS: None, License.CORPORATECLIENTS: None, }, } self.real = { '1': { # Version 1 till UCS 3.1 License.ACCOUNT: 0, License.CLIENT: 0, License.DESKTOP: 0, License.GROUPWARE: 0, }, '2': { # Version 2 since UCS 3.1 License.USERS: 0, License.SERVERS: 0, License.MANAGEDCLIENTS: 0, License.CORPORATECLIENTS: 0, }, } self.names = { '1': { # Version 1 till UCS 3.1 License.ACCOUNT: 'Accounts', License.CLIENT: 'Clients', License.DESKTOP: 'Desktops', License.GROUPWARE: 'Groupware Accounts', }, '2': { # Version 2 since UCS 3.1 License.USERS: 'Users', License.SERVERS: 'Servers', License.MANAGEDCLIENTS: 'Managed Clients', License.CORPORATECLIENTS: 'Corporate Clients', }, } self.keys = { '1': { # Version 1 till UCS 3.1 License.ACCOUNT: 'univentionLicenseAccounts', License.CLIENT: 'univentionLicenseClients', License.DESKTOP: 'univentionLicenseuniventionDesktops', License.GROUPWARE: 'univentionLicenseGroupwareAccounts' }, '2': { # Version 1 till UCS 3.1 License.USERS: 'univentionLicenseUsers', License.SERVERS: 'univentionLicenseServers', License.MANAGEDCLIENTS: 'univentionLicenseManagedClients', License.CORPORATECLIENTS: 'univentionLicenseCorporateClients', }, } self.filters = { '1': { # Version 1 till UCS 3.1 License.ACCOUNT: '(&(|(&(objectClass=posixAccount)(objectClass=shadowAccount))(objectClass=sambaSamAccount))(!(uidNumber=0))(!(uid=*$))(!(&(shadowExpire=1)(krb5KDCFlags=254)(|(sambaAcctFlags=[UD ])(sambaAcctFlags=[ULD ])))))', License.CLIENT: '(|(objectClass=univentionThinClient)(objectClass=univentionClient)(objectClass=univentionMobileClient)(objectClass=univentionWindows)(objectClass=univentionMacOSClient))', License.DESKTOP: '(|(objectClass=univentionThinClient)(&(objectClass=univentionClient)(objectClass=posixAccount))(objectClass=univentionMobileClient))', License.GROUPWARE: '(&(objectclass=kolabInetOrgPerson)(kolabHomeServer=*)(!(&(shadowExpire=1)(krb5KDCFlags=254)(|(sambaAcctFlags=[UD ])(sambaAcctFlags=[ULD ])))))', }, '2': { # Version 2 since UCS 3.1 License.USERS: '(&%s)' % ''.join([ LDAP_FILTER_normal_user_account, ldap_filter_not_objectflag(user_exclude_objectflags), LDAP_FILTER_account_not_disabled ]), License.SERVERS: '(&(|(objectClass=univentionDomainController)(objectClass=univentionMemberServer))(!(univentionObjectFlag=docker)))', # Managed Clients, Windows Clients, Ubuntu Clients, Linux Clients, MaxOS X Clients License.MANAGEDCLIENTS: '(&%s)' % ''.join([ LDAP_FILTER_managedclients, ldap_filter_not_objectflag( managedclient_exclude_objectflags) ]), License.CORPORATECLIENTS: '(&(objectclass=univentionCorporateClient))', }, } self.__selected = False