Exception when subscribing to exchange streaming notifications - c#

I'm currently working on a project that has me integrating with Exchange. One of the requirements is to monitor mailboxes for new incoming messages and I thought that leveraging a streaming notifications would be a good idea.
I wrote a sample application to get familiar with how to leverage streaming notifications, however I am encountering the following error: The expected XML node type was Element, but the actual type is Text.
The following is the source of the sample application that I wrote:
using Microsoft.Exchange.WebServices.Data;
using System;
using System.Net;
namespace ExampleProgram
{
class Program
{
public static StreamingSubscriptionConnection streamingConnection;
public static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
public static void NewMailSubscriptionDisconnect(object sender, SubscriptionErrorEventArgs args)
{
Exception e = args.Exception;
Console.Write("Disconnect: ");
Console.WriteLine(e.Message);
if (streamingConnection != null && !streamingConnection.IsOpen)
{
streamingConnection.Open();
}
}
public static void NewMailSubscriptionError(object sender, SubscriptionErrorEventArgs args)
{
Exception e = args.Exception;
Console.Write("Disconnect: ");
Console.WriteLine(e.Message);
}
public static void NewMailSubscriptionNotification(object sender, NotificationEventArgs args)
{
Console.WriteLine("New message has arrived");
}
static void Main(string[] args)
{
var exchangeService = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
exchangeService.Credentials = new NetworkCredential("username", "password", "domain");
exchangeService.TraceEnabled = true;
exchangeService.TraceFlags = TraceFlags.All;
exchangeService.TraceEnablePrettyPrinting = true;
exchangeService.AutodiscoverUrl("username#example.com", RedirectionUrlValidationCallback);
var newMailSubscription = exchangeService.SubscribeToStreamingNotificationsOnAllFolders(EventType.NewMail);
streamingConnection = new StreamingSubscriptionConnection(exchangeService, 30);
streamingConnection.AddSubscription(newMailSubscription);
streamingConnection.OnNotificationEvent += new StreamingSubscriptionConnection.NotificationEventDelegate(NewMailSubscriptionNotification);
streamingConnection.OnSubscriptionError += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(NewMailSubscriptionError);
streamingConnection.OnDisconnect += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(NewMailSubscriptionDisconnect);
streamingConnection.Open();
do { } while (Console.ReadKey(true).Key != ConsoleKey.Escape);
}
}
}
As you can see from the above source, I have tracing turned on. The following is what is yielded from those traces:
EwsResponseHttpHeader
<Trace Tag="EwsResponseHttpHeaders" Tid="17" Time="2015-10-20 17:42:31Z">
HTTP/1.1 200 OK
Transfer-Encoding: chunked
request-id: <redacted>
X-CalculatedBETarget: EXAMPLE-EXCHANGE-01.example.com
X-NoBuffering: 1
X-DiagInfo: EXAMPLE-EXCHANGE-01
X-BEServer: EXAMPLE-EXCHANGE-01
Cache-Control: private
Set-Cookie: exchangecookie=<redacted>; path=/,X-BackEndCookie=<redacted>; expires=Thu, 19-Nov-2015 17:42:30 GMT; path=/ews; secure; HttpOnly
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
Persistent-Auth: true
X-Powered-By: ASP.NET
X-FEServer: EXAMPLE-EXCHANGE-02
Date: Tue, 20 Oct 2015 17:42:30 GMT
</Trace>
EwsResponse
<Trace Tag="EwsResponse"
Tid="15"
Time="2015-10-20 16:52:07Z"
Version="0.0.0.0">
417 <!-- What is this? -->
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<soap11:Header xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<ServerVersionInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
MajorVersion="15"
MinorVersion="0"
MajorBuildNumber="1130"
MinorBuildNumber="6"
Version="V2_23"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types" />
</soap11:Header>
<soap11:Body xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<m:GetStreamingEventsResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
<m:ResponseMessages>
<m:GetStreamingEventsResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:ConnectionStatus>OK</m:ConnectionStatus>
</m:GetStreamingEventsResponseMessage>
</m:ResponseMessages>
</m:GetStreamingEventsResponse>
</soap11:Body>
</Envelope>
2 <!-- Not sure what this is either... -->
</Trace>
Exception Detail
Microsoft.Exchange.WebServices.Data.ServiceXmlDeserializationException occurred
HResult=-2146233088
Message=The expected XML node type was Element, but the actual type is Text.
Source=Microsoft.Exchange.WebServices
StackTrace:
at Microsoft.Exchange.WebServices.Data.EwsXmlReader.Read(XmlNodeType nodeType) in C:\Projects\ews-managed-api\Core\EwsXmlReader.cs:line 187
InnerException:
The source of EwsXmlReader.cs can be found at: https://github.com/OfficeDev/ews-managed-api/blob/master/Core/EwsXmlReader.cs
It looks like "something" is prepending 417 and appending 2 to the response from the Exchange server. It's quite obvious to me why the exception is being thrown, there is text data where there shouldn't be. What's not obvious to me, is why that text data is there.
Any ideas?

