Exemplo n.º 1
0
    def test_secure_connect(self):

        target_server = object()
        insecure = SIPClient(target_server, 999, use_ssl=False)
        no_cert = SIPClient(target_server, 999, use_ssl=True)
        with_cert = SIPClient(
            target_server, 999, ssl_cert="cert", ssl_key="key"
        )

        # Mock the socket.socket function.
        old_socket = socket.socket
        socket.socket = MockSocket

        # Mock the ssl.wrap_socket function
        old_wrap_socket = ssl.wrap_socket
        wrap_socket = MockWrapSocket()
        ssl.wrap_socket = wrap_socket

        try:
            # When an insecure connection is created, wrap_socket is
            # not called.
            insecure.connect()
            eq_(None, wrap_socket.called_with)

            # When a secure connection is created with no SSL
            # certificate, wrap_socket() is called on the connection
            # (in this case, a MockSocket), but no other arguments are
            # passed in to wrap_socket().
            no_cert.connect()
            connection, kwargs = wrap_socket.called_with
            assert isinstance(connection, MockSocket)
            eq_(dict(keyfile=None, certfile=None), kwargs)

            # When a secure connection is created with an SSL
            # certificate, the certificate and key are written to
            # temporary files, and the paths to those files are passed
            # in along with the collection to wrap_socket().
            wrap_socket.called_with = None
            with_cert.connect()
            connection, kwargs = wrap_socket.called_with
            assert isinstance(connection, MockSocket)
            eq_(set(['keyfile', 'certfile']), set(kwargs.keys()))
            for tmpfile in kwargs.values():
                assert tmpfile.startswith("/tmp")
                # By the time the SSL socket has been wrapped, the
                # temporary file has already been removed.  Because of
                # that we can't verify from within a unit test that the
                # correct contents were written to the file.
                assert not os.path.exists(tmpfile)
        finally:
            # Un-mock the old functions.
            socket.socket = old_socket
            ssl.wrap_socket = old_wrap_socket
Exemplo n.º 2
0
    def test_connect(self):
        target_server = object()
        sip = SIPClient(target_server, 999)

        old_socket = socket.socket

        # Mock the socket.socket function.
        socket.socket = MockSocket

        # Call connect() and make sure timeout is set properly.
        try:
            sip.connect()
            assert 12 == sip.connection.timeout
        finally:
            # Un-mock the socket.socket function
            socket.socket = old_socket
Exemplo n.º 3
0
    def __init__(self, library, integration, analytics=None, client=None, connect=True):
        """An object capable of communicating with a SIP server.

        :param server: Hostname of the SIP server.
        :param port: The port number to connect to on the SIP server.

        :param login_user_id: SIP field CN; the user ID to use when
         initiating a SIP session, if necessary. This is _not_ a
         patron identifier (SIP field AA); it identifies the SC
         creating the SIP session. SIP2 defines SC as "...any library
         automation device dealing with patrons or library materials."

        :param login_password: Sip field CO; the password to use when
         initiating a SIP session, if necessary.

        :param location_code: SIP field CP; the location code to use
         when initiating a SIP session. A location code supposedly
         refers to the physical location of a self-checkout machine
         within a library system. Some libraries require a special
         location code to be provided when authenticating patrons;
         others may require the circulation manager to be treated as
         its own special 'location'.

        :param field_separator: The field delimiter (see
        "Variable-length fields" in the SIP2 spec). If no value is
        specified, the default (the pipe character) will be used.

        :param client: A drop-in replacement for the SIPClient
        object. Only intended for use during testing.

        :param connect: If this is false, the generated SIPClient will
        not attempt to connect to the server. Only intended for use
        during testing.
        """
        super(SIP2AuthenticationProvider, self).__init__(
            library, integration, analytics
        )
        try:
            server = None
            if client:
                if callable(client):
                    client = client()
            else:
                server = integration.url
                port = integration.setting(self.PORT).int_value
                login_user_id = integration.username
                login_password = integration.password
                location_code = integration.setting(self.LOCATION_CODE).value
                field_separator = integration.setting(
                    self.FIELD_SEPARATOR).value or '|'
                client = SIPClient(
                    target_server=server, target_port=port,
                    login_user_id=login_user_id, login_password=login_password,
                    location_code=location_code, separator=field_separator,
                    connect=connect
                )
        except IOError, e:
            raise RemoteIntegrationException(
                server or 'unknown server', e.message
            )
Exemplo n.º 4
0
    def test_connect(self):
        target_server = object()
        sip = SIPClient(target_server, 999)

        old_socket = socket.socket

        # Mock the socket.socket function.
        socket.socket = MockSocket

        # Call connect() and make sure timeout is set properly.
        try:
            sip.connect()
            eq_(12, sip.connection.timeout)
        finally:
            # Un-mock the socket.socket function
            socket.socket = old_socket
