internal ClientContext CloneContext(string url) { var context = ContextCache.FirstOrDefault(c => new Uri(c.Url).AbsoluteUri == new Uri(url).AbsoluteUri); if (context == null) { context = Context.Clone(url); try { context.ExecuteQueryRetry(); } catch (Exception ex) { #if !ONPREMISES && !PNPPSCORE if ((ex is WebException || ex is NotSupportedException) && CurrentConnection.PSCredential != null) { // legacy auth? using (var authManager = new OfficeDevPnP.Core.AuthenticationManager()) { context = authManager.GetAzureADCredentialsContext(url.ToString(), CurrentConnection.PSCredential.UserName, CurrentConnection.PSCredential.Password); } context.ExecuteQueryRetry(); } else { #endif throw; #if !ONPREMISES && !PNPPSCORE } #endif } ContextCache.Add(context); } Context = context; return(context); }
/// <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="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> public static ClientContext Clone(this ClientRuntimeContext clientContext, 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 = new ClientContext(siteUrl); clonedClientContext.AuthenticationMode = clientContext.AuthenticationMode; clonedClientContext.ClientTag = clientContext.ClientTag; #if !ONPREMISES || SP2016 || SP2019 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; } 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 && !NETSTANDARD2_0 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); } #endif if (newClientContext != null) { //Take over the form digest handling setting newClientContext.FormDigestHandlingEnabled = (clientContext as ClientContext).FormDigestHandlingEnabled; newClientContext.ClientTag = clientContext.ClientTag; #if !ONPREMISES || SP2016 || SP2019 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 clonedClientContext.FormDigestHandlingEnabled = (clientContext as ClientContext).FormDigestHandlingEnabled; 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 SPOnlineConnection InstantiateSPOnlineConnection(Uri url, PSCredential credentials, PSHost host, bool currentCredentials, int minimalHealthScore, int retryCount, int retryWait, int requestTimeout, string tenantAdminUrl, bool disableTelemetry, bool skipAdminCheck = false, ClientAuthenticationMode authenticationMode = ClientAuthenticationMode.Default) { var context = new PnPClientContext(url.AbsoluteUri); context.RetryCount = retryCount; context.Delay = retryWait * 1000; context.ApplicationName = Properties.Resources.ApplicationName; #if !ONPREMISES context.DisableReturnValueCache = true; #elif SP2016 || SP2019 context.DisableReturnValueCache = true; #endif context.RequestTimeout = requestTimeout; context.AuthenticationMode = authenticationMode; if (authenticationMode == ClientAuthenticationMode.FormsAuthentication) { var formsAuthInfo = new FormsAuthenticationLoginInfo(credentials.UserName, EncryptionUtility.ToInsecureString(credentials.Password)); context.FormsAuthenticationLoginInfo = formsAuthInfo; } if (!currentCredentials) { try { SharePointOnlineCredentials onlineCredentials = new SharePointOnlineCredentials(credentials.UserName, credentials.Password); context.Credentials = onlineCredentials; try { context.ExecuteQueryRetry(); } #if !ONPREMISES catch (NotSupportedException nox) { #if NETSTANDARD2_1 // Legacy auth is not supported with .NET Standard throw nox; #else // legacy auth? var authManager = new OfficeDevPnP.Core.AuthenticationManager(); context = PnPClientContext.ConvertFrom(authManager.GetAzureADCredentialsContext(url.ToString(), credentials.UserName, credentials.Password)); context.ExecuteQueryRetry(); #endif } #endif catch (ClientRequestException) { context.Credentials = new NetworkCredential(credentials.UserName, credentials.Password); } catch (ServerException) { context.Credentials = new NetworkCredential(credentials.UserName, credentials.Password); } } catch (ArgumentException) { // OnPrem? context.Credentials = new NetworkCredential(credentials.UserName, credentials.Password); try { context.ExecuteQueryRetry(); } catch (ClientRequestException ex) { throw new Exception("Error establishing a connection", ex); } catch (ServerException ex) { throw new Exception("Error establishing a connection", ex); } } } else { if (credentials != null) { context.Credentials = new NetworkCredential(credentials.UserName, credentials.Password); } else { // If current credentials should be used, use the DefaultNetworkCredentials of the CredentialCache. This has the same effect // as using "UseDefaultCredentials" in a HttpClient. context.Credentials = CredentialCache.DefaultNetworkCredentials; } } #if SP2013 || SP2016 || SP2019 var connectionType = ConnectionType.OnPrem; #else var connectionType = ConnectionType.O365; #endif if (url.Host.ToUpperInvariant().EndsWith("SHAREPOINT.COM")) { connectionType = ConnectionType.O365; } if (skipAdminCheck == false) { if (IsTenantAdminSite(context)) { connectionType = ConnectionType.TenantAdmin; } } var spoConnection = new SPOnlineConnection(context, connectionType, minimalHealthScore, retryCount, retryWait, credentials, url.ToString(), tenantAdminUrl, PnPPSVersionTag, host, disableTelemetry, InitializationType.Credentials); spoConnection.ConnectionMethod = Model.ConnectionMethod.Credentials; return(spoConnection); }