Outlook Notify v2 API - Create calendar subscription - outlook-restapi

I am setting up a subscription request. I receive the validationtoken url param so according to the docs I have to reply in the next five seconds doing this:
Set the content type in the response header to text\plain.
Include only the validation token in the response body.
Return an HTTP 200 response code.
This tells the Outlook notifications service that the listener received the URL validation request, and the validation succeeded.
I am receiving an error though:
{"error":{"code":"ErrorInvalidParameter","message":"Notification URL 'https://mycallbackurl.com/api/notify?validationtoken=NTk4NzliNzktNTE1MS00ZjE1LWJjNzctMTE4NzI4NTNhODlh' verification failed 'System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.\r\n at System.Net.HttpWebRequest.GetResponse()\r\n at Microsoft.Exchange.Services.OData.ODataPushSubscriptionCallbackUrlValidationHelper.SendRequestAndVerifyResponse(Uri callbackUrl, PushSubscription pushSubscription)'."}
This is my reply that attempts to use that validation token:
REQUEST
https://mycallbackurl.com/api/notify?validationtoken=NTk4NzliNzktNTE1MS00ZjE1LWJjNzctMTE4NzI4NTNhODlh
RESPONSE CODE
200
RESPONSE BODY
NTk4NzliNzktNTE1MS00ZjE1LWJjNzctMTE4NzI4NTNhODlh
RESPONSE HEADERS
Date: Mon, 16 May 2016 09:42:50 GMT
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: chrome-extension://aejoelaoggembcahagimdiliamlcdmfm
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Authorization, Accept, Origin, Content-Type, Access-Control-Allow-Credentials, Access-Control-Allow-Origin
Access-Control-Expose-Headers: X-Api-Version
Access-Control-Max-Age: 3600
Access-Control-Allow-Methods: POST, PATCH, PUT, GET, OPTIONS, DELETE
Allow: POST, PATCH, PUT, GET, OPTIONS, DELETE
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Expires: 0
Pragma: no-cache
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
X-Api-Version: 1.3
Content-Type: text/plain;charset=UTF-8
Content-Length: 48
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
The only think that changes between what is expected for and what I am providing is content type:
Expected: text/plain
Produced: text/plain;charset=UTF-8
Assuming this is the reason of the error, would not make sense to allow both cases?

The error indicates a failure to establish a secure connection (SSL). There may be a problem with your SSL certificate. Is it a self-issued cert perhaps?

Related

How do I get set cookie value when there are multiple set cookie request in varnish?

I am trying to unset cookie if my cookie has certain value.
I tried getting the value using beresp.http.Set-Cookie but this seems to get first value set in Set-Cookie on response. Is there any way I can pull the second Set-Cookie's value ?
Edit
This is my Response header
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Fri, 19 Feb 2021 09:47:53 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 12297
Connection: keep-alive
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Encoding: br
Set-Cookie: VarnishCustomerIsGuest=True; path=/
Set-Cookie: .Nop.Customer=62a224b9-3b5b-4e74-8200-cf341df111af; expires=Sat, 19 Feb 2022 09:47:53 GMT; path=/; httponly
Set-Cookie: .Nop.TempData=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; samesite=lax; httponly
Vary: Accept-Encoding
X-MiniProfiler-Ids: ["4f9a095d-bbd1-4ffe-81e1-31761363af25"]
X-TMP1000: VarnishCustomerIsGuest=True; path=/
X-Varnish: 163854
Age: 0
Via: 1.1 varnish (Varnish/5.2)
X-Cache: MISS
Accept-Ranges: bytes
What I am trying to do is get the customer cookie at vcl_backend_response. But
beresp.http.Set-Cookie
gives me the first set-cookie value of VarnishCustomerIsGuest and I am not sure if I can get the customer cookie .Nop.Customer.
My application backend always sets cookie for every request so what I am trying to do is unset the cookies depending on .Nop.Customer value so that for some particular customer the page is always served from the varnish cache.
Varnish's vmod_std has the std.collect() function that collapses headers into a single header.
In your case, the following VCL snippet could be used to collapse all occurrences of the Set-Cookie header into a single Set-Cookie:
vcl 4.0;
import std;
sub vcl_backend_response {
std.collect(beresp.http.Set-Cookie);
}
Of course your existing VCL logic should be part of the VCL file as well. This example just shows the need to import the VMOD and to call std.collect() within vcl_backend_response.
An important disclaimer that comes directly from the std.collect() documentation page:
Care should be taken when collapsing headers. In particular collapsing Set-Cookie will lead to unexpected results on the browser side.
Once the Set-Cookie header is collapsed, you can use regsub() logic to extract the necessary values.

Issue with CDN strong caching without Cache-Control or Expires headers

We're using Azure CDN to serve images, and I'm trying to understand why images are being strong-cached by web browsers even though there is no Cache-Control or Expires headers in the image response.
For example, the following response headers are returned for an image from Azure CDN:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Content-MD5: KuQCJm6GQyEjejWwmRgRwQ==
Content-Type: image/jpeg
Date: Tue, 21 Nov 2017 00:15:57 GMT
Etag: 0x8D523228F0F4C42
Last-Modified: Sat, 04 Nov 2017 01:22:47 GMT
Server: ECAcc (meb/A744)
X-Cache: HIT
x-ms-blob-type: BlockBlob
x-ms-lease-status: unlocked
x-ms-request-id: 00822b7c-001e-0045-4194-61d246000000
x-ms-version: 2009-09-19
Content-Length: 5143
<<image data>>
As you can see there is an Etag header returned, but no Cache-Control or Expires headers.
When tracing the network traffic (using Fiddler) from the browser (Chrome), we are NOT seeing any subsequent requests for these images.
My understanding of Etags is that subsequent requests for this image should be sent back to the server (weak caching), and then the server can return a 304 not modified response if the file has not changed.
Can anyone shed any light on this?
I think you need the header cache-control: must-revalidate to get the browser to check the source and have 304 mot modified returned if there is no change.
This is not optimal in terms of caching though.
You are better to invalidate the js with QS changes ("v=??") or set a short expires / max-age header (60 / 120 seconds, or whatever you can handle in terms of deployment, 5 minutes???).
Having an expires header combined with etags should still mean the browser receives a 304 not modified from the server after expiration.

Upgrading to Azure (Microsoft) websocket not acknowledged

Due to constraints of current project, I am having to write the WebSocket protocol by hand in C++. I am able to get the authorization key, but when I try to upgrade the next socket connection, the server stalls after getting a completed MIME header. Then when I send anything after it, I get a 400 error. I do not get an acknowledgement from the server that the connection has been upgraded to a WebSocket. Here is a dump:
=========================================================================
POST /sts/v1.0/issueToken HTTP/1.1
Accept: */*
Connection: Keep-Alive
Content-Length: 0
Content-Type: application/x-www-form-urlencoded
Host: api.cognitive.microsoft.com
Ocp-Apim-Subscription-Key: 21cedc8aaab847369294240b2122b08d
Origin: https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fapi.cognitive.microsoft.com&data=04%7C01%7Cv-lufil%40microsoft.com%7C427ffe760b7a4f6ffe6a08d4d8fa0613%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636372015735060988%7CUnknown%7CVW5rbm93bnx7IlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiT3RoZXIifQ%3D%3D%7C-1&sdata=823HpmiJeZ54tzq6CpX86ZS8B0yUiOYSNMXvrmDSunA%3D&reserved=0
User-Agent: Gideon/0.0.1
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 495
Content-Type: application/jwt; charset=us-ascii
Expires: -1
Server: Microsoft-IIS/8.5 Microsoft-HTTPAPI/2.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
apim-request-id: 00fe24bc-ba53-4d91-9363-ea7fddfe2a5a
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
x-content-type-options: nosniff
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Operation-Location
Date: Tue, 01 Aug 2017 15:21:40 GMT
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzY29wZSI6Imh0dHBzOi8vc3BlZWNoLnBsYXRmb3JtLmJpbmcuY29tIiwic3Vic2NyaXB0aW9uLWlkIjoiZmMwOGVlNGM5ZmNkNGI0MWFmNTZiNzJmZDliZTE4ZWEiLCJwcm9kdWN0LWlkIjoiQmluZy5TcGVlY2guUHJldmlldyIsImNvZ25pdGl2ZS1zZXJ2aWNlcy1lbmRwb2ludCI6Imh0dHBzOi8vYXBpLmNvZ25pdGl2ZS5taWNyb3NvZnQuY29tL2ludGVybmFsL3YxLjAvIiwiYXp1cmUtcmVzb3VyY2UtaWQiOiIiLCJpc3MiOiJ1cm46bXMuY29nbml0aXZlc2VydmljZXMiLCJhdWQiOiJ1cm46bXMuc3BlZWNoIiwiZXhwIjoxNTAxNjAxNDk5fQ.2RQhid_B45fN5M2BmUlodhIe4Xxx71Ws1b03JylERUw
=========================================================================
POST /speech/recognition/dictation/cognitiveservices/v1?language=en-US HTTP/1.1
Accept: */*
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzY29wZSI6Imh0dHBzOi8vc3BlZWNoLnBsYXRmb3JtLmJpbmcuY29tIiwic3Vic2NyaXB0aW9uLWlkIjoiZmMwOGVlNGM5ZmNkNGI0MWFmNTZiNzJmZDliZTE4ZWEiLCJwcm9kdWN0LWlkIjoiQmluZy5TcGVlY2guUHJldmlldyIsImNvZ25pdGl2ZS1zZXJ2aWNlcy1lbmRwb2ludCI6Imh0dHBzOi8vYXBpLmNvZ25pdGl2ZS5taWNyb3NvZnQuY29tL2ludGVybmFsL3YxLjAvIiwiYXp1cmUtcmVzb3VyY2UtaWQiOiIiLCJpc3MiOiJ1cm46bXMuY29nbml0aXZlc2VydmljZXMiLCJhdWQiOiJ1cm46bXMuc3BlZWNoIiwiZXhwIjoxNTAxNjAxNDk5fQ.2RQhid_B45fN5M2BmUlodhIe4Xxx71Ws1b03JylERUw
Connection: upgrade
Content-Length: 8002
Content-Type: audio/wav; codec=audio/pcm; samplerate=16000
Host: speech.platform.bing.com
Path: audio
Sec-WebSocket-Key: Z2lkZW9ucm9ja3MK
Transfer-Encoding: chunked
Upgrade: websocket
User-Agent: Gideon/0.0.1
X-RequestId: 21cedc8aaab847369294240b2122b08d
X-Timestamp: 2017-08-01T15:21:40
HTTP/1.1 400 Bad Request
Exception: 4xx Client failure
Note that the server does not reply despite getting two "\r\n" to indicate an end of MIME header. When I send anything afterwards I get a 400 error.
According to your dump logs, it seems that you want to use Microsoft's Speech Service to convert the speech to text.
By using Microsoft's Speech Service,the 400 error means you don't have applied all the required parameters and HTTP headers and that the values are correct.
I found your request missed the X-ConnectionId in your request.
According to this article:
The Microsoft Speech Service requires that all clients include a unique id to identify the connection. Clients must include the X-ConnectionId header when starting a web socket handshake. The X-ConnectionId header value must be a universally unique identifier. Web socket upgrade requests that do not include the X-ConnectionId, that do not specify a value for the X-ConnectionId header, or that do not include a valid universally unique identifier value will be rejected by the service with a 400 Bad Request response.
So I suggest you could add the identify id and test again.

Where can I see Server http header?

One of our applications is tested by Whitehat Sentinel and one of their findings was that in some cases our response header for Server is set to:
Microsoft-HTTPAPI/2.0
I have tried accessing the URL they identified with Postman and Fiddler but I do not see the Server header. I have also tried an online web sniffer http://web-sniffer.net/
Can someone advise how I can see this header?
In Chrome Network tab I see these headers
HTTP/1.1 404 Not Found
Content-Type: text/html
Strict-Transport-Security: max-age=300
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Date: Thu, 13 Jul 2017 13:59:15 GMT
Content-Length: 1245
No Server header.
The URL reported by Whitehat was not working for me, I changed the target URL to domain.com/%% and this caused the request to be handled by http.sys and it returned the Server attribute.
That is not the name of the header. That is the value found in the Server header when an application serves files over HTTP via http.sys, which is the kernel-mode HTTP server built into Windows.
For example, when serving a file via a C# HttpListener, I get this header:
Server: Microsoft-HTTPAPI/2.0
This header can be disabled by setting the following registry value:
Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters
Name: DisableServerHeader
Type: DWORD
Value: 1

CORS Header Missing on Angular Resource Requests Only

I have a working node/express backend running on localhost. I'm building a project application that needs to fetch data from goodreads api. When I execute the request, I get:
Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at
https://www.goodreads.com/book/title.json?author=Arthur+Conan+Doyle&key=[my_key]&title=Hound+of+the+Baskervilles.
(Reason: CORS header 'Access-Control-Allow-Origin' missing).1 <unknown>
Server side, everything is working correctly. I have enabled CORS, and when I check the headers, 'Access-Control-Allow-Origin' is available on everything coming from my server after checking the header in Firefox and Chrome dev tools. When I make a request via $resource, however, 'Allow-Access...' is not present in my header. Here is the code for the resource:
.factory('goodReads', function($resource) {
return $resource('https://www.goodreads.com/book/title.json');
})
.controller('AddBookSelectorController', function($resource, goodReads) {
this.fetch = function() {
var key = '[my_key]';
var data = goodReads.query({author: 'Arthur Conan Doyle', key: key, title: 'Hound of the Baskervilles'});
console.log(data);
};
});
I'm calling fetch via ng-click, and everything executes fine except I get the CORS error. Can anyone point me in the right direction? I am new to angular, and my suspicion is there is a problem with my resource request or something in configuration, but I can't seem to find an answer to fix my problem in the documentation or other stackoverflow questions.
Update 3: It is not a localhost issue. I tried pushing it to my domain and using a simple button which ran an xhr request to the OpenBooks api, and the problem got worse. It is hosted via Openshift, and now the 'Allow-Control-Access-x' headers are gone even for other files on my server. Really beginning to bang my head against the wall here. I am removing the Angular tags, because it has nothing to do with Angular.
UPDATE 2: I got it working after installing 'Allow-Control-Allow-Origin' extension in Chrome. Has my problem been the fact that I'm running this on localhost? Or is there something else going on? The header is still not being set without the extension.
UPDATE: I've been working on this since 8am, and still no luck. I have tried rewriting the request using Angular's $http and also with Javascript's xhr following the example from HTML5 Rocks | Using Cors and I'm still having the same problem with each method. Like I said, the necessary header information is available from files on my server, but it breaks when I make requests to other sites.
I'm starting to think this might not be an Angular problem, but I really have no clue. Just to be safe, here is the code I added to Express to enable CORS, including app.use so you can get an idea for where I called it:
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, Content-Length");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Credentials", "true");
next();
});
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
Edit: Here are the headers from the API request:
Request Headers
Host: www.goodreads.com
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://localhost:3000/
Origin: http://localhost:3000
Connection: keep-alive
Response Headers
Cache-Control: max-age=0, private, must-revalidate
Content-Encoding: gzip
Content-Length: 686
Content-Type: application/json; charset=utf-8
Date: Wed, 02 Sep 2015 17:20:35 GMT
Etag: "a2be782f32638d2a435bbeaf4b01274a-gzip"
Server: Server
Set-Cookie: csid=BAhJIhg1MzgtNTk4NjMzNy0wNzQ4MTM5BjoGRVQ%3D--afed14b563e5a6eb7b3fa9005de3010474230702; path=/; expires=Sun, 02 Sep 2035 17:20:33 -0000
locale=en; path=/
_session_id2=fd45336b8ef86010d46c7d73adb5f004; path=/; expires=Wed, 02 Sep 2015 23:20:35 -0000; HttpOnly
Status: 200 OK
Vary: Accept-Encoding,User-Agent
X-Content-Type-Options: nosniff, nosniff
X-Frame-Options: ALLOWALL
X-Request-Id: 1K8EJWG30GWDE4MZ4R5K
X-Runtime: 2.277972
X-XSS-Protection: 1; mode=block
Headers for the .js file from my server:
Request
Host: localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://localhost:3000/
Cookie: _ga=GA1.1.1924088292.1439681064; connect.sid=s%3AB4O0Up9WF5iqkfky__I0XCiBD2aMATlq.gbJUC9GseqnJvRTEIbcwxD6cwFQeL7ljNScURCJ5As0
Connection: keep-alive
If-Modified-Since: Wed, 02 Sep 2015 17:08:40 GMT
If-None-Match: W/"886-14f8f0828c1"
Cache-Control: max-age=0
Response:
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0
Connection: keep-alive
Date: Wed, 02 Sep 2015 17:20:30 GMT
Etag: W/"886-14f8f0828c1"
Last-Modified: Wed, 02 Sep 2015 17:08:40 GMT
X-Powered-By: Express
access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept
I guess this problem exposed my ignorance, but maybe this will help other newbies to CORs like me. I finally figured out the problem after getting a copy of CORs in Action and working through the first example using the Flickr API.
My problem had nothing to do with the backend, Angular, jQuery's .ajax method, or xhr. All of my requests were properly formatted. The problem was the APIs I attempted to use did not have CORs enabled on their server. O.o As soon as I changed the data type to jsonp, everything went through.
Anyway, for you newbs out there like me, here are some pointers to help you if you run into this problem:
1. Don't assume the API you are using has CORs enabled
I don't know why, but I blindly picked two APIs that don't have CORs enabled, which is what caused all the fuss for me. I have never run into this problem before because the work I have done with APIs have always been from big companies like Flickr that had CORs enabled. If they don't set Access-Control-Allow-Origin on their server, you can request them to enable it and use JSONP in the meantime.
If the API has an option for a callback at the end, that's a good sign you should use JSONP for your request. JSONP works by wrapping your request in a callback and exploiting a feature of the script tag. Scripts can pull other scripts from any domain, so it works as a hack to get the data. Here's a good link that helped me. Exactly What is JSONP? | CameronSpear.com
2. Check The Response Headers
I got tricked by this, but remember that the response header on your request to an external API is the response from their server, not yours. It doesn't matter if CORs is enabled on your server, you are making the request to someone else, and the browser automatically sends your information to them in the request header. Remember, all of this checking is done by the browser for security reasons, so its doing the heavy lifting for you on the request side based on your ajax call. If Access-Control-Whatever doesn't show up in the response header, they don't have CORs enabled. If you are working on the frontend and requesting someone else's data, you can't do anything about it. Use JSONP and your problems will disappear (probably).
This whole fiasco for me started because I was confusing responses coming from my server with responses coming for their server. I correctly enabled CORs on my own server, but I was thinking it wasn't attaching the origin information to the request header which is why it was absent in the response header. In reality, everything was working correctly, but the API server didn't have it enabled.
So a day spent, but many lessons learned. Hopefully my wasted time helps someone else with their CORs problems. Note that my issue was stack agnostic, so regardless of how you are making your request, checking the response header is the first course of action to take if you run into a problem with CORs. After that, I would suggest looking into the request itself for errors.
Check out that book above or this link from the same author for more help, especially when it comes to non-simple requests HTML5 Rocks | Using CORs.

Resources