Exemple #1
0
    def __init__(self,
                 pkg_name,
                 spn=None,
                 scflags=None,
                 datarep=sspicon.SECURITY_NETWORK_DREP):
        self.spn = spn
        self.datarep = datarep

        if scflags is None:
            scflags = (sspicon.ASC_REQ_INTEGRITY
                       | sspicon.ASC_REQ_SEQUENCE_DETECT
                       | sspicon.ASC_REQ_REPLAY_DETECT
                       | sspicon.ASC_REQ_CONFIDENTIALITY)
        # Should we default to sspicon.KerbAddExtraCredentialsMessage
        # if pkg_name=='Kerberos'?
        self.scflags = scflags

        self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name)

        (
            self.credentials,
            self.credentials_expiry,
        ) = win32security.AcquireCredentialsHandle(spn, self.pkg_info["Name"],
                                                   sspicon.SECPKG_CRED_INBOUND,
                                                   None, None)
        _BaseAuth.__init__(self)
Exemple #2
0
 def __init__(
     self,
     pkg_name,  # Name of the package to used.
     client_name=None,  # User for whom credentials are used.
     auth_info=None,  # or a tuple of (username, domain, password)
     targetspn=None,  # Target security context provider name.
     scflags=None,  # security context flags
     datarep=sspicon.SECURITY_NETWORK_DREP,
 ):
     if scflags is None:
         scflags = (sspicon.ISC_REQ_INTEGRITY
                    | sspicon.ISC_REQ_SEQUENCE_DETECT
                    | sspicon.ISC_REQ_REPLAY_DETECT
                    | sspicon.ISC_REQ_CONFIDENTIALITY)
     self.scflags = scflags
     self.datarep = datarep
     self.targetspn = targetspn
     self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name)
     (
         self.credentials,
         self.credentials_expiry,
     ) = win32security.AcquireCredentialsHandle(
         client_name,
         self.pkg_info["Name"],
         sspicon.SECPKG_CRED_OUTBOUND,
         None,
         auth_info,
     )
     _BaseAuth.__init__(self)
Exemple #3
0
    def __init__(
            self,
            pkg_name,  # Name of the package to used.
            client_name=None,  # User for whom credentials are used.
            auth_info=None,  # or a tuple of (username, domain, password)
            targetspn=None,  # Target security context provider name.
            scflags=None,  # security context flags
            datarep=sspicon.SECURITY_NETWORK_DREP):

        if scflags is None:
            scflags = sspicon.ISC_REQ_INTEGRITY | sspicon.ISC_REQ_SEQUENCE_DETECT | sspicon.ISC_REQ_REPLAY_DETECT | sspicon.ISC_REQ_CONFIDENTIALITY  #|sspicon.SEC_WINNT_AUTH_IDENTITY_ANSI

        self.scflags = scflags
        self.datarep = datarep
        self.targetspn = targetspn

        username = win32api.GetUserName()
        domain = win32api.GetDomainName()
        password = None

        auth_info = username, domain, password

        self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name)
        self.credentials, \
        self.credentials_expiry = win32security.AcquireCredentialsHandle(
            client_name, self.pkg_info['Name'],
            sspicon.SECPKG_CRED_OUTBOUND,
            None, auth_info)
        _BaseAuth.__init__(self)
 def __init__(self, pkg_name):
     self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name)
     auth = PasswordAuthentication('workgroup',
                                   'developer',
                                   'password',
                                   compatibility=4)
     ntlm_context = NtlmContext(auth, session_security='none')
     self.context = ntlm_context.initialize_security_context()
     _BaseAuth.__init__(self)
    def __init__(self,
                 pkg_name,
                 spn=None,
                 flags=None,
                 data_representation=sspicon.SECURITY_NETWORK_DREP):
        self.spn = spn
        self.datarep = data_representation

        if flags is None:
            flags = sspicon.ASC_REQ_REPLAY_DETECT | sspicon.ASC_REQ_SEQUENCE_DETECT
            # sspicon.ASC_REQ_INTEGRITY|sspicon.ASC_REQ_SEQUENCE_DETECT|\
            #sspicon.ASC_REQ_REPLAY_DETECT|sspicon.ASC_REQ_CONFIDENTIALITY

        self.scflags = flags
        self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name)
        self.credentials, \
        self.credentials_expiry=win32security.AcquireCredentialsHandle(spn,
                self.pkg_info['Name'], sspicon.SECPKG_CRED_INBOUND, None, None)
        _BaseAuth.__init__(self)
