def __init__(self, username=None, password=None, hostname=None, service=None, channel_bindings=None, context_req=ContextReq.default, usage='initiate', protocol='negotiate', options=0): if not HAS_SSPI: reraise( ImportError( "SSPIProxy requires the SSPI Cython extension to be compiled" ), SSPI_IMP_ERR) super(SSPIProxy, self).__init__(username, password, hostname, service, channel_bindings, context_req, usage, protocol, options, False) self._attr_sizes = None self._complete = False self._credential = None self._context = SSPISecContext() self.__seq_num = 0 credential_kwargs = { 'package': to_text(protocol), } if usage == 'initiate': # TODO: It seems like the SPN is just an empty string for anon auth. credential_kwargs['principal'] = None credential_kwargs['credential_use'] = CredentialUse.outbound if self.username: domain, username = split_username(self.username) credential_kwargs['auth_data'] = WinNTAuthIdentity( to_text(username, nonstring='passthru'), to_text(domain, nonstring='passthru'), to_text(password, nonstring='passthru')) else: credential_kwargs['principal'] = self.spn credential_kwargs['credential_use'] = CredentialUse.inbound try: self._credential = acquire_credentials_handle(**credential_kwargs) except NativeError as win_err: reraise( SpnegoError(base_error=win_err, context_msg="Getting SSPI credential"))
def store_lines(text): for line in text.splitlines(): line_split = line.split(':') if len(line_split) == 3: yield line_split[0], line_split[1], line_split[2], None, None elif len(line_split) == 6: domain_entry, user_entry = split_username(line_split[0]) lm_entry = base64.b16decode(line_split[2].upper()) nt_entry = base64.b16decode(line_split[3].upper()) yield domain_entry or u"", user_entry, None, lm_entry, nt_entry
def test_split_username(value, expected_domain, expected_user): actual_domain, actual_user = context.split_username(value) assert actual_domain == expected_domain assert actual_user == expected_user
def __init__(self, username, password, hostname=None, service=None, channel_bindings=None, context_req=ContextReq.default, usage='initiate', protocol='ntlm', options=0, _is_wrapped=False): super(NTLMProxy, self).__init__(username, password, hostname, service, channel_bindings, context_req, usage, protocol, options, _is_wrapped) self._complete = False # type: bool self._credential = None # type: Optional[_NTLMCredential] # Set the default flags, these might change depending on the LM_COMPAT_LEVEL set. self._context_req = self._context_req | \ NegotiateFlags.key_128 | \ NegotiateFlags.key_56 | \ NegotiateFlags.key_exch | \ NegotiateFlags.extended_session_security | \ NegotiateFlags.always_sign | \ NegotiateFlags.ntlm | \ NegotiateFlags.lm_key | \ NegotiateFlags.request_target | \ NegotiateFlags.oem | \ NegotiateFlags.unicode # gss-ntlmssp uses the env var 'LM_COMPAT_LEVEL' to control the NTLM compatibility level. To try and make our # NTLM implementation similar in functionality we will also use that behaviour. # https://github.com/gssapi/gss-ntlmssp/blob/e498737a96e8832a2cb9141ab1fe51e129185a48/src/gss_ntlmssp.c#L159-L170 # See the below policy link for more details on what these mean, for now 3 is the sane behaviour. # https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-security-lan-manager-authentication-level lm_compat_level = int(os.environ.get('LM_COMPAT_LEVEL', 3)) # type: int if lm_compat_level < 0 or lm_compat_level > 5: raise SpnegoError( ErrorCode.failure, context_msg= "Invalid LM_COMPAT_LEVEL %d, must be between 0 and 5" % lm_compat_level) if lm_compat_level == 0: self._context_req &= ~NegotiateFlags.extended_session_security if self.usage == 'initiate': domain, user = split_username(self.username) self._credential = _NTLMCredential(domain=domain, username=user, password=self.password) self._lm = lm_compat_level < 2 # type: bool self._nt_v1 = lm_compat_level < 3 # type: bool self._nt_v2 = lm_compat_level > 2 # type: bool if lm_compat_level > 1: self._context_req &= ~NegotiateFlags.lm_key else: self._lm = lm_compat_level < 4 # type: bool self._nt_v1 = lm_compat_level < 5 # type: bool self._nt_v2 = True # type: bool # Make sure that the credential file is set and exists if not _get_credential_file(): raise OperationNotAvailableError( context_msg= "Retrieving NTLM store without NTLM_USER_FILE set to a " "filepath") self._temp_msg = { 'negotiate': None, 'challenge': None, } # type: Dict[str, any] self._mic_required = False # type: bool # Crypto state for signing and sealing. self._session_key = None # type: Optional[bytes] self._sign_key_out = None # type: Optional[bytes] self._sign_key_in = None # type: Optional[bytes] self._handle_out = None # type: Optional[RC4Handle] self._handle_in = None # type: Optional[RC4Handle] self.__seq_num_in = 0 # type: int self.__seq_num_out = 0 # type: int