client recieves data as [object object] - signalr

I am trying to send some objects back to client after connecting, but somehow they are receiving them as empty arrays {} when List<T> is sent and as [object Object] for
here is my hub code:
public class MyHub : Hub
{
private static readonly List<User> Users = new List<User>();
private const string DateTimeFormat = "HH:mm:ss tt zzz";
public async Task Join(string username, UserType usertype, string locale, CallerInfo callerInfo)
{
// Add the new user
var user = Users.FirstOrDefault(e => e.Username == username);
if (user != null)
{
Users.Remove(user);
}
Users.Add(new User
{
Username = username,
ConnectionId = Context.ConnectionId,
Type = usertype,
Locale = locale,
ConnectionStartTime = DateTime.Now.ToString(DateTimeFormat),
CallerInfo = callerInfo
});
await SendUserListUpdate(StatusConstants.Join, usertype);
}
public async Task SendUserListUpdate(string status, UserType userType, string conID = "")
{
object[] args = { Users, status, conID == string.Empty ? Context.ConnectionId : conID, userType };
await Clients.All.SendCoreAsync(MethodNameConstants.UpdateUserList, args);
}
}
and here is my client code:
"use strict";
var locale = 'ar-SA';
var username = 'test-user';
var usersList;
var connection = new signalR.HubConnectionBuilder().withUrl("/MyHub").withAutomaticReconnect().build();
// register listeners
connection.on('UpdateUserList',
function(users,status, connectionId, userType) {
usersList = users;
console.log(users);
console.log(usersList);
console.log('status : '+ status);
console.log('connection id : '+ connectionId);
});
// join client list
connection.start().then(async function () {
console.log('trying to join users list');
await connection.invoke('Join',username,'guest', locale, null);
console.log('join successful');
}).catch(function (err) { console.error(err); });
I am trying to receive correct objects on client side so that I can handle them correctly. I couldn't figure out why it is received like this

Related

hash and salt problem when using IPasswordHasher<User> and BCrypt algorhitm

I faced problem with hashing, salting and verifying password in ASP.NET.
I am creating a new User and then using hashing method.
But when I try to get some resources which requires Authorization and I
enter the same username and password as I saved in database the result is failed.
Here is my password hasher class:
using Microsoft.AspNetCore.Identity;
namespace FlowerShop.ApplicationServices.Components.PasswordHasher
{
public class BCryptPasswordHasher<User> : IPasswordHasher<User> where User : class
{
public string HashPassword(User user, string password)
{
return BCrypt.Net.BCrypt.HashPassword(password, 12);
}
public PasswordVerificationResult VerifyHashedPassword(User user, string hashedPassword, string providedPassword)
{
var isValid = BCrypt.Net.BCrypt.Verify(providedPassword, hashedPassword);
if (isValid && BCrypt.Net.BCrypt.PasswordNeedsRehash(hashedPassword, 12))
{
return PasswordVerificationResult.SuccessRehashNeeded;
}
return isValid ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
}
}
This is my authentication class:
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IQueryExecutor queryExecutor;
private readonly IPasswordHasher<User> passwordHasher;
public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock,
IQueryExecutor queryExecutor, IPasswordHasher<User> passwordHasher)
: base(options, logger, encoder, clock)
{
this.queryExecutor = queryExecutor;
this.passwordHasher = passwordHasher;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var endpoint = Context.GetEndpoint();
if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
{
return AuthenticateResult.NoResult();
}
if (!Request.Headers.ContainsKey("Authorization"))
{
return AuthenticateResult.Fail("Missing Authorization Header");
}
User user = null;
try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
var username = credentials[0];
var providedPassword = passwordHasher.HashPassword(user, credentials[1]);
var query = new GetUserQuery()
{
UserName = username
};
user = await this.queryExecutor.Execute(query);
if (user == null || passwordHasher.VerifyHashedPassword(user, user.PasswordHash, providedPassword)
== PasswordVerificationResult.Failed)
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Role, user.Role.ToString()),
new Claim(ClaimTypes.Email, user.Email),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
And in this place I am creating a new User:
using MediatR;
using Microsoft.AspNetCore.Identity;
using System.Threading;
using System.Threading.Tasks;
public class AddUserHandler : IRequestHandler<AddUserRequest,
AddUserResponse>
{
private readonly ICommandExecutor commandExecutor;
private readonly IQueryExecutor queryExecutor;
private readonly IMapper mapper;
private readonly IPasswordHasher<User> passwordHasher;
public AddUserHandler(ICommandExecutor commandExecutor,
IQueryExecutor queryExecutor,
IMapper mapper, IPasswordHasher<User> passwordHasher)
{
this.commandExecutor = commandExecutor;
this.queryExecutor = queryExecutor;
this.mapper = mapper;
this.passwordHasher = passwordHasher;
}
public async Task<AddUserResponse> Handle(AddUserRequest
request, CancellationToken cancellationToken)
{
var query = new GetUserQuery()
{
UserName = request.UserName,
Email = request.Email
};
var getUser = await this.queryExecutor.Execute(query);
if (getUser != null)
{
if (getUser.UserName == request.UserName)
{
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.ValidationError +
"! The name is already taken.")
};
}
if (getUser.Email == request.Email)
{
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.ValidationError +
"! Email address is in use.")
};
}
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.Conflict)
};
}
request.PasswordHash = passwordHasher.HashPassword(getUser,
request.Password);
var user = this.mapper.Map<User>(request);
var command = new AddUserCommand()
{
Parameter = user
};
var addedUser = await this.commandExecutor.Execute(command);
var response = new AddUserResponse()
{
Data =
this.mapper.Map<Domain.Models.UserDTO>(addedUser)
};
return response;
}
}
This is my Startup.cs :
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions,
BasicAuthenticationHandler>("BasicAuthentication", null);
services.AddScoped<IPasswordHasher<User>,
BCryptPasswordHasher<User>>();
}
Maybe first of all, is it all correct implemented?
Is hash in AddUserHandler correct assigned to request.PasswordHash?
How to retrieve salt and assign to request.PasswordSalt?
Sorry for any unclear things if they occur.
Any feedback and help will be appreciated.
Thanks in advance :)
Edit:
for example if I add user with password "pass123" and it is stored in database as 'user.PasswordHash = "$2a$12$Iqpy7FyQh/pt2O8upTtG5eOQKzo1V395wRNdAXPpp5Qf.NQ.KxUyy"' and provided password after hashing is 'providedPassword = "$2a$12$9vSz8Sw/WtmqGY6jyDiTleN/btZ0wXJkXdoB3sDpANVIIDGBpaqT."'
I fixed the bug if anyone needs to use it in thee future.
The problem was in my authentication class.
In place of:
var username = credentials[0];
var providedPassword = passwordHasher.HashPassword(user, credentials[1]);
Should be:
var username = credentials[0];
var providedPassword = credentials[1];
I am sure that I have checked it a few times but somehow didn't work then. Anyway, it finally works properly.

