Beispiel #1
0
def get_gssapi_token(principal, host, domain):
    '''
    Get the gssapi token for Kerberos connection

    principal
       The service principal
    host
       Host url where we would like to authenticate
    domain
       Kerberos user domain
    '''

    if not HAS_GSSAPI:
        raise ImportError('The gssapi library is not imported.')

    service = '{0}/{1}@{2}'.format(principal, host, domain)
    log.debug('Retrieving gsspi token for service {0}'.format(service))
    service_name = gssapi.Name(service, gssapi.C_NT_USER_NAME)
    ctx = gssapi.InitContext(service_name)
    in_token = None
    while not ctx.established:
        out_token = ctx.step(in_token)
        if out_token:
            encoded_token = base64.b64encode(out_token)
            return encoded_token
        if ctx.established:
            break
        if not in_token:
            raise salt.exceptions.CommandExecutionError(
                'Can\'t receive token, no response from server')
    raise salt.exceptions.CommandExecutionError(
        'Context established, but didn\'t receive token')
def sasl_gssapi(connection, controls):
    """
    Performs a bind using the Kerberos v5 ("GSSAPI") SASL mechanism
    from RFC 4752. Does not support any security layers, only authentication!
    """

    NO_SECURITY_LAYER = 1
    INTEGRITY_PROTECTION = 2
    CONFIDENTIALITY_PROTECTION = 4

    authz_id = b''
    krb5mech = gssapi.OID.mech_from_string()
    target_name = gssapi.Name('ldap@' + connection.server.host, gssapi.C_NT_HOSTBASED_SERVICE)
    ctx_kwargs = {
        'mech_type': krb5mech, 'req_flags': (gssapi.C_INTEG_FLAG,)
    }
    if (
            isinstance(connection.sasl_credentials, (list, tuple))
            and len(connection.sasl_credentials) == 2
    ):
        # connection.sasl_credentials can be a 2-tuple. The first element can be a
        # gssapi.Credential to use as the initiator credential. The second can be an authorization ID.
        # Either can be None if the default credential, or no authorization ID is to be used.
        if isinstance(connection.sasl_credentials[0], gssapi.Credential):
            ctx_kwargs['cred'] = connection.sasl_credentials
        if connection.sasl_credentials[1] is not None:
            authz_id = connection.sasl_credentials[1].encode('utf-8')
    ctx = gssapi.InitContext(target_name, **ctx_kwargs)

    in_token = None
    try:
        while not ctx.established:
            # Client calls init_sec_context...
            out_token = ctx.step(in_token)
            if out_token is None:
                out_token = b''
            # and sends the server the result
            result = send_sasl_negotiation(connection, controls, out_token)
            in_token = result['saslCreds']

        # once the Context is established, decode the server's token
        unwrapped_token = ctx.unwrap(in_token, conf_req=False)
        if len(unwrapped_token) != 4:
            raise ValueError("Incorrect response from server.")
        server_security_layers = ord(unwrapped_token[0])
        if server_security_layers in (0, NO_SECURITY_LAYER):
            if unwrapped_token[1:] != b'\x00\x00\x00':
                raise ValueError("Server max buffer size must be 0 if no security layer.")
        if not (server_security_layers & NO_SECURITY_LAYER):
            raise ValueError("Server requires a security layer, but we don't support any.")
        client_security_layers = bytearray([NO_SECURITY_LAYER, 0, 0, 0])
        out_token = ctx.wrap(bytes(client_security_layers) + authz_id, conf_req=False)
        return send_sasl_negotiation(connection, controls, out_token)
    except (gssapi.GSSException, ValueError) as exc:
        abort_sasl_negotiation(connection, controls)
        raise
Beispiel #3
0
    def ssh_init_sec_context(self,
                             target,
                             desired_mech=None,
                             username=None,
                             recv_token=None):
        """
        Initialize a GSS-API context.

        :param str username: The name of the user who attempts to login
        :param str target: The hostname of the target to connect to
        :param str desired_mech: The negotiated GSS-API mechanism
                                 ("pseudo negotiated" mechanism, because we
                                 support just the krb5 mechanism :-))
        :param str recv_token: The GSS-API token received from the Server
        :raises:
            `.SSHException` -- Is raised if the desired mechanism of the client
            is not supported
        :return: A ``String`` if the GSS-API has returned a token or
            ``None`` if no token was returned
        """
        from pyasn1.codec.der import decoder

        self._username = username
        self._gss_host = target
        targ_name = gssapi.Name("host@" + self._gss_host,
                                gssapi.C_NT_HOSTBASED_SERVICE)
        ctx = gssapi.Context()
        ctx.flags = self._gss_flags
        if desired_mech is None:
            krb5_mech = gssapi.OID.mech_from_string(self._krb5_mech)
        else:
            mech, __ = decoder.decode(desired_mech)
            if mech.__str__() != self._krb5_mech:
                raise SSHException("Unsupported mechanism OID.")
            else:
                krb5_mech = gssapi.OID.mech_from_string(self._krb5_mech)
        token = None
        try:
            if recv_token is None:
                self._gss_ctxt = gssapi.InitContext(
                    peer_name=targ_name,
                    mech_type=krb5_mech,
                    req_flags=ctx.flags,
                )
                token = self._gss_ctxt.step(token)
            else:
                token = self._gss_ctxt.step(recv_token)
        except gssapi.GSSException:
            message = "{} Target: {}".format(sys.exc_info()[1], self._gss_host)
            raise gssapi.GSSException(message)
        self._gss_ctxt_status = self._gss_ctxt.established
        return token