Exemple #6
0
    def _retry_using_http_Negotiate_auth(self, response, scheme, args):
        if 'Authorization' in response.request.headers:
            return response

        if self._host is None:
            targeturl = urlparse(response.request.url)
            self._host = targeturl.hostname
            try:
                self._host = socket.getaddrinfo(self._host, None, 0, 0, 0,
                                                socket.AI_CANONNAME)[0][3]
            except socket.gaierror as e:
                _logger.info(
                    'Skipping canonicalization of name %s due to error: %s',
                    self._host, e)

        targetspn = '{}/{}'.format(self._service, self._host)

        # Set up SSPI connection structure
        pkg_info = win32security.QuerySecurityPackageInfo(scheme)
        clientauth = sspi.ClientAuth(scheme,
                                     targetspn=targetspn,
                                     auth_info=self._auth_info)
        sec_buffer = win32security.PySecBufferDescType()

        # Channel Binding Hash (aka Extended Protection for Authentication)
        # If this is a SSL connection, we need to hash the peer certificate, prepend the RFC5929 channel binding type,
        # and stuff it into a SEC_CHANNEL_BINDINGS structure.
        # This should be sent along in the initial handshake or Kerberos auth will fail.
        if hasattr(response, 'peercert') and response.peercert is not None:
            md = hashlib.sha256()
            md.update(response.peercert)
            appdata = 'tls-server-end-point:'.encode('ASCII') + md.digest()
            cbtbuf = win32security.PySecBufferType(
                pkg_info['MaxToken'], sspicon.SECBUFFER_CHANNEL_BINDINGS)
            cbtbuf.Buffer = struct.pack('LLLLLLLL{}s'.format(len(appdata)), 0,
                                        0, 0, 0, 0, 0, len(appdata), 32,
                                        appdata)
            sec_buffer.append(cbtbuf)

        content_length = int(response.request.headers.get(
            'Content-Length', '0'),
                             base=10)

        if hasattr(response.request.body, 'seek'):
            if content_length > 0:
                response.request.body.seek(-content_length, 1)
            else:
                response.request.body.seek(0, 0)

        # Consume content and release the original connection
        # to allow our new request to reuse the same one.
        response.content
        response.raw.release_conn()
        request = response.request.copy()

        # this is important for some web applications that store
        # authentication-related info in cookies
        if response.headers.get('set-cookie'):
            request.headers['Cookie'] = response.headers.get('set-cookie')

        # Send initial challenge auth header
        try:
            error, auth = clientauth.authorize(sec_buffer)
            request.headers['Authorization'] = '{} {}'.format(
                scheme,
                base64.b64encode(auth[0].Buffer).decode('ASCII'))
            _logger.debug(
                'Sending Initial Context Token - error={} authenticated={}'.
                format(error, clientauth.authenticated))
        except pywintypes.error as e:
            _logger.error('Error calling {}: {}'.format(e[1], e[2]),
                          exc_info=e)
            return response

        # A streaming response breaks authentication.
        # This can be fixed by not streaming this request, which is safe
        # because the returned response3 will still have stream=True set if
        # specified in args. In addition, we expect this request to give us a
        # challenge and not the real content, so the content will be short
        # anyway.
        args_nostream = dict(args, stream=False)
        response2 = response.connection.send(request, **args_nostream)

        # Should get another 401 if we are doing challenge-response (NTLM)
        if response2.status_code != 401:
            if response2.status_code == 200:
                # Kerberos may have succeeded; if so, finalize our auth context
                final = response2.headers.get('WWW-Authenticate')
                if final is not None:
                    try:
                        # Sometimes Windows seems to forget to prepend 'Negotiate' to the success response,
                        # and we get just a bare chunk of base64 token. Not sure why.
                        final = final.replace(scheme, '', 1).lstrip()
                        tokenbuf = win32security.PySecBufferType(
                            pkg_info['MaxToken'], sspicon.SECBUFFER_TOKEN)
                        tokenbuf.Buffer = base64.b64decode(final)
                        sec_buffer.append(tokenbuf)
                        error, auth = clientauth.authorize(sec_buffer)
                        _logger.debug(
                            'Kerberos Authentication succeeded - error={} authenticated={}'
                            .format(error, clientauth.authenticated))
                    except TypeError:
                        pass

            # Regardless of whether or not we finalized our auth context,
            # without a 401 we've got nothing to do. Update the history and return.
            response2.history.append(response)
            return response2

        # Consume content and release the original connection
        # to allow our new request to reuse the same one.
        response2.content
        response2.raw.release_conn()
        request = response2.request.copy()

        # Keep passing the cookies along
        if response2.headers.get('set-cookie'):
            request.headers['Cookie'] = response2.headers.get('set-cookie')

        # Extract challenge message from server
        challenge = [
            val[len(scheme) + 1:] for val in response2.headers.get(
                'WWW-Authenticate', '').split(', ') if scheme in val
        ]
        if len(challenge) != 1:
            raise HTTPError(
                'Did not get exactly one {} challenge from server.'.format(
                    scheme))

        # Add challenge to security buffer
        tokenbuf = win32security.PySecBufferType(pkg_info['MaxToken'],
                                                 sspicon.SECBUFFER_TOKEN)
        tokenbuf.Buffer = base64.b64decode(challenge[0])
        sec_buffer.append(tokenbuf)
        _logger.debug('Got Challenge Token (NTLM)')

        # Perform next authorization step
        error, auth = clientauth.authorize(sec_buffer)
        request.headers['Authorization'] = '{} {}'.format(
            scheme,
            base64.b64encode(auth[0].Buffer).decode('ASCII'))
        _logger.debug('Sending Response - error={} authenticated={}'.format(
            error, clientauth.authenticated))

        response3 = response2.connection.send(request, **args)

        # Update the history and return
        response3.history.append(response)
        response3.history.append(response2)

        return response3
    def retry_using_http_NTLM_auth(self, auth_header_field, auth_header,
                                   response, auth_type, args):
        """Attempt to authenticate using HTTP NTLM challenge/response."""
        if auth_header in response.request.headers:
            return response

        content_length = int(response.request.headers.get(
            'Content-Length', '0'),
                             base=10)
        if hasattr(response.request.body, 'seek'):
            if content_length > 0:
                response.request.body.seek(-content_length, 1)
            else:
                response.request.body.seek(0, 0)

        # Consume content and release the original connection
        # to allow our new request to reuse the same one.
        response.content
        response.raw.release_conn()
        request = response.request.copy()

        # initial auth header with username. will result in challenge
        if self._use_default_credentials:
            pkg_info = win32security.QuerySecurityPackageInfo(_package)
            clientauth = sspi.ClientAuth(_package)
            sec_buffer = win32security.PySecBufferDescType()
            error, auth = clientauth.authorize(sec_buffer)
            request.headers[auth_header] = '{} {}'.format(
                _package,
                b64encode(auth[0].Buffer).decode('ascii'))
        else:
            msg = "%s\\%s" % (self.domain,
                              self.username) if self.domain else self.username

            # ntlm returns the headers as a base64 encoded bytestring. Convert to
            # a string.
            auth = '%s %s' % (auth_type, ntlm.create_NTLM_NEGOTIATE_MESSAGE(
                msg).decode('ascii'))
            request.headers[auth_header] = auth

        # A streaming response breaks authentication.
        # This can be fixed by not streaming this request, which is safe
        # because the returned response3 will still have stream=True set if
        # specified in args. In addition, we expect this request to give us a
        # challenge and not the real content, so the content will be short
        # anyway.
        args_nostream = dict(args, stream=False)
        response2 = response.connection.send(request, **args_nostream)

        # needed to make NTLM auth compatible with requests-2.3.0

        # Consume content and release the original connection
        # to allow our new request to reuse the same one.
        response2.content
        response2.raw.release_conn()
        request = response2.request.copy()

        # this is important for some web applications that store
        # authentication-related info in cookies (it took a long time to
        # figure out)
        if response2.headers.get('set-cookie'):
            request.headers['Cookie'] = response2.headers.get('set-cookie')

        # get the challenge
        auth_header_value = response2.headers[auth_header_field]

        auth_strip = auth_type + ' '

        ntlm_header_value = next(
            s for s in (val.lstrip() for val in auth_header_value.split(','))
            if s.startswith(auth_strip)).strip()

        challenge_value = ntlm_header_value[len(auth_strip):]

        # build response
        if self._use_default_credentials:
            # Add challenge to security buffer
            tokenbuf = win32security.PySecBufferType(pkg_info['MaxToken'],
                                                     sspicon.SECBUFFER_TOKEN)
            tokenbuf.Buffer = b64decode(challenge_value)
            sec_buffer.append(tokenbuf)

            # Perform next authorization step
            error, auth = clientauth.authorize(sec_buffer)
            request.headers[auth_header] = '{} {}'.format(
                _package,
                b64encode(auth[0].Buffer).decode('ascii'))
        else:
            ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(
                challenge_value)
            # ntlm returns the headers as a base64 encoded bytestring. Convert to a
            # string.
            auth = '%s %s' % (auth_type,
                              ntlm.create_NTLM_AUTHENTICATE_MESSAGE(
                                  ServerChallenge, self.username, self.domain,
                                  self.password,
                                  NegotiateFlags).decode('ascii'))
            request.headers[auth_header] = auth

        response3 = response2.connection.send(request, **args)

        # Update the history.
        response3.history.append(response)
        response3.history.append(response2)

        return response3