1 /* 2 * Copyright 2021 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.testing.integration; 18 19 import static com.google.common.base.Preconditions.checkState; 20 import static io.grpc.alts.internal.HandshakerReq.ReqOneofCase.CLIENT_START; 21 import static io.grpc.alts.internal.HandshakerReq.ReqOneofCase.NEXT; 22 import static io.grpc.alts.internal.HandshakerReq.ReqOneofCase.SERVER_START; 23 24 import com.google.protobuf.ByteString; 25 import io.grpc.alts.internal.HandshakerReq; 26 import io.grpc.alts.internal.HandshakerResp; 27 import io.grpc.alts.internal.HandshakerResult; 28 import io.grpc.alts.internal.HandshakerServiceGrpc.HandshakerServiceImplBase; 29 import io.grpc.alts.internal.Identity; 30 import io.grpc.alts.internal.RpcProtocolVersions; 31 import io.grpc.alts.internal.RpcProtocolVersions.Version; 32 import io.grpc.stub.StreamObserver; 33 import java.util.Random; 34 import java.util.logging.Level; 35 import java.util.logging.Logger; 36 37 /** 38 * A fake HandshakeService for ALTS integration testing in non-gcp environments. 39 * */ 40 public class AltsHandshakerTestService extends HandshakerServiceImplBase { 41 private static final Logger log = Logger.getLogger(AltsHandshakerTestService.class.getName()); 42 43 private final Random random = new Random(); 44 private static final int FIXED_LENGTH_OUTPUT = 16; 45 private final ByteString fakeOutput = data(FIXED_LENGTH_OUTPUT); 46 private final ByteString secret = data(128); 47 private State expectState = State.CLIENT_INIT; 48 49 @Override doHandshake( final StreamObserver<HandshakerResp> responseObserver)50 public StreamObserver<HandshakerReq> doHandshake( 51 final StreamObserver<HandshakerResp> responseObserver) { 52 return new StreamObserver<HandshakerReq>() { 53 @Override 54 public void onNext(HandshakerReq value) { 55 log.log(Level.FINE, "request received: " + value); 56 synchronized (AltsHandshakerTestService.this) { 57 switch (expectState) { 58 case CLIENT_INIT: 59 checkState(CLIENT_START.equals(value.getReqOneofCase())); 60 HandshakerResp initClient = HandshakerResp.newBuilder() 61 .setOutFrames(fakeOutput) 62 .build(); 63 log.log(Level.FINE, "init client response " + initClient); 64 responseObserver.onNext(initClient); 65 expectState = State.SERVER_INIT; 66 break; 67 case SERVER_INIT: 68 checkState(SERVER_START.equals(value.getReqOneofCase())); 69 HandshakerResp initServer = HandshakerResp.newBuilder() 70 .setBytesConsumed(FIXED_LENGTH_OUTPUT) 71 .setOutFrames(fakeOutput) 72 .build(); 73 log.log(Level.FINE, "init server response" + initServer); 74 responseObserver.onNext(initServer); 75 expectState = State.CLIENT_FINISH; 76 break; 77 case CLIENT_FINISH: 78 checkState(NEXT.equals(value.getReqOneofCase())); 79 HandshakerResp resp = HandshakerResp.newBuilder() 80 .setResult(getResult()) 81 .setBytesConsumed(FIXED_LENGTH_OUTPUT) 82 .setOutFrames(fakeOutput) 83 .build(); 84 log.log(Level.FINE, "client finished response " + resp); 85 responseObserver.onNext(resp); 86 expectState = State.SERVER_FINISH; 87 break; 88 case SERVER_FINISH: 89 resp = HandshakerResp.newBuilder() 90 .setResult(getResult()) 91 .setBytesConsumed(FIXED_LENGTH_OUTPUT) 92 .build(); 93 log.log(Level.FINE, "server finished response " + resp); 94 responseObserver.onNext(resp); 95 expectState = State.CLIENT_INIT; 96 break; 97 default: 98 throw new RuntimeException("unknown state"); 99 } 100 } 101 } 102 103 @Override 104 public void onError(Throwable t) { 105 log.log(Level.INFO, "onError " + t); 106 } 107 108 @Override 109 public void onCompleted() { 110 responseObserver.onCompleted(); 111 } 112 }; 113 } 114 115 private HandshakerResult getResult() { 116 return HandshakerResult.newBuilder().setApplicationProtocol("grpc") 117 .setRecordProtocol("ALTSRP_GCM_AES128_REKEY") 118 .setKeyData(secret) 119 .setMaxFrameSize(131072) 120 .setPeerIdentity(Identity.newBuilder() 121 .setServiceAccount("123456789-compute@developer.gserviceaccount.com") 122 .build()) 123 .setPeerRpcVersions(RpcProtocolVersions.newBuilder() 124 .setMaxRpcVersion(Version.newBuilder() 125 .setMajor(2).setMinor(1) 126 .build()) 127 .setMinRpcVersion(Version.newBuilder() 128 .setMajor(2).setMinor(1) 129 .build()) 130 .build()) 131 .build(); 132 } 133 134 private ByteString data(int len) { 135 byte[] k = new byte[len]; 136 random.nextBytes(k); 137 return ByteString.copyFrom(k); 138 } 139 140 private enum State { 141 CLIENT_INIT, 142 SERVER_INIT, 143 CLIENT_FINISH, 144 SERVER_FINISH 145 } 146 } 147