Beispiel #4
0
    def _gssapi_sspi_test(self):
        """
        Test the used methods of python-gssapi or sspi, sspicon from pywin32.
        """
        try:
            import gssapi

            if (
                hasattr(gssapi, "__title__")
                and gssapi.__title__ == "python-gssapi"
            ):
                _API = "PYTHON-GSSAPI-OLD"
            else:
                _API = "PYTHON-GSSAPI-NEW"
        except ImportError:
            import sspicon
            import sspi

            _API = "SSPI"

        c_token = None
        gss_ctxt_status = False
        mic_msg = b"G'day Mate!"

        if _API == "PYTHON-GSSAPI-OLD":
            if self.server_mode:
                gss_flags = (
                    gssapi.C_PROT_READY_FLAG,
                    gssapi.C_INTEG_FLAG,
                    gssapi.C_MUTUAL_FLAG,
                    gssapi.C_DELEG_FLAG,
                )
            else:
                gss_flags = (
                    gssapi.C_PROT_READY_FLAG,
                    gssapi.C_INTEG_FLAG,
                    gssapi.C_DELEG_FLAG,
                )
            # Initialize a GSS-API context.
            ctx = gssapi.Context()
            ctx.flags = gss_flags
            krb5_oid = gssapi.OID.mech_from_string(self.krb5_mech)
            target_name = gssapi.Name(
                "host@" + self.targ_name, gssapi.C_NT_HOSTBASED_SERVICE
            )
            gss_ctxt = gssapi.InitContext(
                peer_name=target_name, mech_type=krb5_oid, req_flags=ctx.flags
            )
            if self.server_mode:
                c_token = gss_ctxt.step(c_token)
                gss_ctxt_status = gss_ctxt.established
                self.assertEquals(False, gss_ctxt_status)
                # Accept a GSS-API context.
                gss_srv_ctxt = gssapi.AcceptContext()
                s_token = gss_srv_ctxt.step(c_token)
                gss_ctxt_status = gss_srv_ctxt.established
                self.assertNotEquals(None, s_token)
                self.assertEquals(True, gss_ctxt_status)
                # Establish the client context
                c_token = gss_ctxt.step(s_token)
                self.assertEquals(None, c_token)
            else:
                while not gss_ctxt.established:
                    c_token = gss_ctxt.step(c_token)
                self.assertNotEquals(None, c_token)
            # Build MIC
            mic_token = gss_ctxt.get_mic(mic_msg)

            if self.server_mode:
                # Check MIC
                status = gss_srv_ctxt.verify_mic(mic_msg, mic_token)
                self.assertEquals(0, status)
        elif _API == "PYTHON-GSSAPI-NEW":
            if self.server_mode:
                gss_flags = (
                    gssapi.RequirementFlag.protection_ready,
                    gssapi.RequirementFlag.integrity,
                    gssapi.RequirementFlag.mutual_authentication,
                    gssapi.RequirementFlag.delegate_to_peer,
                )
            else:
                gss_flags = (
                    gssapi.RequirementFlag.protection_ready,
                    gssapi.RequirementFlag.integrity,
                    gssapi.RequirementFlag.delegate_to_peer,
                )
            # Initialize a GSS-API context.
            krb5_oid = gssapi.MechType.kerberos
            target_name = gssapi.Name(
                "host@" + self.targ_name,
                name_type=gssapi.NameType.hostbased_service,
            )
            gss_ctxt = gssapi.SecurityContext(
                name=target_name,
                flags=gss_flags,
                mech=krb5_oid,
                usage="initiate",
            )
            if self.server_mode:
                c_token = gss_ctxt.step(c_token)
                gss_ctxt_status = gss_ctxt.complete
                self.assertEquals(False, gss_ctxt_status)
                # Accept a GSS-API context.
                gss_srv_ctxt = gssapi.SecurityContext(usage="accept")
                s_token = gss_srv_ctxt.step(c_token)
                gss_ctxt_status = gss_srv_ctxt.complete
                self.assertNotEquals(None, s_token)
                self.assertEquals(True, gss_ctxt_status)
                # Establish the client context
                c_token = gss_ctxt.step(s_token)
                self.assertEquals(None, c_token)
            else:
                while not gss_ctxt.complete:
                    c_token = gss_ctxt.step(c_token)
                self.assertNotEquals(None, c_token)
            # Build MIC
            mic_token = gss_ctxt.get_signature(mic_msg)

            if self.server_mode:
                # Check MIC
                status = gss_srv_ctxt.verify_signature(mic_msg, mic_token)
                self.assertEquals(0, status)
        else:
            gss_flags = (
                sspicon.ISC_REQ_INTEGRITY
                | sspicon.ISC_REQ_MUTUAL_AUTH
                | sspicon.ISC_REQ_DELEGATE
            )
            # Initialize a GSS-API context.
            target_name = "host/" + socket.getfqdn(self.targ_name)
            gss_ctxt = sspi.ClientAuth(
                "Kerberos", scflags=gss_flags, targetspn=target_name
            )
            if self.server_mode:
                error, token = gss_ctxt.authorize(c_token)
                c_token = token[0].Buffer
                self.assertEquals(0, error)
                # Accept a GSS-API context.
                gss_srv_ctxt = sspi.ServerAuth("Kerberos", spn=target_name)
                error, token = gss_srv_ctxt.authorize(c_token)
                s_token = token[0].Buffer
                # Establish the context.
                error, token = gss_ctxt.authorize(s_token)
                c_token = token[0].Buffer
                self.assertEquals(None, c_token)
                self.assertEquals(0, error)
                # Build MIC
                mic_token = gss_ctxt.sign(mic_msg)
                # Check MIC
                gss_srv_ctxt.verify(mic_msg, mic_token)
            else:
                error, token = gss_ctxt.authorize(c_token)
                c_token = token[0].Buffer
                self.assertNotEquals(0, error)
