Microsoft Graph /users subscription no longer works - c#

We're using Microsoft.Graph to read /users and get notifications. This is the working example on how we subscribe:
var result = await _client.Subscriptions.Request().AddAsync(new Subscription() {
ChangeType = "updated,deleted",
NotificationUrl = /* skipped */,
ExpirationDateTime = DateTimeOffset.UtcNow.AddMinutes(10),
Resource = "/users",
}, token);
Up until 6th or 7th of December 2018 this was a valid code. Currently it returns:
Code: ExtensionError
Message: Operation: Create; Exception: [Status Code: Forbidden; Reason: Forbidden]
Inner error
Read /users works.
Read and subscribe to /users/some#email/contacts works.
Verification request on my callback url is received and properly processed.
I have an application token with Directory.Read.All and Contacts.Read application permissions.
Was there a change in permissions or API ?
UPDATE:
It is broken again approx 20th of January 2019.
Are there any updates on that?

I also encountered the same problem. The description is as follows: there is no Reston code, just code is forbidden:
{
"Error": {
"code": "ExtensionError",
"message": "Operation: Create; Exception: [Status Code: Forbidden; Reason: ]",
"innerError": {
"request-id": "81d5439d-aebb-41e4-9b8f-df8475a60f1e",
"date": "2019-12-24T09:01:32"
}
}
}
I don't know if it's Microsoft's problem. The error prompt is not comprehensive. I'm a little worried...

Related

how to get AWS SMS publish results in code

