private ClientContext BuildClientContext(IClientApplicationBase application, string siteUrl, string[] scopes, ClientContextType contextType)
        {
            var clientContext = new ClientContext(siteUrl)
            {
                DisableReturnValueCache = true
            };

            clientContext.ExecutingWebRequest += (sender, args) =>
            {
                AuthenticationResult ar = null;

                var accounts = application.GetAccountsAsync().GetAwaiter().GetResult();
                if (accounts.Count() > 0)
                {
                    ar = application.AcquireTokenSilent(scopes, accounts.First()).ExecuteAsync().GetAwaiter().GetResult();
                }
                else
                {
                    switch (contextType)
                    {
                    case ClientContextType.AzureADCertificate:
                    {
                        ar = ((IConfidentialClientApplication)application).AcquireTokenForClient(scopes).ExecuteAsync().GetAwaiter().GetResult();
                        break;
                    }

                    case ClientContextType.AzureADCredentials:
                    {
                        ar = ((IPublicClientApplication)application).AcquireTokenByUsernamePassword(scopes, username, password).ExecuteAsync().GetAwaiter().GetResult();
                        break;
                    }

                    case ClientContextType.AzureADInteractive:
                    {
                        ar = ((IPublicClientApplication)application).AcquireTokenInteractive(scopes).ExecuteAsync().GetAwaiter().GetResult();
                        break;
                    }
                    }
                }
                if (ar != null && ar.AccessToken != null)
                {
                    args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + ar.AccessToken;
                }
            };

            ClientContextSettings clientContextSettings = new ClientContextSettings()
            {
                Type    = contextType,
                SiteUrl = siteUrl,
                AuthenticationManager = this,
            };

            clientContext.AddContextSettings(clientContextSettings);

            return(clientContext);
        }
        /// <summary>
        /// Returns an app only ClientContext object
        /// </summary>
        /// <param name="siteUrl">Site for which the ClientContext object will be instantiated</param>
        /// <param name="realm">Realm of the environment (tenant) that requests the ClientContext object</param>
        /// <param name="appId">Application ID which is requesting the ClientContext object</param>
        /// <param name="appSecret">Application secret of the Application which is requesting the ClientContext object</param>
        /// <param name="acsHostUrl">Azure ACS host, defaults to accesscontrol.windows.net but internal pre-production environments use other hosts</param>
        /// <param name="globalEndPointPrefix">Azure ACS endpoint prefix, defaults to accounts but internal pre-production environments use other prefixes</param>
        /// <returns>ClientContext to be used by CSOM code</returns>
        public ClientContext GetACSAppOnlyContext(string siteUrl, string realm, string appId, string appSecret, string acsHostUrl = "accesscontrol.windows.net", string globalEndPointPrefix = "accounts")
        {
            ACSEnsureToken(siteUrl, realm, appId, appSecret, acsHostUrl, globalEndPointPrefix);
            ClientContext clientContext = Utilities.TokenHelper.GetClientContextWithAccessToken(siteUrl, appOnlyAccessToken);

            clientContext.DisableReturnValueCache = true;

            ClientContextSettings clientContextSettings = new ClientContextSettings()
            {
                Type    = ClientContextType.SharePointACSAppOnly,
                SiteUrl = siteUrl,
                AuthenticationManager = this,
                Realm                = realm,
                ClientId             = appId,
                ClientSecret         = appSecret,
                AcsHostUrl           = acsHostUrl,
                GlobalEndPointPrefix = globalEndPointPrefix
            };

            clientContext.AddContextSettings(clientContextSettings);

            return(clientContext);
        }