Transfer-Encoding: chunked
That's the key to this puzzle, you are seeing the "chunks". 417 is a value in hexadecimal for the length of the <Envelope> chunk when you remove the pretty-print formatting. 2 is the final chunk, just whitespace. Chunked transfer formatting is explained here.
I reformatted the XML to remove the white space, You can count off exactly 0x417 = 1047 characters:
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><soap11:Header xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"><ServerVersionInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MajorVersion="15" MinorVersion="0" MajorBuildNumber="1130" MinorBuildNumber="6" Version="V2_23" xmlns="http://schemas.microsoft.com/exchange/services/2006/types"/></soap11:Header><soap11:Body xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"><m:GetStreamingEventsResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"><m:ResponseMessages><m:GetStreamingEventsResponseMessage ResponseClass="Success"><m:ResponseCode>NoError</m:ResponseCode><m:ConnectionStatus>OK</m:ConnectionStatus></m:GetStreamingEventsResponseMessage></m:ResponseMessages></m:GetStreamingEventsResponse></soap11:Body></Envelope>
Obviously the http transfer is supposed to remove them, your question gives no decent lead why this did not happen. But hopefully a pretty good lead to find the underlying cause. Fun puzzle btw :)

Related

Authenticate an EWS application by using OAuth

I was trying to follow the steps from this this tutorial to authenticate my app by oAuth and use the retrieved token for EWS managed API.
Here is the final code:
static void Run()
{
string authority = ConfigurationSettings.AppSettings["authority"];
string clientID = ConfigurationSettings.AppSettings["clientID"];
Uri clientAppUri = new Uri(ConfigurationSettings.AppSettings["clientAppUri"]);
string serverName = ConfigurationSettings.AppSettings["serverName"];
AuthenticationResult authenticationResult = null;
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
string errorMessage = null;
try
{
Console.WriteLine("Trying to acquire token");
authenticationResult = authenticationContext.AcquireToken(serverName, clientID, clientAppUri, PromptBehavior.Auto);
}
catch (AdalException ex)
{
errorMessage = ex.Message;
if (ex.InnerException != null)
{
errorMessage += "\nInnerException : " + ex.InnerException.Message;
}
}
catch (ArgumentException ex)
{
errorMessage = ex.Message;
}
if (!string.IsNullOrEmpty(errorMessage))
{
Console.WriteLine("Failed: {0}" + errorMessage);
return;
}
Console.WriteLine("\nMaking the protocol call\n");
ExchangeService exchangeService = new ExchangeService(ExchangeVersion.Exchange2013);
exchangeService.Url = new Uri(serverName + "ews/exchange.asmx");
exchangeService.TraceEnabled = true;
exchangeService.TraceFlags = TraceFlags.All;
exchangeService.Credentials = new OAuthCredentials(authenticationResult.AccessToken);
//exchangeService.TraceListener = new TraceListener();
var res = exchangeService.FindFolders(WellKnownFolderName.Root, new FolderView(10));
}
and here is the configuration file:
<add key="authority" value="https://login.windows.net/???.onmicrosoft.com" />
<add key="clientId" value="???" />
<add key="clientAppUri" value="https://localhost/8a4abb13c70dab64a18ae81089bc2cff"/>
<add key="serverName" value="https://outlook.office365.com/" />
Here is the error message:
The request failed. The remote server returned an error: (401) Unauthorized.
and here is trace of ExchangeService:
<Trace Tag="EwsRequestHttpHeaders" Tid="12" Time="2015-08-13 13:56:24Z">
POST /ews/exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
User-Agent: ExchangeServicesClient/15.00.0847.030
Accept-Encoding: gzip,deflate
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9.eyJhdWQiOiJodHRwczovL291dGxvb2sub2ZmaWNlMzY1LmNvbS8iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9mMTFjYjAzOS05NzFlLTQxOWItYjg5NS01ZjIxZTkxOWFlZmUvIiwiaWF0IjoxNDM5NDczOTI0LCJuYmYiOjE0Mzk0NzM5MjQsImV4cCI6MTQzOTQ3NzgyNCwidmVyIjoiMS4wIiwidGlkIjoiZjExY2IwMzktOTcxZS00MTliLWI4OTUtNWYyMWU5MTlhZWZlIiwiZW1haWwiOiJoYW1pZC5lbG1pQGNvbnNldHRvLmNvbSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2JiZDIwM2I4LTkwMjEtNDZiZi05NzE2LTUyZWE5MzY1MjQ3Zi8iLCJhbHRzZWNpZCI6IjU6OjEwMDNCRkZEOEIxMTQxMTUiLCJzdWIiOiJPc0t2cnY3YU1hX3VKZktYNGltYXduSVp6SVIybDdkTXBkcUV6M0Y2U2U0IiwiZ2l2ZW5fbmFtZSI6IkhhbWlkIiwibmFtZSI6IkhhbWlkIEVsbWkiLCJhbXIiOlsicHdkIl0sInVuaXF1ZV9uYW1lIjoiaGFtaWQuZWxtaUBjb25zZXR0by5jb20iLCJhcHBpZCI6IjFkMGFiN2ZmLTU5NzItNDJlZS1iZGMwLWYzMzQwNTJhZmZjOCIsImFwcGlkYWNyIjoiMCIsInNjcCI6IkNhbGVuZGFycy5SZWFkIENhbGVuZGFycy5SZWFkV3JpdGUgQ29udGFjdHMuUmVhZCBDb250YWN0cy5SZWFkV3JpdGUgRGlyZWN0b3J5LkFjY2Vzc0FzVXNlci5BbGwgRGlyZWN0b3J5LlJlYWQgRGlyZWN0b3J5LldyaXRlIEZpbGVzLlJlYWQgRmlsZXMuUmVhZC5TZWxlY3RlZCBGaWxlcy5SZWFkV3JpdGUgRmlsZXMuUmVhZFdyaXRlLlNlbGVjdGVkIGZ1bGxfYWNjZXNzX2FzX3VzZXIgR3JvdXAuUmVhZC5BbGwgR3JvdXAuUmVhZFdyaXRlLkFsbCBNYWlsLlJlYWQgTWFpbC5SZWFkV3JpdGUgTWFpbC5TZW5kIG9mZmxpbmVfYWNjZXNzIG9wZW5pZCBTaXRlcy5SZWFkLkFsbCBTaXRlcy5SZWFkV3JpdGUuQWxsIFVzZXIuUmVhZCBVc2VyLlJlYWQuQWxsIFVzZXIuUmVhZEJhc2ljLkFsbCBVc2VyLlJlYWRXcml0ZSBVc2VyLlJlYWRXcml0ZS5BbGwiLCJhY3IiOiIxIn0.tZAyNFquVvyg46lsN79bmpdHhVEPwCIbBXfgsQ3kCzXgmf0LmX3s0A6SV7eSfEKef_-U78HBViAIaUexWeKAV0SKzJZUiQJ0dpDossYt6CfBAlFn4J6_5oZ_jygeNH3xeiCgU4tQrlz5t8iMOeSmBjwIsa2K-Sizd_zC8m3wptg6HI2ubdFJd0VXYqb7WFW_Sb-7wmOZqp8Lybpf3W6qRO14FRpm1f0RGec7kx4jd0EobPUaYWnQaet2I8P-5tuq6fmkJx78mQLGCrkZMcSJVakWVgepgO3LrEvKRKLuzJ9p5fiRiEVGNAzHUubrIjCVcXuquYaPdF16dK3gUT3Uiw
</Trace>
<Trace Tag="EwsRequest" Tid="12" Time="2015-08-13 13:56:24Z" Version="15.00.0847.030">
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<t:RequestServerVersion Version="Exchange2013" />
</soap:Header>
<soap:Body>
<m:FindFolder Traversal="Shallow">
<m:FolderShape>
<t:BaseShape>AllProperties</t:BaseShape>
</m:FolderShape>
<m:IndexedPageFolderView MaxEntriesReturned="10" Offset="0" BasePoint="Beginning" />
<m:ParentFolderIds>
<t:DistinguishedFolderId Id="root" />
</m:ParentFolderIds>
</m:FindFolder>
</soap:Body>
</soap:Envelope>
</Trace>
A first chance exception of type 'System.Net.WebException' occurred in System.dll
<Trace Tag="EwsResponseHttpHeaders" Tid="12" Time="2015-08-13 13:56:26Z">
HTTP/1.1 401 Unauthorized
request-id: ea025c98-9e74-4799-8ac2-77251f641912
X-CalculatedBETarget: HE1PR09MB0330.eurprd09.prod.outlook.com
X-BackEndHttpStatus: 401
Content-Length: 0
Set-Cookie: ClientId=4HGSRI510SWOAIFT0U31G; expires=Fri, 12-Aug-2016 13:57:17 GMT; path=/; secure; HttpOnly,exchangecookie=86f12da3fb89403bb91c5fe8b525f43d; expires=Sat, 13-Aug-2016 13:57:18 GMT; path=/; HttpOnly,ClientId=4HGSRI510SWOAIFT0U31G; expires=Fri, 12-Aug-2016 13:57:17 GMT; path=/; secure; HttpOnly
Server: Microsoft-IIS/8.0
x-ms-diagnostics: 2000001;reason="No applicable user context claims found.";error_category="invalid_token"
X-DiagInfo: HE1PR09MB0330
X-BEServer: HE1PR09MB0330
X-Powered-By: ASP.NET
X-FEServer: DB5PR09CA0061
WWW-Authenticate: Bearer client_id="00000002-0000-0ff1-ce00-000000000000", trusted_issuers="00000001-0000-0000-c000-000000000000#*", token_types="app_asserted_user_v1", authorization_uri="https://login.windows.net/common/oautA first chance exception of type 'Microsoft.Exchange.WebServices.Data.ServiceRequestException' occurred in Microsoft.Exchange.WebServices.dll
h2/authorize", error="invalid_token",Basic Realm="",Basic Realm=""
Date: Thu, 13 Aug 2015 13:57:17 GMT
</Trace>
Any idea would be greatly appreciated.
Your token has too many scopes in it (i.e. the scp claim). That value should only be full_access_as_user. In the Azure Management Portal, the only Office 365 Exchange Online permission you should have is "Access mailboxes as the signed-in user via Exchange Web Services".

