How to purge Front Door Standard/Premium (Preview) endpoint using code - purge

In the subscription (name: test-subscription) in the resource group (name: test-resource-group), I created Front Door Standard/Premium (Preview) (name: test-front-door-profile) with endpoint test-front-door-profile-endpoint.z01.azurefd.net and added new endpoint (endpoint name: test-endpoint.z01.azurefd.net).
For example: I created a request: https://test-endpoint.z01.azurefd.net/test/pictures/abcdefghi.jpeg. How can I purge test-endpoint.z01.azurefd.net/test/pictures/* using code?
I tried with this code, and different variants of contentPaths
using Microsoft.Azure.Management.FrontDoor;
using Microsoft.Azure.Management.FrontDoor.Models;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Rest;
...
public async Task PurgeContentAsync()
{
var authContext = new AuthenticationContext(Authority);
var credential = new ClientCredential(ClientId, ClientSecret);
var authResult = await authContext.AcquireTokenAsync(_resource, credential);
var frontDoor = new FrontDoorManagementClient(new TokenCredentials(authResult.AccessToken)) { SubscriptionId = _subscriptionId };
var contentPaths = new List<string> { "/test-endpoint.z01.azurefd.net/test/pictures/*" };
var contentFilePaths = new PurgeParameters(contentPaths);
await frontDoor.Endpoints.BeginPurgeContentAsync("test-resource-group", "test-front-door-profile", contentFilePaths);
}
but I always get exception:
The exception Microsoft.Azure.Management.FrontDoor.Models.ErrorResponseException was unhandled on the service and could not be serialized for transferring to the client.
Detailed Remote Exception Information: Microsoft.Azure.Management.FrontDoor.Models.ErrorResponseException: Operation returned an invalid status code 'NotFound'
I tried with Microsoft.Azure.Management.Cdn library but I am getting back the same exception.

Related

Sending mail multiple times by Microsoft Graph

Blazor server application
I have a web appliction that is using AzureAd and OpenIdConnect to login to this application.
I am sending mail by using Microsoft graph and I am using the example in Microsoft doc with some changes like this:
#inject Microsoft.Graph.GraphServiceClient GraphServiceClient
#inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
var message = new Message
{
Subject = "Meet for lunch?",
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = "The new cafeteria is open."
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "fannyd#contoso.onmicrosoft.com"
}
}
},
CcRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "danas#contoso.onmicrosoft.com"
}
}
}
};
var saveToSentItems = false;
try
{
await GraphServiceClient.Me
.SendMail(message,saveToSentItems)
.Request()
.PostAsync();
}
catch(Exception ex)
{
ConsentHandler.HandleException(ex);
}
Scenario of the error
This works perfect but just for one time , if I try to send the same email again it doesn't work and I got no error but just redirect me to empty page.
If I logout and login again, then it works fine.
The error that I got in the second time:
Message = "IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent. "
MsalUiRequiredException = {"No account or login hint was passed to the AcquireTokenSilent call. "}
My Question
How can fix the code up to send multi emails?. I think that I have a problem with token but I don't know where should I start?.
Thanks
Add the other catch block to retrieve the specific issue if we have any related to permissions or other ServiceExceptions.
try
{
SendMail(); // Sending mail code here.
}
catch (Microsoft.Graph.ServiceException e)
{
// get the error here if we have any.
}
After some search, I think that I have to move the the permission Delegated permissions to Application Permissions like this:
Why should I use application permission?
In my case the user logged in for the first time and clicked on the button then the email will be send, but in the second time the application has to communicate with API graph without interaction from the user, that means without user and this exactly what I need(application permission).
I adjust the code like the following:
Client credentials provider:
The client credential flow enables service applications to run without user interaction. Access is based on the identity of the application. this is from Microsoft doc
private GraphServiceClient CreateGraphServiceClient()
{
// The client credentials flow requires that you request the
// /.default scope, and preconfigure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { "https://graph.microsoft.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";
// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
return new GraphServiceClient(clientSecretCredential, scopes);
}
Send mail with UserId, you can see the code in Microsoft doc:
puplic SendMyEmail()
{
GraphServiceClient graphClient = CreateGraphServiceClient;
var message = new Message
{
Subject = "Meet for lunch?",
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = "The new cafeteria is open."
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "fannyd#contoso.onmicrosoft.com"
}
}
},
CcRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "danas#contoso.onmicrosoft.com"
}
}
}
};
var saveToSentItems = false;
//See GetUserId down
string userId = await GetUserId();
await graphClient.Users[UserId]
.SendMail(message,saveToSentItems)
.Request()
.PostAsync();
}
}
UserId:
To get user Id you need AuthenticationStateProvider, this has to inject in the service of your application and then add to the constructor of your class, then you can use it.
puplic class MyClass
{
private readonly MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler;
private readonly AuthenticationStateProvider authenticationState;
puplic MyClass(
MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler,
AuthenticationStateProvider authenticationState)
{
this.authenticationState = authenticationState;
this.ConsentHandler = ConsentHandler;
}
public async Task<string> GetUserId()
{
var authSate = await authenticationState.GetAuthenticationStateAsync();
return authSate.User.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");
}
//Here your
private GraphServiceClient CreateGraphServiceClient() { ...}
puplic SendMyEmail() {....}
}

