@@ -21,12 +21,9 @@ class LoginManager : ILoginManager
2121 {
2222 private readonly ILogging logger = LogHelper . GetLogger < LoginManager > ( ) ;
2323
24- private readonly string [ ] scopes = { "user" , "repo" , "gist" , "write:public_key" } ;
2524 private readonly IKeychain keychain ;
2625 private readonly string clientId ;
2726 private readonly string clientSecret ;
28- private readonly string authorizationNote ;
29- private readonly string fingerprint ;
3027 private readonly IProcessManager processManager ;
3128 private readonly ITaskManager taskManager ;
3229 private readonly NPath nodeJsExecutablePath ;
@@ -38,8 +35,6 @@ class LoginManager : ILoginManager
3835 /// <param name="keychain"></param>
3936 /// <param name="clientId">The application's client API ID.</param>
4037 /// <param name="clientSecret">The application's client API secret.</param>
41- /// <param name="authorizationNote">An note to store with the authorization.</param>
42- /// <param name="fingerprint">The machine fingerprint.</param>
4338 /// <param name="processManager"></param>
4439 /// <param name="taskManager"></param>
4540 /// <param name="nodeJsExecutablePath"></param>
@@ -48,8 +43,6 @@ public LoginManager(
4843 IKeychain keychain ,
4944 string clientId ,
5045 string clientSecret ,
51- string authorizationNote = null ,
52- string fingerprint = null ,
5346 IProcessManager processManager = null , ITaskManager taskManager = null , NPath nodeJsExecutablePath = null , NPath octorunScript = null )
5447 {
5548 Guard . ArgumentNotNull ( keychain , nameof ( keychain ) ) ;
@@ -59,8 +52,6 @@ public LoginManager(
5952 this . keychain = keychain ;
6053 this . clientId = clientId ;
6154 this . clientSecret = clientSecret ;
62- this . authorizationNote = authorizationNote ;
63- this . fingerprint = fingerprint ;
6455 this . processManager = processManager ;
6556 this . taskManager = taskManager ;
6657 this . nodeJsExecutablePath = nodeJsExecutablePath ;
@@ -82,108 +73,59 @@ public async Task<LoginResultData> Login(
8273 keychain . Connect ( host ) ;
8374 keychain . SetCredentials ( new Credential ( host , username , password ) ) ;
8475
85- var newAuth = new NewAuthorization
86- {
87- Scopes = scopes ,
88- Note = authorizationNote ,
89- Fingerprint = fingerprint ,
90- } ;
91-
92- ApplicationAuthorization auth = null ;
93-
76+ string token ;
9477 try
9578 {
96- auth = await TryLogin ( host , username , password ) ;
97- EnsureNonNullAuthorization ( auth ) ;
98- }
99- catch ( TwoFactorAuthorizationException e )
100- {
101- LoginResultCodes result ;
102- if ( e is TwoFactorRequiredException )
79+ token = await TryLogin ( host , username , password ) ;
80+ if ( string . IsNullOrEmpty ( token ) )
10381 {
104- result = LoginResultCodes . CodeRequired ;
105- logger . Trace ( "2FA TwoFactorAuthorizationException: {0} {1}" , LoginResultCodes . CodeRequired , e . Message ) ;
82+ throw new InvalidOperationException ( "Returned token is null or empty" ) ;
10683 }
107- else
108- {
109- result = LoginResultCodes . CodeFailed ;
110- logger . Error ( e , "2FA TwoFactorAuthorizationException: {0} {1}" , LoginResultCodes . CodeRequired , e . Message ) ;
111- }
112-
113- return new LoginResultData ( result , e . Message , host , newAuth ) ;
114- }
115- catch ( LoginAttemptsExceededException e )
116- {
117- logger . Warning ( e , "Login LoginAttemptsExceededException: {0}" , e . Message ) ;
118-
119- await keychain . Clear ( host , false ) ;
120- return new LoginResultData ( LoginResultCodes . LockedOut , Localization . LockedOut , host ) ;
12184 }
122- catch ( ApiValidationException e )
85+ catch ( TwoFactorRequiredException e )
12386 {
124- logger . Warning ( e , "Login ApiValidationException: {0}" , e . Message ) ;
87+ LoginResultCodes result ;
88+ result = LoginResultCodes . CodeRequired ;
89+ logger . Trace ( "2FA TwoFactorAuthorizationException: {0} {1}" , LoginResultCodes . CodeRequired , e . Message ) ;
12590
126- var message = e . ApiError . FirstErrorMessageSafe ( ) ;
127- await keychain . Clear ( host , false ) ;
128- return new LoginResultData ( LoginResultCodes . Failed , message , host ) ;
91+ return new LoginResultData ( result , e . Message , host , password ) ;
12992 }
13093 catch ( Exception e )
13194 {
13295 logger . Warning ( e , "Login Exception" ) ;
13396
134- // Some enterprise instances don't support OAUTH, so fall back to using the
135- // supplied password - on instances that don't support OAUTH the user should
136- // be using a personal access token as the password.
137- if ( EnterpriseWorkaround ( host , e ) )
138- {
139- auth = new ApplicationAuthorization ( password ) ;
140- }
141- else
142- {
143- await keychain . Clear ( host , false ) ;
144- return new LoginResultData ( LoginResultCodes . Failed , Localization . LoginFailed , host ) ;
145- }
97+ await keychain . Clear ( host , false ) ;
98+ return new LoginResultData ( LoginResultCodes . Failed , Localization . LoginFailed , host ) ;
14699 }
147100
148- keychain . SetToken ( host , auth . Token ) ;
101+ keychain . SetToken ( host , token ) ;
149102 await keychain . Save ( host ) ;
150103
151104 return new LoginResultData ( LoginResultCodes . Success , "Success" , host ) ;
152105 }
153106
154107 public async Task < LoginResultData > ContinueLogin ( LoginResultData loginResultData , string twofacode )
155108 {
156- var newAuth = loginResultData . NewAuth ;
109+ var token = loginResultData . Token ;
157110 var host = loginResultData . Host ;
158111 var keychainAdapter = keychain . Connect ( host ) ;
159112 var username = keychainAdapter . Credential . Username ;
160113 var password = keychainAdapter . Credential . Token ;
161114 try
162115 {
163116 logger . Trace ( "2FA Continue" ) ;
164- var auth = await TryContinueLogin ( host , username , password , twofacode ) ;
165-
166- EnsureNonNullAuthorization ( auth ) ;
117+ token = await TryContinueLogin ( host , username , password , twofacode ) ;
167118
168- keychain . SetToken ( host , auth . Token ) ;
119+ if ( string . IsNullOrEmpty ( token ) )
120+ {
121+ throw new InvalidOperationException ( "Returned token is null or empty" ) ;
122+ }
123+
124+ keychain . SetToken ( host , token ) ;
169125 await keychain . Save ( host ) ;
170126
171127 return new LoginResultData ( LoginResultCodes . Success , "" , host ) ;
172128 }
173- catch ( TwoFactorAuthorizationException e )
174- {
175- logger . Trace ( e , "2FA TwoFactorAuthorizationException: {0} {1}" , LoginResultCodes . CodeFailed , e . Message ) ;
176-
177- return new LoginResultData ( LoginResultCodes . CodeFailed , Localization . Wrong2faCode , host , newAuth ) ;
178- }
179- catch ( ApiValidationException e )
180- {
181- logger . Trace ( e , "2FA ApiValidationException: {0}" , e . Message ) ;
182-
183- var message = e . ApiError . FirstErrorMessageSafe ( ) ;
184- await keychain . Clear ( host , false ) ;
185- return new LoginResultData ( LoginResultCodes . Failed , message , host ) ;
186- }
187129 catch ( Exception e )
188130 {
189131 logger . Trace ( e , "Exception: {0}" , e . Message ) ;
@@ -201,56 +143,12 @@ public async Task Logout(UriString hostAddress)
201143 await new ActionTask ( keychain . Clear ( hostAddress , true ) ) . StartAwait ( ) ;
202144 }
203145
204- private async Task < ApplicationAuthorization > CreateAndDeleteExistingApplicationAuthorization (
205- IGitHubClient client ,
206- NewAuthorization newAuth ,
207- string twoFactorAuthenticationCode )
208- {
209- ApplicationAuthorization result ;
210- var retry = 0 ;
211-
212- do
213- {
214- if ( twoFactorAuthenticationCode == null )
215- {
216-
217- result = await client . Authorization . GetOrCreateApplicationAuthentication (
218- clientId ,
219- clientSecret ,
220- newAuth ) ;
221- }
222- else
223- {
224- result = await client . Authorization . GetOrCreateApplicationAuthentication (
225- clientId ,
226- clientSecret ,
227- newAuth ,
228- twoFactorAuthenticationCode ) ;
229- }
230-
231- if ( result . Token == string . Empty )
232- {
233- if ( twoFactorAuthenticationCode == null )
234- {
235- await client . Authorization . Delete ( result . Id ) ;
236- }
237- else
238- {
239- await client . Authorization . Delete ( result . Id , twoFactorAuthenticationCode ) ;
240- }
241- }
242- } while ( result . Token == string . Empty && retry ++ == 0 ) ;
243-
244- return result ;
245- }
246-
247- private async Task < ApplicationAuthorization > TryLogin (
146+ private async Task < string > TryLogin (
248147 UriString host ,
249148 string username ,
250149 string password
251150 )
252151 {
253- ApplicationAuthorization auth ;
254152 var loginTask = new OctorunTask ( taskManager . Token , nodeJsExecutablePath , octorunScript ,
255153 "login" , ApplicationInfo . ClientId , ApplicationInfo . ClientSecret ) ;
256154 loginTask . Configure ( processManager , workingDirectory : octorunScript . Parent . Parent , withInput : true ) ;
@@ -270,15 +168,14 @@ string password
270168
271169 if ( ret [ 0 ] == "success" )
272170 {
273- auth = new ApplicationAuthorization ( ret [ 1 ] ) ;
274- return auth ;
171+ return ret [ 1 ] ;
275172 }
276173
277174 if ( ret [ 0 ] == "2fa" )
278175 {
279176 keychain . SetToken ( host , ret [ 1 ] ) ;
280177 await keychain . Save ( host ) ;
281- throw new TwoFactorRequiredException ( TwoFactorType . Unknown ) ;
178+ throw new TwoFactorRequiredException ( ) ;
282179 }
283180
284181 if ( ret . Count > 2 )
@@ -289,7 +186,7 @@ string password
289186 throw new Exception ( "Authentication failed" ) ;
290187 }
291188
292- private async Task < ApplicationAuthorization > TryContinueLogin (
189+ private async Task < string > TryContinueLogin (
293190 UriString host ,
294191 string username ,
295192 string password ,
@@ -298,7 +195,6 @@ string code
298195 {
299196 logger . Info ( "Continue Username:{0} {1} {2}" , username , password , code ) ;
300197
301- ApplicationAuthorization auth ;
302198 var loginTask = new OctorunTask ( taskManager . Token , nodeJsExecutablePath , octorunScript ,
303199 "login --twoFactor" , ApplicationInfo . ClientId , ApplicationInfo . ClientSecret ) ;
304200 loginTask . Configure ( processManager , workingDirectory : octorunScript . Parent . Parent , withInput : true ) ;
@@ -321,8 +217,7 @@ string code
321217
322218 if ( ret [ 0 ] == "success" )
323219 {
324- auth = new ApplicationAuthorization ( ret [ 1 ] ) ;
325- return auth ;
220+ return ret [ 1 ] ;
326221 }
327222
328223 if ( ret . Count > 2 )
@@ -332,47 +227,21 @@ string code
332227
333228 throw new Exception ( "Authentication failed" ) ;
334229 }
335-
336- ApplicationAuthorization EnsureNonNullAuthorization ( ApplicationAuthorization auth )
337- {
338- // If a mock IGitHubClient is not set up correctly, it can return null from
339- // IGitHubClient.Authorization.Create - this will cause an infinite loop in Login()
340- // so prevent that.
341- if ( auth == null )
342- {
343- throw new InvalidOperationException ( "IGitHubClient.Authorization.Create returned null." ) ;
344- }
345-
346- return auth ;
347- }
348-
349- bool EnterpriseWorkaround ( UriString hostAddress , Exception e )
350- {
351- // Older Enterprise hosts either don't have the API end-point to PUT an authorization, or they
352- // return 422 because they haven't white-listed our client ID. In that case, we just ignore
353- // the failure, using basic authentication (with username and password) instead of trying
354- // to get an authorization token.
355- var apiException = e as ApiException ;
356- return ! HostAddress . IsGitHubDotCom ( hostAddress ) &&
357- ( e is NotFoundException ||
358- e is ForbiddenException ||
359- apiException ? . StatusCode == ( HttpStatusCode ) 422 ) ;
360- }
361230 }
362231
363232 class LoginResultData
364233 {
365234 public LoginResultCodes Code ;
366235 public string Message ;
367- internal NewAuthorization NewAuth { get ; set ; }
236+ internal string Token { get ; set ; }
368237 internal UriString Host { get ; set ; }
369238
370239 internal LoginResultData ( LoginResultCodes code , string message ,
371- UriString host , NewAuthorization newAuth )
240+ UriString host , string token )
372241 {
373242 this . Code = code ;
374243 this . Message = message ;
375- this . NewAuth = newAuth ;
244+ this . Token = token ;
376245 this . Host = host ;
377246 }
378247
@@ -382,4 +251,8 @@ internal LoginResultData(LoginResultCodes code, string message, UriString host)
382251 }
383252 }
384253
254+ class TwoFactorRequiredException : Exception
255+ {
256+
257+ }
385258}
0 commit comments