HttpContext, alternative approach to Context.Request.Unvalidated for pre .Net 4.5 servers

I have a method in my project as per below which takes a HttpContext object and returns a string.
//returns the xml document as string
private static string GetXmlReceiptFromContext(HttpContext context)
{
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetNoStore();
context.Response.Cache.SetExpires(DateTime.MinValue);
return context.Request.Unvalidated.Form.Get("status");
}
The result of this is ultimately passed into a very important method that requires this string.
It appears that Context.Request.Unvalidated is only available from .Net 4.5.
I need to alternative approach to this method for our servers which do not have .Net 4.5 and will be making use of this assembly.
Can anyone suggest an alternative way of accessing and returning the status parameter who's value will be an XML Document from the context without using Context.Request.Unvalidated?
edit
This is not for a webform or MVC project, we have developed a class library whch we ideally want to contain all the payment related features within the assembly, i.e. single responsibility, our front end apps which will be using this do not need to know about the payment side of things.
I don't know weither you are using MVC or Web Forms/Web Pages, but there are several solutions available for you. Take a look at this MSDN page for more info about disabling request validation.
Web Forms: add <# Page validateRequest="false" %> to the top of your page to disable validation for a single page (other options for more pages/parts of an application are in the MSDN page).
MVC: add attribute [ValidateInput(false)] to the top of your action OR add an [AllowHtml] attribute to the property in the model you are binding to.
You can use BinaryRead and parse the raw request body yourself. See the RawPostValues() method below.
public class Handler1 : IHttpHandler
{
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write(GetXmlReceiptFromContext(context));
context.Response.Write("</ br>");
context.Response.Write(GetXmlReceiptFromContext(context));
}
//returns the xml document as string
private static string GetXmlReceiptFromContext(HttpContext context)
{
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetNoStore();
context.Response.Cache.SetExpires(DateTime.MinValue);
return RawPostValues(context)
.SingleOrDefault(kvp => kvp.Key.Equals("status", StringComparison.InvariantCultureIgnoreCase))
.Value;
}
private static IEnumerable<KeyValuePair<string, string>> RawPostValues(HttpContext context)
{
if (context.Request.HttpMethod != "POST") yield break;
var tmpPosition = context.Request.InputStream.Position;
string[] formElements;
try
{
formElements = System.Text.Encoding.Default.GetString(
context.Request.BinaryRead(context.Request.ContentLength))
.Split('&');
if (formElements.Length < 1) yield break;
}
finally
{
context.Request.InputStream.Position = tmpPosition;
}
foreach (var element in formElements)
{
if (string.IsNullOrEmpty(element)) continue;
var key = element.Substring(0, element.IndexOf('='));
var value = element.Substring(key.Length + 1, element.Length - key.Length - 1);
yield return new KeyValuePair<string, string>(key, value);
}
}
}
Some quick smoke tests with Fiddler2 revealed that this works. You may have to hammer out some kinks.
Request
POST http://localhost:48707/Handler1.ashx HTTP/1.1
Host: localhost:48707
Content-Length: 19
content-type: application/x-www-form-urlencoded
status=<b>oops!</b>
Response
HTTP/1.1 200 OK
Server: ASP.NET Development Server/11.0.0.0
Date: Thu, 22 May 2014 05:29:26 GMT
X-AspNet-Version: 2.0.50727
Cache-Control: no-cache, no-store
Pragma: no-cache
Expires: -1
Content-Type: text/plain; charset=utf-8
Content-Length: 12
Connection: Close
<b>oops!</b>

