Outlook 2016 querying Add-in root route - outlook

So I have a question about some odd behavior I'm seeing in my Outlook Add-in logs and finally found the culprit. The client is Outlook 2016 and the user is backed by an on prem exchange server.
Whenever I open Outlook-2016 that has a user with the Add-in, Outlook seems to query the Add-in host for the root route https://<$host>/. This is odd because in my manifest I have not specified this path.
This is an easy enough fix to just add a root route, but my main question is why is it querying this route? Is it working as some sort of health check and if so can I specify another route that I already have a health check setup on?

If anyone else runs into this issue, Outlook 2016 when opened performs an HTTP OPTION on the root route. In nodejs with express, the solution was
router.options("/*", (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
res.sendStatus(200);
});

Related

Office-JS - Outlook addin not setting x-headers in outlook 2019

Based on Set custom header (x-header) on Outlook compose mail with JS addin post, I used the following code to set a custom x-header when composing emails in OWA or Outlook 2019.
function addCustomHeadersAsync(classificationMarking) {
return new Office.Promise(function (resolve, reject) {
try {
/* The itemId property is not available in compose mode. If an item identifier is required,
the saveAsync method can be used to save the item to the store, which will return the item identifier in the asyncResult.value parameter in the callback function.*/
Office.context.mailbox.item.saveAsync(function (saveAsyncResult) {
/* The getCallbackTokenAsync method makes an asynchronous call to get an opaque token from the Exchange Server that hosts the user's mailbox.
The lifetime of the callback token is 5 minutes. The token is returned as a string in the asyncResult.value property.*/
Office.context.mailbox.getCallbackTokenAsync({ isRest: true }, function (getCallbackTokenAsyncResult) {
var ewsId = saveAsyncResult.value;
var token = getCallbackTokenAsyncResult.value;
var restId = Office.context.mailbox.convertToRestId(ewsId, Office.MailboxEnums.RestVersion.v2_0);
var getMessageUrl = Office.context.mailbox.restUrl + '/v2.0/me/messages/' + restId;
// The PropertyId for PS_INTERNET_HEADERS is {00020386-0000-0000-C000-000000000046}.
// https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/commonly-used-property-sets?redirectedfrom=MSDN
// https://stackoverflow.com/questions/38214197/set-a-custom-header-with-outlook-office-365-rest
var securityHeaders = JSON.stringify({
SingleValueExtendedProperties: [
{
PropertyId: "String {00020386-0000-0000-C000-000000000046} Name X-Custom-header",
Value: classificationMarking
}
]
});
// https://learn.microsoft.com/en-us/previous-versions/office/office-365-api/api/version-2.0/extended-properties-rest-operations#ExtendedpropertyoperationsCreateextendedpropertyinanewitem
// PATCH request is required to create an extended property in an existing item
var xhr = new XMLHttpRequest();
xhr.open('PATCH', getMessageUrl);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer " + token);
xhr.onload = function (e) {
//console.log(this.response);
resolve();
}
xhr.send(securityHeaders);
});
});
}
catch (error) {
reject("Unable to set email custom security headers");
}
})
}
As on-premises Office 2019 + Exchange 2016 only supports API 1.5, I'm not able to use the new setCustomHeaders function which has been available since API 1.8 (https://learn.microsoft.com/en-us/office/dev/add-ins/outlook/internet-headers)
Everything works in https://outlook.office.com/mail/inbox & on-premises OWA (Exchange2016).
When using Outlook 2019 (online mode) :
The saveAsync function saves the draft
The XMLHttpRequest correctly sets the X-Custom-header : when calling the Exchange 2016 REST just after trying to set the XMLHttpRequest with a GET request, Exchange correctly reports the SingleValueExtendedProperties beeing set
After this step, when manually saving or sending the email, the SingleValueExtendedProperties seems to be removed or overwritten by Outlook which doesnt seems to be aware of this SingleValueExtendedProperties having been added to the draft email.
Same behavior noticed with Oulook 2019 on Office 365
Is this code correct to set custom email headers using SingleValueExtendedProperties with Outlook 2019 ?
How can I make Outlook 2019 aware of the new SingleValueExtendedProperties / x-header added to the draft message though the Exchange REST API ?
Edit 11/10/2021 : tested with makeEwsRequestAsync & test summary
Outlook 2019 build 2108 (Office 365)
Outlook on the web
Outlook 2019 build 1808 (Exchange 2016)
OWA Exchange 2016
Exchange REST API XMLHttpRequest
X-Custom-header correctly set server side but removed when sending the draft email from Outlook. If opening and sending the draft from OWA after having set the X-header from the addin in Outlook, X-Custom-header is preserved
OK
X-Custom-header correctly set server side but removed when sending the draft email from Outlook. If opening and sending the draft from OWA after having set the X-header from the addin in Outlook, X-Custom-header is preserved
OK
makeEwsRequestAsync()
OK
OK
X-Custom-header correctly set server side but removed when sending the draft email from Outlook. If opening and sending the draft from OWA after having set the X-header from the addin in Outlook, X-Custom-header is preserved
EWS request proxy error
What you are trying to do is not possible on Win32 Outlook Client. Your Step #2 (XMLHttpRequest) effectively creates two version of the item, one on the client and one on the server. When the item is eventually sent, one will overwrite the other (most likely the one sent from the client), and overrides the changes that you made.
setCustomHeaders in 1.8 was created to address this problem. setCustomHeaders, actually does not rely on the server for it's functionality, so it should work as long as your client supports 1.8.
Office 2019 (retail) does support 1.8. Office 2019 (volume-licensing) does not.
https://learn.microsoft.com/en-us/office/dev/add-ins/reference/requirement-sets/outlook-api-requirement-sets
Users on the volume licensed version will need to upgrade to get this support.