HttpClient not sending post data to NancyFX endpoint

I am doing some integration testing of my web API that uses NancyFX end points. I have the xUnit test create a test server for the integration test
private readonly TestServer _server;
private readonly HttpClient _client;
public EventsModule_Int_Tester()
{
//Server setup
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_server.AllowSynchronousIO = true;//Needs to be overriden in net core 3.1
_client = _server.CreateClient();
}
Inside a Test Method I tried the following
[Fact]
public async Task EventTest()
{
// Arrange
HttpResponseMessage expectedRespone = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
var data = _server.Services.GetService(typeof(GenijalnoContext)) as GenijalnoContext;
//Get come random data from the DBcontext
Random r = new Random();
List<Resident> residents = data.Residents.ToList();
Resident random_residnet = residents[r.Next(residents.Count)];
List<Apartment> apartments = data.Apartments.ToList();
Apartment random_Apartment = apartments[r.Next(apartments.Count)];
EventModel model = new EventModel()
{
ResidentId = random_residnet.Id,
ApartmentNumber = random_Apartment.Id
};
//Doesnt work
IList<KeyValuePair<string, string>> nameValueCollection = new List<KeyValuePair<string, string>> {
{ new KeyValuePair<string, string>("ResidentId", model.ResidentId.ToString()) },
{ new KeyValuePair<string, string>("ApartmentNumber", model.ApartmentNumber.ToString())}
};
var result = await _client.PostAsync("/Events/ResidentEnter", new FormUrlEncodedContent(nameValueCollection));
//Also Doesnt work
string json = JsonConvert.SerializeObject(model, Formatting.Indented);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.PostAsync("/Events/ResidentEnter", httpContent);
//PostAsJsonAsync also doesnt work
// Assert
Assert.Equal(response.StatusCode, expectedRespone.StatusCode);
}
The NancyFX module does trigger the endpoint and receives the request but without the body
What am I doing wrong? Note that the NancyFX endpoint has no issue transforming a Postman call into a valid model.
The NancyFX endpoint
Alright I fixed it, for those curious the issue was that the NancyFX body reader sometimes does not properly start reading the request body. That is that the stream reading position isn't 0 (the start) all the time.
To fix this you need to create a CustomBoostrapper and then override the ApplicationStartup function so you can set up a before request pipeline that sets the body position at 0
Code below
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
pipelines.BeforeRequest.AddItemToStartOfPipeline(ctx =>
{
ctx.Request.Body.Position = 0;
return null;
});
}

How to move a blob document from one container to another with metadata from azure function?

