Password reset link using identity and web api - email

I'm trying to create in my WebApi controller an action to send an email with a passwors reset link. But when the email arrives, the link url is "http://Account/ResetPassword/........"
Please, note the site url is missing from de link. I need something like "http://www.domain.com/account/resetpassword/........."
This is my code. Thanks!
[System.Web.Http.AllowAnonymous]
[System.Web.Http.HttpGet]
[System.Web.Http.Route("ForgotPassword")]
public async Task<IHttpActionResult> ForgotPassword(string email)
{
if (string.IsNullOrWhiteSpace(email))
{
ModelState.AddModelError("", "Email is required");
return BadRequest(ModelState);
}
var user = await AppUserManager.FindByNameAsync(email);
if (user != null)
{
string code = await AppUserManager.GeneratePasswordResetTokenAsync(user.Id);
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
urlHelper.Action("ResetPassword", "Account", new RouteValueDictionary(new { userId = user.Id, code }), protocol: Request.RequestUri.Scheme);
await AppUserManager.SendEmailAsync(user.Id, "Redefinir Senha", "Redefina sua senha clicando aqui");
return Ok();
}
return NotFound();
}

Related

Facebook complains that the app is not secure

When I try to login via Facebook, it throws the following error;
facebook has detected app isn't using a secure connection to transfer information
But I'm pretty sure that it is secured via 'Let's encrypt'.
I have checked Web and Client OAuth login boxes and set the corresponding redirect uris on developer facebook.
On maui side, I am calling the following code piece and AppSettings.BaseUrl is correct, I have checked that;
WebAuthenticatorResult authResult = await WebAuthenticator.Default.AuthenticateAsync(
new WebAuthenticatorOptions()
{
Url = new Uri($"{AppSettings.BaseUrl}account/authentication/{scheme}"),
CallbackUrl = new Uri("tibi://"),
PrefersEphemeralWebBrowserSession = true
});
And on backend side, the following api is requested;
[HttpGet("authentication/{scheme}")]
[AllowAnonymous]
public async Task Get([FromRoute] string scheme)
{
var auth = await Request.HttpContext.AuthenticateAsync(scheme);
if (!auth.Succeeded
|| auth?.Principal == null
|| !auth.Principal.Identities.Any(id => id.IsAuthenticated)
|| string.IsNullOrEmpty(auth.Properties.GetTokenValue("access_token")))
{
// Not authenticated, challenge
await Request.HttpContext.ChallengeAsync(scheme);
}
else
{
var claims = auth.Principal.Identities.FirstOrDefault()?.Claims;
var email = string.Empty;
email = claims?.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Email)?.Value;
// Get parameters to send back to the callback
var qs = new Dictionary<string, string>
{
{ "access_token", auth.Properties.GetTokenValue("access_token") },
{ "refresh_token", auth.Properties.GetTokenValue("refresh_token") ?? string.Empty },
{ "expires_in", (auth.Properties.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToString() },
{ "email", email }
};
// Build the result url
var url = callbackScheme + "://#" + string.Join(
"&",
qs.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1")
.Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"));
// Redirect to final url
Request.Host = HostString.FromUriComponent(AppSettingsProvider.GatewayUrl);
Request.HttpContext.Response.Redirect(url);
}
}
Challenge is invoked successfully and redirects me to the Facebook login but when I sign in, I get the error above.

SSE "data" field not being received by Dart http.client

I'm building a Flutter app that receives SSE from a server and translates them to specific notifications. The server is a Spring Boot app returning events containing "event:" and "data:" fields:
public void pushNotification(String username, PushEvent event) {
var emitter = emitters.get(username);
if (emitter == null) {
return;
}
try {
emitter.send(event.toSseEvent());
} catch (IOException e) {
log.debug("Could not send event for user " + username);
emitters.remove(username);
}
}
public class PushEvent {
private String type;
private Map<String, Object> body;
public SseEmitter.SseEventBuilder toSseEvent() {
return SseEmitter.event().name(type).data(body);
}
}
On the Flutter app, I use the Dart http package to open a Stream and receive the events:
Future<void> subscribe() async {
if (!_userModel.hasAuthentication()) {
return;
}
var user = _userModel.user as AuthenticatedUser;
var username = user.username;
var token = _userModel.getToken();
var uri = Uri.https(ApiUtils.API_BASE, '/api/push/subscribe/$username');
try {
var client = http.Client();
_client = client;
var request = new http.Request("GET", uri);
request.headers["Accept"] = "text/event-stream";
request.headers["Cache-Control"] = "no-cache";
request.headers["Authorization"] = token;
var response = await client.send(request);
if (response.statusCode == 200) {
_isSubscribed = true;
response.stream.toStringStream().forEach((value) {
var event = ServerEvent.parse(value);
_handleEvents(event);
}).onError((error, stackTrace) {
log.info("Connection closed");
log.info(error);
log.info(stackTrace);
unsubscribe();
}).whenComplete(() {
log.info("Connection completed");
unsubscribe();
subscribe();
});
} else {
_isSubscribed = false;
}
notifyListeners();
} catch (e) {
unsubscribe();
log.warning("Could not subscribe to notifications");
log.warning(e);
}
}
However, when I receive an event containing data from the server, the data does not show on the log:
I/flutter (14779): event:FRIEND_REQUEST
I/flutter (14779): data:
I am certain the data is being sent by the server since the React app on the same domain decodes the SSE and shows the notifications as intended:
const subscribePush = () => {
const username = sessionStorage.getItem('loggedUsername');
const token = sessionStorage.getItem('token');
var es = new EventSourcePolyfill(
'/api/push/subscribe/' + username,
{
headers: {
"Authorization": token,
}
}
);
es.onerror = () => es.close();
es.addEventListener("FRIEND_REQUEST", e => handleFriendRequestEvent(e));
es.addEventListener("FRIEND_ACCEPT", e => handleFriendAcceptEvent(e));
}
const handleFriendRequestEvent = function (event) {
const username = sessionStorage.getItem("loggedUsername");
const data = JSON.parse(event.data);
const source = data.source;
if (source !== username) {
var note = `${source} solicitou sua amizade!`;
var newNotifs = notifications.concat(note);
setNotifications(newNotifs);
setNewNotifications(newNotifications + 1);
}
}
Could something be missing from the request on the Flutter app, or is it possibly a bug?
Your implementation looks strangely similar to this one:
https://github.com/stevenroose/dart-eventsource
Take a look at the client implementation and how the response in decoded using the decoder.dart file.

Web App Bot throws invalid status code 'Unauthorized' on Facebook Channel

I'm developing a Facebook with the Microsoft.Bot.Builder Framework (4.2.2)
The Bot Works on emulator and on Azure with the "Test in Web Chat" Really fine. But on the Facebook Channel I get an "There was an error sending this message to your bot: HTTP status code InternalServerError"
My log stream says:
019-04-12 13:23:22.154 +00:00 [Information]
Microsoft.AspNetCore.Hosting.Internal.WebHost: Request starting
HTTP/1.1 POST
http://thomasreigltestbot1995.azurewebsites.net/api/messages
application/json; charset=utf-8 688
2019-04-12 13:23:22.155 +00:00 [Information]
Microsoft.Bot.Builder.Integration.IAdapterIntegration: Received an
incoming activity. ActivityId: Vg2USjaJGCZ1Ib_-
LTftnL9F6qg_DCJaV3XbIqGzSpisuO10eYLezkjHJxSVcYAAUWQvynDJbUyfvyBgN30B3w
2019-04-12 13:23:22.155 +00:00 [Information]
Microsoft.Bot.Builder.Integration.IAdapterIntegration: Sending
activity. ReplyToId: Vg2USjaJGCZ1Ib_-
LTftnL9F6qg_DCJaV3XbIqGzSpisuO10eYLezkjHJxSVcYAAUWQvynDJbUyfvyBgN30B3w
2019-04-12 13:23:22.388 +00:00 [Error]
Facebook_Events_Bot.FacebookEventsBot: Exception caught :
Microsoft.Bot.Schema.ErrorResponseException: Operation returned an
invalid status code 'Unauthorized'at
Microsoft.Bot.Connector.Conversations.
This is my simple Bot from this repo:
https://github.com/Microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/23.facebook-events
public class FacebookEventsBot : IBot
{
private const string DialogId = "question";
/// </summary>
private readonly DialogSet _dialogs;
private Tuple<int, string> tuple;
public FacebookEventsBot(BotAccessors accessors)
{
if (accessors == null)
{
throw new ArgumentNullException(nameof(accessors));
}
_dialogs = new DialogSet(accessors.ConversationDialogState);
_dialogs.Add(new AttachmentPrompt(DialogId));
}
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
const string facebookPageNameOption = "Facebook Page Name";
const string quickRepliesOption = "Quick Replies";
const string postBackOption = "PostBack";
if (turnContext == null)
{
throw new ArgumentNullException(nameof(turnContext));
}
// Check if we are on the Facebook channel.
if (turnContext.Activity.ChannelId == Channel.Channels.Facebook)
{
// Analyze Facebook payload from channel data.
ProcessFacebookPayload(turnContext.Activity.ChannelData);
// Initially the bot offers to showcase 3 Facebook features: Quick replies, PostBack and getting the Facebook Page Name.
// Below we also show how to get the messaging_optin payload separately as well.
switch (turnContext.Activity.Text)
{
// Here we showcase how to obtain the Facebook page name.
// This can be useful for the Facebook multi-page support provided by the Bot Framework.
// The Facebook page name from which the message comes from is in turnContext.Activity.Recipient.Name.
case facebookPageNameOption:
{
var reply = turnContext.Activity.CreateReply($"This message comes from the following Facebook Page: {turnContext.Activity.Recipient.Name}");
await turnContext.SendActivityAsync(reply);
break;
}
// Here we send a HeroCard with 2 options that will trigger a Facebook PostBack.
case postBackOption:
{
var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);
var results = await dialogContext.ContinueDialogAsync(cancellationToken);
var card = new HeroCard
{
Text = "Is 42 the answer to the ultimate question of Life, the Universe, and Everything?",
Buttons = new List<CardAction>
{
new CardAction() { Title = "Yes", Type = ActionTypes.PostBack, Value = "Yes" },
new CardAction() { Title = "No", Type = ActionTypes.PostBack, Value = "No" },
},
};
var reply = turnContext.Activity.CreateReply();
reply.Attachments = new List<Attachment> { card.ToAttachment() };
await turnContext.SendActivityAsync(reply);
break;
}
// By default we offer the users different actions that the bot supports, through quick replies.
case quickRepliesOption:
default:
{
var reply = turnContext.Activity.CreateReply("What Facebook feature would you like to try? Here are some quick replies to choose from!");
reply.SuggestedActions = new SuggestedActions()
{
Actions = new List<CardAction>()
{
new CardAction() { Title = quickRepliesOption, Type = ActionTypes.PostBack, Value = quickRepliesOption },
new CardAction() { Title = facebookPageNameOption, Type = ActionTypes.PostBack, Value = facebookPageNameOption },
new CardAction() { Title = postBackOption, Type = ActionTypes.PostBack, Value = postBackOption },
},
};
await turnContext.SendActivityAsync(reply);
break;
}
}
}
else
{
// Check if we are on the Facebook channel.
if (turnContext.Activity.ChannelId == Channel.Channels.Facebook)
{
// Here we can check for messaging_optin webhook event.
// Facebook Documentation for Message optin:
// https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_optins/
}
await turnContext.SendActivityAsync($"Received activity of type {turnContext.Activity.Type}.");
}
}
private void ProcessFacebookPayload(object channelData)
{
// At this point we know we are on Facebook channel, and can consume the Facebook custom payload
// present in channelData.
var facebookPayload = (channelData as JObject)?.ToObject<FacebookPayload>();
if (facebookPayload != null)
{
// PostBack
if (facebookPayload.PostBack != null)
{
OnFacebookPostBack(facebookPayload.PostBack);
}
// Optin
else if (facebookPayload.Optin != null)
{
OnFacebookOptin(facebookPayload.Optin);
}
// Quick reply
else if (facebookPayload.Message?.QuickReply != null)
{
OnFacebookQuickReply(facebookPayload.Message.QuickReply);
}
// TODO: Handle other events that you're interested in...
}
}
private void OnFacebookOptin(FacebookOptin optin)
{
// TODO: Your optin event handling logic here...
}
private void OnFacebookPostBack(FacebookPostback postBack)
{
// TODO: Your PostBack handling logic here...
}
private void OnFacebookQuickReply(FacebookQuickReply quickReply)
{
// TODO: Your quick reply event handling logic here...
}
}
}

