public async Task DeleteTapAsync(string userPrincipalName, string id) { _logger.LogInformation($"Deleting tap for {userPrincipalName}"); var accessToken = await _tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default"); var request = new HttpRequestMessage(HttpMethod.Delete, $"users/{userPrincipalName}/authentication/temporaryAccessPassMethods/{id}"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); _logger.LogInformation("Sending request"); HttpResponseMessage response = await _httpClient.SendAsync(request); _logger.LogInformation("Response received"); await _logger.LogHttpResponseAsync(response); if (!response.IsSuccessStatusCode) { _logger.LogError($"Error occurred while deleting TAP"); _logger.LogError($"Status code is {response.StatusCode}"); _logger.LogError($"Reason phrase is {response.ReasonPhrase}"); } response.EnsureSuccessStatusCode(); }
public async Task <IActionResult> CreateAppOnly() { string clientState = Guid.NewGuid().ToString(); // Initialize the GraphServiceClient var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(appSettings.Value.BaseUrlWithoutVersion, async() => { return(await tokenAcquisition.GetAccessTokenForAppAsync($"{appSettings.Value.BaseUrlWithoutVersion}/.default")); }); try { // Create a subscription. var newSubscription = await CreateSubscription(string.Empty, string.Empty, clientState, graphClient).ConfigureAwait(false); return(View("Subscription", newSubscription)); } catch (Exception e) { // If a tenant admin hasn't granted consent, this operation returns an Unauthorized error. // This sample caches the initial unauthorized token, so you'll need to start a new browser session. ViewBag.Message = BuildErrorMessage(e); return(View("Error")); } }
/// <summary> /// Adds an authorization header to an HttpRequestMessage. /// </summary> /// <param name="request">HttpRequest message to authenticate.</param> /// <returns>A Task (as this is an async method).</returns> public async Task AuthenticateRequestAsync(HttpRequestMessage request) { // Default options to settings provided during intialization var scopes = _initialOptions.Scopes; bool appOnly = _initialOptions.AppOnly ?? false; string?tenant = _initialOptions.Tenant ?? null; // Extract per-request options from the request if present TokenAcquisitionAuthenticationProviderOption?msalAuthProviderOption = GetMsalAuthProviderOption(request); if (msalAuthProviderOption != null) { scopes = msalAuthProviderOption.Scopes ?? scopes; appOnly = msalAuthProviderOption.AppOnly ?? appOnly; tenant = msalAuthProviderOption.Tenant ?? tenant; } if (!appOnly && scopes == null) { throw new InvalidOperationException(IDWebErrorMessage.ScopesRequiredToCallMicrosoftGraph); } string token; if (appOnly) { token = await _tokenAcquisition.GetAccessTokenForAppAsync(Constants.DefaultGraphScope, tenant).ConfigureAwait(false); } else { token = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes !).ConfigureAwait(false); } request.Headers.Authorization = new AuthenticationHeaderValue(Constants.Bearer, token); }
/// <inheritdoc/> public async Task <HttpResponseMessage> CallWebApiForAppAsync( string optionsInstanceName, Action <DownstreamWebApiOptions>?downstreamApiOptionsOverride = null, StringContent?requestContent = null) { DownstreamWebApiOptions effectiveOptions = MergeOptions(optionsInstanceName, downstreamApiOptionsOverride); if (effectiveOptions.Scopes == null) { throw new ArgumentException(IDWebErrorMessage.ScopesNotConfiguredInConfigurationOrViaDelegate); } string accessToken = await _tokenAcquisition.GetAccessTokenForAppAsync( effectiveOptions.Scopes, effectiveOptions.Tenant) .ConfigureAwait(false); HttpResponseMessage response; using (HttpRequestMessage httpRequestMessage = new HttpRequestMessage( effectiveOptions.HttpMethod, effectiveOptions.GetApiUrl())) { httpRequestMessage.Headers.Add( Constants.Authorization, string.Format( CultureInfo.InvariantCulture, "{0} {1}", Constants.Bearer, accessToken)); response = await _httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false); } return(response); }
public async Task <ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { //transform can run more than once. //the service is scoped, so setting and testing the Principal property allows short-circuiting if (ScopePrincipal != null) { return(ScopePrincipal); } ScopePrincipal = principal; //if there is no oid, then principal didn't come from AzureAD / OpenIdConnect if (principal.GetObjectId() == null) { return(principal); } var claimsIdentity = principal.Identities.First(); //mark principal with claim for this transform claimsIdentity.AddClaim(new Claim("transform", GetType()?.FullName ?? "AzureGroupsClaimsTransform")); var claimsCacheResult = await Cache.GetGroupClaimsAsync(principal); var groupNames = claimsCacheResult.Value; if (!claimsCacheResult.Success) { var accessToken = await TokenAcquisition.GetAccessTokenForAppAsync(Options.GraphEndpoint, authenticationScheme : Options.Scheme); try { groupNames = (await GraphService.GroupsAsync(principal, accessToken))?.Select(x => x.DisplayName); } catch (Exception e) { var requestId = Activity.Current?.Id ?? "<null>"; Logger.LogCritical(e, "AzureGroupsClaimsTransform exception from RequestId: {requestId}.", requestId); claimsIdentity.AddClaim(new Claim("transform-error", e.Message)); claimsIdentity.AddClaim(new Claim("transform-error-request-id", requestId)); return(principal); } if (groupNames != null) { await Cache.SetGroupClaimsAsync(principal, groupNames, Options.DistributedCacheEntryOptions); } } foreach (var group in groupNames !) { claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, group, ClaimValueTypes.String, "AzureAD")); } return(principal); }
// Get information about the changed messages and send to browser via SignalR. // A production application would typically queue a background job for reliability. private async Task GetChangedMessagesAsync(IEnumerable <ChangeNotification> notifications) { List <NotificationViewModel> notificationsToDisplay = new List <NotificationViewModel>(); foreach (var notification in notifications) { SubscriptionStore subscription = subscriptionStore.GetSubscriptionInfo(notification.SubscriptionId.Value); // Set the claims for ObjectIdentifier and TenantId, and // use the above claims for the current HttpContext if (!string.IsNullOrEmpty(subscription.UserId)) { HttpContext.User = ClaimsPrincipalFactory.FromTenantIdAndObjectId(subscription.TenantId, subscription.UserId); } if (notification.Resource.Contains("/message", StringComparison.InvariantCultureIgnoreCase)) { // Initialize the GraphServiceClient. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(appSettings.Value.BaseUrlWithoutVersion, async() => { return(await tokenAcquisition.GetAccessTokenForAppAsync($"{appSettings.Value.BaseUrlWithoutVersion}/.default")); }); var request = new MessageRequest(graphServiceClient.BaseUrl + "/" + notification.Resource, string.IsNullOrEmpty(subscription.UserId) ? graphClient : graphServiceClient, null); try { var responseValue = await request.GetAsync(); notificationsToDisplay.Add(new NotificationViewModel(new { From = responseValue?.From?.EmailAddress?.Address, responseValue?.Subject, SentDateTime = responseValue?.SentDateTime.HasValue ?? false ? responseValue?.SentDateTime.Value.ToString() : string.Empty, To = responseValue?.ToRecipients?.Select(x => x.EmailAddress.Address)?.ToList(), })); } catch (ServiceException se) { string errorMessage = se.Error.Message; string requestId = se.Error.InnerError?.AdditionalData["request-id"]?.ToString(); string requestDate = se.Error.InnerError?.AdditionalData["date"]?.ToString(); logger.LogError($"RetrievingMessages: { errorMessage } Request ID: { requestId } Date: { requestDate }"); } } else { notificationsToDisplay.Add(new NotificationViewModel(notification.Resource)); } } if (notificationsToDisplay.Count > 0) { await notificationService.SendNotificationToClient(notificationHub, notificationsToDisplay); } }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); var(authenticationStatus, authenticationResponse) = await req.HttpContext.AuthenticateAzureFunctionAsync(); if (!authenticationStatus) { return(authenticationResponse); } var token = await _tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default"); string name = req.HttpContext.User.Identity.IsAuthenticated ? req.HttpContext.User.Identity.Name : null; string responseMessage = string.IsNullOrEmpty(name) ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." : $"Hello, {name}. This HTTP triggered function executed successfully."; return(new OkObjectResult(responseMessage)); }
// Gets a Graph client configured with // the specified scopes protected GraphServiceClient GetGraphClientForScopes(string[] scopes) { return(GraphServiceClientFactory .GetAuthenticatedGraphClient(async() => { //https://github.com/AzureAD/microsoft-identity-web/wiki/daemon-scenarios //var token = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes); var token = await _tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default", <tenantid>); // Uncomment to print access token to debug console // This will happen for every Graph call, so leave this // out unless you're debugging your token //_logger.LogInformation($"Access token: {token}"); return token; } )); }
public async Task <IEnumerable <string> > GetApiDataAsync() { var client = _clientFactory.CreateClient(); var scope = "api://b178f3a5-7588-492a-924f-72d7887b7e48/.default"; // CC flow access_as_application"; var accessToken = await _tokenAcquisition.GetAccessTokenForAppAsync(scope); client.BaseAddress = new Uri("https://localhost:44324"); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var response = await client.GetAsync("ApiForServiceData"); if (response.IsSuccessStatusCode) { var data = await JsonSerializer.DeserializeAsync <List <string> >( await response.Content.ReadAsStreamAsync()); return(data); } throw new Exception("oh no..."); }
public async Task <string> GetTokenForAppAsync() { return(await _tokenAcquisition.GetAccessTokenForAppAsync( TestConstants.s_scopeForApp).ConfigureAwait(false)); }
protected async Task <T> PerformRequest <T>(string url, HttpMethod method, HttpContent content = null, bool needsAuth = true, Dictionary <string, string> additionalHeaders = null, CancellationToken cancellationToken = default) { if (needsAuth) { var token = _apiTokenType == ApiTokenType.App ? await _tokenAcquisition.GetAccessTokenForAppAsync(_scope) : await _tokenAcquisition.GetAccessTokenForUserAsync(scopes : new List <string>() { _scope }); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); } if (additionalHeaders != null) { foreach (var curHeader in additionalHeaders) { _httpClient.DefaultRequestHeaders.Add(curHeader.Key, curHeader.Value); } } HttpResponseMessage responseMessage = null; if (method == HttpMethod.Get) { responseMessage = await _httpClient.GetAsync(url, cancellationToken); } else if (method == HttpMethod.Post) { responseMessage = await _httpClient.PostAsync(url, content, cancellationToken); } else if (method == HttpMethod.Put) { responseMessage = await _httpClient.PutAsync(url, content, cancellationToken); } else if (method == HttpMethod.Patch) { responseMessage = await _httpClient.PatchAsync(url, content, cancellationToken); } else if (method == HttpMethod.Delete) { responseMessage = await _httpClient.DeleteAsync(url, cancellationToken); } if (responseMessage.IsSuccessStatusCode) { var responseText = await responseMessage.Content.ReadAsStringAsync(); var deserializedResponse = JsonSerializerUtil.Deserialize <T>(responseText); return(deserializedResponse); } else { var errorMessageBuilder = new StringBuilder(); errorMessageBuilder.Append($"{this.GetType()}: Response for {method} against the url {url} failed with status code {responseMessage.StatusCode}"); if (!String.IsNullOrWhiteSpace(responseMessage.ReasonPhrase)) { errorMessageBuilder.Append($", reason: {responseMessage.ReasonPhrase}"); } var responseString = await responseMessage.Content.ReadAsStringAsync(); if (!String.IsNullOrWhiteSpace(responseString)) { errorMessageBuilder.Append($", response content: {responseString}"); } throw new Exception(errorMessageBuilder.ToString()); } }
public async Task <IActionResult> Index() { var model = new HomeViewModel(); _logger.LogInformation($"{model.CorrelationId}: Home.Index starting"); var email = User.FindFirst("preferred_username").Value; model.Email = email; _logger.LogInformation($"{model.CorrelationId}: {email}"); var tid = User.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value; model.Tid = tid; if (tid == _invitationOptions.Value.HostTenantId) { _logger.LogInformation($"{model.CorrelationId}: Current memeber: {tid}"); model.RedirectUrl = _invitationOptions.Value.RedirectUrl; model.Message = "You are already a member of this domain"; return(View(model)); } if (!_invitationOptions.Value.TenantToGroupMapping.Keys.Contains(tid)) { _logger.LogError($"{model.CorrelationId}: Unauthorized: {tid}"); model.Message = $"Unauthorized."; return(View(model)); } _logger.LogInformation($"{model.CorrelationId}: Acquiring token"); var token = await _tokenAcquisition.GetAccessTokenForAppAsync( scope : "https://graph.microsoft.com/.default", tenant : _invitationOptions.Value.HostTenantName); var http = new HttpClient(); http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); _logger.LogInformation($"{model.CorrelationId}: Token acquired: {token.Split('.')[0]}.{token.Split('.')[1]}.signature"); var invitation = new { invitedUserEmailAddress = email, inviteRedirectUrl = _invitationOptions.Value.RedirectUrl, invitedUserDisplayName = User.FindFirst("name")?.Value, }; var request = new HttpRequestMessage(HttpMethod.Post, "https://graph.microsoft.com/v1.0/invitations") { Content = new StringContent(JsonSerializer.Serialize(invitation), Encoding.UTF8, "application/json") }; var resp = await http.SendAsync(request); var newId = String.Empty; if (!resp.IsSuccessStatusCode) { var err = await resp.Content.ReadAsStringAsync(); if (err.Contains("The invited user already exists in the directory")) { var msg = JsonDocument.Parse(err).RootElement.GetProperty("error").GetProperty("message").GetString(); _logger.LogWarning($"{model.CorrelationId}: {msg}"); newId = msg.Split(": ")[1].Split('.')[0]; } else { _logger.LogError($"{model.CorrelationId}: Failed to process invitation. {err}"); model.Message = "Invitation failed."; return(View(model)); } } else { _logger.LogInformation($"{model.CorrelationId}:User {email} successfully invited"); var json = await resp.Content.ReadAsStringAsync(); newId = JsonDocument.Parse(json).RootElement.GetProperty("invitedUser").GetProperty("id").GetString(); } request = new HttpRequestMessage(HttpMethod.Post, $"https://graph.microsoft.com/v1.0/groups/{_invitationOptions.Value.TenantToGroupMapping[tid]}/members/$ref") { Content = new StringContent( $"{{\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/{newId}\"}}", Encoding.UTF8, "application/json") }; resp = await http.SendAsync(request); if (resp.IsSuccessStatusCode) { _logger.LogInformation($"User {email} added to group"); } else if (resp.StatusCode == System.Net.HttpStatusCode.BadRequest) { var json = await resp.Content.ReadAsStringAsync(); var msg = JsonDocument.Parse(json).RootElement.GetProperty("error").GetProperty("message").GetString(); if (msg.StartsWith("One or more added object references already exist")) { _logger.LogInformation($"{model.CorrelationId}: User {email} already exists as member of the group"); } else { _logger.LogError($"{model.CorrelationId}: Unusual bad request error when adding {email} to the security group. {msg}"); model.Message = "Error adding to security group."; return(View(model)); } } else { var err = await resp.Content.ReadAsStringAsync(); _logger.LogError($"{model.CorrelationId}: Failed to add {email} to the security group. {err}"); model.Message = "Unexpected error occurred."; return(View(model)); } model.RedirectUrl = _invitationOptions.Value.RedirectUrl; _logger.LogInformation($"{model.CorrelationId}: Home.Index exiting"); return(View(model)); }