Exemplo n.º 5
0
    def _run_self_tests(self, _db):
        def makeConnection(sip):
            sip.connect()
            return sip.connection

        if self.client:
            sip = self.client
        else:
            sip = SIPClient(target_server=self.server,
                            target_port=self.port,
                            login_user_id=self.login_user_id,
                            login_password=self.login_password,
                            location_code=self.location_code,
                            institution_id=self.institution_id,
                            separator=self.field_separator,
                            use_ssl=self.use_ssl,
                            ssl_cert=self.ssl_cert,
                            ssl_key=self.ssl_key,
                            dialect=self.dialect)

        connection = self.run_test(("Test Connection"), makeConnection, sip)
        yield connection

        if not connection.success:
            return

        login = self.run_test(
            ("Test Login with username '%s' and password '%s'" %
             (self.login_user_id, self.login_password)), sip.login)
        yield login

        # Log in was successful so test patron's test credentials
        if login.success:
            results = [
                r for r in super(SIP2AuthenticationProvider,
                                 self)._run_self_tests(_db)
            ]
            for result in results:
                yield result

            if results[0].success:

                def raw_patron_information():
                    info = sip.patron_information(self.test_username,
                                                  self.test_password)
                    return json.dumps(info, indent=1)

                yield self.run_test("Patron information request",
                                    sip.patron_information_request,
                                    self.test_username,
                                    patron_password=self.test_password)

                yield self.run_test(("Raw test patron information"),
                                    raw_patron_information)
Exemplo n.º 6
0
    def test_read_message(self):
        target_server = object()
        sip = SIPClient(target_server, 999)

        old_socket = socket.socket

        # Mock the socket.socket function.
        socket.socket = MockSocket

        try:
            sip.connect()
            conn = sip.connection

            # Queue bytestrings and read them.
            for data in (
                    # Simple message.
                    b"abcd\n",
                    # Message that contains non-ASCII characters.
                    "LE CARRÉ, JOHN\r".encode("cp850"),
                    # Message that spans multiple blocks.
                (b"a" * 4097) + b"\n",
            ):
                conn.queue_data(data)
                assert data == sip.read_message()

            # IOError on a message that's too large.
            conn.queue_data("too big\n")
            with pytest.raises(IOError, match="SIP2 response too large."):
                sip.read_message(max_size=2)

            # IOError if transmission stops without ending on a newline.
            conn.queue_data("no newline")
            with pytest.raises(IOError, match="No data read from socket."):
                sip.read_message()
        finally:
            # Un-mock the socket.socket function
            socket.socket = old_socket
Exemplo n.º 7
0
    def test_secure_connect(self):

        target_server = object()
        insecure = SIPClient(target_server, 999, use_ssl=False)
        no_cert = SIPClient(target_server, 999, use_ssl=True)
        with_cert = SIPClient(target_server,
                              999,
                              ssl_cert="cert",
                              ssl_key="key")

        # Mock the socket.socket function.
        old_socket = socket.socket
        socket.socket = MockSocket

        # Mock the ssl.wrap_socket function
        old_wrap_socket = ssl.wrap_socket
        wrap_socket = MockWrapSocket()
        ssl.wrap_socket = wrap_socket

        try:
            # When an insecure connection is created, wrap_socket is
            # not called.
            insecure.connect()
            assert None == wrap_socket.called_with

            # When a secure connection is created with no SSL
            # certificate, wrap_socket() is called on the connection
            # (in this case, a MockSocket), but no other arguments are
            # passed in to wrap_socket().
            no_cert.connect()
            connection, kwargs = wrap_socket.called_with
            assert isinstance(connection, MockSocket)
            assert dict(keyfile=None, certfile=None) == kwargs

            # When a secure connection is created with an SSL
            # certificate, the certificate and key are written to
            # temporary files, and the paths to those files are passed
            # in along with the collection to wrap_socket().
            wrap_socket.called_with = None
            with_cert.connect()
            connection, kwargs = wrap_socket.called_with
            assert isinstance(connection, MockSocket)
            assert set(["keyfile", "certfile"]) == set(kwargs.keys())
            for tmpfile in list(kwargs.values()):
                tmpfile = os.path.abspath(tmpfile)
                assert os.path.basename(tmpfile).startswith("tmp")
                # By the time the SSL socket has been wrapped, the
                # temporary file has already been removed.  Because of
                # that we can't verify from within a unit test that the
                # correct contents were written to the file.
                assert not os.path.exists(tmpfile)
        finally:
            # Un-mock the old functions.
            socket.socket = old_socket
            ssl.wrap_socket = old_wrap_socket
Exemplo n.º 8
0
    def patron_information(self, username, password):
        try:
            if self.client:
                sip = self.client
            else:
                sip = SIPClient(target_server=self.server,
                                target_port=self.port,
                                login_user_id=self.login_user_id,
                                login_password=self.login_password,
                                location_code=self.location_code,
                                institution_id=self.institution_id,
                                separator=self.field_separator,
                                use_ssl=self.use_ssl,
                                ssl_cert=self.ssl_cert,
                                ssl_key=self.ssl_key,
                                dialect=self.dialect)
            sip.connect()
            sip.login()
            info = sip.patron_information(username, password)
            sip.end_session(username, password)
            sip.disconnect()
            return info

        except IOError, e:
            raise RemoteIntegrationException(self.server or 'unknown server',
                                             e.message)