The request timed out on reading users from graph

I have the following to read users:
public asaync Task<IGroupTransitiveMembersCollectionWithReferencesPage> GetGroupMembersPageByIdAsync(string groupId)
{
return await _graphServiceClient
.Groups[groupId]
.TransitiveMembers
.Request()
.Top(MaxResultCount)
.WithMaxRetry(MaxRetries)
.GetAsync();
}
public async Task<IGroupTransitiveMembersCollectionWithReferencesPage> GetGroupMembersNextPageAsnyc(
IGroupTransitiveMembersCollectionWithReferencesPage groupMembersRef,
string nextPageUrl)
{
groupMembersRef.InitializeNextPageRequest(_graphServiceClient, nextPageUrl);
return await groupMembersRef
.NextPageRequest
.GetAsync();
}
public async Task<(List<AzureADUser> users,
Dictionary<string, int> nonUserGraphObjects,
string nextPageUrl,
IGroupTransitiveMembersCollectionWithReferencesPage usersFromGroup)> GetFirstUsersPageAsync(Guid objectId)
{
var users = new List<AzureADUser>();
var nonUserGraphObjects = new Dictionary<string, int>();
var usersFromGroup = await GetGroupMembersPageByIdAsync(objectId.ToString());
TrackMetrics(usersFromGroup.AdditionalData);
usersFromGroup.AdditionalData.TryGetValue("#odata.nextLink", out object nextLink1);
var nextPageUrl = (nextLink1 == null) ? string.Empty : nextLink1.ToString();
users.AddRange(ToUsers(usersFromGroup, nonUserGraphObjects));
return (users, nonUserGraphObjects, nextPageUrl, usersFromGroup);
}
public async Task<(List<AzureADUser> users,
Dictionary<string, int> nonUserGraphObjects,
string nextPageUrl,
IGroupTransitiveMembersCollectionWithReferencesPage usersFromGroup)> GetNextUsersPageAsync(string nextPageUrl, IGroupTransitiveMembersCollectionWithReferencesPage usersFromGroup)
{
var users = new List<AzureADUser>();
var nonUserGraphObjects = new Dictionary<string, int>();
usersFromGroup = await GetGroupMembersNextPageAsnyc(usersFromGroup, nextPageUrl);
TrackMetrics(usersFromGroup.AdditionalData);
usersFromGroup.AdditionalData.TryGetValue("#odata.nextLink", out object nextLink2);
nextPageUrl = (nextLink2 == null) ? string.Empty : nextLink2.ToString();
users.AddRange(ToUsers(usersFromGroup, nonUserGraphObjects));
return (users, nonUserGraphObjects, nextPageUrl, usersFromGroup);
}
On running this code, I see the following exception from the function GetGroupMembersNextPageAsnyc:
Message: The request timed out.
The operation was canceled. Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request.
What am I missing?