In AspBoilerPlate - Unauthorized error when calling from Angular when Windows Authentication is On

Have already raised this before and thought I have addressed it as per what suggested on THIS and THIS but seems not!
I am using ABP template (Angular and ASP .NET CORE Application) on Full .Net Framework. I simply want to use Windows Authentication to Authenticate user.
I added [Authorize] to the Authenticate in the TokenAuthController and have finally got the HttpContext.User.Identity.Name populated but only when I call the Authenticate from the Swagger (http://localhost:21021/swagger). But I am getting Unauthorized error when calling the method from Angular (login.service.ts):
POST http://localhost:21021/api/TokenAuth/Authenticate 401 (Unauthorized)
Here is the steps I have taken so far:
Changed launchSetting.json:
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:21021/",
"sslPort": 0
}
},
Added ExternalAuthenticationSource:
public class WindowsAuthSource : DefaultExternalAuthenticationSource<Tenant, User>, ITransientDependency
{
public override string Name
{
get { return "Windows Authentication"; }
}
public override Task<bool> TryAuthenticateAsync(string userNameOrEmailAddress, string plainPassword, Tenant tenant)
{
return Task.FromResult(true);
}
}
Added it to CoreModule:
Configuration.Modules.Zero().UserManagement.ExternalAuthenticationSources.Add<WindowsAuthSource>();
4.Adjust AuthConfigurer:
services.AddAuthentication(opt => {
opt.DefaultScheme = IISDefaults.AuthenticationScheme;
opt.DefaultAuthenticateScheme = IISDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = IISDefaults.AuthenticationScheme;
});
Adjust StartUp.cs:
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "WINDOWS";
iis.AutomaticAuthentication = true;
});
Changed Authenticate method in the TokenAuthController:
public async Task<AuthenticateResultModel> Authenticate([FromBody]
AuthenticateModel model)
{
//var username = WindowsIdentity.GetCurrent().Name.Split('\\').Last();
var username = HttpContext.User.Identity.Name;
model.UserNameOrEmailAddress = username;
var loginResult = await GetLoginResultAsync(
model.UserNameOrEmailAddress,
model.Password,
null
);
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new AuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncrpyedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
UserId = loginResult.User.Id
};
}
Sending dummy username and password from login.service.ts:
authenticate(finallyCallback?: () => void): void {
finallyCallback = finallyCallback || (() => { });
//Dummy data
this.authenticateModel.userNameOrEmailAddress = "DummyUsername";
this.authenticateModel.password = "DummyPassword";
this._tokenAuthService
.authenticate(this.authenticateModel)
.finally(finallyCallback)
.subscribe((result: AuthenticateResultModel) => {
this.processAuthenticateResult(result);
});
}

