Can anyone help me with Azure notification hub, how to set up device installation form c# code. I have problem with the Installation object. How to set it to pass it as parameter to CreateOrUpdateInstallation method of hub client instance. It's not clear to me.
I have a hub on azure that works with device registration like charm in local, but uploaded on azure are not working. Now I wanna try with istalation.
thnx
update: after 4 days, I figured out, that you can't send notification to yourself. Azure somehow knows that you are sending notification to yours phone, and that's why my welcome message never delivered to my phone.
update: this is how now I install the device i my backend code:
[HttpGet]
[Route("api/push/test-installation")]
public async Task<IActionResult> NotificationInstalationTest()
{
string connectionString = "{{my connection string}}";
string hubName = "{{my hub name}}";
string token = "{{tokne}}";
NotificationHubClient hubClient = NotificationHubClient.CreateClientFromConnectionString(connectionString, hubName);
string notificationText = $"Test message for Azure delivery for Atila at: {DateTime.Now.ToShortTimeString()}";
var alert = new JObject
(
new JProperty("aps", new JObject(new JProperty("alert", notificationText))),
new JProperty("inAppMessage", notificationText)
).ToString(Newtonsoft.Json.Formatting.None);
IList<string> tags = new List<string>();
tags.Add("email");
IDictionary<string, string> pushVariables = new Dictionary<string, string>();
pushVariables.Add( "email", "atila#panonicit.com" );
Installation installation = new Installation();
installation.InstallationId = Guid.NewGuid().ToString();
installation.Platform = NotificationPlatform.Apns;
installation.PushChannel = token;
installation.Tags = tags;
installation.PushVariables = pushVariables;
await hubClient.CreateOrUpdateInstallationAsync(installation);
NotificationOutcome result = await hubClient.SendAppleNativeNotificationAsync(alert);
return Ok("Success");
}
Now when I hit this endpoint with Postman it works, if the same endpoint call comes from iOS it not works!
thnx
How to set it to pass it as parameter to CreateOrUpdateInstallation method of hub client instance. It's not clear to me.
Based on my understanding, you are registering the notification hub from your backend using the installation model. For your WebAPI project, assuming your method for create/update an installation as follows:
InstallationController.cs
//PUT api/installation
public async Task<HttpResponseMessage> Put(DeviceInstallation deviceUpdate)
{
Installation installation = new Installation();
installation.InstallationId = deviceUpdate.InstallationId;
//TODO:
await hub.CreateOrUpdateInstallationAsync(installation);
return Request.CreateResponse(HttpStatusCode.OK);
}
For your mobile client, you could refer to the following method:
private async Task<HttpStatusCode> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation)
{
using (var httpClient = new HttpClient())
{
//TODO: set your authorization header
//httpClient.DefaultRequestHeaders.Authorization
var putUri =$"{your-backend-endpoint}/api/installation";
string json = JsonConvert.SerializeObject(deviceInstallation);
var response = await httpClient.PutAsync(putUri, new StringContent(json, Encoding.UTF8, "application/json"));
return response.StatusCode;
}
}
Moreover, for more details you could refer to Registration management and here for building backend with the registration model to build your backend using the installation model.
Related
I have been testing some code to sign in users to their Microsoft/school/work accounts using raw HttpRequestMessage and HttpResponseMessage. I know there are libraries available to do this but I want to test the raw approach as well (especially usage of refresh tokens), while looking for the right library to handle it.
I'm currently learning authentication, with limited knowledge of ASP.NET/Core.
I'm following this guide: https://learn.microsoft.com/en-us/graph/auth-v2-user
I've just modified the SignIn() method in AccountController in an example project that used more high level libraries to sign in.
I'm requesting an authorization code.
The SignIn() code:
public void SignIn()
{
using (var httpClient = new HttpClient())
{
try
{
var tenant = "my tenant id";
var clientId = ConfigurationManager.AppSettings["ida:AppID"];
var responseType = "id_token+code";
var redirectURI = ConfigurationManager.AppSettings["ida:RedirectUri"];
var responseMode = "form_post";//query";
var appScopes = ConfigurationManager.AppSettings["ida:AppScopes"];
var scopes = $"openid profile offline_access {appScopes}";
var state = "12345";
//var prompt = "consent";
var url = string.Format("https://login.microsoftonline.com/{0}/oauth2/v2.0/authorize", tenant);
var body = string.Format("client_id={1}&response_type={2}&redirect_uri={3}&response_mode={4}&scope={5}&state={6}", tenant, clientId, responseType, redirectURI, responseMode, scopes, state);
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Content = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
var response = httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead).Result;
var content = response.Content.ReadAsStringAsync().Result;
}
catch (Exception ex)
{
}
}
//if (!Request.IsAuthenticated)
//{
// // Signal OWIN to send an authorization request to Azure
// Request.GetOwinContext().Authentication.Challenge(
// new AuthenticationProperties { RedirectUri = "/" },
// OpenIdConnectAuthenticationDefaults.AuthenticationType);
//}
}
I'm just returning void from the method now because I'm not sure what I should return yet.
Debugging and looking at the response variable, the status code is 200, and has some other information to it. However, the content of the HttpResponseMessage, when I paste it into a file and opening it in a browser, displays (or redirects to) https://login.microsoftonline.com/cookiesdisabled, which shows a message saying that I could not be logged in because my browser blocks cookies. However, I don't think this really is the case.
How can I resolve this and have the user log in and consent, and get the authorization code?
I couldn't really find any example in ASP.NET that uses this raw approach. Is it not recommended?
You should fistly understand how OAuth 2.0 authorization code flow works in Azure AD V2.0 :
Microsoft identity platform and OAuth 2.0 authorization code flow
The general process would be like :
When login in client application, user will be redirect to Azure AD login endpoint(https://login.microsoftonline.com/{0}/oauth2/v2.0/authorize) and provides info like which client(client_id) in which tenant(tenant id) user wants to login , and redirect back to which url(redirect_uri) after successful login.
User enter credential , Azure AD validate credential and issue code and redirect user back to redirect url provided in step 1 (Also match one of the redirect_uris you registered in the portal).
The client application will get the code and send http post request with code to acquire access token .
So if you want to manally implement the code flow in your application , you can refer to below code sample :
public async Task<IActionResult> Login()
{
string authorizationUrl = string.Format(
"https://login.microsoftonline.com/{0}/oauth2/v2.0/authorize?response_type=code&client_id={1}&redirect_uri={2}&scope={3}",
"tenantID", "ClientID", "https://localhost:44360/Home/CatchCode",
"openid offline_access https://graph.microsoft.com/user.read");
return Redirect(authorizationUrl);
}
private static readonly HttpClient client = new HttpClient();
public async Task<ActionResult> CatchCode(string code)
{
var values = new Dictionary<string, string>
{
{ "grant_type", "authorization_code" },
{ "client_id", "XXXXXX"},
{ "code", code},
{ "redirect_uri", "https://localhost:44360/Home/CatchCode"},
{ "scope", "https://graph.microsoft.com/user.read"},
{ "client_secret", "XXXXXXXXXXX"},
};
var content = new FormUrlEncodedContent(values);
//POST the object to the specified URI
var response = await client.PostAsync("https://login.microsoftonline.com/cb1c3f2e-a2dd-4fde-bf8f-f75ab18b21ac/oauth2/v2.0/token", content);
//Read back the answer from server
var responseString = await response.Content.ReadAsStringAsync();
//you can deserialize an Object use Json.NET to get tokens
}
That just is simple code sample which will get Microsoft Graph's access token , you still need to care about url encode and catch exception , but it shows how code flow works .
In need of some help accessing an external Web API passing along credentials in order to access the methods available. I have included the code below that i use in order to attempt to access the Web API. However, i receive the following error every time i attempt to access it:
"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel."
What am i missing or what am i doing wrong? I have been circling around this for a couple days and have tried a couple different techniques but continue to get the same error. Here is one technique that i used.
private static async Task<string> GetAPIToken(string userName, string password, string apiBaseUri)
{
try
{
using (var client = new HttpClient())
{
//setup client
client.BaseAddress = new Uri(apiBaseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//setup login data
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string,string>("username",userName),
new KeyValuePair<string,string>("password",password),
});
//send request
HttpResponseMessage responseMessage = await client.PostAsync("Token", formContent);
//get access token from response body
var responseJson = await responseMessage.Content.ReadAsStringAsync();
var jobject = JObject.Parse(responseJson);
return jobject.GetValue("access_token").ToString();
}
}
catch (Exception ex)
{
return null;
}
}
Any help would be greatly appreciated.
Thanks
There is a little bit of a difference when using HTTPS vs HTTP. This question should give you the information you need to fix your problem.
Make Https call using HttpClient
I have created a custom Authorize attribute where I use the Office Graph to get AAD groups the current user is member of, and based on those I reject or authorize the user. I want to save the groups, because the call to Office Graph takes some performance. What would be the correct way to save that kind of data? I can see some people saves it to a SQL server, but then I would need to ensure cleanup etc.
Also I can see in some threads the session state is stated to be a bad choice due to concurrency. So the question is what options do you have to store this kind of information?
All suggestions are welcome.
If you were only using the group_id info, there is no need to use Office Graph and store it at all. We can enable Azure AD issue the groups claims by change the manifest of Azure AD like below:(refer this code sample)
"groupMembershipClaims": "All",
And if you are also using other info about groups, you can store these info into claims. Here is a code sample that add the name of groups into claims for your reference:
AuthorizationCodeReceived = async context =>
{
ClientCredential credential = new ClientCredential(ConfigHelper.ClientId, ConfigHelper.AppKey);
string userObjectId = context.AuthenticationTicket.Identity.FindFirst(Globals.ObjectIdClaimType).Value;
AuthenticationContext authContext = new AuthenticationContext(ConfigHelper.Authority, new TokenDbCache(userObjectId));
AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
context.Code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, ConfigHelper.GraphResourceId);
ActiveDirectoryClient graphClient = new ActiveDirectoryClient(new Uri(ConfigHelper.GraphServiceRoot),
async () => { return await Task.FromResult(result.AccessToken); }
);
try
{
foreach (var groupClaim in context.AuthenticationTicket.Identity.FindAll("groups"))
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri($"https://graph.windows.net/adfei.onmicrosoft.com/groups/{groupClaim.Value}?api-version=1.6"),
Method = HttpMethod.Get,
};
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", result.AccessToken);
using (HttpClient httpClient = new HttpClient())
{
HttpResponseMessage httpResponse = httpClient.SendAsync(request).Result;
var retJSON = httpResponse.Content.ReadAsStringAsync().Result;
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(retJSON);
((ClaimsIdentity)context.AuthenticationTicket.Identity).AddClaim(new Claim("groupName", dict["displayName"].ToString()));
}
}
}
catch (Exception ex)
{
}
},
Then we can these info from controller using the code below:
ClaimsPrincipal.Current.FindAll("groupName")
I am working on a Microsoft Bot Framework project to add a chatbot to my website.
I need to pass data continuously from the chat UI to the Bot to get user details and current page details. Therefore I cannot use the Web Chat client.
What other methods can I use apart from creating my own chat interface ?
What other methods can I use apart from creating my own chat interface ? According to this statement, WebChat is the easiest way. Because only with an embeded Iframe you are done creating your chatbot. Apart from that,
There is a REST Api to access the botframework. It is called as Direct Line API. You can find documentation from,
HERE
Below is a code sample about how you can use it. I tried with the ASP.NET MVC application.
private async Task<bool> PostMessage(string message)
{
bool IsReplyReceived = false;
client = new HttpClient();
client.BaseAddress = new Uri("https://directline.botframework.com/api/conversations/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("BotConnector", "[YourAccessToken]");
response = await client.GetAsync("/api/tokens/");
if (response.IsSuccessStatusCode)
{
var conversation = new Conversation();
response = await client.PostAsJsonAsync("/api/conversations/", conversation);
if (response.IsSuccessStatusCode)
{
Conversation ConversationInfo = response.Content.ReadAsAsync(typeof(Conversation)).Result as Conversation;
string conversationUrl = ConversationInfo.conversationId+"/messages/";
BotDirectLineApproch.Models.Message msg = new BotDirectLineApproch.Models.Message() { text = message };
response = await client.PostAsJsonAsync(conversationUrl,msg);
if (response.IsSuccessStatusCode)
{
response = await client.GetAsync(conversationUrl);
if (response.IsSuccessStatusCode)
{
MessageSet BotMessage = response.Content.ReadAsAsync(typeof(MessageSet)).Result as MessageSet;
ViewBag.Messages = BotMessage;
IsReplyReceived = true;
}
}
}
}
return IsReplyReceived;
}
In here Message, MessageSet and Conversation are classes created by looking at the Json response in the documentation. If you need, I can add that also.
Cheers!
I am accessing Rackspace Cloud APIs.
I have one api call which authenticates me on the rackspace cloud.
The method works perfectly, however, from time to time, i get this exception, randomly :
The remote name could not be resolved: 'identity.api.rackspacecloud.com'
When i am not getting this exception, the method returns the expected result, as it should be.
Is there any specific reason why it does this?
Here is my .net code:
private async Task<XDocument> AuthenticateAsync()
{
XNamespace ns = "http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0";
XDocument doc =
new XDocument(
new XDeclaration("1.0", "UTF-8", "Yes"),
new XElement("auth",
new XElement(ns + "apiKeyCredentials",
new XAttribute("username", "the userName"),
new XAttribute("apiKey", "the apiKey")
)
)
);
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
StringContent content = new StringContent(doc.ToString(), Encoding.UTF8, "application/xml");
// i randomly get "The remote name could not be resolved" exception
HttpResponseMessage response = await client.PostAsync("https://identity.api.rackspacecloud.com/v2.0/tokens", content);
response.EnsureSuccessStatusCode();
string stringResponse = await response.Content.ReadAsStringAsync();
return XDocument.Parse(stringResponse);
}
}
This certainly sounds like a DNS failure. Can you configure your machine to use the Google DNS servers and try again?