Search in sources :

Example 1 with MessagingChannel

use of org.voltcore.utils.ssl.MessagingChannel in project voltdb by VoltDB.

the class ConnectionUtil method getAuthenticatedConnection.

private static Object[] getAuthenticatedConnection(String service, InetSocketAddress addr, String username, byte[] hashedPassword, final Subject subject, ClientAuthScheme scheme, SSLEngine sslEngine) throws IOException {
    Object[] returnArray = new Object[3];
    boolean success = false;
    if (addr.isUnresolved()) {
        throw new java.net.UnknownHostException(addr.getHostName());
    }
    SocketChannel aChannel = SocketChannel.open(addr);
    returnArray[0] = aChannel;
    assert (aChannel.isConnected());
    if (!aChannel.isConnected()) {
        // TODO Can open() be asynchronous if configureBlocking(true)?
        throw new IOException("Failed to open host " + ReverseDNSCache.hostnameOrAddress(addr.getAddress()));
    }
    synchronized (aChannel.blockingLock()) {
        aChannel.configureBlocking(false);
        aChannel.socket().setTcpNoDelay(true);
    }
    if (sslEngine != null) {
        TLSHandshaker handshaker = new TLSHandshaker(aChannel, sslEngine);
        boolean shookHands = false;
        try {
            shookHands = handshaker.handshake();
        } catch (IOException e) {
            aChannel.close();
            throw new IOException("SSL handshake failed", e);
        }
        if (!shookHands) {
            aChannel.close();
            throw new IOException("SSL handshake failed");
        }
    }
    final long[] retvals = new long[4];
    returnArray[1] = retvals;
    MessagingChannel messagingChannel = MessagingChannel.get(aChannel, sslEngine);
    try {
        /*
             * Send login info
             */
        synchronized (aChannel.blockingLock()) {
            aChannel.configureBlocking(true);
            aChannel.socket().setTcpNoDelay(true);
        }
        // encode strings
        byte[] serviceBytes = service == null ? null : service.getBytes(Constants.UTF8ENCODING);
        byte[] usernameBytes = username == null ? null : username.getBytes(Constants.UTF8ENCODING);
        // get the length of the data to serialize
        int requestSize = 4;
        //version and scheme
        requestSize += 2;
        requestSize += serviceBytes == null ? 4 : 4 + serviceBytes.length;
        requestSize += usernameBytes == null ? 4 : 4 + usernameBytes.length;
        requestSize += hashedPassword.length;
        ByteBuffer b = ByteBuffer.allocate(requestSize);
        // serialize it
        // length prefix
        b.putInt(requestSize - 4);
        // version
        b.put((byte) 1);
        b.put((byte) scheme.getValue());
        // data service (export|database)
        SerializationHelper.writeVarbinary(serviceBytes, b);
        SerializationHelper.writeVarbinary(usernameBytes, b);
        b.put(hashedPassword);
        b.flip();
        try {
            messagingChannel.writeMessage(b);
        } catch (IOException e) {
            throw new IOException("Failed to write authentication message to server.", e);
        }
        if (b.hasRemaining()) {
            throw new IOException("Failed to write authentication message to server.");
        }
        ByteBuffer loginResponse;
        try {
            loginResponse = messagingChannel.readMessage();
        } catch (IOException e) {
            throw new IOException("Authentication rejected", e);
        }
        byte version = loginResponse.get();
        byte loginResponseCode = loginResponse.get();
        if (version == Constants.AUTH_HANDSHAKE_VERSION) {
            byte tag = loginResponseCode;
            if (subject == null) {
                aChannel.close();
                throw new IOException("Server requires an authenticated JAAS principal");
            }
            if (tag != Constants.AUTH_SERVICE_NAME) {
                aChannel.close();
                throw new IOException("Wire protocol format violation error");
            }
            String servicePrincipal = SerializationHelper.getString(loginResponse);
            loginResponse = performAuthenticationHandShake(aChannel, subject, servicePrincipal);
            loginResponseCode = loginResponse.get();
        }
        if (loginResponseCode != 0) {
            aChannel.close();
            switch(loginResponseCode) {
                case Constants.MAX_CONNECTIONS_LIMIT_ERROR:
                    throw new IOException("Server has too many connections");
                case Constants.WIRE_PROTOCOL_TIMEOUT_ERROR:
                    throw new IOException("Connection timed out during authentication. " + "The VoltDB server may be overloaded.");
                case Constants.EXPORT_DISABLED_REJECTION:
                    throw new IOException("Export not enabled for server");
                case Constants.WIRE_PROTOCOL_FORMAT_ERROR:
                    throw new IOException("Wire protocol format violation error");
                case Constants.AUTHENTICATION_FAILURE_DUE_TO_REJOIN:
                    throw new IOException("Failed to authenticate to rejoining node");
                default:
                    throw new IOException("Authentication rejected");
            }
        }
        retvals[0] = loginResponse.getInt();
        retvals[1] = loginResponse.getLong();
        retvals[2] = loginResponse.getLong();
        retvals[3] = loginResponse.getInt();
        int buildStringLength = loginResponse.getInt();
        byte[] buildStringBytes = new byte[buildStringLength];
        loginResponse.get(buildStringBytes);
        returnArray[2] = new String(buildStringBytes, Constants.UTF8ENCODING);
        synchronized (aChannel.blockingLock()) {
            aChannel.configureBlocking(false);
            aChannel.socket().setKeepAlive(true);
        }
        success = true;
    } finally {
        messagingChannel.cleanUp();
        if (!success) {
            aChannel.close();
        }
    }
    return returnArray;
}
Also used : SocketChannel(java.nio.channels.SocketChannel) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) MessagingChannel(org.voltcore.utils.ssl.MessagingChannel)

Aggregations

IOException (java.io.IOException)1 ByteBuffer (java.nio.ByteBuffer)1 SocketChannel (java.nio.channels.SocketChannel)1 MessagingChannel (org.voltcore.utils.ssl.MessagingChannel)1