Esempio n. 3
0
        /// <summary>
        /// Clones a ClientContext object while "taking over" the security context of the existing ClientContext instance
        /// </summary>
        /// <param name="clientContext">ClientContext to be cloned</param>
        /// <param name="targetContext">CientContext stub to be used for cloning</param>
        /// <param name="siteUrl">Site URL to be used for cloned ClientContext</param>
        /// <param name="accessTokens">Dictionary of access tokens for sites URLs</param>
        /// <returns>A ClientContext object created for the passed site URL</returns>
        internal static ClientContext Clone(this ClientRuntimeContext clientContext, ClientContext targetContext, Uri siteUrl, Dictionary <String, String> accessTokens = null)
        {
            if (siteUrl == null)
            {
                throw new ArgumentException(CoreResources.ClientContextExtensions_Clone_Url_of_the_site_is_required_, nameof(siteUrl));
            }

            ClientContext clonedClientContext = targetContext;

#if !NETSTANDARD2_0
            clonedClientContext.AuthenticationMode = clientContext.AuthenticationMode;
#endif
            clonedClientContext.ClientTag = clientContext.ClientTag;
#if !SP2013
            clonedClientContext.DisableReturnValueCache = clientContext.DisableReturnValueCache;
#endif

            // In case of using networkcredentials in on premises or SharePointOnlineCredentials in Office 365
            if (clientContext.Credentials != null)
            {
                clonedClientContext.Credentials = clientContext.Credentials;

                // In case of existing Event Handlers
                clonedClientContext.ExecutingWebRequest += (sender, webRequestEventArgs) =>
                {
                    // Call the ExecutingWebRequest delegate method from the original ClientContext object, but pass along the webRequestEventArgs of
                    // the new delegate method
                    MethodInfo methodInfo      = clientContext.GetType().GetMethod("OnExecutingWebRequest", BindingFlags.Instance | BindingFlags.NonPublic);
                    object[]   parametersArray = new object[] { webRequestEventArgs };
                    methodInfo.Invoke(clientContext, parametersArray);
                };
            }
            else
            {
                // Check if we do have context settings
                var contextSettings = clientContext.GetContextSettings();

                if (contextSettings != null) // We do have more information about this client context, so let's use it to do a more intelligent clone
                {
                    string newSiteUrl = siteUrl.ToString();

                    // A diffent host = different audience ==> new access token is needed
                    if (contextSettings.UsesDifferentAudience(newSiteUrl))
                    {
                        // We need to create a new context using a new authentication manager as the token expiration is handled in there
                        OfficeDevPnP.Core.AuthenticationManager authManager = new OfficeDevPnP.Core.AuthenticationManager();

                        ClientContext newClientContext = null;
                        if (contextSettings.Type == ClientContextType.SharePointACSAppOnly)
                        {
                            newClientContext = authManager.GetAppOnlyAuthenticatedContext(newSiteUrl, TokenHelper.GetRealmFromTargetUrl(new Uri(newSiteUrl)), contextSettings.ClientId, contextSettings.ClientSecret, contextSettings.AcsHostUrl, contextSettings.GlobalEndPointPrefix);
                        }
#if !ONPREMISES
                        else if (contextSettings.Type == ClientContextType.AzureADCredentials)
                        {
                            newClientContext = authManager.GetAzureADCredentialsContext(newSiteUrl, contextSettings.UserName, contextSettings.Password);
                        }
                        else if (contextSettings.Type == ClientContextType.AzureADCertificate)
                        {
                            newClientContext = authManager.GetAzureADAppOnlyAuthenticatedContext(newSiteUrl, contextSettings.ClientId, contextSettings.Tenant, contextSettings.Certificate, contextSettings.Environment);
                        }
                        else if (contextSettings.Type == ClientContextType.Cookie)
                        {
                            newClientContext = new ClientContext(newSiteUrl);
                            newClientContext.ExecutingWebRequest += (sender, webRequestEventArgs) =>
                            {
                                // Call the ExecutingWebRequest delegate method from the original ClientContext object, but pass along the webRequestEventArgs of
                                // the new delegate method
                                MethodInfo methodInfo      = clientContext.GetType().GetMethod("OnExecutingWebRequest", BindingFlags.Instance | BindingFlags.NonPublic);
                                object[]   parametersArray = new object[] { webRequestEventArgs };
                                methodInfo.Invoke(clientContext, parametersArray);
                            };
                            ClientContextSettings clientContextSettings = new ClientContextSettings()
                            {
                                Type    = ClientContextType.Cookie,
                                SiteUrl = newSiteUrl,
                            };

                            newClientContext.AddContextSettings(clientContextSettings);
                        }
#endif

                        if (newClientContext != null)
                        {
                            //Take over the form digest handling setting
#if !NETSTANDARD2_0
                            newClientContext.FormDigestHandlingEnabled = (clientContext as ClientContext).FormDigestHandlingEnabled;
#endif
                            newClientContext.ClientTag = clientContext.ClientTag;
#if !SP2013
                            newClientContext.DisableReturnValueCache = clientContext.DisableReturnValueCache;
#endif
                            return(newClientContext);
                        }
                        else
                        {
                            throw new Exception($"Cloning for context setting type {contextSettings.Type} was not yet implemented");
                        }
                    }
                    else
                    {
                        // Take over the context settings, this is needed if we later on want to clone this context to a different audience
                        contextSettings.SiteUrl = newSiteUrl;
                        clonedClientContext.AddContextSettings(contextSettings);

                        clonedClientContext.ExecutingWebRequest += delegate(object oSender, WebRequestEventArgs webRequestEventArgs)
                        {
                            // Call the ExecutingWebRequest delegate method from the original ClientContext object, but pass along the webRequestEventArgs of
                            // the new delegate method
                            MethodInfo methodInfo      = clientContext.GetType().GetMethod("OnExecutingWebRequest", BindingFlags.Instance | BindingFlags.NonPublic);
                            object[]   parametersArray = new object[] { webRequestEventArgs };
                            methodInfo.Invoke(clientContext, parametersArray);
                        };
                    }
                }
                else // Fallback the default cloning logic if there were not context settings available
                {
                    //Take over the form digest handling setting
#if !NETSTANDARD2_0
                    clonedClientContext.FormDigestHandlingEnabled = (clientContext as ClientContext).FormDigestHandlingEnabled;
#endif

                    var originalUri = new Uri(clientContext.Url);
                    // If the cloned host is not the same as the original one
                    // and if there is an active PnPProvisioningContext
                    if (originalUri.Host != siteUrl.Host &&
                        PnPProvisioningContext.Current != null)
                    {
                        // Let's apply that specific Access Token
                        clonedClientContext.ExecutingWebRequest += (sender, args) =>
                        {
                            // We get a fresh new Access Token for every request, to avoid using an expired one
                            var accessToken = PnPProvisioningContext.Current.AcquireToken(siteUrl.Authority, null);
                            args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessToken;
                        };
                    }
                    // Else if the cloned host is not the same as the original one
                    // and if there is a custom Access Token for it in the input arguments
                    else if (originalUri.Host != siteUrl.Host &&
                             accessTokens != null && accessTokens.Count > 0 &&
                             accessTokens.ContainsKey(siteUrl.Authority))
                    {
                        // Let's apply that specific Access Token
                        clonedClientContext.ExecutingWebRequest += (sender, args) =>
                        {
                            args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessTokens[siteUrl.Authority];
                        };
                    }
                    // Else if the cloned host is not the same as the original one
                    // and if the client context is a PnPClientContext with custom access tokens in its property bag
                    else if (originalUri.Host != siteUrl.Host &&
                             accessTokens == null && clientContext is PnPClientContext &&
                             ((PnPClientContext)clientContext).PropertyBag.ContainsKey("AccessTokens") &&
                             ((Dictionary <string, string>)((PnPClientContext)clientContext).PropertyBag["AccessTokens"]).ContainsKey(siteUrl.Authority))
                    {
                        // Let's apply that specific Access Token
                        clonedClientContext.ExecutingWebRequest += (sender, args) =>
                        {
                            args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + ((Dictionary <string, string>)((PnPClientContext)clientContext).PropertyBag["AccessTokens"])[siteUrl.Authority];
                        };
                    }
                    else
                    {
                        // In case of app only or SAML
                        clonedClientContext.ExecutingWebRequest += (sender, webRequestEventArgs) =>
                        {
                            // Call the ExecutingWebRequest delegate method from the original ClientContext object, but pass along the webRequestEventArgs of
                            // the new delegate method
                            MethodInfo methodInfo      = clientContext.GetType().GetMethod("OnExecutingWebRequest", BindingFlags.Instance | BindingFlags.NonPublic);
                            object[]   parametersArray = new object[] { webRequestEventArgs };
                            methodInfo.Invoke(clientContext, parametersArray);
                        };
                    }
                }
            }

            return(clonedClientContext);
        }
 internal static void AddContextSettings(this ClientRuntimeContext clientContext, ClientContextSettings contextData)
 {
     clientContext.StaticObjects[PnPSettingsKey] = contextData;
 }