コード例 #1
0
        /// <summary>
        /// Performs the app launch flow for the current request
        /// </summary>
        /// <param name="args">An <see cref="AppLauncherFunctionArgs"/> instance specifying the location of the client configuration in Azure storage.</param>
        /// <returns>If launch succeeds the response is a 302 redirect back to the SharePoint site's home page.</returns>
        public HttpResponseMessage Execute(AppLauncherFunctionArgs args)
        {
            try
            {
                _clientClientConfiguration = GetConfiguration(ClientId, args.StorageAccount, args.StorageAccountKey);
                var spContextToken = TokenHelper.ReadAndValidateContextToken(ContextToken, _requestAuthority, ClientId,
                                                                             _clientClientConfiguration.AcsClientConfig.ClientSecret);
                var spHostUri = new Uri(SPWebUrl);

                var accessToken = TokenHelper.GetACSAccessTokens(spContextToken, spHostUri.Authority,
                                                                 _clientClientConfiguration.ClientId,
                                                                 _clientClientConfiguration.AcsClientConfig.ClientSecret);


                var ctx = ConnectToSPWeb(accessToken);

                var securityTokens = new SecurityTokens()
                {
                    ClientId           = ClientId,
                    AccessToken        = accessToken.AccessToken,
                    AccessTokenExpires = accessToken.ExpiresOn,
                    AppWebUrl          = SPWebUrl,
                    Realm        = spContextToken.Realm,
                    RefreshToken = spContextToken.RefreshToken
                };

                var encodedCacheKey = TokenHelper.Base64UrlEncode(spContextToken.CacheKey);
                Log($"Storing tokens for {ClientId}/{encodedCacheKey}");
                StoreSecurityTokens(securityTokens, encodedCacheKey, args.StorageAccount, args.StorageAccountKey);

                Log($"Ensuring web properties for {ctx.Web.Url}");
                EnsureBaseConfiguration(encodedCacheKey);

                Log($"Sending app launch event for {ctx.Web.Url}");
                SendQueueMessage(new QueuedAppLaunchEvent()
                {
                    ClientId        = ClientId,
                    AppWebUrl       = ctx.Web.Url,
                    UserAccessToken = securityTokens.AccessToken,
                    AppAccessToken  = GetACSAccessTokens(ClientId, encodedCacheKey, true),
                    RetryCount      = 5
                });

                _response.StatusCode = HttpStatusCode.Moved;
                // TODO: add Doug worthy validation on SPHostUrl, whatever that means
                _response.Headers.Location = new Uri($"{ctx.Web.Url}?cId={ClientId}&cKey={encodedCacheKey}&SPHostUrl={_queryParams["SPHostUrl"]}");

                return(_response);
            }
            catch (Exception ex)
            {
                _response.StatusCode = HttpStatusCode.OK;
                _response.Content    = new StringContent(GetErrorPage(ex.ToString()));
                _response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
                return(_response);
            }
        }
