1
+ using System . Collections . Generic ;
2
+ using Microsoft . VisualStudio . TestTools . UnitTesting ;
3
+ using Moq ;
4
+ using Renci . SshNet . Common ;
5
+
6
+ namespace Renci . SshNet . Tests . Classes
7
+ {
8
+ /// <summary>
9
+ /// * ConnectionInfo provides the following authentication methods (in order):
10
+ /// o publickey
11
+ /// o password
12
+ /// * Partial success limit is 2
13
+ ///
14
+ /// none
15
+ /// (1=FAIL)
16
+ /// |
17
+ /// +------------------------+------------------------+
18
+ /// | | |
19
+ /// password ◄--\ publickey keyboard-interactive
20
+ /// (7=SKIP) | (2=PS)
21
+ /// | |
22
+ /// | password
23
+ /// | (3=PS)
24
+ /// | |
25
+ /// | password
26
+ /// | (4=PS)
27
+ /// | |
28
+ /// | publickey
29
+ /// | (5=PS)
30
+ /// | |
31
+ /// \---- publickey
32
+ /// (6=SKIP)
33
+ /// </summary>
34
+ [ TestClass ]
35
+ public class ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit : ClientAuthenticationTestBase
36
+ {
37
+ private int _partialSuccessLimit ;
38
+ private ClientAuthentication _clientAuthentication ;
39
+ private SshAuthenticationException _actualException ;
40
+
41
+ protected override void SetupData ( )
42
+ {
43
+ _partialSuccessLimit = 2 ;
44
+ }
45
+
46
+ protected override void SetupMocks ( )
47
+ {
48
+ var seq = new MockSequence ( ) ;
49
+
50
+ SessionMock . InSequence ( seq ) . Setup ( p => p . RegisterMessage ( "SSH_MSG_USERAUTH_FAILURE" ) ) ;
51
+ SessionMock . InSequence ( seq ) . Setup ( p => p . RegisterMessage ( "SSH_MSG_USERAUTH_SUCCESS" ) ) ;
52
+ SessionMock . InSequence ( seq ) . Setup ( p => p . RegisterMessage ( "SSH_MSG_USERAUTH_BANNER" ) ) ;
53
+
54
+ ConnectionInfoMock . InSequence ( seq ) . Setup ( p => p . CreateNoneAuthenticationMethod ( ) )
55
+ . Returns ( NoneAuthenticationMethodMock . Object ) ;
56
+
57
+ /* 1 */
58
+
59
+ NoneAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Authenticate ( SessionMock . Object ) )
60
+ . Returns ( AuthenticationResult . Failure ) ;
61
+ ConnectionInfoMock . InSequence ( seq )
62
+ . Setup ( p => p . AuthenticationMethods )
63
+ . Returns ( new List < IAuthenticationMethod >
64
+ {
65
+ PublicKeyAuthenticationMethodMock . Object ,
66
+ PasswordAuthenticationMethodMock . Object
67
+ } ) ;
68
+ NoneAuthenticationMethodMock . InSequence ( seq )
69
+ . Setup ( p => p . AllowedAuthentications )
70
+ . Returns ( new [ ] { "password" , "publickey" , "keyboard-interactive" } ) ;
71
+
72
+ /* Enumerate supported authentication methods */
73
+
74
+ PublicKeyAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "publickey" ) ;
75
+ PasswordAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "password" ) ;
76
+
77
+ /* 2 */
78
+
79
+ PublicKeyAuthenticationMethodMock . InSequence ( seq )
80
+ . Setup ( p => p . Authenticate ( SessionMock . Object ) )
81
+ . Returns ( AuthenticationResult . PartialSuccess ) ;
82
+ PublicKeyAuthenticationMethodMock . InSequence ( seq )
83
+ . Setup ( p => p . AllowedAuthentications )
84
+ . Returns ( new [ ] { "password" } ) ;
85
+
86
+ /* Enumerate supported authentication methods */
87
+
88
+ PublicKeyAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "publickey" ) ;
89
+ PasswordAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "password" ) ;
90
+
91
+ /* 3 */
92
+
93
+ PasswordAuthenticationMethodMock . InSequence ( seq )
94
+ . Setup ( p => p . Authenticate ( SessionMock . Object ) )
95
+ . Returns ( AuthenticationResult . PartialSuccess ) ;
96
+ PasswordAuthenticationMethodMock . InSequence ( seq )
97
+ . Setup ( p => p . AllowedAuthentications )
98
+ . Returns ( new [ ] { "password" } ) ;
99
+
100
+ /* Enumerate supported authentication methods */
101
+
102
+ PublicKeyAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "publickey" ) ;
103
+ PasswordAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "password" ) ;
104
+
105
+ /* 4 */
106
+
107
+ PasswordAuthenticationMethodMock . InSequence ( seq )
108
+ . Setup ( p => p . Authenticate ( SessionMock . Object ) )
109
+ . Returns ( AuthenticationResult . PartialSuccess ) ;
110
+ PasswordAuthenticationMethodMock . InSequence ( seq )
111
+ . Setup ( p => p . AllowedAuthentications )
112
+ . Returns ( new [ ] { "publickey" } ) ;
113
+
114
+ /* Enumerate supported authentication methods */
115
+
116
+ PublicKeyAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "publickey" ) ;
117
+ PasswordAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "password" ) ;
118
+
119
+ /* 5 */
120
+
121
+ PublicKeyAuthenticationMethodMock . InSequence ( seq )
122
+ . Setup ( p => p . Authenticate ( SessionMock . Object ) )
123
+ . Returns ( AuthenticationResult . PartialSuccess ) ;
124
+ PublicKeyAuthenticationMethodMock . InSequence ( seq )
125
+ . Setup ( p => p . AllowedAuthentications )
126
+ . Returns ( new [ ] { "publickey" } ) ;
127
+
128
+ /* Enumerate supported authentication methods */
129
+
130
+ PublicKeyAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "publickey" ) ;
131
+ PasswordAuthenticationMethodMock . InSequence ( seq ) . Setup ( p => p . Name ) . Returns ( "password" ) ;
132
+
133
+ /* 6: Record partial success limit reached exception, and skip password authentication method */
134
+
135
+ PublicKeyAuthenticationMethodMock . InSequence ( seq )
136
+ . Setup ( p => p . Name )
137
+ . Returns ( "publickey-partial1" ) ;
138
+
139
+ /* 7: Record partial success limit reached exception, and skip password authentication method */
140
+
141
+ PasswordAuthenticationMethodMock . InSequence ( seq )
142
+ . Setup ( p => p . Name )
143
+ . Returns ( "password-partial1" ) ;
144
+
145
+ SessionMock . InSequence ( seq ) . Setup ( p => p . UnRegisterMessage ( "SSH_MSG_USERAUTH_FAILURE" ) ) ;
146
+ SessionMock . InSequence ( seq ) . Setup ( p => p . UnRegisterMessage ( "SSH_MSG_USERAUTH_SUCCESS" ) ) ;
147
+ SessionMock . InSequence ( seq ) . Setup ( p => p . UnRegisterMessage ( "SSH_MSG_USERAUTH_BANNER" ) ) ;
148
+ }
149
+
150
+ protected override void Arrange ( )
151
+ {
152
+ base . Arrange ( ) ;
153
+
154
+ _clientAuthentication = new ClientAuthentication ( _partialSuccessLimit ) ;
155
+ }
156
+
157
+ protected override void Act ( )
158
+ {
159
+ try
160
+ {
161
+ _clientAuthentication . Authenticate ( ConnectionInfoMock . Object , SessionMock . Object ) ;
162
+ Assert . Fail ( ) ;
163
+ }
164
+ catch ( SshAuthenticationException ex )
165
+ {
166
+ _actualException = ex ;
167
+ }
168
+ }
169
+
170
+ [ TestMethod ]
171
+ public void AuthenticateOnPasswordAuthenticationMethodShouldHaveBeenInvokedTwice ( )
172
+ {
173
+ PasswordAuthenticationMethodMock . Verify ( p => p . Authenticate ( SessionMock . Object ) , Times . Exactly ( 2 ) ) ;
174
+ }
175
+
176
+ [ TestMethod ]
177
+ public void AuthenticateOnPublicKeyAuthenticationMethodShouldHaveBeenInvokedTwice ( )
178
+ {
179
+ PublicKeyAuthenticationMethodMock . Verify ( p => p . Authenticate ( SessionMock . Object ) , Times . Exactly ( 2 ) ) ;
180
+ }
181
+
182
+ [ TestMethod ]
183
+ public void AuthenticateShouldThrowSshAuthenticationException ( )
184
+ {
185
+ Assert . IsNotNull ( _actualException ) ;
186
+ Assert . IsNull ( _actualException . InnerException ) ;
187
+ Assert . AreEqual ( "Reached authentication attempt limit for method (password-partial1)." , _actualException . Message ) ;
188
+ }
189
+ }
190
+ }
0 commit comments