/// <summary> /// Generates a "personal access token" or service specific, usage restricted access token. /// <para/> /// Returns a "personal access token" for the user if successful; otherwise `<see langword="null"/>`. /// </summary> /// <param name="targetUri">The target resource for which to acquire the personal access token for.</param> /// <param name="accessToken">Azure Directory access token with privileges to grant access to the target resource.</param> /// <param name="options">Set of options related to generation of personal access tokens.</param> protected async Task <Credential> GeneratePersonalAccessToken( TargetUri targetUri, Token accessToken, PersonalAccessTokenOptions options) { if (targetUri is null) { throw new ArgumentNullException(nameof(targetUri)); } if (accessToken is null) { throw new ArgumentNullException(nameof(accessToken)); } TokenScope requestedScope = TokenScope; if (options.TokenScope != null) { // Take the intersection of the authority scope and the requested scope requestedScope &= options.TokenScope; // If the result of the intersection is none, then fail if (string.IsNullOrWhiteSpace(requestedScope.Value)) { throw new InvalidOperationException("Invalid scope requested. Requested scope would result in no access privileges."); } } Credential credential = null; Token personalAccessToken; if ((personalAccessToken = await Authority.GeneratePersonalAccessToken(targetUri, accessToken, requestedScope, options.RequireCompactToken, options.TokenDuration)) != null) { credential = (Credential)personalAccessToken; Trace.WriteLine($"personal access token created for '{targetUri}'."); try { await PersonalAccessTokenStore.WriteCredentials(targetUri, credential); } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception); Trace.WriteLine($"failed to write credentials to the secure store: {exception.GetType().Name}."); } } return(credential); }
/// <summary> /// Creates an interactive logon session, using ADAL secure browser GUI, which enables users to authenticate with the Azure tenant and acquire the necessary access tokens to exchange for a VSTS personal access token. /// <para/> /// Tokens acquired are stored in the secure secret stores provided during initialization. /// <para/> /// Return a `<see cref="Credential"/>` for resource access if successful; otherwise `<see langword="null"/>`. /// </summary> /// <param name="targetUri">The URI of the VSTS resource.</param> public async Task <Credential> InteractiveLogon(TargetUri targetUri, PersonalAccessTokenOptions options) { BaseSecureStore.ValidateTargetUri(targetUri); try { Token token; if ((token = await Authority.InteractiveAcquireToken(targetUri, ClientId, Resource, new Uri(RedirectUrl), null)) != null) { Trace.WriteLine($"token acquisition for '{targetUri}' succeeded."); return(await GeneratePersonalAccessToken(targetUri, token, options)); } } catch (AuthenticationException) { Trace.WriteLine($"token acquisition for '{targetUri}' failed."); } Trace.WriteLine($"interactive logon for '{targetUri}' failed"); return(null); }
/// <summary> /// Opens an interactive logon prompt to acquire an authentication token from the Microsoft Live authentication and identity service. /// <para/> /// Returns a `<see cref="Credential"/>` for packing into a basic authentication header; otherwise `<see langword="null"/>`. /// </summary> /// <param name="targetUri"> /// The uniform resource indicator of the resource access tokens are being requested for. /// </param> /// <param name="options"></param> public async Task <Credential> InteractiveLogon(TargetUri targetUri, PersonalAccessTokenOptions options) { BaseSecureStore.ValidateTargetUri(targetUri); try { Token token; if ((token = await Authority.InteractiveAcquireToken(targetUri, ClientId, Resource, new Uri(RedirectUrl), QueryParameters)) != null) { Trace.WriteLine($"token '{targetUri}' successfully acquired."); return(await GeneratePersonalAccessToken(targetUri, token, options)); } } catch (AdalException exception) { Debug.Write(exception); } Trace.WriteLine($"failed to acquire token for '{targetUri}'."); return(null); }
public static async Task <Credential> QueryCredentials(Program program, OperationArguments operationArguments) { if (program is null) { throw new ArgumentNullException(nameof(program)); } if (operationArguments is null) { throw new ArgumentNullException(nameof(operationArguments)); } if (operationArguments.TargetUri is null) { var innerException = new NullReferenceException($"{operationArguments.TargetUri} cannot be null."); throw new ArgumentException(innerException.Message, nameof(operationArguments), innerException); } BaseAuthentication authentication = await program.CreateAuthentication(operationArguments); Credential credentials = null; switch (operationArguments.Authority) { default: case AuthorityType.Basic: { var basicAuth = authentication as BasicAuthentication; // Attempt to get cached credentials or acquire credentials if interactivity is allowed. if ((operationArguments.Interactivity != Interactivity.Always && (credentials = await authentication.GetCredentials(operationArguments.TargetUri)) != null) || (operationArguments.Interactivity != Interactivity.Never && (credentials = await basicAuth.AcquireCredentials(operationArguments.TargetUri)) != null)) { program.Trace.WriteLine("credentials found."); // No need to save the credentials explicitly, as Git will call back // with a store command if the credentials are valid. } else { program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); program.LogEvent($"Failed to retrieve credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } } break; case AuthorityType.AzureDirectory: { var aadAuth = authentication as Vsts.AadAuthentication; var patOptions = new Vsts.PersonalAccessTokenOptions() { RequireCompactToken = true, TokenDuration = operationArguments.TokenDuration, TokenScope = null, }; // Attempt to get cached credentials -> non-interactive logon -> interactive // logon note that AAD "credentials" are always scoped access tokens. if (((operationArguments.Interactivity != Interactivity.Always && ((credentials = await aadAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) || (operationArguments.Interactivity != Interactivity.Always && ((credentials = await aadAuth.NoninteractiveLogon(operationArguments.TargetUri, patOptions)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await aadAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); program.LogEvent($"Azure Directory credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); program.LogEvent($"Failed to retrieve Azure Directory credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } } break; case AuthorityType.MicrosoftAccount: { var msaAuth = authentication as Vsts.MsaAuthentication; var patOptions = new Vsts.PersonalAccessTokenOptions() { RequireCompactToken = true, TokenDuration = operationArguments.TokenDuration, TokenScope = null, }; // Attempt to get cached credentials -> interactive logon note that MSA // "credentials" are always scoped access tokens. if (((operationArguments.Interactivity != Interactivity.Always && ((credentials = await msaAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await msaAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null) && (!operationArguments.ValidateCredentials || await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); program.LogEvent($"Microsoft Live credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); program.LogEvent($"Failed to retrieve Microsoft Live credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } } break; case AuthorityType.GitHub: { var ghAuth = authentication as Github.Authentication; if ((operationArguments.Interactivity != Interactivity.Always && ((credentials = await ghAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await ghAuth.InteractiveLogon(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); program.LogEvent($"GitHub credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); program.LogEvent($"Failed to retrieve GitHub credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } } break; case AuthorityType.Bitbucket: { var bbcAuth = authentication as Bitbucket.Authentication; if (((operationArguments.Interactivity != Interactivity.Always) && ((credentials = await bbcAuth.GetCredentials(operationArguments.TargetUri, operationArguments.Username)) != null) && (!operationArguments.ValidateCredentials || ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.Username, credentials)) != null))) || ((operationArguments.Interactivity != Interactivity.Never) && ((credentials = await bbcAuth.InteractiveLogon(operationArguments.TargetUri, operationArguments.Username)) != null) && (!operationArguments.ValidateCredentials || ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.Username, credentials)) != null)))) { program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); // Bitbucket relies on a username + secret, so make sure there is a // username to return. if (operationArguments.Username != null) { credentials = new Credential(operationArguments.Username, credentials.Password); } program.LogEvent($"Bitbucket credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { program.LogEvent($"Failed to retrieve Bitbucket credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } } break; case AuthorityType.Ntlm: { program.Trace.WriteLine($"'{operationArguments.TargetUri}' is NTLM."); credentials = BasicAuthentication.NtlmCredentials; } break; } if (credentials != null) { operationArguments.Credentials = credentials; } return(credentials); }