Teams Tab API access to Sharepoint FIle Contents causing 405 on OPTIONS call

In Microsoft Teams, I have crated an App that lists files of a certain type in a Tab
The use case is that the contents of the file need to be read by my Javascript
the Javascript in the Tab already successfully gets an ID Token and Access Token (via ADAL)
this code already successfully lists the DriveItems in the group the current logged in user can see
via https://graph.microsoft.com/v1.0/groups/${groupId}/drive/root/search(q='{pdf}');`
when I attempt to GET the DriveItem via
https://graph.microsoft.com/v1.0/groups/${groupId}/drive/items/${itemId}/content
where the itemId is returned from the first call
I successfully see the HTTP 302 from the https://graph.microsoft.com endpoint redirecting to https://<thesharepointsite>.sharepoint.com/<etc>
Axios (and the Microsoft Graph Javascript API) are successfully traversing to the redirect
Postman, with the same https://graph... URL with the AccessToken successfully downloads the binary content from the 302 redirect (so it is not an Auth issue)
PROBLEM
in Microsoft Teams, inside my Tab, the browser (built inside of the Teams desktop app) HTTP calls to https://<thesharepointside>.sharepoint.com respond with a 405 error on the OPTIONS call
usually this means there is a CORS issue, and so the solution is to add the domain to the validDomains of the app
Attempted Solution
the Manifest has the following entries in validDomains
"validDomains": [
...
"*.sharepoint.com",
"graph.microsoft.com",
"login.microsoftonline.com"
]
manually add the full domain the the Teams App's Manifest
use the suggested "{teamsitedomain}" as per https://learn.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema#validdomains
*.sharepoint.com as per above
use the Microsoft Graph Javascript APIs
In all instances, I get 405 on the OPTIONS call
No file download from within the Tab within Microsoft Teams.
Suggestions?
THIS MAY answer your question in the future
my code now does a https://graph.microsoft.com/v1.0/groups/${groupId}/drive/items/${itemId}
this is an Instance of DriveItem and returns a property on the JSON response:
#microsoft.graph.downloadUrl
as per Microsoft Graph API Download File content return Unauthorized 401 this is a short-lived URL you can traverse without Auth headers
the content of my file was returned successfully (no CORS issue)
I can now download the contents of the DriveItem within a Tab
I hope this helps someone