Why is my Azure SignalR Hub method not being triggered?

I am unable to resolve why my Azure SignalR Hub method is not being triggered?
Environment: Xamarin.Forms client
Disclaimer:
My LocationHub class is in a separate project that is referenced by the project that hosts my Azure Function.
Can Azure SignalR invoke a hub method that's in a separate library?
Server: Here's the hub class:
type LocationHub() =
inherit Hub()
member x.SendLocation(v:SubjectLocation) =
async { do! (x :> Hub).Clients.All.SendAsync($"{v.SessionId}", v) |> Async.AwaitTask } |> Async.StartAsTask
Server: Here's the Azure function that is suppose to trigger the method on the hub class:
public static class LocationFn
{
[FunctionName(nameof(LocationFn))]
public static async Task<IActionResult> Run(
[HttpTrigger(
AuthorizationLevel.Anonymous,
"post",
Route = "locationfn")]
HttpRequest req,
[SignalR(HubName = "LocationHub")]
IAsyncCollector<SignalRMessage> signalRMessages,
ILogger log)
{
log.LogInformation($"{nameof(LocationFn)} has been invoked.");
try
{
using (var streamReader = new StreamReader(req.Body))
{
var json = await streamReader.ReadToEndAsync();
var subjectLocation = JsonConvert.DeserializeObject<SubjectLocation>(json);
await signalRMessages.AddAsync(
new SignalRMessage
{
Target = "SendLocation",
Arguments = new[] { subjectLocation }
});
var message = Log(log, subjectLocation);
return new OkObjectResult(message);
}
}
catch (Exception ex)
{
return new BadRequestObjectResult("There was an error: " + ex.Message);
}
}
static string Log(ILogger log, SubjectLocation subjectLocation)
{
var location = subjectLocation.Location;
var latitude = location.Latitude;
var longitude = location.Longitude;
var message = $"Received location: {subjectLocation.SubjectId} at '({latitude},{longitude})'";
log.LogInformation($"{nameof(LocationFn)} {message}");
return message;
}
}
Appendix:
Client: I have the following client request:
var sessionId = "some_session_id";
await CourierTracking.connectOn(sessionId, locationTracking(), "negotiatefn");
Client: The bird's-eye view of establishing a connection is implemented here:
open System.Diagnostics
open OrderRequest.SignalR.Client
module CourierTracking =
let private onConnectionChanged (_,_) = ()
let private onMessageReceived msg = Debug.WriteLine(sprintf "%A" msg)
let private signalR = SignalRService();
let connectOn(sessionId:string) (serviceHost:string) (resourceName:string) =
signalR.Connected .Add onConnectionChanged
signalR.ConnectionFailed .Add onConnectionChanged
signalR.MessageReceived .Add onMessageReceived
async {
do! signalR.ConnectOn(serviceHost, resourceName, sessionId) |> Async.AwaitTask
} |> Async.StartAsTask
Client: Here's the core implementation for connecting and receiving messages:
public class SignalRService
{
HttpClient _client = new HttpClient();
public delegate void MessageReceivedHandler(object sender, CourierLocation message);
public delegate void ConnectionHandler(object sender, bool successful, string message);
public event MessageReceivedHandler MessageReceived;
public event ConnectionHandler Connected;
public event ConnectionHandler ConnectionFailed;
public bool IsConnected { get; private set; }
public bool IsBusy { get; private set; }
public async Task ConnectOn(string host, string nameOfNegotiationFn, string sessionId)
{
try
{
IsBusy = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var negotiateJson = await _client.GetStringAsync($"{host}{nameOfNegotiationFn}");
var negotiate = JsonConvert.DeserializeObject<NegotiateInfo>(negotiateJson);
var connection = new HubConnectionBuilder()
.AddNewtonsoftJsonProtocol()
.WithUrl(negotiate.Url, options => options.AccessTokenProvider = async () => negotiate.AccessToken)
.Build();
connection.Closed += Connection_Closed;
connection.On<JObject>(sessionId, OnIncomingMessage);
await connection.StartAsync();
IsConnected = true;
IsBusy = false;
Connected?.Invoke(this, true, "Connection successful.");
}
catch (Exception ex)
{
ConnectionFailed?.Invoke(this, false, ex.Message);
IsConnected = false;
IsBusy = false;
}
}
Task Connection_Closed(Exception arg)
{
ConnectionFailed?.Invoke(this, false, arg.Message);
IsConnected = false;
IsBusy = false;
return Task.CompletedTask;
}
void OnIncomingMessage(JObject message)
{
var courierId = message.GetValue("SubjectId").ToString();
var location = message.SelectToken("Location");
var latitude = double.Parse(location.SelectToken("Latitude").ToString());
var longitude = double.Parse(location.SelectToken("Longitude").ToString());
var courierLocation = new CourierLocation(courierId, new Coordinate(latitude, longitude));
MessageReceived?.Invoke(this, courierLocation);
}
}
I needed the client to pass in the exact name of the hub method that it subscribes to:
var hubMethodName = "LocationUpdate";
...
var connection = new HubConnectionBuilder()
.AddNewtonsoftJsonProtocol()
.WithUrl(negotiate.Url, options => options.AccessTokenProvider = async () => negotiate.AccessToken)
.Build();
connection.Closed -= Connection_Closed;
connection.Closed += Connection_Closed;
connection.On<JObject>(hubMethodName, OnIncomingMessage); // ** REF: HUB METHOD NAME **
await connection.StartAsync();