I am trying to copy a blob document from one container to another along with the metadata. I have tried the following code from azure function but getting error mentioned in the code.
HTTP Request:
{
"SourceUrl": "https://devstorage.blob.core.windows.net/test-docs/123.jpeg",
"DestinationUrl": "https://devstorage.blob.core.windows.net/test-docs-completed/123.jpeg"
}
Azure Function Code:
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, ILogger log)
{
string reqAsString = await req.Content.ReadAsStringAsync();
MoveProcessedDocumentRequest blobCopyRequest = JsonConvert.DeserializeObject<MoveProcessedDocumentRequest>(reqAsString);
CloudBlockBlob cloudBlockSource = new CloudBlockBlob(new Uri(blobCopyRequest.SourceUrl));
await cloudBlockSource.FetchAttributesAsync();
CloudBlobContainer cloudBlockDestinationContainer = new CloudBlockBlob(new Uri(blobCopyRequest.DestinationUrl)).Container;
string name = cloudBlockSource.Uri.Segments.Last();
CloudBlockBlob cloudBlockDestination;
cloudBlockDestination = cloudBlockDestinationContainer.GetBlockBlobReference(name);
// Copy metadata
foreach (var meta in cloudBlockSource.Metadata)
{
cloudBlockDestination.Metadata.Add(new KeyValuePair<string, string>(meta.Key, meta.Value));
}
await cloudBlockDestination.StartCopyAsync(cloudBlockSource);
// Exception: Microsoft.Azure.Storage.Common: The specified resource does not exist.
return req.CreateResponse(HttpStatusCode.OK);
}
You should modify your code with CloudBlobContainer instance.
Change:
CloudBlobContainer cloudBlockDestinationContainer = new CloudBlockBlob(new Uri(blobCopyRequest.DestinationUrl)).Container;
To:
var uri = new Uri("blobCopyRequest.DestinationUrl");
var storage = new StorageCredentials("your account name", "your storage key");
CloudBlobContainer cloudBlockDestinationContainer = new CloudBlobContainer(uri, storage);
And the DestinationUrl is destcontainer url.
HTTP Request:
{
"SourceUrl": "https://devstorage.blob.core.windows.net/test-docs/123.jpeg",
"DestinationUrl": "https://devstorage.blob.core.windows.net/test-docs-completed"
}

Microsoft Graph: Current authenticated context is not valid for this request

I had an app that used MSAL and the v2.0 endpoint to sign in users and get token.
I recently changed it to ADAL and the normal AAD endpoint (also changing the app), and now when I try to use the GraphService I get the following error: Current authenticated context is not valid for this request
My user is admin
All permissions have been delegated
The token is successfully retrieved
Here is the code I use:
public static GraphServiceClient GetAuthenticatedClient()
{
GraphServiceClient graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
string accessToken = await SampleAuthProvider.Instance.GetUserAccessTokenAsync();
// Append the access token to the request.
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
}));
return graphClient;
}
Calling the method, where the actual error happens:
try
{
// Initialize the GraphServiceClient.
GraphServiceClient graphClient = SDKHelper.GetAuthenticatedClient();
// Get events.
items = await eventsService.GetMyEvents(graphClient);
}
catch (ServiceException se)
{
}
Getting the token:
public async Task<string> GetTokenAsync()
{
ClientCredential cc = new ClientCredential(appId, appSecret);
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/tenant.onmicrosoft.com");
AuthenticationResult result = await authContext.AcquireTokenAsync("https://graph.microsoft.com", cc);
return result.AccessToken;
}
Can't find anything on this online so I am not sure how to continue.
Error:
This exception is caused by the token acquired using the client credentials flow. In this flow, there is no context for Me.
To fix this issue, you need to specify the whose event you want to get. Or you need to provide the delegate-token.
code for your reference:
//var envens=await graphClient.Me.Events.Request().GetAsync();
var envens = await graphClient.Users["xxx#xxx.onmicrosoft.com"].Events.Request().GetAsync();

How do I authenticate OneDrive for Business with Service to Service oauth2 authentication?

The tutorial for OneDrive for Business (here: https://dev.onedrive.com/auth/aad_oauth.htm)
However, I don't want the user to have to login as I'm building a web API - I want the app to login. So, I have followed the tutorial for service to service authentication (here: https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx) which gets me an access token.
However, when I try to authenticate with the service I get an error saying "unsupported app only token". The code I'm using is below (btw, I'm using RestSharp):
public string GetAccessToken()
{
var client = new RestClient("https://login.microsoftonline.com/<tenant>/oauth2");
var request = new RestRequest("token", Method.POST);
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", <client_id>);
request.AddParameter("client_secret", <client_secert);
request.AddParameter("resource", "https://<tenant>-my.sharepoint.com/");
var response = client.Execute(request);
var content = response.Content;
var authModel = JsonConvert.DeserializeObject<AuthResponseModel>(content);
return authModel.AccessToken;
}
this gets me the access token
This is how I try to access my drive:
public string GetDrive()
{
var accessToken = GetAccessToken();
var client = new RestClient("https://<tenant>-my.sharepoint.com/_api/v2.0/");
var request = new RestRequest("drive", Method.GET);
request.AddHeader("Authorization: Bearer", accessToken);
var response = client.Execute(request);
var content = response.Content;
return content;
}
Does anyone have any tips? This is getting slightly maddening.