Beispiel #5
0
    def test_2_gssapi_sspi(self):
        """
        Test the used methods of python-gssapi or sspi, sspicon from pywin32.
        """
        _API = "MIT"
        try:
            import gssapi
        except ImportError:
            import sspicon
            import sspi
            _API = "SSPI"

        c_token = None
        gss_ctxt_status = False
        mic_msg = b"G'day Mate!"

        if _API == "MIT":
            if server_mode:
                gss_flags = (gssapi.C_PROT_READY_FLAG, gssapi.C_INTEG_FLAG,
                             gssapi.C_MUTUAL_FLAG, gssapi.C_DELEG_FLAG)
            else:
                gss_flags = (gssapi.C_PROT_READY_FLAG, gssapi.C_INTEG_FLAG,
                             gssapi.C_DELEG_FLAG)
            # Initialize a GSS-API context.
            ctx = gssapi.Context()
            ctx.flags = gss_flags
            krb5_oid = gssapi.OID.mech_from_string(krb5_mech)
            target_name = gssapi.Name("host@" + targ_name,
                                      gssapi.C_NT_HOSTBASED_SERVICE)
            gss_ctxt = gssapi.InitContext(peer_name=target_name,
                                          mech_type=krb5_oid,
                                          req_flags=ctx.flags)
            if server_mode:
                c_token = gss_ctxt.step(c_token)
                gss_ctxt_status = gss_ctxt.established
                self.assertEquals(False, gss_ctxt_status)
                # Accept a GSS-API context.
                gss_srv_ctxt = gssapi.AcceptContext()
                s_token = gss_srv_ctxt.step(c_token)
                gss_ctxt_status = gss_srv_ctxt.established
                self.assertNotEquals(None, s_token)
                self.assertEquals(True, gss_ctxt_status)
                # Establish the client context
                c_token = gss_ctxt.step(s_token)
                self.assertEquals(None, c_token)
            else:
                while not gss_ctxt.established:
                    c_token = gss_ctxt.step(c_token)
                self.assertNotEquals(None, c_token)
            # Build MIC
            mic_token = gss_ctxt.get_mic(mic_msg)

            if server_mode:
                # Check MIC
                status = gss_srv_ctxt.verify_mic(mic_msg, mic_token)
                self.assertEquals(0, status)
        else:
            gss_flags = (sspicon.ISC_REQ_INTEGRITY
                         | sspicon.ISC_REQ_MUTUAL_AUTH
                         | sspicon.ISC_REQ_DELEGATE)
            # Initialize a GSS-API context.
            target_name = "host/" + socket.getfqdn(targ_name)
            gss_ctxt = sspi.ClientAuth("Kerberos",
                                       scflags=gss_flags,
                                       targetspn=target_name)
            if server_mode:
                error, token = gss_ctxt.authorize(c_token)
                c_token = token[0].Buffer
                self.assertEquals(0, error)
                # Accept a GSS-API context.
                gss_srv_ctxt = sspi.ServerAuth("Kerberos", spn=target_name)
                error, token = gss_srv_ctxt.authorize(c_token)
                s_token = token[0].Buffer
                # Establish the context.
                error, token = gss_ctxt.authorize(s_token)
                c_token = token[0].Buffer
                self.assertEquals(None, c_token)
                self.assertEquals(0, error)
                # Build MIC
                mic_token = gss_ctxt.sign(mic_msg)
                # Check MIC
                gss_srv_ctxt.verify(mic_msg, mic_token)
            else:
                error, token = gss_ctxt.authorize(c_token)
                c_token = token[0].Buffer
                self.assertNotEquals(0, error)