Unable to connect to OnVif enabled camera using C#

I am working with IPCams for the first time and I am trying to connect to an OnVif camera. I have looked on various forums and stack overflow and I have come up with the following code.I know the code doesn't do anything useful but it is just a proof of concept for now. It finds all 4 cameras on my network and then I am manually connecting to one of them to pull back some information such as GetServices.
I get a 400 bad response error at this stage. I have looked at the traffic back and forth with WireShark and it appears that everything is working ok regarding the password being generated in so far as I can tell (security and encryption is not my area at all!).
Can anyone help or advise?
class Program
{
static void Main(string[] args)
{
var endPoint = new UdpDiscoveryEndpoint(DiscoveryVersion.WSDiscoveryApril2005);
var discoveryClient = new DiscoveryClient(endPoint);
discoveryClient.FindProgressChanged += discoveryClient_FindProgressChanged;
discoveryClient.FindCompleted += discoveryClient_FindCompleted;
FindCriteria findCriteria = new FindCriteria();
findCriteria.Duration = new TimeSpan(0, 0, 2);//TimeSpan.MaxValue;
findCriteria.MaxResults = int.MaxValue;
discoveryClient.FindAsync(findCriteria);
Console.ReadKey();
}
private static void discoveryClient_FindCompleted(object sender, FindCompletedEventArgs e)
{
Console.WriteLine("Discovery complete");
}
static void discoveryClient_FindProgressChanged(object sender, FindProgressChangedEventArgs e)
{
foreach (var u in e.EndpointDiscoveryMetadata.ListenUris)
{
string uri = u.OriginalString;
if (uri.Contains("http://192.168.1.162/onvif/device_service"))
{
Console.WriteLine(uri);
EndpointAddress serviceAddress = new EndpointAddress(uri);
HttpTransportBindingElement httpBinding = new HttpTransportBindingElement();
httpBinding.AuthenticationScheme = AuthenticationSchemes.Digest;
var messegeElement = new TextMessageEncodingBindingElement();
messegeElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None);
CustomBinding bind = new CustomBinding(messegeElement, httpBinding);
DeviceClient client = new DeviceClient(bind, serviceAddress);
// Add our custom behavior - this require the Microsoft WSE 3.0 SDK
PasswordDigestBehavior behavior = new PasswordDigestBehavior("test", "test");
client.Endpoint.Behaviors.Add(behavior);
foreach (Service s in client.GetServices(false))
Console.WriteLine(s.ToString());
client.Open();
Console.WriteLine("WSDL = " + client.GetWsdlUrl());
Console.WriteLine("DateTime = " + client.GetSystemDateAndTime());
string a1, b1, c1, d1;
Console.Write(client.GetDeviceInformation(out a1, out b1, out c1, out d1));
}
}
}
}
Wireshark (username and passwor are both test)
POST /onvif/device_service HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver10/device/wsdl/GetServices"
Host: 192.168.1.162
Content-Length: 1232
Expect: 100-continue
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo7uVma6HRQNDh2l6T2ZDNzIAAAAA2/ITWE91IUaNFF3UObayz0mz6QvnZppBlYrNJBd1QGsACQAA</VsDebuggerCausalityData>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="SecurityToken-56f9081e-e9b4-4660-9158-7419af1efde0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>test</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">WSKWE5XjP5aPiIiA9JicCOYoDkU=</wsse:Password>
<wsse:Nonce>6sYgS41VHsWKj7n8TNKFjA==</wsse:Nonce>
<wsu:Created>2013-08-09T14:52:45Z</wsu:Created>
</wsse:UsernameToken>
</Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GetServices xmlns="http://www.onvif.org/ver10/device/wsdl">
<IncludeCapability>false</IncludeCapability>
</GetServices>
</s:Body>
</s:Envelope>HTTP/1.1 400 Bad Request
Server: gSOAP/2.7
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 2751
Connection: close
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:c14n="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:xmime="http://tempuri.org/xmime.xsd" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2" xmlns:aa="http://www.axis.com/vapix/ws/action1" xmlns:aev="http://www.axis.com/vapix/ws/event1" xmlns:tan1="http://www.onvif.org/ver20/analytics/wsdl/RuleEngineBinding" xmlns:tan2="http://www.onvif.org/ver20/analytics/wsdl/AnalyticsEngineBinding" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tev1="http://www.onvif.org/ver10/events/wsdl/NotificationProducerBinding" xmlns:tev2="http://www.onvif.org/ver10/events/wsdl/EventBinding" xmlns:tev3="http://www.onvif.org/ver10/events/wsdl/SubscriptionManagerBinding" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tev4="http://www.onvif.org/ver10/events/wsdl/PullPointSubscriptionBinding" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tnsaxis="http://www.axis.com/2009/event/topics">
<SOAP-ENV:Header>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo7uVma6HRQNDh2l6T2ZDNzIAAAAA2/ITWE91IUaNFF3UObayz0mz6QvnZppBlYrNJBd1QGsACQAA</VsDebuggerCausalityData>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<SOAP-ENV:Fault SOAP-ENV:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<SOAP-ENV:Code>
<SOAP-ENV:Value>SOAP-ENV:Sender</SOAP-ENV:Value>
<SOAP-ENV:Subcode>
<SOAP-ENV:Value>ter:NotAuthorized</SOAP-ENV:Value>
</SOAP-ENV:Subcode>
</SOAP-ENV:Code>
<SOAP-ENV:Reason>
<SOAP-ENV:Text xml:lang="en">Sender not authorized</SOAP-ENV:Text>
</SOAP-ENV:Reason>
<SOAP-ENV:Detail>
<SOAP-ENV:Text>The action requested requires authorization and the sender is not authorized</SOAP-ENV:Text>
</SOAP-ENV:Detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I have onvif enabled on the camera (by creating an administrator user called "test" with a password "test". The camera password is the default "root" and "pass" as it is an Axis camera.
Configure the connection to the camera this way:
ServicePointManager.Expect100Continue = false;
var endPointAddress = new EndpointAddress("http://" + cameraAddress + "/onvif/device_service");
var httpTransportBinding = new HttpTransportBindingElement { AuthenticationScheme = AuthenticationSchemes.Digest };
var textMessageEncodingBinding = new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None) };
var customBinding = new CustomBinding(textMessageEncodingBinding, httpTransportBinding);
var passwordDigestBehavior = new PasswordDigestBehavior(adminName, adminPassword);
var deviceClient = new DeviceClient(customBinding, endPointAddress);
deviceClient.Endpoint.Behaviors.Add(passwordDigestBehavior);
I know it's almost what you have done but it is important to make ServicePointManager.Expect100Continue false.
Check if the camera have the replay attack protection enabled. If so check the time difference between your computer's time and the camera's. According to the ONVIF's specs the allowed time difference must be +- 5 seconds. Otherwise you get your error.
If this is your case you have several options:
1- Disable the replay attack protection feature. This is not recommended because you would need to disable this feature in all the cameras you need to work with.
2- You can sync the camera's time with your computer time. Again not recommended for the same issue of the first option.
3- If you can change the WSE 3.0 for other option. In WSE3.0 once you have created the UsernameToken you can't change the Created property, which is used to create the encryption. This problem is described in here