CORS request did not succeed

I have a problem when I want to create an authentication system using VueJs as the frontend (http://localhost:8080/#/login) and Laravel 5.6 as the backend. When I try to submit login form using the api login url http://127.0.0.1:8000/api/v1/login, I get the error message:
Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at http://127.0.0.1:8000/api/v1/login.
(Reason: CORS request did not succeed).
I don't know how to solve this problem.
Could anyone here help me to solve my problem?
NOTE : I have to install laravel-cors before
This is an old question, but I'll reply nonetheless.
For me this error was caused by a self-signed certificate. If you open developer tools, select the network tab, click the call that failed CORS you can see the security tab. Click it to open it. If a cert is giving you problems the text "An error occurred: SEC_ERROR_INADEQUATE_KEY_USAGE" should be visible.
To resolve this just go to the URL that gave you the CORS error, and accept the cert manually.
Cross Origin Resource Sharing is a mechanism that uses additional HTTP headers to tell a browser to allow the web application running on one origin (client) have permission to access selected resources from a server at a different origin.
Basically, your Vue app (http://localhost:8080) needs to be allowed access to your Laravel endpoint (http://127.0.0.1:8000/api/v1/login) This is to prevent me from hitting your Laravel endpoint from my malicious website and acting like an authenticated user.
Based on the docs, you need to add 'allowedOrigins' => ['*'], but that means you're opening up your backend to all requests. That's fine if it's a public API but in this context it doesn't sound like you want that. Instead, in this case it would be 'allowedOrigins' => ['localhost:8080'], so that your Vue app can consume your Laravel server.
You have to use either localhost or 127.0.0.1 for all the requests. In general in your code you should make calls to the server by just appending the URI to the current host, without re-adding the host and port in the URI string. If you load your page from a given host, for example 127.0.0.1 and then try to make an AJAX request to another host, for example www.host.com, the request gets blocked to prevent XSS attacks
It sounds like you are running this in dev mode via webpack currently? If that is correct and your workflow is that you are going to build the Vue application and have it co-reside with your Laravel backend then you just need to update config/index.js to have a proxyTable entry that forwards webpack requests to the correct dev Laravel backend server.
This would look something like this.
module.exports = {
dev: {
proxyTable: {
"/": "http://127.0.0.1:8000/api/v1/login"
}
}
}
There is additional information available on how this works; https://vuejs-templates.github.io/webpack/proxy.html
I was stuck with this error recently while I was trying to get one of our old websites hosted via Azure (App Services) up and running again.
Reason: CORS request did not succeed was the error showing in the browser console, however, it turned that for our case the URL mentioned in the CORS error doesn't exist anymore - its referring to the old https://******.azurewebsites.net service url we had (previous hosted in Azure - App Services).
So also check that the URL mentioned in the CORS-error is in fact working.
In my case the computer was not displaying the correct date and time. When I try to view the page I would get the "CORS request did not succeed." Once I updated to the correct time and date the page displayed normally.
I had to change the base URL of axios. I didn't notice it was https://, not http://
file: src\store\index.js
change the
axios.defaults.baseURL = 'https://127.0.0.1:8000/api'
to
axios.defaults.baseURL = 'http://127.0.0.1:8000/api'
Note: Make sure it's exactly same URL and Port. You can see that in terminal where you start the laravel application (php artisan serve).

Angular 2 - No 'Access-Control-Allow-Origin' header is present on the requested resource

When trying to make API Calls from my Angular 2 App to my API, I get the following error:
XMLHttpRequest cannot load http://localhost/myAPI/public/api/v1/auth/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 422.
I've been checking every single question on the web and anything releated to CORS, nothing solved my problem!
My Laravel API running on port 80. (localhost)
My angular 2 app running on port 3000. (localhost:3000)
I've been trying to enable cors in Laravel side with Cors middleware
The API calls are working using chrome web security off. The first answer here solves the problem, But I really want to stop using the CMD and unsecured chrome version everytime im testing my app.
Using chrome extension POSTMAN API calls to my API are working.
So.. What's wrong? Why my Angular 2 app cant get records from my API?
Ok. seem like need to configure apache for it.
i'm using xampp webserver, and I had to edit my httpd.conf as explained here to solve this.
Added this line:
Header set Access-Control-Allow-Origin "http://localhost:3000"
solved my problem.
Restarting apache is neccessary.
Open chrome inspect tool, switch to Network tab and inspect the request Angular2 sent.
In Headers->Response Headers, check whether there is Access-Control-Allow-Origin:* (I bet not)
If you are building an API, the easiest workaround is to add
if (Request::is("api/*")) {
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, If-Modified-Since, Cache-Control, Pragma");
}
in the beginning of routes.php, using a Middleware would be a better approach, but make sure it is working properly and adding the Access-Control-Allow-Origin to the response header.
//Add this middleware in your express app
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.header('access-Control-Allow-Origin', '*');
next();
});
I've been trying to enable cors in Laravel side with Cors middleware
Have you registered routes to handle OPTIONS requests?
If you simply add middleware to existing GET and POST routes, and the browser is making an OPTIONS request, the middleware is never reached.

