通过 C# 应用使用 Azure AD MFA 查询 On-premise SharePoint
Querying On-premise SharePoint using Azure AD MFA through C# app
我正在尝试使用 Microsoft.Identity.Client 和 Microsoft.SharePoint.Client 库对 On-premise SharePoint 服务器进行身份验证,然后对其进行查询。
我获取了 Azure AD 访问令牌,SharePoint 服务器是其中的一部分,如下所示:
private readonly string[] m_scopes = { "user.read", "https://sql.azuresynapse-dogfood.net/user_impersonation" };
var publicAppBuilder = PublicClientApplicationBuilder.Create("MyClientId").WithAuthority("https://login.microsoftonline.com/a******com.onmicrosoft.com");
publicAppBuilder.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient");
var app = publicAppBuilder.Build();
AuthenticationResult result = null;
result = app.AcquireTokenInteractive(m_scopes).ExecuteAsync().GetAwaiter().GetResult();
if (result != null)
{
m_mediator.AccessToken = result.AccessToken;
}
当我获得访问令牌时,我将其放入请求 header 中,如下所示:
args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + m_mediator.AccessToken;
在 ClientContext.ExecutingWebRequest
订阅的方法中:
clientContext.ExecutingWebRequest += (sender, args) =>
由
触发
context.ExecuteQuery();
The remote server returned an error: (401) Unauthorized.
or
The remote server returned an error: (403) Forbidden.
如何建立连接?我想避免使用 app-only 注册,我想使用 Azure AD MFA(交互式)进行身份验证 method.Please 请注意,我拥有所需的所有权限,并且我是加入 SharePoint 的两个 Azure AD 的管理员,以及 SharePoint 服务器本身。我通过浏览器验证就好了。
到目前为止我已经尝试了多种方法:
我尝试创建一个单独的请求,在其中转发之前获取的 accessToken 作为授权:不记名令牌
我尝试从身份验证连接读取 FedAuth window,因此我可以在我的 HTTP 请求中转发它,但没有成功
我尝试使用 WebBrowser C# 创建“Web 浏览器”class 并读取浏览器级别的 cookie,如下所示:cookieContainer = webBrowser1.Document.Cookie;
但我没有成功。
我希望通过 Azure AD 进行身份验证,然后连接到 SharePoint 以进行查询
To resolve the error "The remote server returned an error: (401)
Unauthorized", please try checking the following:
- 检查你的URL是否正确:
SharePoint Online URL 必须始终以 HTTPS 开头。
$SiteURL` `=` `"https://crescent.sharepoint.com/sites/marketing"`
- 检查您是否拥有该网站的正确权限:
检查您是否有足够的权限,是否可以在浏览器中打开网站。确保具有 SharePoint Online 管理员角色。
- 检查是否开启了Legacy认证协议:
如果未启用,请确保在您的租户中启用旧版身份验证协议。
To resolve the error "The remote server returned an error: (403)
Forbidden.", please try checking the following:
确保您是否提供了正确的 URL 和凭据。
请确认您是否安装了最新版本的 SharePoint Online 客户端组件 SDK。
尝试将您自己显式添加到站点
检查您网站的锁定状态,如果锁定则解锁。
请检查您的租户是否启用了任何条件访问策略。
如果您尝试连接到租户管理站点,请确保租户管理 URL 如下所示:
https://YourDomain-admin.sharepoint.com
我找到了解决办法。
每当浏览器浏览新页面时,我基本上都会遍历所有 cookie 并解析所有 cookie,直到获得 fedAuth cookie:
我从 System.Windows.Forms.WebBrowser
创建了一个网络浏览器
在 WebBrowserNavigatedEventHandler
中 Navigated
我做了以下操作:
if (webBrowser1.Url.AbsoluteUri == "about:blank")
{
return;
}
var cookieData = GetWebBrowserCookie.GetCookieInternal(webBrowser1.Url, false);
if (string.IsNullOrEmpty(cookieData) == false)
{
var dict = ParseCookieData(cookieData);
如果 (dict.ContainsKey("FedAuth") && !string.IsNullOrEmpty(dict["FedAuth"]))
{
m_mediator.FedAuthCookie = dict["FedAuth"];
如果 (dict.ContainsKey("rtFa") && !string.IsNullOrEmpty(dict["rtFa"]))
{
m_mediator.RtFaCookie = dict["rtFa"];
}
m_mediator.UpdateConfiguration();
this.Close();
}
}
ParseCookieData 方法如下所示:
private IDictionary<string, string> ParseCookieData(string cookieData)
{
var cookieDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrEmpty(cookieData))
{
return cookieDictionary;
}
var values = cookieData.TrimEnd(';').Split(';');
foreach (var parts in values.Select(c => c.Split(new[] { '=' }, 2)))
{
var cookieName = parts[0].Trim();
var cookieValue = parts.Length == 1 ? string.Empty : parts[1];
cookieDictionary[cookieName] = cookieValue;
}
return cookieDictionary;
}
和 GetWebBrowserCookie class 看起来像这样:
[SecurityCritical]
public static string GetCookieInternal(Uri uri, bool throwIfNoCookie)
{
uint pchCookieData = 0;
string url = UriToString(uri);
uint flag = (uint)NativeMethods.InternetFlags.INTERNET_COOKIE_HTTPONLY;
//Gets the size of the string builder
if (NativeMethods.InternetGetCookieEx(url, null, null, ref pchCookieData, flag, IntPtr.Zero))
{
pchCookieData++;
StringBuilder cookieData = new StringBuilder((int)pchCookieData);
//Read the cookie
if (NativeMethods.InternetGetCookieEx(url, null, cookieData, ref pchCookieData, flag, IntPtr.Zero))
{
DemandWebPermission(uri);
return cookieData.ToString();
}
}
int lastErrorCode = Marshal.GetLastWin32Error();
if (throwIfNoCookie || (lastErrorCode != (int)NativeMethods.ErrorFlags.ERROR_NO_MORE_ITEMS))
{
throw new Win32Exception(lastErrorCode);
}
return null;
}
private static void DemandWebPermission(Uri uri)
{
string uriString = UriToString(uri);
if (uri.IsFile)
{
string localPath = uri.LocalPath;
new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
}
else
{
new WebPermission(NetworkAccess.Connect, uriString).Demand();
}
}
private static string UriToString(Uri uri)
{
if (uri == null)
{
return string.Empty;
}
UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);
return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
}
这样我们打开一个 pop-up C# 网络浏览器,使用 MFA 通过网络对用户进行身份验证,然后在我们获取身份验证 cookie 时关闭浏览器,以便我们可以继续处理对 Sharepoint 的 HTTP 请求服务器。
来源:https://github.com/OceanAirdrop/SharePointOnlineGetFedAuthAndRtfaCookie
我正在尝试使用 Microsoft.Identity.Client 和 Microsoft.SharePoint.Client 库对 On-premise SharePoint 服务器进行身份验证,然后对其进行查询。
我获取了 Azure AD 访问令牌,SharePoint 服务器是其中的一部分,如下所示:
private readonly string[] m_scopes = { "user.read", "https://sql.azuresynapse-dogfood.net/user_impersonation" };
var publicAppBuilder = PublicClientApplicationBuilder.Create("MyClientId").WithAuthority("https://login.microsoftonline.com/a******com.onmicrosoft.com");
publicAppBuilder.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient");
var app = publicAppBuilder.Build();
AuthenticationResult result = null;
result = app.AcquireTokenInteractive(m_scopes).ExecuteAsync().GetAwaiter().GetResult();
if (result != null)
{
m_mediator.AccessToken = result.AccessToken;
}
当我获得访问令牌时,我将其放入请求 header 中,如下所示:
args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + m_mediator.AccessToken;
在 ClientContext.ExecutingWebRequest
订阅的方法中:
clientContext.ExecutingWebRequest += (sender, args) =>
由
触发context.ExecuteQuery();
The remote server returned an error: (401) Unauthorized. or The remote server returned an error: (403) Forbidden.
如何建立连接?我想避免使用 app-only 注册,我想使用 Azure AD MFA(交互式)进行身份验证 method.Please 请注意,我拥有所需的所有权限,并且我是加入 SharePoint 的两个 Azure AD 的管理员,以及 SharePoint 服务器本身。我通过浏览器验证就好了。
到目前为止我已经尝试了多种方法:
我尝试创建一个单独的请求,在其中转发之前获取的 accessToken 作为授权:不记名令牌
我尝试从身份验证连接读取 FedAuth window,因此我可以在我的 HTTP 请求中转发它,但没有成功
我尝试使用 WebBrowser C# 创建“Web 浏览器”class 并读取浏览器级别的 cookie,如下所示:
cookieContainer = webBrowser1.Document.Cookie;
但我没有成功。
我希望通过 Azure AD 进行身份验证,然后连接到 SharePoint 以进行查询
To resolve the error "The remote server returned an error: (401) Unauthorized", please try checking the following:
- 检查你的URL是否正确:
SharePoint Online URL 必须始终以 HTTPS 开头。
$SiteURL` `=` `"https://crescent.sharepoint.com/sites/marketing"`
- 检查您是否拥有该网站的正确权限:
检查您是否有足够的权限,是否可以在浏览器中打开网站。确保具有 SharePoint Online 管理员角色。
- 检查是否开启了Legacy认证协议:
如果未启用,请确保在您的租户中启用旧版身份验证协议。
To resolve the error "The remote server returned an error: (403) Forbidden.", please try checking the following:
确保您是否提供了正确的 URL 和凭据。
请确认您是否安装了最新版本的 SharePoint Online 客户端组件 SDK。
尝试将您自己显式添加到站点
检查您网站的锁定状态,如果锁定则解锁。
请检查您的租户是否启用了任何条件访问策略。
如果您尝试连接到租户管理站点,请确保租户管理 URL 如下所示:
https://YourDomain-admin.sharepoint.com
我找到了解决办法。
每当浏览器浏览新页面时,我基本上都会遍历所有 cookie 并解析所有 cookie,直到获得 fedAuth cookie:
我从 System.Windows.Forms.WebBrowser
创建了一个网络浏览器在
WebBrowserNavigatedEventHandler
中Navigated
我做了以下操作:if (webBrowser1.Url.AbsoluteUri == "about:blank") { return; }
var cookieData = GetWebBrowserCookie.GetCookieInternal(webBrowser1.Url, false);
if (string.IsNullOrEmpty(cookieData) == false) { var dict = ParseCookieData(cookieData); 如果 (dict.ContainsKey("FedAuth") && !string.IsNullOrEmpty(dict["FedAuth"])) { m_mediator.FedAuthCookie = dict["FedAuth"]; 如果 (dict.ContainsKey("rtFa") && !string.IsNullOrEmpty(dict["rtFa"])) { m_mediator.RtFaCookie = dict["rtFa"]; } m_mediator.UpdateConfiguration(); this.Close(); } }
ParseCookieData 方法如下所示:
private IDictionary<string, string> ParseCookieData(string cookieData)
{
var cookieDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrEmpty(cookieData))
{
return cookieDictionary;
}
var values = cookieData.TrimEnd(';').Split(';');
foreach (var parts in values.Select(c => c.Split(new[] { '=' }, 2)))
{
var cookieName = parts[0].Trim();
var cookieValue = parts.Length == 1 ? string.Empty : parts[1];
cookieDictionary[cookieName] = cookieValue;
}
return cookieDictionary;
}
和 GetWebBrowserCookie class 看起来像这样:
[SecurityCritical]
public static string GetCookieInternal(Uri uri, bool throwIfNoCookie)
{
uint pchCookieData = 0;
string url = UriToString(uri);
uint flag = (uint)NativeMethods.InternetFlags.INTERNET_COOKIE_HTTPONLY;
//Gets the size of the string builder
if (NativeMethods.InternetGetCookieEx(url, null, null, ref pchCookieData, flag, IntPtr.Zero))
{
pchCookieData++;
StringBuilder cookieData = new StringBuilder((int)pchCookieData);
//Read the cookie
if (NativeMethods.InternetGetCookieEx(url, null, cookieData, ref pchCookieData, flag, IntPtr.Zero))
{
DemandWebPermission(uri);
return cookieData.ToString();
}
}
int lastErrorCode = Marshal.GetLastWin32Error();
if (throwIfNoCookie || (lastErrorCode != (int)NativeMethods.ErrorFlags.ERROR_NO_MORE_ITEMS))
{
throw new Win32Exception(lastErrorCode);
}
return null;
}
private static void DemandWebPermission(Uri uri)
{
string uriString = UriToString(uri);
if (uri.IsFile)
{
string localPath = uri.LocalPath;
new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
}
else
{
new WebPermission(NetworkAccess.Connect, uriString).Demand();
}
}
private static string UriToString(Uri uri)
{
if (uri == null)
{
return string.Empty;
}
UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);
return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
}
这样我们打开一个 pop-up C# 网络浏览器,使用 MFA 通过网络对用户进行身份验证,然后在我们获取身份验证 cookie 时关闭浏览器,以便我们可以继续处理对 Sharepoint 的 HTTP 请求服务器。
来源:https://github.com/OceanAirdrop/SharePointOnlineGetFedAuthAndRtfaCookie