Google Groups Migration C# API Not Working

I'm trying to use the C# Google Groups Migration API and not having much luck.
I have the following code:
public static void Main(string[] args)
{
var body =
#"Received: by 10.143.160.15 with HTTP; Mon, 16 Jul 2007 10:12:26 -0700 (PDT)
Message-ID: NNNN#mail.samplegroup.com
Date: Mon, 16 Jul 2007 10:12:26 -0700
From: ""xxx""
To: ""xxx""
Subject: SUBJECT
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Delivered-To: xxx
This is the body of the migrated email message.";
var bytes = ASCIIEncoding.ASCII.GetBytes(body);
var messageStream = new MemoryStream(bytes);
var auth = new OAuth2LeggedAuthenticator("xxx.com", "xxx", "xxx", "xxx");
var service = new GroupsmigrationService(auth);
service.Key = "xxx";
var request = service.Archive.Insert("xxx", messageStream, "message/rfc822");
request.Upload();
}
...but this results in an Invalid Credentials exception.
I also tried the following:
public static class Program
{
public static void Main(string[] args)
{
var body =
#"Received: by 10.143.160.15 with HTTP; Mon, 16 Jul 2007 10:12:26 -0700 (PDT)
Message-ID: NNNN#mail.samplegroup.com
Date: Mon, 16 Jul 2007 10:12:26 -0700
From: ""xxx""
To: ""xxx""
Subject: SUBJECT
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Delivered-To: xxx
This is the body of the migrated email message.";
var bytes = ASCIIEncoding.ASCII.GetBytes(body);
var messageStream = new MemoryStream(bytes);
// Register the authenticator.
var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
provider.ClientIdentifier = "xxx";
provider.ClientSecret = "xxx";
var auth = new OAuth2Authenticator<NativeApplicationClient>(provider, GetAuthorization);
// Create the service.
var service = new GroupsmigrationService(auth);
service.Key = "xxx";
var request = service.Archive.Insert("xxx", messageStream, "message/rfc822");
request.Upload();
Console.ReadKey();
}
private static IAuthorizationState GetAuthorization(NativeApplicationClient arg)
{
// Get the auth URL:
// IAuthorizationState state = new AuthorizationState(new[] { TasksService.Scopes.Tasks.GetStringValue() });
IAuthorizationState state = new AuthorizationState(new[] { "https://www.googleapis.com/auth/apps.groups.migration" });
state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
Uri authUri = arg.RequestUserAuthorization(state);
// Request authorization from the user (by opening a browser window):
Process.Start(authUri.ToString());
Console.Write(" Authorization Code: ");
string authCode = Console.ReadLine();
Console.WriteLine();
// Retrieve the access token by using the authorization code:
return arg.ProcessUserAuthorization(authCode, state);
}
}
...but that fails with: Backend Error. The inner exception is:
The remote server returned an error: (503) Server Unavailable.
Ideally I'd prefer the to use the 2 Legged Authenticator approach as it doesn't require manual intervention in copying and pasting an auth-key, but right now getting anything to work would be a plus.
Any help gratefully appreciated!
503 error usually indicated that you are hitting the API quota
https://developers.google.com/google-apps/groups-migration/v1/limits
Would you wait a 24 hours period and try to re-run again? The quota resets itself on a daily basics.
Additionally, you should tag your migration related question with google-email-migration and for group migration with google-groups-migration
I had same problem, and asked to google's support team.
In result, we found that this problem reproduce because "Message-ID" header in example has invalid format.
This typo has been fixed at August 12, 2013.
Please try to change Message-ID from NNNN#mail.samplegroup.com to <NNNN#mail.samplegroup.com>.

