Как использовать XML-API WebEx с SSO (SAML)
Я пишу небольшой инструмент для открытия WebEx с нашими клиентами поддержки, используя информацию о билетах поддержки. Когда сайт использовал Имя пользователя / Пароль, я мог заставить его работать, теперь мы используем SSO. Сервер WebEx уже настроен на прием единого входа (наш ИТ-менеджер, а не я).
Ссылка на WebEx (ссылка ниже) не уточняется, а форум разработчиков WebEx на официальном сайте настолько дремлет и лишен ответов по этому вопросу, что я решил попытать счастья здесь.
опубликовал этот же вопрос на официальном форуме
У кого-нибудь есть идея, как заставить код, приведенный ниже, действительно работать? Что входит в <samlResponse>
пометьте и замените приведенную ниже строку в коде на то, что заставит его работать:
<samlResponse>samlResponse message will go here</samlResponse>
Что означает утверждение SAML в документации (см. Ниже)?
Что я узнал до сих пор
Документация WebEx по XML-API (стр. 68) описывает следующее:
3.1 AuthenticateUser
API AuthenticateUser примет утверждение SAML вместо пароля пользователя. Возвращенное значение может использоваться для последующих запросов XML API без использования продолжительности сеанса, как определено в Super Admin. Это может занять место текущего требования для и для аутентификации....
Следующая схема показывает структуру элемента сообщения запроса AuthenticateUser.
А затем он предоставляет схему схемы XML и образец.
Ссылаясь на пример кода.NET (который не использует SAML), я придумал следующий код:
string strXMLServer = "https://varonis.webex.com/WBXService/XMLService";
WebRequest request = WebRequest.Create(strXMLServer);
// Set the Method property of the request to POST.
request.Method = "POST";
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Create POST data and convert it to a byte array.
Func<StringBuilder, StringBuilder> webExXML =
bodySB => new StringBuilder(1024) // Currently 294 bytes in length
.AppendLine("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>")
.Append("<serv:message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"")
.Append(" xmlns:serv=\"http://www.webex.com/schemas/2002/06/service\"")
.Append(" xsi:schemaLocation=\"http://www.webex.com/schemas/2002/06/service")
.Append(" http://www.webex.com/schemas/2002/06/service/service.xsd\">")
.AppendLine("<header>")
.AppendLine("<securityContext>")
.AppendLine("<siteName>siteName</siteName>")
.AppendLine("<webExID>username</webExID>")
.AppendLine("<password></password>")
.AppendLine("<partnerID></partnerID>")
.AppendLine("</securityContext>")
.AppendLine("</header>")
.AppendLine()
.AppendLine("<body>")
.Append(bodySB)
.AppendLine()
.AppendLine("</body>")
.AppendLine("</serv:message>");
var xmlAuthBodyContent = new StringBuilder()
.AppendLine("<bodyContent ")
.AppendLine("xsi:type=\"java:com.webex.service.binding.user.AuthenticateUser\">")
.AppendLine("<samlResponse>samlResponse message will go here</samlResponse>")
.AppendLine("</bodyContent>");
byte[] byteArray = Encoding.UTF8.GetBytes(webExXML(xmlAuthBodyContent).ToString());
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
DataSet DSResponse = new DataSet();
DSResponse.ReadXml(response.GetResponseStream());
DSResponse.GetXml().Dump();
Результат, который я получаю:
<serv:message xmlns:serv="http://www.webex.com/schemas/2002/06/service">
<serv:header>
<serv:response>
<serv:result>FAILURE</serv:result>
<serv:reason>Authentication Server can't generate a valid session ticket</serv:reason>
<serv:gsbStatus>PRIMARY</serv:gsbStatus>
<serv:exceptionID>030048</serv:exceptionID>
<serv:subErrors>
<serv:subError>
<serv:exceptionID>AS0062</serv:exceptionID>
<serv:reason>Validate assertion failed</serv:reason>
<serv:value />
</serv:subError>
</serv:subErrors>
</serv:response>
</serv:header>
<serv:body>
<serv:bodyContent />
</serv:body>
</serv:message>
2 ответа
Я наконец получил ответ на форумах WebEx от одного Натана Морроу, я копирую содержание здесь с его разрешения, на случай, если кто-то здесь посчитает это полезным.
Ответ:
Утверждение SAML - это документ в стиле XML, который используется для проверки подлинности на основе SAML. Он включает в себя несколько значений, необходимых для аутентификации, и цифровую подпись с использованием предварительно настроенного сертификата доверия. Вам нужно будет работать с ИТ-отделом, чтобы получить доступ к получению утверждений SAML из используемой системы Identity Management. Как только вы сможете извлечь утверждение SAML в формате BASE64 (он не будет выглядеть как XML в этом формате, просто как блок символов), вы поместите все утверждение в элемент samlResponse в вашем запросе authenticateUser.
Затем я спросил о том, как это делает инструмент WebEx One-Click, и он ответил:
Инструменты повышения производительности WebEx используют собственные внутренние API и возможности веб-браузера для доступа к порталу проверки подлинности вашей компании для подтверждения подлинности. За кулисами происходит утверждение SAML. Как только вы сможете получить утверждение для своего инструмента, оно также появится за кулисами для конечного пользователя.
Извините за некромантию потока, но ответ здесь не очень полезен, и я подумал, что я бы включил полный рабочий пример на C# (проверенный на сервере ADFS 3.0), взломанный вместе из приведенного выше кода, плюс некоторые дополнительные элементы:
var handler = new HttpClientHandler
{
UseDefaultCredentials = true,
AllowAutoRedirect = true,
CookieContainer = new System.Net.CookieContainer(),
UseCookies = true
};
var client = new HttpClient(handler) {MaxResponseContentBufferSize = 256000};
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
client.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
client.DefaultRequestHeaders.ExpectContinue = false;
var samlResponseString = client
.GetStringAsync(
new Uri("https://AdfsServer/adfs/ls/IdpInitiatedSignOn.aspx?logintoRP=RPIdentifier")).Result;
var parsedSamlResponse = "";
Regex reg = new Regex("SAMLResponse\\W+value\\=\\\"([^\\\"]+)\\\"");
MatchCollection matches = reg.Matches(samlResponseString);
foreach (Match m in matches)
{
parsedSamlResponse = m.Groups[1].Value;
}
string strXMLServer = "https://mysite.webex.com/WBXService/XMLService";
WebRequest request = WebRequest.Create(strXMLServer);
// Set the Method property of the request to POST.
request.Method = "POST";
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Create POST data and convert it to a byte array.
Func<StringBuilder, StringBuilder> webExXML =
bodySB => new StringBuilder(1024) // Currently 294 bytes in length
.AppendLine("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>")
.Append("<serv:message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"")
.Append(" xmlns:serv=\"http://www.webex.com/schemas/2002/06/service\"")
.Append(" xsi:schemaLocation=\"http://www.webex.com/schemas/2002/06/service")
.Append(" http://www.webex.com/schemas/2002/06/service/service.xsd\">")
.AppendLine("<header>")
.AppendLine("<securityContext>")
.AppendLine("<siteName>siteName</siteName>")
.AppendLine("<webExID>adminUsername</webExID>")
.AppendLine("</securityContext>")
.AppendLine("</header>")
.AppendLine()
.AppendLine("<body>")
.Append(bodySB)
.AppendLine()
.AppendLine("</body>")
.AppendLine("</serv:message>");
var xmlAuthBodyContent = new StringBuilder()
.AppendLine("<bodyContent ")
.AppendLine("xsi:type=\"java:com.webex.service.binding.user.AuthenticateUser\">")
.AppendLine($"<samlResponse>{parsedSamlResponse}</samlResponse>")
.AppendLine("<protocol>SAML2.0</protocol>")
.AppendLine("</bodyContent>");
byte[] byteArray = Encoding.UTF8.GetBytes(webExXML(xmlAuthBodyContent).ToString());
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
DataSet DSResponse = new DataSet();
DSResponse.ReadXml(response.GetResponseStream());
string xmlResponse = DSResponse.GetXml();
Измените код так, чтобы он отражал ваш сервер ADFS, идентификатор RP, имя сайта Webex и имя администратора.
Важные части, которые отсутствовали:
- Код для получения SAMLResponse из ADFS
protocol
тег вbodyContent
блок (установлен наSAML2.0
)