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);
        }
Esempio n. 5
0
        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);
            }
        }
Esempio n. 7
0
        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));
        }
Esempio n. 8
0
        // 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));
 }
Esempio n. 11
0
        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());
            }
        }
Esempio n. 12
0
        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));
        }