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); }
/// <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; }