I need list of Azure storage from my subscription ID and authentication token.
I am doing code as per reference -`
https://msdn.microsoft.com/en-us/library/azure/ee460787.aspx?f=255&MSPPError=-2147217396
But I am not able to get that data and in response I am only getting code 401 Unauthorized access
I have tried code in c# as per below -
Get Authorization Token -
private static string GetAuthorizationToken()
{
ClientCredential cc = new ClientCredential(ClientId, ServicePrincipalPassword);
var context = new AuthenticationContext("https://login.windows.net/" + AzureTenantId);
var result = context.AcquireTokenAsync("https://management.azure.com/", cc);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
return result.Result.AccessToken;
}
And then
AuthToken = GetAuthorizationToken();
TokenCredentials = new TokenCredentials(AuthToken);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://management.core.windows.net/<My Subscription ID>/services/storageservices");
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + AuthToken);
request.ContentType = "application/json";
request.Method = "GET";
//request.Headers["Authorization"] = "Bearer " + AuthToken; // Also tried this
request.Headers["x-ms-version"] = "2016-05-31";//
//https://management.core.windows.net/<subscription-id>/services/storageservices
//header - "x-ms-version"
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
//ex.Message;
}
Please suggest any solution to get storage account list from Subscription ID and Authentication token. and if you have any better solution other then this to get storage list then also please suggest.
I use the below function to create similar requests:
private static async Task<HttpWebRequest> createHttpRequestWithToken(Uri uri)
{
HttpWebRequest newRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
string clientId = ConfigurationManager.AppSettings["ClientId"]);
string clientSecret = ConfigurationManager.AppSettings["ClientSecret"]);
ClientCredential creds = new ClientCredential(clientId, clientSecret);
AuthenticationContext authContext = new AuthenticationContext(string.Format("https://login.microsoftonline.com/{0}/", ConfigurationManager.AppSettings["OrganizationId"]));
AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://management.core.windows.net/", creds);
newRequest.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + authResult.AccessToken);
return newRequest;
}
And create request like this:
HttpWebRequest request = createHttpRequestWithToken(uri).Result;
Additionally, Windows Azure Service Management API needs to be granted permission to access the resources. This can be done in the Configure tab in AD Service Principal.
To list all the storage accounts available under the subscription, you could try to use:
GET /subscriptions/{subscriptionId}/providers/Microsoft.Storage/storageAccounts?api-version=2016-01-01
the following sample code works fine on my side, please refer to it.
string tenantId = "xxxx";
string clientId = "xxxx";
string clientSecret = "xxxx";
string subscriptionid = "xxxx";
string authContextURL = "https://login.windows.net/" + tenantId;
var authenticationContext = new AuthenticationContext(authContextURL);
var credential = new ClientCredential(clientId, clientSecret);
var result = await authenticationContext.AcquireTokenAsync(resource: "https://management.azure.com/", clientCredential: credential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(string.Format("https://management.azure.com/subscriptions/{0}/providers/Microsoft.Storage/storageAccounts?api-version=2016-01-01", subscriptionid));
request.Method = "GET";
request.Headers["Authorization"] = "Bearer " + token;
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
//ex.Message;
}
response in fiddler looks like this.
Besides, please make sure if you assign the application to a role, if not assign the application to a role, 403 error will appear.
Related
The goal it use Graph API to send an email.
I am able to get the Authorization token by using the below code - https://login.microsoftonline.com/Some_Tenant_ID/oauth2/v2.0/authorize?client_id=SOME_Client_ID&response_type=code&redirect_uri=https://localhost&response_mode=query&scope=offline_access%20user.read%20mail.read&state=12345
The scope is user.read and mail.send with offline access. Now from using this authorization code, I want to get the refresh token. From my understanding this should work without any problem but for some reason the code is breaking at this line var httpResponse = (HttpWebResponse)request.GetResponse(); and I not sure why.
The exception code error 400 Bad Request.
my console output.
Can any one help me here and is there another way to get the Access token and/or refresh token from Authorization token. the end goal is to send email from graph API.
string tokenUrl = "https://login.microsoftonline.com/myAppTenantID/oauth2/token";
//string tokenUrl = "https://login.microsoftonline.com/myAppTenantID/oauth2/v2.0/token"; I have tried this URL too
string grant_type= "authorization_code";
string ClientID = "MyAppClientID";
string Auth_Code = "My Auth Code";
string RedirectURI = "https://localhost";
string ClientSecret = "my App secret";
Dictionary<string, string> res_dic = null;
string TargetURL = String.Format(tokenUrl);
var request = (System.Net.HttpWebRequest)WebRequest.Create(TargetURL);
request.ContentType = "application/x-www-form-urlencoded";
string RefreshToken = null;
string requestBody = String.Format(#"client_id={0}&scope=user.read%20mail.read&code={1}&redirect_uri={2}&grant_type=authorization_code&client_secret={3}", ClientID, Auth_Code,RedirectURI, ClientSecret);
request.Method = "POST";
using (var streamwriter = new StreamWriter(request.GetRequestStream()))
{
Console.WriteLine("stage 0....");
streamwriter.Write(requestBody);
streamwriter.Flush();
streamwriter.Close();
}
try
{
Console.WriteLine("stage 1....");
//Console.WriteLine("prting response"+ (HttpWebResponse)request.GetResponse());
var httpResponse = (HttpWebResponse)request.GetResponse();
Console.WriteLine("Stage 2....");
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
Console.WriteLine("Stage 3");
string Result = streamReader.ReadToEnd();
string StatusCode = httpResponse.StatusCode.ToString();
res_dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(Result);
}
}
catch (WebException ex)
{
Console.WriteLine("stage 4");
string ErrorMessage = ex.Message.ToString();
Console.WriteLine(ErrorMessage);
}
RefreshToken = res_dic["refresh_token"].ToString();
}
This is better for you to debug for full error message, there are many situations where this error occurs.
The scope in your code needs to add offline_access because refresh_token will be only provided if offline_access scope is requested.
You could use SDK. Code sample here:
string[] scopes = new string[] { "", "" };
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithRedirectUri(redirectUri)
.WithClientSecret(clientSecret)
.WithAuthority(authority)
.Build();
AuthorizationCodeProvider auth = new AuthorizationCodeProvider(app, scopes);
GraphServiceClient graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) => {
// Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
var authResult = await app.AcquireTokenByAuthorizationCode(scopes, auth_code).ExecuteAsync();
// Add the access token in the Authorization header of the API request.
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
})
);
And this API is used for sending mail, you need to add Mail.Send permission first.
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;
await graphClient.Me
.SendMail(message,saveToSentItems)
.Request()
.PostAsync();
I have a web app running in Azure which has azure Active Directory authentication enabled. This is given below (I have configured this correctly there is no issue with this): -
Now I want to call one of the API of this web app. Code for getting access token based on the client credentials: -
public static string GetAccessToken()
{
string authContextURL = "https://login.microsoftonline.com/" + "TENANT_ID";
var authenticationContext = new AuthenticationContext(authContextURL);
var credential = new ClientCredential("CLIENT_ID", "CLIENT_SECRET");
var result = authenticationContext.AcquireTokenAsync("URL_FOR_MY_WEBAPP", credential).Result;
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the token");
}
string token = result.AccessToken;
return token;
}
Code for calling the desired API: -
private static string GET(string URI, string token)
{
Uri uri = new Uri(string.Format(URI));
// Create the request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
// Get the response
HttpWebResponse httpResponse;
try
{
httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
}
catch (Exception ex)
{
return ex.Message;
}
string result = null;
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
return result;
}
I am getting an unauthorized error while getting the response. Could anyone tell what is wrong here? The same service principal is working with graph client. Any help or suggestion will be appreciated.
The resource to acquire access token is not correct. You should use the same client id of your AD app.
var result = authenticationContext.AcquireTokenAsync("{CLIENT_ID}", credential).Result;
I have requirement to read data from Dynamics 365 online and to write data as well.
Since my application Target Framework is .Net Core 2.1 so I am unable to use Microsoft.Xrm.Sdk and decided to use Web api instead.
In my code I am using HttpWebRequest with "GET" and "POST" methods, the GET operation works fine and am able to retrieve records from D365 using web api.
When I use the POST operation the code executes properly without any error but when I navigate to D365 entity I do not see any newly created record.
Below is my code
The GetContactDetailsAsync function works fine and returns result but the CreateCaseAsync function is not working
public static async Task<string> GetContactDetailsAsync()
{
string organizationUrl = "https://xxxxx.crmX.dynamics.com";
string clientId = "xxxxxxxx-73aa-xxxx-94cc-8dc7941f6600";
string appKey = "Xxxx81H/7TUFErt5C/xxxxxxxxxxxxxxxxxxxxxxx=";
string aadInstance = "https://login.microsoftonline.com/";
string tenantID = "xxxxxxxx.onmicrosoft.com";
try
{
ClientCredential clientcred = new ClientCredential(clientId, appKey);
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(organizationUrl, clientcred);
var requestedToken = authenticationResult.AccessToken;
var webRequest = (HttpWebRequest)WebRequest.Create(new Uri("https://xxxxxxxxxx.api.crmx.dynamics.com/api/data/v9.1/contacts()?$select=fullname,contactid,emailaddress1&$filter=mobilephone eq '"+History.userMobile+"'"));
webRequest.KeepAlive = false;
webRequest.ServicePoint.ConnectionLimit = 1;
webRequest.Method = "GET";
webRequest.ContentLength = 0;
webRequest.Headers.Add("Authorization", String.Format("Bearer {0}", requestedToken));
webRequest.Headers.Add("OData-MaxVersion", "4.0");
webRequest.Headers.Add("OData-Version", "4.0");
webRequest.Accept = "application/json";
webRequest.ContentType = "application/json";
//if contact with user provided phone number found, ask for problem description
try
{
using (var response1 = webRequest.GetResponse() as System.Net.HttpWebResponse)
{
using (var reader = new System.IO.StreamReader(response1.GetResponseStream()))
{
var response = reader.ReadToEnd();
}
}
}
catch (Exception ex)
{
History.isUserFound = false;
string error = ex.Message;
return "Sorry, I found that you are not using any of our services...";
}
}
catch (Exception ex) { return ex.ToString(); }
}
public static async void CreateCaseAsync()
{
string organizationUrl = "https://xxxxx.crmX.dynamics.com";
string clientId = "xxxxxxxx-73aa-xxxx-94cc-8dc7941f6600";
string appKey = "Xxxx81H/7TUFErt5C/xxxxxxxxxxxxxxxxxxxxxxx=";
string aadInstance = "https://login.microsoftonline.com/";
string tenantID = "xxxxxxxx.onmicrosoft.com";
//trying to establish connection with D365 here
try
{
ClientCredential clientcred = new ClientCredential(clientId, appKey);
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(organizationUrl, clientcred);
var requestedToken = authenticationResult.AccessToken;
var webRequest = (HttpWebRequest)WebRequest.Create(new Uri("https://xxxxxxxx.api.crmx.dynamics.com/api/data/v9.1/incidents"));
webRequest.KeepAlive = false;
webRequest.ServicePoint.ConnectionLimit = 1;
webRequest.Method = "POST";
webRequest.Headers.Add("Authorization", String.Format("Bearer {0}", requestedToken));
webRequest.Headers.Add("OData-MaxVersion", "4.0");
webRequest.Headers.Add("OData-Version", "4.0");
webRequest.Accept = "application/json";
webRequest.ContentType = "application/json";
string json = "{\"title\":\"title by chat bot\"}";
byte[] byteArray;
byteArray = Encoding.UTF8.GetBytes(json);
webRequest.ContentLength = byteArray.Length;
try
{
Stream requestDataStream = await webRequest.GetRequestStreamAsync();
requestDataStream.Write(byteArray, 0, byteArray.Length);
requestDataStream.Close();
}
catch (Exception ex) { }
}
catch (Exception ex) { }
}
I have tried changing
string json = "{\"title\":\"title by chat bot\"}" to
"{'title':'title by chat bot'}" and "{title:title by chat bot}" as well.
Also I have tried changing
Stream requestDataStream = await webRequest.GetRequestStreamAsync(); to
Stream requestDataStream = webRequest.GetRequestStream(); as well
but nothing worked.
Unable to figure out what I am missing in my code. Any help is highly appriciated.
Actually code looks fine but you should get 400 Bad request exception. Because the json is missing customerid and the basic payload for creating incident should be like below:
{
"title": "title by chat bot",
"customerid_account#odata.bind": "/accounts(f686f062-e542-e811-a955-000d3ab27a43)"
}
You can refer this SO thread for clarity.
Here is the Code for Webapi using Javascript. I just tried below code in my Org and it worked for me.
var entity = {};
entity.title = "CCCCAAAASSSEEEE";
var req = new XMLHttpRequest();
req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v9.1/incidents(BA8BC3CD-D94F-E911-A82F-000D3A385A1C)", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 204) {
//Success - No Return Data - Do Something
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send(JSON.stringify(entity));
and Below is the link where you could find exactly how to use PATCH method for CRM using c#
https://learn.microsoft.com/en-us/dynamics365/customer-engagement/developer/webapi/web-api-functions-actions-sample-csharp
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 am using Azure REST API for fetching Billing Usage and Ratecard details.
To acquire Token using AcquireToken() Method, initially I used only Client Id which then asks for User Credentials in login window.
However, I am looking for Non-Interactive Approach, so I used Client Credentials in which I passed Client Id and Client Secret Key.
But it gives "Remote Server returns an error 401 Unauthorized"
When I look into error deeply, I found that it gives error "The access token is from wrong audience or resource"
Please give me any solution using which I can access the API without any user interaction.
Thanks in Advance.
Here is my code:
{
string token = GetOAuthTokenFromAAD();
string requestURL = String.Format("{0}/{1}/{2}/{3}",
ConfigurationManager.AppSettings["ARMBillingServiceURL"],
"subscriptions",
ConfigurationManager.AppSettings["SubscriptionID"],
"providers/Microsoft.Commerce/RateCard?api-version=2015-06-01-preview&$filter=OfferDurableId eq 'MS-AZR-*****' and Currency eq 'INR' and Locale eq 'en-IN' and RegionInfo eq 'IN'");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
request.ContentType = "application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(String.Format("RateCard service response status: {0}", response.StatusDescription));
}
public static string GetOAuthTokenFromAAD()
{
AuthenticationContext authenticationContext = new AuthenticationContext(string.Format("{0}/{1}",ConfigurationManager.AppSettings["ADALServiceURL"], ConfigurationManager.AppSettings["TenantDomain"]));
AuthenticationResult result = null;
ClientCredential uc = new ClientCredential(Client_Id, Secret_Key);
try
{
result = authenticationContext.AcquireToken("https://management.core.windows.net/", uc);
}
return result.AccessToken;
}
//App Config File
<add key="ADALServiceURL" value="https://login.microsoftonline.com" />
<add key="ADALRedirectURL" value="http://*****-authentication.cloudapp.net" />
<add key="ARMBillingServiceURL" value="https://management.core.windows.net" />
<add key="TenantDomain" value="********.onmicrosoft.com" />
<add key="SubscriptionID" value="*******-****-****-****-********" />
<add key="ClientId" value="*******-****-****-****-********" />
Update: I have also provided these methods as a Reusable Authentication Helper Class Library. You can find the same at this link:
Azure Authentication - Authenticating any Azure API Request in your Application
Method 1: To use the password approach non-interactively you need to first follow the below post's section "Authenticate with password - PowerShell":
Authenticating a service principal with ARM
Then use the below code snippet to fetch token.
var authenticationContext = new AuthenticationContext(String.Format("{0}/{1}",
ConfigurationManager.AppSettings["ADALServiceURL"],
ConfigurationManager.AppSettings["TenantDomain"]));
var credential = new ClientCredential(clientId: "11a11111-11a1-111a-a111-1afeda2bca1a", clientSecret: "passwordhere");
var result = authenticationContext.AcquireToken(resource: "https://management.core.windows.net/", clientCredential: credential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
return token;
Alternatively (Method 2), you can also use the certificate method. In that case use the same link as above but follow section "Authenticate with certificate - PowerShell" from that link. Then use the below code snippet to fetch the token non-interactively:
var subscriptionId = "1a11aa11-5c9b-4c94-b875-b7b55af5d316";
string tenant = "1a11111a-5713-4b00-a1c3-88da50be3ace";
string clientId = "aa11a111-1050-4892-a2d8-4747441be14d";
var authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenant));
X509Certificate2 cert = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
string certName = "MyCert01";
try
{
store.Open(OpenFlags.ReadOnly);
var certCollection = store.Certificates;
var certs = certCollection.Find(X509FindType.FindBySubjectName, certName, false);
//var certs = certCollection.Find(X509FindType.FindBySerialNumber, "E144928868B609D35F72", false);
if (certs == null || certs.Count <= 0)
{
throw new Exception("Certificate " + certName + " not found.");
}
cert = certs[0];
}
finally
{
store.Close();
}
var certCred = new ClientAssertionCertificate(clientId, cert);
var token = authContext.AcquireToken("https://management.core.windows.net/", certCred);
var creds = new TokenCloudCredentials(subscriptionId, token.AccessToken);
//var client = new ResourceManagementClient(creds);
return token.AccessToken;