/// <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> /// <returns>A ClientContext object created for the passed site url</returns> public static ClientContext Clone(this ClientRuntimeContext clientContext, Uri siteUrl) { if (siteUrl == null) { throw new ArgumentException(CoreResources.ClientContextExtensions_Clone_Url_of_the_site_is_required_, "siteUrl"); } ClientContext clonedClientContext = new ClientContext(siteUrl); clonedClientContext.AuthenticationMode = clientContext.AuthenticationMode; // In case of using networkcredentials in on premises or SharePointOnlineCredentials in Office 365 if (clientContext.Credentials != null) { clonedClientContext.Credentials = clientContext.Credentials; } else { //Take over the form digest handling setting clonedClientContext.FormDigestHandlingEnabled = (clientContext as ClientContext).FormDigestHandlingEnabled; // In case of app only or SAML 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); }; } return(clonedClientContext); }
/// <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 clonedClientContext.DisableReturnValueCache = clientContext.DisableReturnValueCache; #elif SP2016 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 { //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 a custom Access Token for it in the input arguments 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 { // In case of app only or SAML 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); }; } } return(clonedClientContext); }
/// <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> /// <returns>A ClientContext object created for the passed site url</returns> public static ClientContext Clone(this ClientRuntimeContext clientContext, Uri siteUrl) { if (siteUrl == null) { throw new ArgumentException("siteUrl"); } ClientContext clonedClientContext = new ClientContext(siteUrl) { AuthenticationMode = clientContext.AuthenticationMode, ClientTag = clientContext.ClientTag, //DisableReturnValueCache = clientContext.DisableReturnValueCache }; //#if !ONPREMISES //#elif SP2016 // //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 { //Take over the form digest handling setting clonedClientContext.FormDigestHandlingEnabled = (clientContext as ClientContext).FormDigestHandlingEnabled; // In case of app only or SAML 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 = { webRequestEventArgs }; methodInfo.Invoke(clientContext, parametersArray); }; } return(clonedClientContext); }
protected virtual bool DetectSharePointOnlineContext(ClientRuntimeContext context) { #if NET35 return(false); #endif #if !NET35 // checking based on the current assembly version // using hash to avoid performance degradation if (!Context2SharePointOnlineHash.ContainsKey(context)) { Context2SharePointOnlineHash.Add(context, false); try { // by assembly version var version = AssemblyVersionService.GetAssemblyFileVersion(context.GetType().Assembly); // 16.1.0.0 for SharePoint Online // 16.0.0.0 for SharePoint 2016, we should be safe // Major.Minor.Build.Revision // currrent assembly? at least 16 (O365 / SharePoint 2016) Context2SharePointOnlineHash[context] = version.Major == 16; // if we talk to SharePoint 2016 from old, SP2013 CSOM // SP2016 CSOM - taxonomy group cannot be found after provision #1103 // https://github.com/SubPointSolutions/spmeta2/issues/1103 if (context.ServerLibraryVersion.Major == 16) { Context2SharePointOnlineHash[context] = version.Major == 16; } } catch (Exception e) { // fallback Context2SharePointOnlineHash[context] = context.Credentials is SharePointOnlineCredentials; } } return(Context2SharePointOnlineHash[context]); #endif }
/// <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); }
/// <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; clonedClientContext.ClientTag = clientContext.ClientTag; clonedClientContext.DisableReturnValueCache = clientContext.DisableReturnValueCache; // 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)) { var authManager = contextSettings.AuthenticationManager; ClientContext newClientContext = null; if (contextSettings.Type == ClientContextType.SharePointACSAppOnly) { newClientContext = authManager.GetACSAppOnlyContext(newSiteUrl, contextSettings.ClientId, contextSettings.ClientSecret, contextSettings.Environment); } else { newClientContext = authManager.GetContextAsync(newSiteUrl).GetAwaiter().GetResult(); } if (newClientContext != null) { //Take over the form digest handling setting newClientContext.ClientTag = clientContext.ClientTag; newClientContext.DisableReturnValueCache = clientContext.DisableReturnValueCache; 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 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); }
public override void DeployModel(object modelHost, DefinitionBase model) { this.ModelHost = modelHost; if (!(modelHost is SiteModelHost || modelHost is WebModelHost || modelHost is ListModelHost)) { throw new ArgumentException("modelHost needs to be SiteModelHost/WebModelHost/ListModelHost instance."); } CurrentHostClientContext = (modelHost as CSOMModelHostBase).HostClientContext; CurrentModelHost = modelHost.WithAssertAndCast <CSOMModelHostBase>("modelHost", value => value.RequireNotNull()); HostSite = ExtractSiteFromHost(modelHost); HostWeb = ExtractWebFromHost(modelHost); TraceService.Verbose((int)LogEventId.ModelProvisionCoreCall, "Casting field model definition"); var fieldModel = model.WithAssertAndCast <FieldDefinition>("model", value => value.RequireNotNull()); Field currentField = null; ClientRuntimeContext context = null; InvokeOnModelEvent(this, new ModelEventArgs { CurrentModelNode = null, Model = null, EventType = ModelEventType.OnProvisioning, Object = null, ObjectType = GetTargetFieldType(fieldModel), ObjectDefinition = model, ModelHost = modelHost }); if (modelHost is ListModelHost) { var listHost = modelHost as ListModelHost; context = listHost.HostList.Context; currentField = DeployListField(modelHost as ListModelHost, fieldModel); } else if (modelHost is WebModelHost) { var webHost = modelHost as WebModelHost; context = webHost.HostWeb.Context; currentField = DeployWebField(webHost as WebModelHost, fieldModel); } else if (modelHost is SiteModelHost) { var siteHost = modelHost as SiteModelHost; context = siteHost.HostSite.Context; currentField = DeploySiteField(siteHost as SiteModelHost, fieldModel); } else { throw new ArgumentException("modelHost needs to be SiteModelHost/WebModelHost/ListModelHost instance."); } object typedField = null; // emulate context.CastTo<>() call for typed field type if (GetTargetFieldType(fieldModel) != currentField.GetType()) { var targetFieldType = GetTargetFieldType(fieldModel); TraceService.VerboseFormat((int)LogEventId.ModelProvisionCoreCall, "Calling context.CastTo() to field type: [{0}]", targetFieldType); var method = context.GetType().GetMethod("CastTo"); var generic = method.MakeGenericMethod(targetFieldType); typedField = generic.Invoke(context, new object[] { currentField }); } InvokeOnModelEvent(this, new ModelEventArgs { CurrentModelNode = null, Model = null, EventType = ModelEventType.OnProvisioned, Object = typedField ?? currentField, ObjectType = GetTargetFieldType(fieldModel), ObjectDefinition = model, ModelHost = modelHost }); if (fieldModel.PushChangesToLists.HasValue) { TraceService.Verbose((int)LogEventId.ModelProvisionCoreCall, string.Format("UpdateAndPushChanges({0})", fieldModel.PushChangesToLists)); currentField.UpdateAndPushChanges(fieldModel.PushChangesToLists.Value); } else { TraceService.Verbose((int)LogEventId.ModelProvisionCoreCall, "UpdateAndPushChanges(true)"); // Why does SSOM handler distinguish between list and web/site fields and csom doesn't? currentField.UpdateAndPushChanges(true); } TraceService.Verbose((int)LogEventId.ModelProvisionCoreCall, "ExecuteQuery()"); context.ExecuteQueryWithTrace(); CurrentHostClientContext = null; }
public override void DeployModel(object modelHost, DefinitionBase model) { if (!(modelHost is SiteModelHost || modelHost is ListModelHost)) { throw new ArgumentException("modelHost needs to be SiteModelHost/ListModelHost instance."); } CurrentSiteModelHost = modelHost as SiteModelHost; TraceService.Verbose((int)LogEventId.ModelProvisionCoreCall, "Casting field model definition"); var fieldModel = model.WithAssertAndCast <FieldDefinition>("model", value => value.RequireNotNull()); Field currentField = null; ClientRuntimeContext context = null; InvokeOnModelEvent(this, new ModelEventArgs { CurrentModelNode = null, Model = null, EventType = ModelEventType.OnProvisioning, Object = null, ObjectType = GetTargetFieldType(fieldModel), ObjectDefinition = model, ModelHost = modelHost }); InvokeOnModelEvent <FieldDefinition, Field>(currentField, ModelEventType.OnUpdating); if (modelHost is SiteModelHost) { var siteHost = modelHost as SiteModelHost; context = siteHost.HostSite.Context; currentField = DeploySiteField(siteHost as SiteModelHost, fieldModel); } else if (modelHost is ListModelHost) { var listHost = modelHost as ListModelHost; context = listHost.HostList.Context; currentField = DeployListField(modelHost as ListModelHost, fieldModel); } object typedField = null; // emulate context.CastTo<>() call for typed field type if (GetTargetFieldType(fieldModel) != currentField.GetType()) { var targetFieldType = GetTargetFieldType(fieldModel); TraceService.InformationFormat((int)LogEventId.ModelProvisionCoreCall, "Calling context.CastTo() to field type: [{0}]", targetFieldType); var method = context.GetType().GetMethod("CastTo"); var generic = method.MakeGenericMethod(targetFieldType); typedField = generic.Invoke(context, new object[] { currentField }); } InvokeOnModelEvent(this, new ModelEventArgs { CurrentModelNode = null, Model = null, EventType = ModelEventType.OnProvisioned, Object = typedField ?? currentField, ObjectType = GetTargetFieldType(fieldModel), ObjectDefinition = model, ModelHost = modelHost }); InvokeOnModelEvent <FieldDefinition, Field>(currentField, ModelEventType.OnUpdated); TraceService.Verbose((int)LogEventId.ModelProvisionCoreCall, "UpdateAndPushChanges(true)"); currentField.UpdateAndPushChanges(true); TraceService.Verbose((int)LogEventId.ModelProvisionCoreCall, "ExecuteQuery()"); context.ExecuteQueryWithTrace(); }