Capture server key before returning from callback
[netconf.git] / netconf / callhome-protocol / src / test / java / org / opendaylight / netconf / callhome / protocol / NetconfCallHomeServerTest.java
1 /*
2  * Copyright (c) 2016 Brocade Communication Systems and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netconf.callhome.protocol;
10
11 import static org.junit.Assert.assertFalse;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.Mockito.doNothing;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.spy;
17 import static org.mockito.Mockito.times;
18 import static org.mockito.Mockito.verify;
19
20 import io.netty.channel.EventLoopGroup;
21 import io.netty.channel.nio.NioEventLoopGroup;
22 import java.io.IOException;
23 import java.net.InetSocketAddress;
24 import java.net.SocketAddress;
25 import java.security.PublicKey;
26 import java.util.HashMap;
27 import java.util.Map;
28 import org.apache.sshd.client.SshClient;
29 import org.apache.sshd.client.future.AuthFuture;
30 import org.apache.sshd.client.session.ClientSession;
31 import org.apache.sshd.client.session.ClientSessionImpl;
32 import org.apache.sshd.common.future.SshFutureListener;
33 import org.apache.sshd.common.io.IoAcceptor;
34 import org.apache.sshd.common.io.IoHandler;
35 import org.apache.sshd.common.io.IoServiceFactory;
36 import org.apache.sshd.common.kex.KeyExchange;
37 import org.apache.sshd.common.session.Session;
38 import org.apache.sshd.common.session.SessionListener;
39 import org.junit.AfterClass;
40 import org.junit.Before;
41 import org.junit.BeforeClass;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.mockito.Mock;
45 import org.mockito.Mockito;
46 import org.mockito.junit.MockitoJUnitRunner;
47
48 @RunWith(MockitoJUnitRunner.class)
49 public class NetconfCallHomeServerTest {
50     private static EventLoopGroup EVENT_LOOP_GROUP;
51     private static InetSocketAddress MOCK_ADDRESS;
52
53     private SshClient mockSshClient;
54     @Mock
55     private CallHomeAuthorizationProvider mockCallHomeAuthProv;
56     @Mock
57     private CallHomeAuthorization mockAuth;
58     @Mock
59     private CallHomeSessionContext.Factory mockFactory;
60     @Mock
61     private ClientSession mockSession;
62     @Mock
63     private StatusRecorder mockStatusRecorder;
64
65     private NetconfCallHomeServer instance;
66
67     @BeforeClass
68     public static void beforeClass() {
69         EVENT_LOOP_GROUP = new NioEventLoopGroup();
70         MOCK_ADDRESS = InetSocketAddress.createUnresolved("127.0.0.1", 123);
71     }
72
73     @AfterClass
74     public static void afterClass() {
75         EVENT_LOOP_GROUP.shutdownGracefully();
76         EVENT_LOOP_GROUP = null;
77         MOCK_ADDRESS = null;
78     }
79
80     @Before
81     public void setup() {
82         mockSshClient = spy(SshClient.setUpDefaultClient());
83         mockCallHomeAuthProv = mock(CallHomeAuthorizationProvider.class);
84         mockAuth = mock(CallHomeAuthorization.class);
85         mockFactory = mock(CallHomeSessionContext.Factory.class);
86         mockSession = mock(ClientSession.class);
87         mockStatusRecorder = mock(StatusRecorder.class);
88
89         Map<String, String> props = new HashMap<>();
90         props.put("nio-workers", "1");
91         doReturn(EVENT_LOOP_GROUP).when(mockFactory).getNettyGroup();
92         instance = new NetconfCallHomeServer(
93             mockSshClient, mockCallHomeAuthProv, mockFactory, MOCK_ADDRESS, mockStatusRecorder);
94     }
95
96     @Test
97     public void sessionListenerShouldHandleEventsOfKeyEstablishedAndAuthenticated() throws IOException {
98         // Weird - IJ was ok but command line compile failed using the usual array initializer syntax ????
99         SessionListener.Event[] evt = new SessionListener.Event[2];
100         evt[0] = SessionListener.Event.KeyEstablished;
101         evt[1] = SessionListener.Event.Authenticated;
102
103         int[] hitOpen = new int[2];
104         hitOpen[0] = 0;
105         hitOpen[1] = 1;
106
107         int[] hitAuth = new int[2];
108         hitAuth[0] = 1;
109         hitAuth[1] = 0;
110
111         for (int pass = 0; pass < evt.length; pass++) {
112             // given
113             AuthFuture mockAuthFuture = mock(AuthFuture.class);
114             doReturn(null).when(mockAuthFuture).addListener(any(SshFutureListener.class));
115             CallHomeSessionContext mockContext = mock(CallHomeSessionContext.class);
116             doNothing().when(mockContext).openNetconfChannel();
117             doReturn(mockContext).when(mockSession).getAttribute(any(Session.AttributeKey.class));
118
119             final KeyExchange kex = mock(KeyExchange.class);
120             doReturn(kex).when(mockSession).getKex();
121             final PublicKey serverKey = mock(PublicKey.class);
122             doReturn(serverKey).when(kex).getServerKey();
123
124             SessionListener listener = instance.createSessionListener();
125             doReturn(mockAuthFuture).when(mockContext).authorize();
126             // when
127             listener.sessionEvent(mockSession, evt[pass]);
128             // then
129             verify(mockContext, times(hitOpen[pass])).openNetconfChannel();
130             verify(mockContext, times(hitAuth[pass])).authorize();
131         }
132     }
133
134     @Test
135     public void verificationOfTheServerKeyShouldBeSuccessfulForServerIsAllowed() {
136         // given
137
138         ClientSessionImpl mockClientSession = mock(ClientSessionImpl.class);
139         Mockito.doReturn("test").when(mockClientSession).toString();
140         SocketAddress mockSocketAddr = mock(SocketAddress.class);
141         PublicKey mockPublicKey = mock(PublicKey.class);
142
143         Mockito.doReturn(true).when(mockAuth).isServerAllowed();
144         Mockito.doReturn("some-session-name").when(mockAuth).getSessionName();
145
146         Mockito.doReturn(mockAuth).when(mockCallHomeAuthProv).provideAuth(mockSocketAddr, mockPublicKey);
147
148         Mockito.doReturn(null).when(mockFactory).createIfNotExists(mockClientSession, mockAuth, mockSocketAddr);
149
150         // expect
151         instance.verifyServerKey(mockClientSession, mockSocketAddr, mockPublicKey);
152     }
153
154     @Test
155     public void verificationOfTheServerKeyShouldFailIfTheServerIsNotAllowed() {
156         // given
157
158         ClientSessionImpl mockClientSession = mock(ClientSessionImpl.class);
159         SocketAddress mockSocketAddr = mock(SocketAddress.class);
160         PublicKey mockPublicKey = mock(PublicKey.class);
161
162         Mockito.doReturn(false).when(mockAuth).isServerAllowed();
163         Mockito.doReturn(mockAuth).when(mockCallHomeAuthProv).provideAuth(mockSocketAddr, mockPublicKey);
164         Mockito.doReturn("").when(mockClientSession).toString();
165
166         // expect
167         assertFalse(instance.verifyServerKey(mockClientSession, mockSocketAddr, mockPublicKey));
168     }
169
170     @Test
171     public void bindShouldStartTheClientAndBindTheAddress() throws IOException {
172         // given
173         IoAcceptor mockAcceptor = mock(IoAcceptor.class);
174         IoServiceFactory mockMinaFactory = mock(IoServiceFactory.class);
175
176         Mockito.doReturn(mockAcceptor).when(mockMinaFactory).createAcceptor(any(IoHandler.class));
177         Mockito.doNothing().when(mockAcceptor).bind(any(SocketAddress.class));
178         instance = new NetconfCallHomeServer(
179                 mockSshClient, mockCallHomeAuthProv, mockFactory, MOCK_ADDRESS, mockStatusRecorder, mockMinaFactory);
180         // when
181         instance.bind();
182         // then
183         verify(mockSshClient, times(1)).start();
184         verify(mockAcceptor, times(1)).bind(MOCK_ADDRESS);
185     }
186 }