Connect to facebook chat using Jabber.net (C#/Mono) with SASL

I am trying to connect to facebook chat using Jabber.net(c#/Mono). The code I am using is this:
static ManualResetEvent done = new ManualResetEvent(false);
const bool VERBOSE = true;
const string TARGET = "friends_username#chat.facebook.com";
void Start ()
{
JabberClient j = new JabberClient();
j.User = "my_facebook_alias"; //Later to be removed
j.Server = "chat.facebook.com";
j.Port = 5222;
j.NetworkHost = "chat.facebook.com";
j.AutoStartCompression = true;
j.KeepAlive = 30F;
j.AutoStartTLS = false;
j.AutoStartCompression = true;
j.PlaintextAuth = true;
j.Password = "my_facebook_password"; //Later to be removed
j.RequiresSASL = true;
j.LocalCertificate = null;
// don't do extra stuff, please.
j.AutoPresence = false;
j.AutoRoster = true;
j.AutoReconnect = -1;
j.OnInvalidCertificate += new System.Net.Security.RemoteCertificateValidationCallback(j_OnInvalidCertificate);
// listen for errors. Always do this!
j.OnError += new bedrock.ExceptionHandler(j_OnError);
// what to do when login completes
j.OnAuthenticate += new bedrock.ObjectHandler(j_OnAuthenticate);
// listen for XMPP wire protocol
if (VERBOSE)
{
j.OnReadText += new bedrock.TextHandler(j_OnReadText);
j.OnWriteText += new bedrock.TextHandler(j_OnWriteText);
}
// Set everything in motion
j.Connect();
// wait until sending a message is complete
done.WaitOne();
// logout cleanly
j.Close();
}
static void j_OnWriteText(object sender, string txt)
{
if (txt == " ") return; // ignore keep-alive spaces
Console.WriteLine("SEND: " + txt);
}
static void j_OnReadText(object sender, string txt)
{
if (txt == " ") return; // ignore keep-alive spaces
Console.WriteLine("RECV: " + txt);
}
static void j_OnAuthenticate(object sender)
{
Debug.Log ("OnAuth...");
// Sender is always the JabberClient.
JabberClient j = (JabberClient)sender;
j.Message(TARGET, "My test message!!!");
// Finished sending. Shut down.
done.Set();
}
static void j_OnError(object sender, Exception ex)
{
// There was an error!
Console.WriteLine("Error: " + ex.ToString());
Debug.Log ("Error: "+ex.ToString());
// Shut down.
done.Set();
}
bool j_OnInvalidCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
Debug.Log("Invalid certificate "+sslPolicyErrors.ToString() +" : "+certificate.ToString(true));
return true;
}
I get to j_OnAuthenticate which is good. And it uses my id/password, since changing password to something else makes an error appear. However I do want to use X-FACEBOOK-PLATFORM SASL mechanism to be able to login without saving the users id/password.
The full log is:
RECV: <?xml version="1.0"?><stream:stream id="E34678B6" from="chat.facebook.com" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" xml:lang="en">
RECV: <stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>X-FACEBOOK-PLATFORM</mechanism><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features>
SEND: <auth mechanism="DIGEST-MD5" xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />
RECV: <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cmVhbG09ImNoYXQuZmFjZWJvb2suY29tIixub25jZT0iMDBENjAwQ0UyNjZBNzgyMEE5MUIzRDhGNjZDODQ1QjMiLHFvcD0iYXV0aCIsY2hhcnNldD11dGYtOCxhbGdvcml0aG09bWQ1LXNlc3M=</challenge>
SEND: <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">dXNlcm5hbWU9ImpvbmFzMiIscmVhbG09ImNoYXQuZmFjZWJvb2suY29tIixub25jZT0iMDBENjAwQ0UyNjZBNzgyMEE5MUIzRDhGNjZDODQ1QjMiLGNub25jZT0iMzUzMzMyM2E2YTZmNmU2MTczMzIzYTUxNGU1ZjQxNjI0YzM4NjYiLG5jPTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvY2hhdC5mYWNlYm9vay5jb20iLHJlc3BvbnNlPTcxN2ExNjM0MzdjOWU5MDM2NDcwYjViNTBhOTYxODIxLGNoYXJzZXQ9dXRmLTg=</response>
RECV: <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cnNwYXV0aD1hM2ZlZGM1NGRmYzNmMGEzMTU5Y2EyZDVmMmVkMmE2Zg==</challenge>
SEND: <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />
RECV: <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
SEND: <stream:stream xmlns:stream="http://etherx.jabber.org/streams" id="10996e3a" xmlns="jabber:client" to="chat.facebook.com" version="1.0">
RECV: <?xml version="1.0"?><stream:stream id="2AF2D483" from="chat.facebook.com" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" xml:lang="en">
RECV: <stream:features><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features>
SEND: <iq id="JN_1" type="set" to="chat.facebook.com"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>Jabber.Net</resource></bind></iq>
RECV: <iq id="JN_1" type="result"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>jonas2#chat.facebook.com/Jabber.Net_c938c6a2_4C7D6EF9DCFDC</jid></bind></iq>
SEND: <iq id="JN_2" type="set" to="chat.facebook.com"><session xmlns="urn:ietf:params:xml:ns:xmpp-session" /></iq>
RECV: <iq type="result" from="chat.facebook.com" id="JN_2"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>
OnAuth...
SEND: <message id="JN_3" type="chat" to="friends_username#chat.facebook.com"><body>My test message!!!</body></message>
SEND: <presence type="unavailable"><status>offline</status></presence>
SEND: </stream:stream>
SEND: <iq id="JN_4" type="get"><query xmlns="jabber:iq:roster" /></iq>
In MatriX XMPP there is a OnBeforeSasl delegate where a custom method can setup the required facebook Sasl properties (like facebook app id, app secret and access token). But there is no such delegate in Jabber.net!
Is there no SASL support i Jabber.net? Or how do you set it up?
there is SASL support in jabber-net, but there is no support for the X-FACEBOOK-PLATFORM SASL mechanism. If you want to use this mechanism you have to extend jabber-net by adding this SASL mechanism.
Facebook is closing the XMPP connection. This can be related to the message you send in the Authenticate event. Try to send your message after jabber-net sent your initial presence, or after you got your roster.
Alex

Categories