private StringContent GetAccessTokenRequestBody(TargetUri targetUri, TokenScope tokenScope, TimeSpan?duration = null) { const string ContentBasicJsonFormat = "{{ \"scope\" : \"{0}\", \"displayName\" : \"Git: {1} on {2}\" }}"; const string ContentTimedJsonFormat = "{{ \"scope\" : \"{0}\", \"displayName\" : \"Git: {1} on {2}\", \"validTo\": \"{3:u}\" }}"; const string HttpJsonContentType = "application/json"; if (targetUri is null) { throw new ArgumentNullException(nameof(targetUri)); } if (tokenScope is null) { throw new ArgumentNullException(nameof(tokenScope)); } string tokenUrl = GetTargetUrl(targetUri, false); Trace.WriteLine($"creating access token scoped to '{tokenScope}' for '{tokenUrl}'"); string jsonContent = (duration.HasValue && duration.Value > TimeSpan.FromHours(1)) ? string.Format(Culture.InvariantCulture, ContentTimedJsonFormat, tokenScope, tokenUrl, Settings.MachineName, DateTime.UtcNow + duration.Value) : string.Format(Culture.InvariantCulture, ContentBasicJsonFormat, tokenScope, tokenUrl, Settings.MachineName); var content = new StringContent(jsonContent, Encoding.UTF8, HttpJsonContentType); return(content); }
public MsaAuthentication( RuntimeContext context, TokenScope tokenScope, ICredentialStore personalAccessTokenStore) : base(context, tokenScope, personalAccessTokenStore) { Authority = new Authority(context, AzureDevOps.Authentication.Authority.DefaultAuthorityHostUrl); }
/// <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 a new authentication broker based for the specified resource. /// <para/> /// Returns `<see langword="true"/>` if an authority could be determined; otherwise `<see langword="false"/>`. /// </summary> /// <param name="targetUri">The resource for which authentication is being requested.</param> /// <param name="scope">The scope of the access being requested.</param> /// <param name="personalAccessTokenStore">Storage container for personal access token secrets.</param> public static async Task <BaseAuthentication> GetAuthentication( RuntimeContext context, TargetUri targetUri, TokenScope scope, ICredentialStore personalAccessTokenStore) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (targetUri is null) { throw new ArgumentNullException(nameof(targetUri)); } if (scope is null) { throw new ArgumentNullException(nameof(scope)); } if (personalAccessTokenStore is null) { throw new ArgumentNullException(nameof(personalAccessTokenStore)); } Guid?result = await DetectAuthority(context, targetUri); if (!result.HasValue) { return(null); } // Query for the tenant's identity Guid tenantId = result.Value; BaseAuthentication authentication = null; // empty identity is MSA, anything else is AAD if (tenantId == Guid.Empty) { context.Trace.WriteLine("MSA authority detected."); authentication = new MsaAuthentication(context, scope, personalAccessTokenStore); } else { context.Trace.WriteLine($"AAD authority for tenant '{tenantId.ToString("N")}' detected."); authentication = new AadAuthentication(context, tenantId, scope, personalAccessTokenStore); (authentication as AadAuthentication).TenantId = tenantId; } return(authentication); }
/// <summary> /// Creates a new instance of `<see cref="AadAuthentication"/>`. /// </summary> /// <param name="tenantId"> /// URI of the responsible Azure tenant. /// <para/> /// Use `<see cref="Authentication.GetAuthentication"/>` to detect the tenant identity and create the authentication object. /// </param> /// <param name="tokenScope">The scope of all access tokens acquired by the authority.</param> /// <param name="personalAccessTokenStore">The secure secret store for storing any personal access tokens acquired.</param> /// <param name="adaRefreshTokenStore">The secure secret store for storing any Azure tokens acquired.</param> public AadAuthentication( RuntimeContext context, Guid tenantId, TokenScope tokenScope, ICredentialStore personalAccessTokenStore) : base(context, tokenScope, personalAccessTokenStore) { if (tenantId == Guid.Empty) { Authority = new Authority(context, AzureDevOps.Authentication.Authority.DefaultAuthorityHostUrl); } else { // Create an authority host URL in the format of https://login.microsoft.com/12345678-9ABC-DEF0-1234-56789ABCDEF0. string authorityHost = AzureDevOps.Authentication.Authority.GetAuthorityUrl(tenantId); Authority = new Authority(context, authorityHost); } }
protected Authentication( RuntimeContext context, TokenScope tokenScope, ICredentialStore personalAccessTokenStore) : base(context) { if (tokenScope is null) { throw new ArgumentNullException(nameof(tokenScope)); } if (personalAccessTokenStore is null) { throw new ArgumentNullException(nameof(personalAccessTokenStore)); } ClientId = DefaultClientId; Resource = DefaultResource; TokenScope = tokenScope; PersonalAccessTokenStore = personalAccessTokenStore; Authority = new Authority(context); }
public static bool Find(string value, out TokenScope devopsScope) { devopsScope = EnumerateValues().FirstOrDefault(v => StringComparer.OrdinalIgnoreCase.Equals(v.Value, value)); return(devopsScope != null); }
public bool Equals(TokenScope other) => Microsoft.Alm.Authentication.TokenScope.Equals(this as Microsoft.Alm.Authentication.TokenScope, other as Microsoft.Alm.Authentication.TokenScope);
public async Task <Token> GeneratePersonalAccessToken(TargetUri targetUri, Token authorization, TokenScope tokenScope, bool requireCompactToken, TimeSpan?tokenDuration) { if (targetUri is null) { throw new ArgumentNullException(nameof(targetUri)); } if (authorization is null) { throw new ArgumentNullException(nameof(authorization)); } if (tokenScope is null) { throw new ArgumentNullException(nameof(tokenScope)); } try { var requestUri = await CreatePersonalAccessTokenRequestUri(targetUri, authorization, requireCompactToken); var options = new NetworkRequestOptions(true) { Authorization = authorization, }; using (StringContent content = GetAccessTokenRequestBody(targetUri, tokenScope, tokenDuration)) using (var response = await Network.HttpPostAsync(requestUri, content, options)) { if (response.IsSuccessStatusCode) { string responseText = response.Content.AsString; if (!string.IsNullOrWhiteSpace(responseText)) { // Find the 'token : <value>' portion of the result content, if any. Match tokenMatch = null; if ((tokenMatch = Regex.Match(responseText, @"\s*""token""\s*:\s*""([^\""]+)""\s*", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)).Success) { string tokenValue = tokenMatch.Groups[1].Value; Token token = new Token(tokenValue, TokenType.Personal); Trace.WriteLine($"personal access token acquisition for '{targetUri}' succeeded."); return(token); } } } Trace.WriteLine($"failed to acquire personal access token for '{targetUri}' [{(int)response.StatusCode}]."); } } catch (Exception exception) { Trace.WriteException(exception); } Trace.WriteLine($"personal access token acquisition for '{targetUri}' failed."); return(null); }
public Task <Token> GeneratePersonalAccessToken(TargetUri targetUri, Token authorization, TokenScope tokenScope, bool requireCompactToken) => GeneratePersonalAccessToken(targetUri, authorization, tokenScope, requireCompactToken, null);