Access Dynamics CRM 4 SPLA (IFD) DiscoveryService from CRM 2011 IFD

We have just upgraded from Microsoft Dynamics CRM 4 to Microsoft Dynamics CRM 2011. Most of the upgrade has gone smoothly, however I have some custom code (written for CRM 4) which uses the CrmDiscoveryService at the URL "https:///MSCRMServices/2007/SPLA/CrmDiscoverService.asmx" which worked fine on our Dynamics CRM 4 server but not with out Dynamics CRM 2011 server.
Our Dynamics CRM 2011 server is set up On Premise, as an IFD deployment. On the actual Dynamics CRM 2011 server box I can navigate to "https://:444/MSCRMServices/2007/SPLA/CrmDiscoveryService.asmx" and I am directed to the correct web service, however if I try to access this from any other computer I get a infinitely looped redirect.
Using Fidler I can read what is being sent when I try to navigate to the CrmDiscoveryService URL and the response, before I am redirected is:
HTTP/1.1 302 Found
Cache-Control: private
Content-Length: 237
Content-Type: text/html; charset=utf-8
Location: https://<server>:444/MSCRMServices/2007/SPLA/CrmDiscoveryService.asmx
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 06 Dec 2011 23:31:26 GMT
<html><head><title>Object moved</title></head><body>
<h2>Object moved to here.</h2>
</body></html>
I believe that Dynamics CRM is trying to redirect me to the actual page I have gone to, and thus it is looping into infinity.
I originally had this issue with the Discovery Service: http://social.microsoft.com/Forums/en-US/crmdeployment/thread/d92924d8-5982-4a11-ac66-602feb4542c8/?prof=required however I was able to correct this by allowing anonymous authentication to the folder the Discover Service was located in.
After some extensive searches I am yet to find anything on the Discovery Service infinite redirect issue I am now having.
Any help would be greatly appreciated.
So I've solved the problem, kind of...
I'll post it here so as anybody else experiencing the same thing will be able to figure it out out (there's nothing worse than seeing an empty thread for a problem that one is having).
It turns out that while I cannot access this URL via Internet Explorer, when used authenticating via IFD in custom code this works correctly.
I'd still be interested though in finding out why it works in my custom code but not Internet Explorer.

Resources