Auth0 - get provider user id

at the moment I am relying on a junky method to get the provider user id (the string/number used in in user page urls of the social) based on splitting the profile "sub" field given from the /profile endpoint.
I saw that the old API had a field named "identities" where seems to be stored the provider user id, is there an equivalent for the new API?
Basically it should return:
facebook: the user number or url nickname http://www.facebook.com/mattiamanzati or http://www.facebook.com/100011120071734 if a nickname was'nt set
twitter: the twitter handle http://www.twitter.com/mattiamanzati
instagram: the instagram handle http://www.instagram.com/cenaacorte
This is the code I've been using now, and you can see how junky is the provider and provider_uid setting is.
var webAuth = new auth0.WebAuth({
domain: "himy.eu.auth0.com",
clientID: "0gz79WpxVxXNH5qeYRXXTxTQiWZZEV9S",
redirectUri: window.location.href,
audience: "https://himy.eu.auth0.com/userinfo",
responseType: "token id_token",
scope: "openid profile"
});
function handleAuthentication() {
webAuth.parseHash(function(err, authResult) {
if (authResult && authResult.accessToken && authResult.idToken) {
window.location.hash = "";
webAuth.client.userInfo(authResult.accessToken, function(err, profile) {
if (profile) {
if (window.postMessage) {
if (profile.sub.indexOf("facebook") === 0) {
profile.provider_uid = profile.sub.split("|")[1];
profile.provider = "facebook";
} else if (profile.sub.indexOf("instagram") === 0) {
profile.provider_uid = profile.nickname;
profile.provider = "instagram";
}
window.postMessage(JSON.stringify(profile));
}
console.log(profile);
}
});
} else if (err) {
console.log(err);
}
});
}
window.addEventListener("load", function(e) {
if (!window.location.hash) {
webAuth.authorize();
} else {
handleAuthentication();
}
});