Azure - Authenticating Service Management Requests - c#

I need to perform few Azure SQL operations. I have an Azure AD native application. I'm using first approach from following article to aquire the token.
https://msdn.microsoft.com/en-us/library/azure/ee460782.aspx
Now following this article, I'm using the above token to perform the db operation.
static void HttpPost(string sourceDb, string targetDb, string pointInTime)
{
var client = new HttpClient();
string uri = "https://management.core.windows.net:8443/" + AzureSubscriptionId + "/services/sqlservers/servers/" + AzureSqlServerName + "/restoredatabaseoperations";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Headers.Add("Authorization", "Bearer " + accessToken);
request.Headers.Add("x-ms-version", "2012-03-01");
string payload = File.ReadAllText("Resources\\Backup.xml");
payload = payload.Replace("$SourceDb", sourceDb);
payload = payload.Replace("$TargetDb", targetDb);
payload = payload.Replace("$PointInTime", pointInTime);
request.Content = new StringContent(payload, Encoding.UTF8, "application/xml");
HttpResponseMessage response = client.SendAsync(request).GetAwaiter().GetResult();
if (response.Content != null)
{
string ss = response.Content.ReadAsStringAsync().Result;
}
}
But the error I receive is:
"<Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Code>AuthenticationFailed</Code><Message>A security token exception occured for the received JWT token.</Message></Error>"