Beispiel #6
0
 def get_context(self, host):
     service_name = gssapi.Name('{0}@{1}'.format(self.service,
                                                 host),
                                gssapi.C_NT_HOSTBASED_SERVICE)
     logging.debug("get_context(): service name={0}".format(service_name))
     return gssapi.InitContext(service_name)
Beispiel #7
0
    def open(self, host, port=4373, principal=None):
        if principal is None:
            gss_name = gssapi.Name('host@' + host, gssapi.C_NT_HOSTBASED_SERVICE)
        elif isinstance(principal, gssapi.Name):
            gss_name = principal
        else:
            gss_name = gssapi.Name(principal, gssapi.C_NT_HOSTBASED_SERVICE)

        args = [(host, port)]
        if self.timeout != 0:
            args.append(self.timeout)
        if self.source is not None:
            args.append((self.source, 0))
        sock = socket.create_connection(*args)

        sock.sendall(self._build_pkt(
            flags=(TOKEN_NOOP | TOKEN_CONTEXT_NEXT | TOKEN_PROTOCOL),
            data='', wrap=False
        ))

        ctx_args = [gss_name]
        if self.credential is not None:
            ctx_args.append(self.credential)
        ctx = gssapi.InitContext(*ctx_args, req_flags=(
            gssapi.C_MUTUAL_FLAG, gssapi.C_CONF_FLAG, gssapi.C_INTEG_FLAG,
            gssapi.C_REPLAY_FLAG, gssapi.C_SEQUENCE_FLAG
        ))
        in_token = None
        receiver = _packet_generator(sock)
        out_token = ctx.step()
        while not ctx.established:
            sock.sendall(self._build_pkt(
                flags=(TOKEN_CONTEXT | TOKEN_PROTOCOL),
                data=out_token, wrap=False
            ))
            try:
                flags, in_token = next(receiver)
            except StopIteration:
                sock.close()
                raise RemctlError("Network error: Server closed connection.")
            if not (flags & TOKEN_PROTOCOL):
                sock.close()
                raise RemctlError("Server is using remctl protocol version 1 which is unsupported.")
            if not (flags & TOKEN_CONTEXT):
                sock.close()
                raise RemctlError("Server failed to set TOKEN_CONTEXT flag on context packet.")
            out_token = ctx.step(in_token)
        if out_token:
            sock.sendall(self._build_pkt(
                flags=(TOKEN_CONTEXT | TOKEN_PROTOCOL),
                data=out_token, wrap=False
            ))
        if not ctx.mutual_auth_negotiated:
            sock.close()
            raise RemctlError("Could not negotiate mutual authentication")
        if not ctx.integrity_negotiated:
            sock.close()
            raise RemctlError("Could not negotiate integrity protection")
        if not ctx.confidentiality_negotiated:
            sock.close()
            raise RemctlError("Could not negotiate confidentiality protection")
        # otherwise, everything is fine, continue:
        self.last_error = None
        self.commands = 0
        self.sock = sock
        self.receiver = receiver
        self.ctx = ctx
Beispiel #8
0
#  sudo yum install -y epel-release
#  sudo yum install -y python-pip krb5-devel python-devel libffi-devel
#  sudo pip install python-gssapi

HOSTNAME = socket.gethostname()
PORT = 8765
URL = "/"
SHOW_TOKENS = False
SHOW_HEADERS = False

# Create a Name identifying the target service
service_name = gssapi.Name('HTTP@%s' % HOSTNAME, gssapi.C_NT_HOSTBASED_SERVICE)
#service_name = gssapi.Name('HTTP@%s' % HOSTNAME)

# Create an InitContext targeting the demo service
ctx = gssapi.InitContext(
    service_name, mech_type=gssapi.oids.OID.mech_from_string("1.3.6.1.5.5.2"))

# Create the connection
conn = httplib.HTTPConnection("%s:%d" % (HOSTNAME, PORT))


def random_string(len):
    hex_characters = "0123456789abcdef"
    return ''.join(random.choice(hex_characters) for _ in range(len))


lengths = [8, 4, 4, 4, 12]
connection_id = "-".join([random_string(x) for x in lengths])
request = {
    "request": "openConnection",
    "connectionId": connection_id,