/* * Copyright (C) 2012 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.facebook.swift.service; import com.facebook.nifty.client.FramedClientConnector; import com.facebook.nifty.client.NettyClientConfig; import com.facebook.nifty.client.NiftyClient; import com.facebook.nifty.core.NiftyTimer; import com.facebook.nifty.processor.NiftyProcessor; import com.facebook.nifty.processor.NiftyProcessorAdapters; import com.facebook.nifty.ssl.OpenSslServerConfiguration; import com.facebook.nifty.ssl.SslClientConfiguration; import com.facebook.nifty.ssl.SslServerConfiguration; import com.facebook.swift.codec.ThriftCodecManager; import com.facebook.swift.service.scribe.LogEntry; import com.facebook.swift.service.scribe.ResultCode; import com.facebook.swift.service.scribe.scribe; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.apache.thrift.TException; import org.apache.thrift.TProcessor; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TSocket; import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory; import org.testng.annotations.Test; import javax.annotation.Nullable; import javax.net.ssl.SSLContext; import java.io.File; import java.io.IOException; import java.net.Socket; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.List; import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.net.HostAndPort.fromParts; import static org.testng.Assert.*; /** * Demonstrates creating a Thrift service using Swift with ssl */ public class TestThriftSslService { @Test public void testSwiftService() throws Exception { SwiftScribe scribeService = new SwiftScribe(); NiftyProcessor processor = new ThriftServiceProcessor(new ThriftCodecManager(), ImmutableList.<ThriftEventHandler>of(), scribeService); List<LogEntry> messages = testProcessor(processor, false); assertEquals(scribeService.getMessages(), newArrayList(concat(toSwiftLogEntry(messages), toSwiftLogEntry(messages)))); } @Test public void testThriftService() throws Exception { ThriftScribeService scribeService = new ThriftScribeService(); TProcessor processor = new scribe.Processor<>(scribeService); List<LogEntry> messages = testProcessor(processor); assertEquals(scribeService.getMessages(), newArrayList(concat(messages, messages))); } @Test public void testSwiftServicePlaintext() throws Exception { SwiftScribe scribeService = new SwiftScribe(); NiftyProcessor processor = new ThriftServiceProcessor(new ThriftCodecManager(), ImmutableList.<ThriftEventHandler>of(), scribeService); List<LogEntry> messages = testProcessor(processor, true); assertEquals(scribeService.getMessages(), newArrayList(concat(toSwiftLogEntry(messages), toSwiftLogEntry(messages)))); } @Test public void testThriftServicePlaintext() throws Exception { ThriftScribeService scribeService = new ThriftScribeService(); TProcessor processor = new scribe.Processor<>(scribeService); List<LogEntry> messages = testProcessor(NiftyProcessorAdapters.processorFromTProcessor(processor), true); assertEquals(scribeService.getMessages(), newArrayList(concat(messages, messages))); } private List<LogEntry> testProcessor(TProcessor processor) throws Exception { return testProcessor(NiftyProcessorAdapters.processorFromTProcessor(processor), false); } private List<LogEntry> testProcessor(NiftyProcessor processor, boolean plaintext) throws Exception { ImmutableList<LogEntry> messages = ImmutableList.of( new LogEntry("hello", "world"), new LogEntry("bye", "world") ); SslServerConfiguration sslConfiguration = OpenSslServerConfiguration.newBuilder() .certFile(new File(getClass().getResource("/rsa.crt").getFile())) .keyFile(new File(getClass().getResource("/rsa.key").getFile())) .allowPlaintext(plaintext) .build(); try (ThriftServer server = new ThriftServer( processor, new ThriftServerConfig(), new NiftyTimer("timer"), ThriftServer.DEFAULT_FRAME_CODEC_FACTORIES, ThriftServer.DEFAULT_PROTOCOL_FACTORIES, ThriftServer.DEFAULT_WORKER_EXECUTORS, ThriftServer.DEFAULT_SECURITY_FACTORY, new ThriftServer.SslServerConfigurationHolder(sslConfiguration), ThriftServer.DEFAULT_TRANSPORT_ATTACH_OBSERVER).start()) { assertEquals(logThrift(server.getPort(), messages), ResultCode.OK); assertEquals(logSwift(server.getPort(), toSwiftLogEntry(messages)), com.facebook.swift.service.ResultCode.OK); } return messages; } private ResultCode logThrift(int port, List<LogEntry> messages) throws TException, IOException, NoSuchAlgorithmException, KeyManagementException { SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, InsecureTrustManagerFactory.INSTANCE.getTrustManagers(), null); Socket sslSocket = ctx.getSocketFactory().createSocket("localhost", port); TSocket socket = new TSocket(sslSocket); try { TBinaryProtocol tp = new TBinaryProtocol(new TFramedTransport(socket)); return new scribe.Client(tp).Log(messages); } finally { socket.close(); } } private com.facebook.swift.service.ResultCode logSwift(int port, List<com.facebook.swift.service.LogEntry> entries) throws Exception { NettyClientConfig nettyClientConfig = NettyClientConfig.newBuilder() .setSSLClientConfiguration( new SslClientConfiguration.Builder() .caFile(new File(getClass().getResource("/rsa.crt").getFile())) .build()).build(); NiftyClient niftyClient = new NiftyClient(nettyClientConfig); try ( ThriftClientManager clientManager = new ThriftClientManager(new ThriftCodecManager(), niftyClient, ImmutableSet.of()); Scribe scribe = clientManager.createClient( new FramedClientConnector(fromParts("localhost", port)), Scribe.class).get() ) { return scribe.log(entries); } } private List<com.facebook.swift.service.LogEntry> toSwiftLogEntry(List<LogEntry> messages) { return Lists.transform(messages, new Function<LogEntry, com.facebook.swift.service.LogEntry>() { @Override public com.facebook.swift.service.LogEntry apply(@Nullable LogEntry input) { return new com.facebook.swift.service.LogEntry(input.category, input.message); } }); } }