According to you mentioned Create Database Restore Request (Classic) REST API, this command is used for classic deployment model. We should use the new REST API, and it is also mentioned in your mentioned document.
You should use the newer Resource Manager based REST API commands located here. 
We could use the ARM REST Create or Update DataBase API. About how to get the token, we need to to registry AD App and assign role to application, more info please refer to official document. I send the http request from fiddler and it works correctly for me. Header and body info please refer to the screenshot.
Body info:
{
"properties": {
"edition": "Standard",
"requestedServiceObjectiveName": "S1",
"sourceDatabaseId": "/subscriptions/{your subscriptionId}/resourceGroups/{ResourceGroup}/providers/Microsoft.Sql/servers/{servername}/databases/sourcedatabasename",
"createMode": "PointInTimeRestore",
"restorePointInTime": "2017-02-09T10:28:20.21+08:00" //source database restorePointTime
},
"location": "East Asia",
"tags": {}
}
We also can use Microsoft Azure SQL Management Library for .NET to that.
SqlMgmtClient.Databases.CreateOrUpdate(resourceGroupName, serverName, databaseName, DatabaseCreateOrUpdateParameters);
We could refer to the tutorial to get started. I do a demo for it. More details please refer to the following steps
1.Create a console app and install the required libraries (detail refer to tutorial)
2.After registry an application, we could get tenantId, applicationId,
SecretKey, then with subscriptionId to get the authentication token.
3.Create SqlManagementClient object with token
var _sqlMgmtClient = new SqlManagementClient(new TokenCloudCredentials(_subscriptionId, _token.AccessToken));
4.Create DatabaseCreateOrUpdateParameters according to our requirement.
Take restore database from a source database for example:
CreateMode = DatabaseCreateMode.PointInTimeRestore, //craete mode from pointtimerestore
Edition = databaseEdition,
SourceDatabaseId = "/subscriptions/subscriptionId/resourceGroups/groupname/providers/Microsoft.Sql/servers/AzureSQlname/databases/databaseName", //source database Id
RestorePointInTime = DateTime.Parse("2017-02-09T02:28:20.21Z"), //resore point Time
RequestedServiceObjectiveName = "S1"
run the demo and check from the portal.
democode:
static void Main(string[] args)
{
_token = GetToken(_tenantId, _applicationId, _applicationSecret);
Console.WriteLine("Token acquired. Expires on:" + _token.ExpiresOn);
// Instantiate management clients:
_resourceMgmtClient = new ResourceManagementClient(new Microsoft.Rest.TokenCredentials(_token.AccessToken));
_sqlMgmtClient = new SqlManagementClient(new TokenCloudCredentials(_subscriptionId, _token.AccessToken));
DatabaseCreateOrUpdateResponse dbr = CreateOrUpdateDatabase(_sqlMgmtClient, _resourceGroupName, _serverName, _databaseName, _databaseEdition, _databasePerfLevel);
Console.WriteLine("Database: " + dbr.Database.Id);
}
private static AuthenticationResult GetToken(string tenantId, string applicationId, string applicationSecret)
{
AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/" + tenantId);
_token = authContext.AcquireToken("https://management.core.windows.net/", new ClientCredential(applicationId, applicationSecret));
return _token;
}
static DatabaseCreateOrUpdateResponse CreateOrUpdateDatabase(SqlManagementClient sqlMgmtClient, string resourceGroupName, string serverName, string databaseName, string databaseEdition, string databasePerfLevel)
{
// Retrieve the server that will host this database
Server currentServer = sqlMgmtClient.Servers.Get(resourceGroupName, serverName).Server;
// Create a database: configure create or update parameters and properties explicitly
DatabaseCreateOrUpdateParameters newDatabaseParameters = new DatabaseCreateOrUpdateParameters()
{
Location = currentServer.Location,
Properties = new DatabaseCreateOrUpdateProperties
{
CreateMode = DatabaseCreateMode.PointInTimeRestore,
Edition = databaseEdition,
SourceDatabaseId = "/subscriptions/subscriptionId/resourceGroups/tomnewgroup/providers/Microsoft.Sql/servers/tomsunsqltest/databases/sourceDatabaseName",
RestorePointInTime = DateTime.Parse("2017-02-09T02:28:20.21Z"),//Restore Point time
RequestedServiceObjectiveName = databasePerfLevel
}
};
DatabaseCreateOrUpdateResponse dbResponse = sqlMgmtClient.Databases.CreateOrUpdate(resourceGroupName, serverName, databaseName, newDatabaseParameters);
return dbResponse;
}
packages.config file:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Hyak.Common" version="1.0.2" targetFramework="net462" />
<package id="Microsoft.Azure.Common" version="2.1.0" targetFramework="net462" />
<package id="Microsoft.Azure.Common.Authentication" version="1.7.0-preview" targetFramework="net462" />
<package id="Microsoft.Azure.Common.Dependencies" version="1.0.0" targetFramework="net462" />
<package id="Microsoft.Azure.Management.ResourceManager" version="1.4.0-preview" targetFramework="net462" />
<package id="Microsoft.Azure.Management.Sql" version="0.51.0-prerelease" targetFramework="net462" />
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net462" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net462" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net462" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.18.206251556" targetFramework="net462" />
<package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net462" />
<package id="Microsoft.Rest.ClientRuntime" version="2.1.0" targetFramework="net462" />
<package id="Microsoft.Rest.ClientRuntime.Azure" version="3.1.0" targetFramework="net462" />
<package id="Microsoft.Rest.ClientRuntime.Azure.Authentication" version="2.0.1-preview" targetFramework="net462" />
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net462" />
</packages>

Please open a support case allowing us to better understand the issue

Related

ServiceStack FallbackRoute failing with upgraded ServiceStack version