コード例 #2
0
        /// <summary>
        /// Processes the received event and sends the result to the client's service bus queue.
        ///
        /// SharePoint's remote event notification lacks the current item state for ItemDeleting and ItemUpdating events.
        /// For these event types, it attempts to fetch the current (unchanged) item and populate the ItemBeforeProperties. It is possible for the attempt to fail if the item is already deleted. If the attempt fails, the event is forwarded with the available information.
        /// </summary>
        /// <param name="args">An <see cref="EventDispatchFunctionArgs"/> instance specifying the location of the client configuration in Azure storage.</param>
        /// <remarks>The event is ignored if it is the result of an action taken by an app only identity</remarks>
        /// <returns>HttpStatusCode.OK if all is well or 500.</returns>
        public HttpResponseMessage Execute(EventDispatchFunctionArgs args)
        {
            try
            {
                _response.StatusCode = HttpStatusCode.OK;

                //Ignore the event if it is the result of an action taken by an app only identity
                if (_eventInfo.EventProperties.ContainsKey("UserLoginName") && _eventInfo.EventProperties["UserLoginName"].Contains(AppOnlyPrincipalId))
                {
                    Log("Event source is an app not a user. Ignoring");
                    return(_response);
                }

                var clientId = GetClientId();

                if (clientId == null)
                {
                    Log("Request has no client ID. Ignoring");
                    return(_response);
                }

                //Connect to the SharePoint site and get access tokens
                try
                {
                    _clientConfiguration = GetConfiguration(clientId, args.StorageAccount, args.StorageAccountKey);
                }
                catch
                {
                    Log("Failed to get client configuration");
                    Log($"Client Id is {clientId}");
                    Log(args.StorageAccount);
                    Log(args.StorageAccountKey);
                    throw;
                }

                var spContextToken = TokenHelper.ReadAndValidateContextToken(ContextToken, _requestAuthority, clientId,
                                                                             _clientConfiguration.AcsClientConfig.ClientSecret);
                var encodedCacheKey = TokenHelper.Base64UrlEncode(spContextToken.CacheKey);
                var spHostUri       = new Uri(SPWebUrl);

                var accessToken = TokenHelper.GetACSAccessTokens(spContextToken, spHostUri.Authority,
                                                                 _clientConfiguration.ClientId,
                                                                 _clientConfiguration.AcsClientConfig.ClientSecret);

                var ctx = ConnectToSPWeb(accessToken);

                var securityTokens = new SecurityTokens()
                {
                    ClientId           = clientId,
                    AccessToken        = accessToken.AccessToken,
                    AccessTokenExpires = accessToken.ExpiresOn,
                    AppWebUrl          = SPWebUrl,
                    Realm        = spContextToken.Realm,
                    RefreshToken = spContextToken.RefreshToken
                };

                Log($"Storing tokens for {clientId}/{encodedCacheKey}");
                StoreSecurityTokens(securityTokens, encodedCacheKey, args.StorageAccount, args.StorageAccountKey);

                //Create the event message to send to the client's service bus queue
                var eventMessage = new QueuedSharePointProcessEvent()
                {
                    SharePointRemoteEventAdapter = _eventInfo,
                    ClientId        = _clientConfiguration.ClientId,
                    AppWebUrl       = SPWebUrl,
                    UserAccessToken = accessToken.AccessToken,
                    AppAccessToken  = GetACSAccessTokens(clientId, encodedCacheKey, true),
                };

                //SharePoint's remote event notification lacks the current item state for ItemDeleting and ItemUpdating events
                //For these event types, attempt to fetch the current (unchanged) item and populate the ItemBeforeProperties
                if (_eventInfo.EventType == "ItemDeleting" || _eventInfo.EventType == "ItemUpdating")
                {
                    //SharePoint feature provisioning sometimes raises this event
                    //and deletes some things in the process with no ListId given
                    var listId = Guid.Parse(_eventInfo.EventProperties["ListId"]);
                    if (listId != default(Guid))
                    {
                        var item =
                            ctx.Web.Lists.GetById(Guid.Parse(_eventInfo.EventProperties["ListId"]))
                            .GetItemById(_eventInfo.EventProperties["ListItemId"]);
                        ctx.Load(item, i => i.FieldValuesAsText);
                        try
                        {
                            ctx.ExecuteQueryRetry();
                            _eventInfo.ItemBeforeProperties = item.FieldValuesAsText.FieldValues;
                        }
                        catch
                        {
                            //The query depends on timing and there are a number of things that can go wrong.
                            //If the BeforeProperties can't be read, forward the event anyway with the info that is available
                        }
                    }
                }

                //Send the event to the client's service bus queue
                SendQueueMessage(eventMessage);
            }
            catch (Exception ex)
            {
                Log(ex.ToString());
                throw;
            }

            return(_response);
        }