I am trying to write a local console application which will swap an Azure Web App slot using the Azure REST API. Using the following code I get a 401 (Unauthorized) response:
public async Task Swap(string subscription, string resourceGroup, string site, string slot)
{
var client = new HttpClient();
var url =
$"https://management.azure.com/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Web/sites/{site}/applySlotConfig?api-version=2016-08-01";
var data = new {preserveVnet = true, targetSlot = slot};
var message = new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Post,
Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json")
};
var response = await client.SendAsync(message);
Console.WriteLine(response.StatusCode);
}
I know I need to put in some kind of credentials but what I have found seems to apply to apps using Azure AD for authentication. This will be a publicly accessible web app with anonymous authentication.
Generally speaking you need to attach a Authorization header to the request with the Auth token. There are numerous ways of getting it, see this link or this.
This is how I managed to do it (using the provided links):
private async Task<string> GetAccessToken(string tenantName, string clientId, string clientSecret)
{
var authString = "https://login.microsoftonline.com/" + tenantName;
var resourceUrl = "https://management.azure.com/";
var authenticationContext = new AuthenticationContext(authString, false);
var clientCred = new ClientCredential(clientId, clientSecret);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resourceUrl, clientCred);
var token = authenticationResult.AccessToken;
return token;
}
And then in my previous method:
public async Task Swap(string subscription, string resourceGroup, string site, string slot)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await GetAccessToken("XXX", "XXX", "XXX"));
var url =
$"https://management.azure.com/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Web/sites/{site}/applySlotConfig?api-version=2016-08-01";
var data = new {preserveVnet = true, targetSlot = slot};
var message = new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Post,
Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json")
};
var response = await client.SendAsync(message);
Console.WriteLine(response.StatusCode);
}
Related
this is my code via asp.net web form:
public string GetAccessToken()
{
ServicePointManager.Expect100Continue=true;
string accessToken = "";
System.Net.ServicePointManager.SecurityProtocol=System.Net.SecurityProtocolType.Tls12;
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("en_US"));
var clientId = "<"+PAYPAL_CLIENT_ID+">";
var clientSecret = "<"+PAYPAL_SECRET_KEY+">";
var bytes = Encoding.UTF8.GetBytes(clientId+":"+clientSecret);
client.DefaultRequestHeaders.Authorization=new AuthenticationHeaderValue("Basic", Convert.ToBase64String(bytes));
var keyValues = new List<KeyValuePair<string, string>>();
keyValues.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
var responseMessage = client.PostAsync("https://api.sandbox.paypal.com/v1/oauth2/token", new FormUrlEncodedContent(keyValues));
accessToken= responseMessage.Status.ToString();
}
return accessToken;
}
But I get this error:
Id = 9, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}" in AccessToken
client.PostAsync is an asynchronous method that returns a Task object. You either need to await it (this is the preferred approach), but that would require a change to the signature of the GetAccessToken() function (and probably to the upstream code) or simply do the following:
var responseTask = client.PostAsync("https://api.sandbox.paypal.com/v1/oauth2/token", new FormUrlEncodedContent(keyValues));
responseTask.Wait();
var responseMessage = responseTask.Result;
I am using Botframework adaptive dialog template (c#). I already obtained a token from a HttpRequest and saved it as a conversation state property conversation.token, now I am trying to use this token to make another API call with HttpRequest. But from the official document of HttpRequest Class, it seems there is no options to add the authentication token. I tried to add the token in the Headers, but did not work, it showed 401 Unauthorized error. How should the authorization be handled in HttpRequest in adaptive dialog?
new HttpRequest()
{
Url = "http://example.com/json",
ResultProperty = "conversation.httpResponse",
Method = HttpRequest.HttpMethod.GET,
ResponseType = HttpRequest.ResponseTypes.Json,
Headers = new Dictionary<string, AdaptiveExpressions.Properties.StringExpression>()
{
{"Authorization", "Bearer ${conversation.token.content.token}"},
},
},
new SendActivity("${conversation.httpResponse}"),
Instead of using HttpRequest, I made the API call inside CodeAction with custom code.
First make a POST request to get the token, then make a GET request to call the main API. In the GET request, the authorization can be added in this way: client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);.
new CodeAction(async (dc, options) =>
{
var my_jsondata = new
{
Username = "username",
Password = "password"
};
var json = JsonConvert.SerializeObject(my_jsondata);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var Tokenurl = "https://example.com/token?HTTP/1.1";
using var Tokenclient = new HttpClient();
var Tokenresponse = await Tokenclient.PostAsync(Tokenurl, data);
string Toeknresult = Tokenresponse.Content.ReadAsStringAsync().Result;
var Tokenjo = JObject.Parse(Tokenresult);
using var client = new HttpClient();
var url = "https://example.com/mainapi?HTTP/1.1";
var accessToken = Tokenjo["token"];
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var response = await client.GetAsync(url);
string result = response.Content.ReadAsStringAsync().Result;
dc.State.SetValue("conversation.httpresponse", response);
dc.State.SetValue("conversation.result", result);
return await dc.EndDialogAsync();
}),
How can I get ID Token from custom token?
[Fact]
public void Get_ID_Token_For_Service_Account_Test()
{
using (Stream stream = new FileStream(ServiceAccountJsonKeyFilePath, FileMode.Open, FileAccess.Read))
{
ServiceAccountCredential credential = ServiceAccountCredential.FromServiceAccountData(stream);
FirebaseApp.Create(new AppOptions
{
Credential = GoogleCredential.FromServiceAccountCredential(credential),
ServiceAccountId = ServiceAccountId,
});
var uid = "Some UID";
var additionalClaims = new Dictionary<string, object>
{
{"dmitry", "pavlov"}
};
string customToken = FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid, additionalClaims).Result;
string idToken= null; // How to get this?
FirebaseToken token = FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken, CancellationToken.None).Result;
Assert.NotNull(token);
Assert.True(token.Claims.ContainsKey("dmitry"));
}
}
I see samples for some other languages/platforms but not for C# - how to get ID token via current user here - Retrieve ID tokens on clients. But for C# neither UserRecord nor FirebaseAuth provides ID Token. Any pointers are much appreciated.
I have found the way to get the ID token in FirebaseAdmin integration tests - see method SignInWithCustomTokenAsync. The only thing I have to adjust was base URL: according to Firebase Auth REST API documentation it should be
https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken
The API KEY refers to the Web API Key, which can be obtained on the project settings page in your admin console.
So the adjusted code looks like this:
private static async Task<string> SignInWithCustomTokenAsync(string customToken)
{
string apiKey = "..."; // see above where to get it.
var rb = new Google.Apis.Requests.RequestBuilder
{
Method = Google.Apis.Http.HttpConsts.Post,
BaseUri = new Uri($"https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken")
};
rb.AddParameter(RequestParameterType.Query, "key", apiKey);
var request = rb.CreateRequest();
var jsonSerializer = Google.Apis.Json.NewtonsoftJsonSerializer.Instance;
var payload = jsonSerializer.Serialize(new SignInRequest
{
CustomToken = customToken,
ReturnSecureToken = true,
});
request.Content = new StringContent(payload, Encoding.UTF8, "application/json");
using (var client = new HttpClient())
{
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var parsed = jsonSerializer.Deserialize<SignInResponse>(json);
return parsed.IdToken;
}
}
I want to use microsoft graph in web api which is using .net core 2.0, I want to authenticate user without login prompt.
Following is the code I have used, Please correct me if my method is wrong.
string clientId = "";
string clientsecret = "";
string tenant = "";
string resourceURL = "https://graph.microsoft.com";
string userMail = "testuser3#company.com";
public async Task<string> GetMyEmailUser()
{
try
{
var result = "";
string AzureADAuthority = "https://login.microsoftonline.com/companyname.com";
AuthenticationContext authenticationContext = new AuthenticationContext(AzureADAuthority, false);
var credential = new ClientCredential(clientId, clientsecret);
var authenticationResult = authenticationContext.AcquireTokenAsync(resourceURL, credential).Result;
var token = authenticationResult.AccessToken;
using (var confClient = new HttpClient())
{
var url = "https://graph.microsoft.com/v1.0";
confClient.BaseAddress = new Uri(url);
confClient.DefaultRequestHeaders.Accept.Clear();
confClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
confClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = confClient.GetAsync(url + "/me/mailFolders/inbox/messages?$filter=isRead eq false&$top=100").Result;
var jsonString = JObject.Parse(await response.Content.ReadAsStringAsync());
IUserMessagesCollectionPage myDetails = JsonConvert.DeserializeObject<IUserMessagesCollectionPage>(jsonString["value"].ToString());
}
I am new to microsoft graph and would really appreciate your help. Thanks.
I'm trying to figure out how to delete an AppRoleAssignment from either an Group or a User using the Graph API for Azure Active Directory. I'm using the .NET SDK (Microsoft.Azure.ActiveDirectory.GraphClient).
I've tried using the standard DeleteAsync method that's on every IEntityBase, but it fails with an error. It's issuing an HTTP request that looks like this:
DELETE /{tenantId}/directoryObjects/{appRoleAssignment ObjectID}/Microsoft.DirectoryServices.AppRoleAssignment?api-version=1.5
which fails with a 400 Bad Request with the error "Direct queries to this resource type are not supported."
This isn't the correct way to delete AppRoleAssignments using the Graph API according to this Microsoft blog post which says you need to do an HTTP request that looks like:
DELETE /{tenantId}/users/{user object ID}/appRoleAssignments/{appRoleAs}?api-version=1.5
If I do a manual HTTP request using HttpClient using that URL format, it works, but I want to know how to do this within the bounds of the .NET library rather than doing manual HTTP requests myself.
How do I delete AppRoleAssignments via the .NET library?
While it is not fixed, you can make a manual HTTP-request, but still using Azure AD SDK to acqure the token. Something like this:
var tenantId = "<guid> tenant id";
var appId = "<guid> your Azure app id";
var appKey = "your app key";
var authority = "i.e. https://login.windows.net/mycompany.onmicrosoft.com";
var graphUrl = "https://graph.windows.net/";
public async Task RemoveRoleFromUser(Guid userId, string roleObjectId) {
var uri = string.Format("{0}/users/{1}/appRoleAssignments/{2}?api-version=1.5", tenantId, userId, roleObjectId);
await ExecuteRequest<object>(uri, HttpMethod.Delete);
}
private async Task<T> ExecuteRequest<T>(string uri, HttpMethod method = null, Object body = null) where T : class {
if (method == null) method = HttpMethod.Get;
T response;
var token = await AcquireTokenAsyncForApplication();
using (var httpClient = new HttpClient { BaseAddress = getServicePointUri() }) {
var request = new HttpRequestMessage(method, uri);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
if (body != null) {
request.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
}
var responseMessage = await httpClient.SendAsync(request).ConfigureAwait(false);
responseMessage.EnsureSuccessStatusCode();
response = await responseMessage.Content.ReadAsAsync<T>();
}
return response;
}
private async Task<string> AcquireTokenAsyncForApplication() {
ClientCredential clientCred = new ClientCredential(appId, appKey);
var authenticationContext = new AuthenticationContext(authority, false);
AuthenticationResult authenticationResult = authenticationContext.AcquireToken(graphUrl, clientCred);
return authenticationResult.AccessToken;
}
private Uri getServicePointUri() {
Uri servicePointUri = new Uri(graphUrl);
Uri serviceRoot = new Uri(servicePointUri, tenantId);
return serviceRoot;
}
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
user = (User) await client.Users.GetByObjectId(objectId).ExecuteAsync();
var roleId = "";
await user.AppRoleAssignments.Where(t=>t.ObjectId==roleId).FirstOrDefault().DeleteAsync();
The following websites might be helpful:
https://github.com/AzureADSamples/WebApp-RoleClaims-DotNet
https://github.com/AzureADSamples/WebApp-GraphAPI-DotNet