I've scoured the AWS documentation to see if there is a a way to get the SMS delivery log via code, but i'm at a miss, I can get the logs via cloud watch but I want to get them in code so if there is a failure ( like delivery.providerResponse
Unknown error attempting to reach phone) I can dequeue the number
this is my code for sending texts, it gets a response code OK all the time even if i've hit my credit limit, the number isnt valid. Viewing failures in the console is great and all, but i want to update my queue programmatically based on success/failure
Regex rgx = new Regex(#"^(07\d{8,12}|447\d{7,11})$");
foreach (var item in accountTextDatas)
{
if (rgx.IsMatch(item.Phone1))
{
item.Phone1 = ReplaceFirst(item.Phone1, "0", "+44");
}
await Task.Delay(2000);
var request = new PublishRequest()
{
Message = $"words go here"
PhoneNumber = item.Phone1,
};
var response = await client.PublishAsync(request);
context.Logger.LogInformation("Response Code to " + item.Phone1 + " " + response.HttpStatusCode);
}
You can fetch the delivery status logs in your code through the CloudWatch API
The CLI equivalent would be something like:
aws logs describe-log-streams --log-group-name sns/$REGION/$ACCOUNT_ID/DirectPublishToPhoneNumber/Failure
{
"logStreams": [
{
"logStreamName": "SOME_LOG_STREAM_NAME", ...
aws logs get-log-events --log-group-name sns/$REGION/$ACCOUNT_ID/DirectPublishToPhoneNumber/Failure --log-stream-name SOME_LOG_STREAM_NAME
{
"events": [
{
"timestamp": 1650659779468,
"message": "{\"notification\":{\"messageId\": ...

Keep getting "Exchange Web Services are not currently available for this request because" error?

We have an application that logs in as an exchange user and does simple tasks like delete / saves / sends emails etc. I'm seeing a lot of two errors in our Splunk report:
"Exchange Web Services are not currently available for this request because none of the Client Access Servers in the destination site could process the request"
and
"Problem deleting email [ item id: (item ID string) ] - The specified object was not found in the store., The process failed to get the correct properties."
I've read that it's important to include:
service.HttpHeaders.Add("X-AnchorMailbox", MailboxToAccess);
when impersonating users and that that may be the issue, but what about when you are just logging in as a user?
Here's the code where we set up the exchange service:
public ExchangeServiceClient(ILog logger, IContentTypeHelper contentTypeHelper)
{
_logger = logger;
_contentTypeHelper = contentTypeHelper;
if (EvidenceSettings.Default.AppEmailUserName.Equals("Windows Credentials", StringComparison.OrdinalIgnoreCase))
{
_exchangeService = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
_exchangeService.Url = new Uri(PartnerEvidenceSettings.Default.ExchangeServiceAddress);
}
else
{
_exchangeService = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
_exchangeService.Url = new Uri(EvidenceSettings.Default.ExchangeServiceAddress);
_exchangeService.Credentials = new WebCredentials(EvidenceSettings.Default.AppEmailUserName, EvidenceSettings.Default.AppEmailPassword);
_exchangeService.TraceEnabled = true;
_exchangeService.UseDefaultCredentials = false;
}
}
And here's an example of when we use the service (just a single example, but all pretty similar functions):
public void DeleteMailMessage(string identifier)
{
// If this email was an attachment in another email, then only delete the container email
if (identifier != null)
{
try
{
var ids = new[] { new ItemId(identifier) };
var responseCollection = _exchangeService.DeleteItems(ids, DeleteMode.MoveToDeletedItems, null, null);
foreach (var response in responseCollection)
{
if (response.Result == ServiceResult.Error)
{
_logger.Error($"Problem deleting email [ item id: {identifier} ] - {response.ErrorMessage}");
}
}
}
catch (Exception ex)
{
_logger.Error($"Error deleting email [ item id: {identifier} ]", ex);
}
}
}
My question is, do we need to be including the HTTPHEADERS, or is something else causing this issue? If it's not that, I'm not quite sure what could be causing this error.
Those two error are different and generally not related
"Exchange Web Services are not currently available for this request because none of the Client Access Servers in the destination site could process the request"
Generally this is a routing error so yes you should always included the X-AnchorMailbox header no matter if its impersonation or not. (Eg if you look at any Microsoft Mail client Outlook,OWA, Outlook Mobile you will always see these headers).
"Problem deleting email [ item id: (item ID string) ] - The specified object was not found in the store., The process failed to get the correct properties."
This is usually an Item error or permissions error eg no access to the Mailbox itself or your trying to access something like the Audit folder in the mailbox etc. It can also mean the Item in question has moved in the Mailbox.

Gmail Mail Api Working in Api explorer but not in code c#

I am using Gmail Api to get all the unread message in inbox , do some operations on it and then mark the mail as READ.
However when i do any of the below:
var markAsReadRequest = new ModifyThreadRequest { RemoveLabelIds = new[] { "UNREAD" } };
service.Users.Threads.Modify(markAsReadRequest, "xxx#gmail.com", email.ThreadId)
.Execute();
var markemail=new ModifyMessageRequest { RemoveLabelIds = new[] { "UNREAD" } };
service.Users.Messages.Modify(markemail, "xxx#gmail.com", email.Id)
.Execute();
I am getting Error:
Google.Apis.Requests.RequestError
Insufficient Permission [403]
Errors [
Message[Insufficient Permission] Location[ - ] Reason[insufficientPermissions] Domain[global]
]
The thing is i open Api explorer and run the same request and it works fine.
So not sure what am i doing wrong here.
gmail.users.threads.modify:
Modifies the labels applied to the thread. This applies to all messages in the thread.
This works and marks the email as UNREAD.
Found the issue had to add this on top:
static string[] Scopes = { mailService.Scope.GmailReadonly,GmailService.Scope.GmailModify };

fine uploader delete custom error message not coming back

I am having trouble getting a custom error message back from my file delete handler. I am not sure but it looks like the delete is handled differently to the upload.
From the docs:
You may return any response you like, as the XMLHttpRequest object will be passed to your onDeleteComplete handler for further examination. However, the response code you return is important to Fine Uploader, as it uses this to determine if the delete has succeeded or not. The following response codes indicate success for this specific request: 200, 202, and 204. Any other response code indicates a failure.
In my server handler for the delete I have this to catch the error and send back response to FineUploader.
catch (Exception ex)
{
//const string json = "{\"success\":false}";
const string json = "{\"success\":false,\"error\":\"THIS IS THE ERROR\"}";
//const string json = "{\"error\":\" HERE IS THE ERROR! \"}";
var response = (Response)json;
response.ContentType = "text/plain";
//response.StatusCode = HttpStatusCode.InternalServerError;
return response;
}
I have tried sending back {"success":false} along with the error, just {"success":false} and just the error. I have checked that the json is valid.
However it seems to do nothing at all. All that matters to FineUploader is response.StatusCode. If I send a fail response code then FineUploader recognises the error and displays the message for that code. It also comes back in errorReason in the onError callback.
If I do not set the response status code it defaults to OK and no error is raised.
I have looked at the example code for php and see this in the delete handler:
if (is_dir($target)){
$this->removeDir($target);
return array("success" => true, "uuid" => $uuid);
} else {
return array("success" => false,
"error" => "File not found! Unable to delete.".$url,
"path" => $uuid
);
}
Clearly, that code is sending back a "success":fail with a custom error message.
But I can't work out in that code what response status is being sent back.
Update 1: Here is the js on the client to handler the server response:
callbacks: {
onError: function(id, name, errorReason, xhrOrXdr) {
alert(qq.format("Error on file number {} - {}. Reason: {}", id, name, errorReason));
console.log(errorReason);
}
So, am I doing something wrong?
Update 2:
Ok, I have had a look at onDeleteComplete and my client code now looks like this:
callbacks: {
onDeleteComplete: function(id, xhr, isError) {
alert("onDeleteComplete => id is:" + id + " Is error?:" + isError);
},
onError: function(id, name, errorReason, xhrOrXdr) {
alert(qq.format("onError => Error on file number {} - {}. Reason: {}", id, name, errorReason));
console.log(errorReason);
},
Now when I delete a file in the browser I get the onError alert first and then the onDeleteComplete. In neither case can I find any way to show the error message I want to send back from my server handler. The onError always seems to just show the HttpStatus error message and not the one defined in my json response. The onDeleteComplete has no parameter to bring back the error.
I am not sure if it's just me but I found this confusing and inconsistent.
For uploads you can do this:
failedUploadTextDisplay: {
mode: "custom",
responseProperty: "errorMessage"
},
What this means is that your server can send back a custom response error and this will be displayed below the file in the event of an error.
So my C# Nancy server code does this on error:
catch (Exception ex)
{
FormResponse.success = false;
FormResponse.errorMessage = ex.Message;
return Response.AsJson(FormResponse).WithStatusCode(HttpStatusCode.BadRequest);
}
This sends back json that looks like this:
{"errorMessage":"A file with that name already exists and cannot be overwritten!","success":false}
FineUploader then shows this message under the file like this:
Which is great. However for file delete there is no such feature I can find.
So for unexpected delete failures I will have to find a workaround:
I have the onDeleteComplete callback which I assumed could use to get the error:
onDeleteComplete: function(id, xhr, isError) {
if (isError) {
console.log("Error in delete!!");
if (typeof xhrOrXdr != 'undefined' && xhrOrXdr != null) {
console.log("resp text=" + xhrOrXdr.responseText);
var t = JSON.parse(xhrOrXdr.responseText);
console.log(t['errorMessage']);
}
}
But this does not work because when isError = true the xhr object is null.
So there's no way to get the error in onDeleteComplete.
It would be nice if FineUploader had something like this:
failedDeleteTextDisplay: {
mode: "custom",
responseProperty: "errorMessage"
},
But it doesn't. So it looks like I have to handle the delete error in the OnError callback. But since I won't know which kind of action it is. Delete or Upload then I will have to send another parameter back in my json to handle the switch since I only need to change the default error message for failed deletes.
So, my final workaround for now is this. The onError handler deals with both delete and upload errors. My server now sends back another parameter in the json called 'actionType'. This can either be 'delete' or 'upload'. If it's a delete action error then some jquery hides the default error messages and shows the new one.
onError: function(id, name, errorReason, xhrOrXdr) {
if (typeof xhrOrXdr != 'undefined' && xhrOrXdr != null) {
var t = JSON.parse(xhrOrXdr.responseText);
// if the error was result of delete then show the custom message on the panel
if (t["actionType"] === "delete") {
$("#CustomError").html("Delete failed: " + t["errorMessage"] );
$("#ErrorContainer").hide();
}
}
},
UPDATE:
Well this is embarrassing. I raised this as a bug and it turns out it was my code at fault. This is a demonstration and reminder to me about the pitfalls of javascript. Id' been looking at this code for some time:
onDeleteComplete: function(id, xhr, isError) {
if (isError) {
console.log("Error in delete!!");
if (typeof xhrOrXdr != 'undefined' && xhrOrXdr != null) {
It was only when Ray looked at my bug report that he spotted an obvious error.
My function variable was called xhr but my code was looking for xhrOrXdr.
I just didn't see it. And since it's javascript there were no complaints in the console. I am used to coding in C# with Resharper where that kind of thing is impossible. Neither Resharper or VS intellisense were able to warn me.
So the bug was my bug and the onDelete callback works as described.
It's a learning process..

Unable to access AWS using a Facebook AssumeRoleWithWebIdentity credentials

Short version
Logged in as a Facebook user, I use my oAuth token to assume an IAM role on AWS. It returns what looks to be valid credentials, e.g. there is an AccessKeyId, SecretAccessKey that are similar length to our master keys.
When I try to use these credentials to access a DynamoDB table, I get one of two exceptions:
"The remote server returned an error: (400) Bad Request."; or
"The security token included in the request is invalid.".
I'm using the AWS C# SDK version 1.5.25.0
Long version
As I said above, I'm trying to access a DynamoDB table on AWS using credentials supplied by AmazonSecurityTokenServiceClient authorized by Facebook Identity as described in this AWS guide.
The policy for the IAM role that I've created is:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
],
"Sid": "Stmt1372350145000",
"Resource": [
"*"
],
"Effect": "Allow"
}
]
}
How I get the credentials:
The user logs in with Facebook using oAuth.
Using the access token, I assume the IAM role using a AmazonSecurityTokenServiceClient.AssumeRoleWithWebIdentity with a request.
This returns what looks like to be valid credentials, e.g. a AccessKeyId, SecretAccessKey that are similar length to our master keys.
using (var tokenServiceClient = new AmazonSecurityTokenServiceClient(RegionEndpoint.USEast1))
{
var request = new AssumeRoleWithWebIdentityRequest
{
DurationSeconds = (int)TimeSpan.FromHours(1).TotalSeconds,
ProviderId = "graph.facebook.com",
RoleArn = "arn:aws:iam::193557284355:role/Facebook-OAuth",
RoleSessionName = result.id,
WebIdentityToken = FBClient.AccessToken
};
var response = tokenServiceClient.AssumeRoleWithWebIdentity(request);
AWSAssumedRoleUser = response.AssumeRoleWithWebIdentityResult.AssumedRoleUser;
AWSCredentials = response.AssumeRoleWithWebIdentityResult.Credentials;
}
How I use these credentials:
Using the returned credentials, I then try to access a AWS DynamoDB resource.
using (var client = new AmazonDynamoDBClient(AWSCredentials.AccessKeyId, AWSCredentials.SecretAccessKey, AWSCredentials.SessionToken, RegionEndpoint.USEast1))
{
var context = new DynamoDBContext(client);
var data = context.Scan<SomeData>();
}
This returns "The remote server returned an error: (400) Bad Request." when trying to Scan the table.
This is where the variation in the exception message is; if I omit the AWSCredentials.SessionToken from the above AmazonDynamoDBClient
using (var client = new AmazonDynamoDBClient(AWSCredentials.AccessKeyId, AWSCredentials.SecretAccessKey, RegionEndpoint.USEast1))
{
var context = new DynamoDBContext(client);
var data = context.Scan<SomeData>();
}
This returns "The security token included in the request is invalid." when trying to Scan the table.
Question
At this point I cannot tell what is wrong, are the credentials invalid or that I'm not passing everything through that is needed to AWS.
Can anyone offer any insight to what is wrong or how I could debug this further?
I cross-posted my question to the AWS forums and received an answer from an Amazon engineer.
https://forums.aws.amazon.com/message.jspa?messageID=465057
DynamoDBContext object invokes DescribeTable on the target table (and caches this data, so for optimal performance you would want to keep the context object around for as long as possible, so this call is only done once per target table). Modify your policy as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem",
"dynamodb:DescribeTable"
],
"Sid": "Stmt1372350145000",
"Resource": [
"*"
],
"Effect": "Allow"
}
]
}

Categories

Resources