We upgraded our C# web services from ServiceStack V4.0.31 to V5.1.0. We're using the following packages in a linux environment with a monodevelop runtime.
<package id="ServiceStack" version="5.1.0" targetFramework="net45" />
<package id="ServiceStack.Client" version="5.1.0" targetFramework="net45" />
<package id="ServiceStack.Common" version="5.1.0" targetFramework="net45" />
<package id="ServiceStack.Interfaces" version="5.1.0" targetFramework="net45" />
<package id="ServiceStack.Redis" version="5.1.0" targetFramework="net45" />
<package id="ServiceStack.Text" version="5.1.0" targetFramework="net45" />
After upgrading we are now having problems when processing some of our client requests. Our request DTO contains several routes but the following one always fails.
[FallbackRoute("/{Path*}")]
public class S3Request : IRequiresRequestStream {
public Stream RequestStream { get; set; }
}
This route is invoked when a client issues a
GET http://endpoint:1310/name/clients/C1/sites/G1
(the port and route don't matter, just examples). We’re getting a 400 Bad Request with the following error response.
{
"ResponseStatus": {
"ErrorCode": "ArgumentException",
"Message": "Could not find property Path on S3Request",
"StackTrace": " at ServiceStack.Host.RestPath.CreateRequest (System.String pathInfo, System.Collections.Generic.Dictionary`2[TKey,TValue] queryStringAndFormData, System.Object fromInstance) [0x000c9] in <629ec152372546cf812fe4a698c7a784>:0 \n at ServiceStack.Host.RestHandler.CreateRequest (ServiceStack.Web.IRequest httpReq, ServiceStack.Web.IRestPath restPath, System.Collections.Generic.Dictionary`2[TKey,TValue] requestParams, System.Object requestDto) [0x0001e] in <629ec152372546cf812fe4a698c7a784>:0 \n at ServiceStack.Host.ServiceController+<>c__DisplayClass26_0.<RegisterService>b__0 (ServiceStack.Web.IRequest req) [0x00035] in <629ec152372546cf812fe4a698c7a784>:0 \n at ServiceStack.Host.Handlers.ServiceStackHandlerBase.GetCustomRequestFromBinder (ServiceStack.Web.IRequest httpReq, System.Type requestType) [0x00018] in <629ec152372546cf812fe4a698c7a784>:0 \n at ServiceStack.Host.RestHandler.CreateRequestAsync (ServiceStack.Web.IRequest httpReq, ServiceStack.Web.IRestPath restPath) [0x00017] in <629ec152372546cf812fe4a698c7a784>:0 \n at ServiceStack.Host.RestHandler+<ProcessRequestAsync>d__14.MoveNext () [0x00125] in <629ec152372546cf812fe4a698c7a784>:0 "
}
}
The exception is thrown method ServiceStack.Host.RestPath.CreateRequest(…) in the following area of the code
for (int i = 0; i < this.TotalComponentsCount; i++) {
string text = this.variablesNames [i];
string key;
if (text == null) {
num++;
} else if (!this.propertyNamesMap.TryGetValue (text.ToLower (), out key)) {
if (!StringExtensions.EqualsIgnoreCase (Keywords.Ignore, text)) {
throw new ArgumentException ("Could not find property " + text + " on " + UrlExtensions.GetOperationName (this.RequestType));
}
It appears that the CreateRequest method expects the propertyNamesMap to have an entry for the route but it’s not there. We’re wondering if the V5.1.0 API requires us to perform some sort of path registration logic that was not necessary in V4.0.31?
Your DTO is missing the Path property on the Request DTO, every variable on the Route except {ignore} needs to match a property on the Request DTO.

How to Append a File using Web HDFS REST API in C#?

I am using Azure Data Lake to upload the file before but still want to append the text file content existing Data Lake text file. Is there any option available to append the text file data using Web HDFS REST API in C#?.
I am refer this link enter link description here
Code: I Can refer the above link get the append URL. But how can i use this URL and Append a File using c#?
private const string AppendUrl = "https://{0}.azuredatalakestore.net/webhdfs/v1/{1}?&op=APPEND&noredirect=true";
If you want to use the Rest Api to do that we could use the following code. I test it with Postman.
private const string AppendUrl = "https://{datalakeName}.azuredatalakestore.net/webhdfs/v1/{filepath}?append=true&op=APPEND&api-version=2016-11-01"
var token = "eyJ0eX.....";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var result = client.GetAsync(url).Result;
var data = result.Content.ReadAsStringAsync().Result;
}
We also could use the Azure Microsoft.Azure.Management.DataLake.Store to do that. How to get the application id and secretkey you could refer to official document. More detail steps to get the permission to access the datalake you could refer to another SO thread.
var applicationId = "application Id";
var secretKey = "secretKey";
var tenantId = "tenant id";
var adlsAccountName = "datalake account name";
var creds = ApplicationTokenProvider.LoginSilentAsync(tenantId, applicationId, secretKey).Result;
var adlsFileSystemClient = new DataLakeStoreFileSystemManagementClient(creds,clientTimeoutInMinutes:60);
var stream = File.OpenRead(#"C:\tom\testtext.txt");
var test = adlsFileSystemClient.FileSystem.AppendWithHttpMessagesAsync(adlsAccountName, "test/abc.txt", stream).Result;
packages:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Azure.Management.DataLake.Store" version="2.3.0-preview" targetFramework="net452" />
<package id="Microsoft.Azure.Management.DataLake.StoreUploader" version="1.0.0-preview" targetFramework="net452" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="3.13.8" targetFramework="net452" />
<package id="Microsoft.Rest.ClientRuntime" version="2.3.9" targetFramework="net452" />
<package id="Microsoft.Rest.ClientRuntime.Azure" version="3.3.9" targetFramework="net452" />
<package id="Microsoft.Rest.ClientRuntime.Azure.Authentication" version="2.2.0-preview" targetFramework="net452" />
<package id="Newtonsoft.Json" version="9.0.2-beta1" targetFramework="net452" />
</packages>

Missing Assembly Reference Using Microsoft.IdentityModel.Clients.ActiveDirectory 3.13.9 with Azure KeyVault C# SDK

For some reason, I have to latest Microsoft.IdentityModel.Clients.ActiveDirectory v3.13.9 with Microsoft.Azure.KeyVault v2.0.6. And it always throws exceptions for missing assembly reference, but downgrading Microsoft.IdentityModel.Clients.ActiveDirectory to v2.28.4, which I'm not allowed to use, can resolve this known issue.
Here's the exception:
InnerException:
HResult=-2146233036
Message=The type initializer for 'Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformPlugin' threw an exception.
Source=Microsoft.IdentityModel.Clients.ActiveDirectory
TypeName=Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformPlugin
StackTrace:
at Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformPlugin.get_Logger()
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext..cctor()
InnerException:
ErrorCode=assembly_not_found
HResult=-2146233088
Message=Assembly required for the platform not found. Make sure assembly 'Microsoft.IdentityModel.Clients.ActiveDirectory.Platform, Version=3.12.0.827, Culture=neutral, PublicKeyToken=31bf3856ad364e35' exists
Source=Microsoft.IdentityModel.Clients.ActiveDirectory
StackTrace:
at Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformPlugin.LoadPlatformSpecificAssembly()
at Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformPlugin.InitializeByAssemblyDynamicLinking()
at Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformPlugin..cctor()
InnerException:
FileName=Microsoft.IdentityModel.Clients.ActiveDirectory.Platform, Version=3.12.0.827, Culture=neutral, PublicKeyToken=31bf3856ad364e35
FusionLog==== Pre-bind state information ===
Code snippets:
protected KeyVaultBase(string clientId, string clientSecret)
{
if (string.IsNullOrWhiteSpace(clientId))
{
throw new ArgumentNullException(nameof(clientId));
}
if (string.IsNullOrWhiteSpace(clientSecret))
{
throw new ArgumentNullException(nameof(clientSecret));
}
this.KeyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
(authority, resource, scope) => GetAccessToken(authority, resource, scope, clientId, clientSecret)
)
);
}
private static async Task<string> GetAccessToken(string authority, string resource, string scope, string clientId, string clientSecret)
{
var authnContext = new AuthenticationContext(authority);
var clientCredential = new ClientCredential(clientId, clientSecret);
var result = await authnContext.AcquireTokenAsync(resource, clientCredential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
return result.AccessToken;
}
The exception throws while executing var authnContext = new AuthenticationContext(authority);.
Does anyone know any solution/workaround to resolve this issue without the downgrading?
In my case the references were installed only to the class library project, not to the executing assembly, so it was throwing this exception.
Adding the Microsoft.IdentityModel.Clients.ActiveDirectory nuget package to the executing assembly worked for me.
Hope it helps
Please have a try uninstall both of Microsoft.IdentityModel.Clients.ActiveDirectory v3.13.9 and Microsoft.Azure.KeyVault v2.0.6 then reinstall them again. If there are multiple projects in the solution are referenced them, please make sure all of the them are the same version.
I create a console or Asp.net MVC project, both are working correctly on my side using Microsoft.IdentityModel.Clients.ActiveDirectory v3.13.9 with Microsoft.Azure.KeyVault v2.0.6.
The following is my detail steps:
1.Create a C# console project.
2.Add the Microsoft.IdentityModel.Clients.ActiveDirectory v3.13.9 with nuget.
3.Add the Microsoft.Azure.KeyVault v2.0.6 from Package manager console with command
Install-Package Microsoft.Azure.KeyVault -Version 2.0.6
Packages.config file:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Azure.KeyVault" version="2.0.6" targetFramework="net452" />
<package id="Microsoft.Azure.KeyVault.WebKey" version="2.0.4" targetFramework="net452" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="3.13.9" targetFramework="net452" />
<package id="Microsoft.Rest.ClientRuntime" version="2.3.2" targetFramework="net452" />
<package id="Microsoft.Rest.ClientRuntime.Azure" version="3.3.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net452" />
</packages>
Add a class in the project:
class KeyVaultBase
{
static string _clientId= "xxxxxxxxxxxxx";
static string _clientSecret = "xxxxxxxxxxxxxxxx";
static string _tenantId = "xxxxxxxxxxxxxxxx";
public static async Task<string> GetAccessToken(string azureTenantId, string azureAppId, string azureSecretKey)
{
var context = new AuthenticationContext("https://login.windows.net/" + _tenantId);
ClientCredential clientCredential = new ClientCredential(_clientId, _clientSecret);
var tokenResponse = await context.AcquireTokenAsync("https://vault.azure.net", clientCredential);
var accessToken = tokenResponse.AccessToken;
return accessToken;
}
}
4.Test Get Secret from the KeyVault
static void Main(string[] args)
{
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(KeyVaultBase.GetAccessToken));
string secretUri = "https://KeyVaultNameSpace.vault.azure.net/secrets/secretsname/6341322679db4f3491814ff6178dee45";
var sec = kv.GetSecretAsync(secretUri).Result;
}

Can't access user photo using client id and secret

I am trying to use the Unified API (Microsoft.Graph 1.0.1) to access my users profil photos, but I only get the following error back when accessing the photo:
Code: ErrorAccessDenied
Message: Access is denied. Check credentials and try again.
Accessing/Listing the other user profile data works fine and my application was added as a "Company Administrator" via PowerShell and has all rights set in the management portal. When I use the GraphExlorer logged in with my admin user it also works fine. Also via the "old" Azure Active Directory Graph API I can read/write to the users thumbnail photo, but thats not the one showing up in Office 365.
How can I get the appropriate access rights to perform actions on users profile photo?
This is the code I use (shortened to the parts in question):
class Program
{
private const string authStringMicrosoft = "https://login.microsoftonline.com/MY_APP_ID/";
private const string clientID = "MY_CLIENT_ID";
private const string clientSecret = "MY_CLIENT_SECRET";
private const string graphResourceId = "https://graph.microsoft.com";
static void Main(string[] args)
{
AsyncContext.Run(RunAsync);
Console.WriteLine("DONE");
Console.ReadLine();
}
private static async Task RunAsync()
{
var token = await GetAppTokenAsync(authStringMicrosoft, graphResourceId);
var authHelper = new AuthenticationHelper() { AccessToken = token }
var graphClient = new GraphServiceClient(authHelper);
await ListUser(graphClient);
}
private static async Task ListUser(GraphServiceClient graphClient)
{
Console.WriteLine("User-List:");
var users = await graphClient.Users.Request().GetAsync();
foreach (var user in users)
{
Console.WriteLine($"{user.UserPrincipalName}:\t\t{user.GivenName} {user.Surname}");
if (user.UserPrincipalName == "USER_WITH_PICTURE")
{
var graphUser = graphClient.Users[user.UserPrincipalName];
var graphPhoto = graphUser.Photo;
var photoInfo = await graphPhoto.Request().GetAsync(); // <= here the exceptions is thrown
Console.WriteLine($"{photoInfo.Id}:\t{photoInfo.Width}x{photoInfo.Height}");
var photoStream = await graphPhoto.Content.Request().GetAsync();
byte[] photoByte = new byte[photoStream.Length];
photoStream.Read(photoByte, 0, (int)photoStream.Length);
File.WriteAllBytes(#"D:\User.jpg", photoByte);
}
}
}
private static async Task<string> GetAppTokenAsync(string authority, string azureGraphAPI)
{
var authenticationContext = new AuthenticationContext(authority);
var clientCred = new ClientCredential(clientID, clientSecret);
var authenticationResult = await authenticationContext.AcquireTokenAsync(azureGraphAPI, clientCred);
return authenticationResult.AccessToken;
}
}
public class AuthenticationHelper : IAuthenticationProvider
{
public string AccessToken { get; set; }
public Task AuthenticateRequestAsync(HttpRequestMessage request)
{
request.Headers.Add("Authorization", "Bearer " + AccessToken);
return Task.FromResult(0);
}
}
I use the following NuGet-packages:
<packages>
<package id="Microsoft.Data.Edm" version="5.7.0" targetFramework="net46" />
<package id="Microsoft.Data.OData" version="5.7.0" targetFramework="net46" />
<package id="Microsoft.Data.Services.Client" version="5.7.0" targetFramework="net46" />
<package id="Microsoft.Graph" version="1.0.1" targetFramework="net46" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.24.304111323" targetFramework="net46" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net46" />
<package id="Nito.AsyncEx" version="3.0.1" targetFramework="net46" />
<package id="System.Spatial" version="5.7.0" targetFramework="net46" />
</packages>
This is an example request delivering the error (using postman with the token read out from the app above):
GET /v1.0/users/MY_USER_WITH_PHOTO/photo/ HTTP/1.1
Host: graph.microsoft.com
Connection: keep-alive
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1...
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
Postman-Token: e756a8a3-22e2-d40c-8e52-15c4d1aa7468
Accept: /
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de,en-US;q=0.8,en;q=0.6
And the response:
HTTP/1.1 403 Forbidden
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: application/json
Server: Microsoft-IIS/8.5
request-id: 96e8dda8-2353-4891-8c42-99cfe7e22887
client-request-id: 96e8dda8-2353-4891-8c42-99cfe7e22887
x-ms-ags-diagnostic: {"ServerInfo":{"DataCenter":"North Europe","Slice":"SliceA","ScaleUnit":"001","Host":"AGSFE_IN_4","ADSiteName":"DUB"}}
Duration: 1367.7691
X-Powered-By: ASP.NET
Date: Sun, 01 May 2016 17:57:02 GMT
Body:
{
"error": {
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again.",
"innerError": {
"request-id": "96e8dda8-2353-4891-8c42-99cfe7e22887",
"date": "2016-05-01T17:57:02"
}
}
}
Again, if I remove the /photo from the request I get all common user details without a problem.
Here the permissions of my app (web-app):
Here a decrypted access token:
{
typ: "JWT",
alg: "RS256",
x5t: "MnC_VZcATfM5pOYiJHMba9goEKY",
kid: "MnC_VZcATfM5pOYiJHMba9goEKY"
}.
{
aud: "https://graph.microsoft.com",
iss: "https://sts.windows.net/11205e59-fa81-480f-b497-571579c5389a/",
iat: 1462795409,
nbf: 1462795409,
exp: 1462799309,
appid: "c34a87ef-352a-4af4-a166-eb7e521a0ec9",
appidacr: "1",
idp: "https://sts.windows.net/11205e59-fa81-480f-b497-571579c5389a/",
oid: "1db8c6b5-10ba-40ac-bbff-86ab440c4fd3",
roles: [
"Mail.ReadWrite",
"Device.ReadWrite.All",
"User.ReadWrite.All",
"Calendars.Read",
"Group.Read.All",
"Directory.ReadWrite.All",
"Contacts.ReadWrite",
"Group.ReadWrite.All",
"Directory.Read.All",
"User.Read.All",
"Mail.Read",
"Calendars.ReadWrite",
"Mail.Send",
"MailboxSettings.ReadWrite",
"Contacts.Read"
],
sub: "1db8c6b5-10ba-40ac-bbff-86ab440c4fd3",
tid: "11205e59-fa81-480f-b497-571579c5389a",
ver: "1.0"
}
Just in case anyone else reads this when getting that error. I had this same error when creating my own graphClient and the reason I got it was due to using a non-admin account with...
var users = await graphClient.Users.Request().Select().GetAsync();
With a non-admin account, you only have access to some basic properties like lastname, firstname etc - this worked for me...
var users = await graphClient.Users.Request().Select("mail,givenName,surname").GetAsync();

Send UDP data from Windows Service to browser running webpage on same machine

Let's say I have the following code running on a Windows service.
I have to send data from a Windows service on a machine to a webpage that is open on the same machine(but not hosted on that machine).
static void Main(string[] args)
{
Int32 counter = 0;
while (counter < 100)
{
SendUDP("127.0.0.1", 49320, counter.ToString(), counter.ToString().Length);
Thread.Sleep(2000);
counter++;
}
}
public static void SendUDP(string hostNameOrAddress, int destinationPort, string data, int count)
{
IPAddress destination = Dns.GetHostAddresses(hostNameOrAddress)[0];
IPEndPoint endPoint = new IPEndPoint(destination, destinationPort);
byte[] buffer = Encoding.ASCII.GetBytes(data);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
for (int i = 0; i < count; i++)
{
socket.SendTo(buffer, endPoint);
}
socket.Close();
System.Console.WriteLine("Sent: " + data);
}
I have to listen for the data sent to port 49320 and then process it in the browser.
I can create a listener on the webpage with Node.js like below, but I have to start this service separately and also install node.js on the client.
Is there any alternative to this? Something more lightweight ?
I could also create an AJAX to query a webservice every 2 seconds that would do the same thing as Windows Service, but it seems like a lot of queries sent all the time for nothing.
//websocket gateway on 8070
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs');
var mysocket = 0;
app.listen(8070);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
console.log('index.html connected');
mysocket = socket;
});
//udp server on 49320
var dgram = require("dgram");
var server = dgram.createSocket("udp4");
server.on("message", function (msg, rinfo) {
console.log("msg: " + msg);
if (mysocket != 0) {
mysocket.emit('field', "" + msg);
mysocket.broadcast.emit('field', "" + msg);
}
});
server.on("listening", function () {
var address = server.address();
console.log("udp server listening " + address.address + ":" + address.port);
});
server.bind(49320);
Use Signal R. This is a technology which automatically negotiates the most efficient transport for pushing events from a server to a browser (eg Forever Frames, Web Sockets) - it will fall back to the polling approach you mention in your question if required. I think this is a better approach to using raw UDP because all the low level work has been done for you.
Here's an example of using Signal R from a windows service:
https://code.msdn.microsoft.com/windowsapps/SignalR-self-hosted-in-6ff7e6c3
From that sample - here's an even more simplified example of SignalR using OWIN to self host (without IIS):
using System;
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Hosting;
using Owin;
namespace SignalRWindowsService
{
static class Program
{
static void Main()
{
string url = "http://localhost:8080";
WebApp.Start(url);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
//This means you can access the web sockets from the local service (on a different URL) than the domain the page in the browser was served up from.
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
}
}
You need the following NUGET packages:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.Cors" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Core" version="2.0.3" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.SelfHost" version="2.0.3" targetFramework="net45" />
<package id="Microsoft.Owin" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Cors" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Diagnostics" version="2.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Host.HttpListener" version="2.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Hosting" version="2.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="2.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.SelfHost" version="2.0.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="5.0.1" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
</packages>

Categories