Stripe.net in Xamarin.Forms PCL with ASP.NET Core MVC Web API

I am trying to implement Stripe.net into my Xamarin.Forms PCL using an ASP.NET Core MVC Web API. The goal is to process credit card payment from users. My web API runs locally on http://localhost:port for testing purposes.
In the PaymentPage, a user enters their credit card information into Entry objects and when they click the submit Button, a method in the PaymentPageViewModel is called to start the logic:
async void OnFinishBookingClicked(object sender, System.EventArgs e)
{
// TODO: Stripe integration
var viewModel = (PaymentPageViewModel)this.BindingContext;
await viewModel.ProcessPayment();
}
This is part of the PaymentPageViewModel:
private readonly IStripeRepository _repository;
private readonly IAPIRepository _api;
public PaymentPageViewModel(IStripeRepository repository, IAPIRepository api)
{
_repository = repository;
_api = api;
}
public async Task ProcessPayment()
{
try
{
if (string.IsNullOrEmpty(ExpirationDate))
ExpirationDate = "09/18";
var exp = ExpirationDate.Split('/');
var token = _repository.CreateToken(CreditCardNumber, exp[0], exp[1], SecurityCode);
await Application.Current.MainPage.DisplayAlert("Test Message", token, "OK");
await _api.ChargeCard(token, 5.00M);
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
}
}
This is what the APIRepository looks like:
public class APIRepository: IAPIRepository
{
const string Url = "http://localhost:5000";
private string authorizationKey;
private async Task<HttpClient> GetClient()
{
HttpClient client = new HttpClient();
if (string.IsNullOrEmpty(authorizationKey))
{
authorizationKey = await client.GetStringAsync(Url);
authorizationKey = JsonConvert.DeserializeObject<string>(authorizationKey);
}
client.DefaultRequestHeaders.Add("Authorization", authorizationKey);
client.DefaultRequestHeaders.Add("Accept", "application/json");
return client;
}
public async Task<string> ChargeCard(string token, decimal amount)
{
HttpClient client = await GetClient();
var json = JsonConvert.SerializeObject(new { token, amount });
var response = await client.PostAsync("/api/Stripe", new StringContent(json));
return await response.Content.ReadAsStringAsync();
}
}
The issue is that I get a series of errors during await _api.ChargeCard(token, 5.00M):
The first exception happens during authorizationKey = await client.GetStringAsync(Url); the exception message is the following:
{System.Net.Http.HttpRequestException: 404 (Not Found) at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode () [0x0000a] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.2.0.11/src/mono/mcs/class/System.Net.Http/System.Net.Http/HttpResponseM…}
I get another exception during response = await client.PostAsync("/api/Stripe", new StringContent(json));
{System.InvalidOperationException: The request URI must either be an absolute URI or BaseAddress must be set at System.Net.Http.HttpClient.SendAsync (System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpCompletionOption completionOption, System.Thr…}
The third exception happens at the catch block of the viewModel.ProcessPayment() method:
{System.NullReferenceException: Object reference not set to an instance of an object at Zwaby.Services.APIRepository+d__3.MoveNext () [0x00184] in /Users/carlos/Projects/Zwaby/Zwaby/Services/APIRepository.cs:57 --- End of stack trace from previou…}
In my Web API project, I have a StripeController, but my implementation may not be fully correct:
[Route("api/Stripe")]
public class StripeController : Controller
{
private readonly StripeContext _context;
public StripeController(StripeContext context)
{
_context = context;
if (_context.StripeCharges.Count() == 0)
{
_context.StripeCharges.Add(new StripeItem { });
_context.SaveChanges();
}
}
[HttpGet]
public IActionResult Get(string key)
{
// TODO: implement method that returns authorization key
}
[HttpPost]
public IActionResult Charge(string stripeToken, decimal amount)
{
var customers = new StripeCustomerService();
var charges = new StripeChargeService();
var customer = customers.Create(new StripeCustomerCreateOptions
{
SourceToken = stripeToken
});
var charge = charges.Create(new StripeChargeCreateOptions
{
Amount = (int)amount,
Description = "Sample Charge",
Currency = "usd",
CustomerId = customer.Id
});
return View();
}
}
For completeness, I am including the StripeRepository class, the other parameter of the PaymentPageViewModel:
public class StripeRepository: IStripeRepository
{
public string CreateToken(string cardNumber, string cardExpMonth, string cardExpYear, string cardCVC)
{
StripeConfiguration.SetApiKey("my_test_key");
//TODO: Wireup card information below
var tokenOptions = new StripeTokenCreateOptions()
{
Card = new StripeCreditCardOptions()
{
Number = "4242424242424242",
ExpirationYear = 2018,
ExpirationMonth = 10,
Cvc = "123"
}
};
var tokenService = new StripeTokenService();
StripeToken stripeToken = tokenService.Create(tokenOptions);
return stripeToken.Id;
}
}
Thank you so much!

SignalR 2.0 Hub public method not accecible via Java Script

I'm trying to get list of connected users by using the following server code in SignalR hub. For store in-memory data I'm using following class:
public class UserInfo
{
public string ConnectionId { get; set; }
public string UserName { get; set; }
public string Role { get; set; }
}
When user connected I'm adding user to the list of connected users:
public override Task OnConnected()
{
if (Context.User.Identity.IsAuthenticated)
{
if (Context.User.IsInRole("User"))
{
ui.Add(new UserInfo { ConnectionId = Context.ConnectionId, UserName = Context.User.Identity.Name, Role = "User" });
}
else
{
ui.Add(new UserInfo { ConnectionId = Context.ConnectionId, UserName = Context.User.Identity.Name, Role = "Operator" });
}
}
return base.OnConnected();
}
Here is the way I'm getting list of currently connected users:
public IEnumerable<UserInfo> GetUsers()
{
var x = (from a in ui where a.Role == "User" select new UserInfo { UserName = a.UserName, ConnectionId = a.ConnectionId }).ToList();
return x;
}
public IEnumerable<UserInfo> GetOperators()
{
var y = (from a in ui where a.Role == "Operator" select new UserInfo { UserName = a.UserName, ConnectionId = a.ConnectionId }).ToList();
return y;
}
Unfortinately public method GetOperators/GetUsers not accessible and I did not receive data on client side:
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
//Here I'm calling hub public methods
chat.getOperators = function (data) {
alert(data);
};
chat.getUsers = function (data) {
alert(data);
};
// Create a function that the hub can call to broadcast messages.
chat.client.addChatMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
// Get the user name and store it to prepend to messages.
$('#displayname').val(prompt('Enter your name:', ''));
// Set initial focus to message input box.
$('#message').focus();
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.sendChatMessage($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
});
Your syntax for the calls to the server is wrong; this here:
chat.getUsers = function (data) {
alert(data);
};
will simply define chat.getUsers to be a function.
You probably want
chat.server.getUsers().done(function(data) {
console.log(data);
}).fail(function(error) {
console.log("failed to get data", error);
});
Take another look at the documentation.
please can you try this
//on your client action do a server call
chat.server.getOperators();
and
//on your client action do a server call
chat.server.getUsers();
instead of
chat.getOperators = function (data) {
alert(data);
};
chat.getUsers = function (data) {
alert(data);
};

Resources