How to trace ChangePassword of authentication in API - authentication

I have an API which dose not any related View and it's for authentication's methods, my change password has been doing something wrong, I don't know what's the exact problem then I have to trace it
My change password is :
[Route("password")]
[BasicAuthenticationFilter]
[HttpPost]
public async Task<UpdateResult<bool>> ChangePassword([FromBody]ChangePasswordViewModel password)
{
try
{
var result = await _userManagerService.ChangePassword(Thread.CurrentPrincipal.Identity.Name, password.NewPassword, password.OldPassword);
return UpdateResult<bool>.Success(result);
var ChangePasswordViewModel = new ChangePasswordViewModel { OldPassword = "", NewPassword = "" };
}
catch (Exception ex)
{
return UpdateResult<bool>.Fail(ex.Message, 1);
}
}
Because it's httpPost I'm using PostMan to trace it and my url is like this :
http://localhost:2511/v1/auth/password?password=new ChangePasswordViewModel{ OldPassword = "13532548", NewPassword = "123456" }
But it send my password parameter null, What's my problem?

You specified that your parameters should be passed in your request body by using [FromBody] attribute like this [FromBody]ChangePasswordViewModel password then this URL
http://localhost:2511/v1/auth/password?password=new ChangePasswordViewModel{ OldPassword = "13532548", NewPassword = "123456" }
is incorrect for passing data to your action. With Postman, you should do this if you want to reach your action:
Second just because you're using basic authentication then make sure to give the authentication data to Postamn too like this:

Related

Sending mail multiple times by Microsoft Graph

Blazor server application
I have a web appliction that is using AzureAd and OpenIdConnect to login to this application.
I am sending mail by using Microsoft graph and I am using the example in Microsoft doc with some changes like this:
#inject Microsoft.Graph.GraphServiceClient GraphServiceClient
#inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
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;
try
{
await GraphServiceClient.Me
.SendMail(message,saveToSentItems)
.Request()
.PostAsync();
}
catch(Exception ex)
{
ConsentHandler.HandleException(ex);
}
Scenario of the error
This works perfect but just for one time , if I try to send the same email again it doesn't work and I got no error but just redirect me to empty page.
If I logout and login again, then it works fine.
The error that I got in the second time:
Message = "IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent. "
MsalUiRequiredException = {"No account or login hint was passed to the AcquireTokenSilent call. "}
My Question
How can fix the code up to send multi emails?. I think that I have a problem with token but I don't know where should I start?.
Thanks
Add the other catch block to retrieve the specific issue if we have any related to permissions or other ServiceExceptions.
try
{
SendMail(); // Sending mail code here.
}
catch (Microsoft.Graph.ServiceException e)
{
// get the error here if we have any.
}
After some search, I think that I have to move the the permission Delegated permissions to Application Permissions like this:
Why should I use application permission?
In my case the user logged in for the first time and clicked on the button then the email will be send, but in the second time the application has to communicate with API graph without interaction from the user, that means without user and this exactly what I need(application permission).
I adjust the code like the following:
Client credentials provider:
The client credential flow enables service applications to run without user interaction. Access is based on the identity of the application. this is from Microsoft doc
private GraphServiceClient CreateGraphServiceClient()
{
// The client credentials flow requires that you request the
// /.default scope, and preconfigure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { "https://graph.microsoft.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";
// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
return new GraphServiceClient(clientSecretCredential, scopes);
}
Send mail with UserId, you can see the code in Microsoft doc:
puplic SendMyEmail()
{
GraphServiceClient graphClient = CreateGraphServiceClient;
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;
//See GetUserId down
string userId = await GetUserId();
await graphClient.Users[UserId]
.SendMail(message,saveToSentItems)
.Request()
.PostAsync();
}
}
UserId:
To get user Id you need AuthenticationStateProvider, this has to inject in the service of your application and then add to the constructor of your class, then you can use it.
puplic class MyClass
{
private readonly MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler;
private readonly AuthenticationStateProvider authenticationState;
puplic MyClass(
MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler,
AuthenticationStateProvider authenticationState)
{
this.authenticationState = authenticationState;
this.ConsentHandler = ConsentHandler;
}
public async Task<string> GetUserId()
{
var authSate = await authenticationState.GetAuthenticationStateAsync();
return authSate.User.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");
}
//Here your
private GraphServiceClient CreateGraphServiceClient() { ...}
puplic SendMyEmail() {....}
}

UserManager: How to check if the code generated by GenerateChangeEmailTokenAsync() was used

I use UserManager's GenerateChangeEmailTokenAsync() to generate and send the verification code to the new email. I'd like to check if the code has been used in an unauthenticated context and display a message to the user if the new email was verified already: "Your new email address has already been verified. Please log in".
Is there a method in UserManager to accomplish this?
I'm afraid there is no method in userManager can achieve your requirement, But i think you can pass this success message by yourself. You can refer to this code:
//I use this code to get the currently logged in user
var user = _userManager.GetUserAsync(User).Result;
var result = await _userManager.ChangeEmailAsync(user, newEmail, token);
if (result.Succeeded)
{
TempData["Message"] = "Your new email address has already been verified. Please log in";
return RedirectToAction("ChangeEmail", "Test");
}
else
{
TempData["Message"] = "Email change failed";
return RedirectToAction("ChangeEmail", "Test");
}
Test/ChangeEmail
[HttpGet]
public IActionResult ChangeEmail()
{
//use ViewBag to pass data from controller to view
ViewBag.Message = TempData["Message"];
return View();
}
View
//.....
<h1>#ViewBag.Message</h1>
If change email successfully, it will show message in the view

.NET Core Identity forgot password broken

I am using the scaffolded Identity with .NET 5. I tried the "Forgot Password" link on the login page. This works in that the email is sent with the link to reset the password.
However, clicking on the link in the email leads to an error relating to the base 64 code being malformed. Malformed input: 321 is an invalid input.
The base 64 code is there but there's an issue with it. The base 64 code is generated with this:
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ResetPassword",
pageHandler: null,
values: new { area = "Identity", code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(
Input.Email,
"Reset Password",
$"Please reset your password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
It breaks on the ResetPassword.cshtml.cs GET.
if (code == null)
{
return BadRequest("A code must be supplied for password reset.");
}
else
{
Input = new InputModel
{
Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code))
};
return Page();
}
Can anyone point me in the right direction to fixing this? I am not sure it's relevant but I am using SendGrid's SMTP server.
UPDATE. I spotted that there is a trailing inverted comma at the end of the code. Removing this fixes the issue.
code = code.Replace("'", "");
Now I just need to find out how it's getting there.
Tried and ruled out the following.
Turned off SendGrid link tracking.
Turned off Outlook safelinks.
The above made no difference.
Then it dawned on me that the email link was not rendering as HTML. i.e. it was showing the link text and not just the "click here".
Then I read that smtp client is now obsolete and MS recommends using MailKit instead.
So I decided to replace my email sender code with the following using Mailkit and the issue went away.
public Task SendEmailAsync(string email, string subject, string htmlMessage)
{
var message = new MimeMessage();
message.From.Add(new MailboxAddress("(Admin)", "test#test.com"));
message.To.Add(new MailboxAddress("Recipient Name", email));
message.Subject = subject;
message.Body = new TextPart("html")
{
Text = htmlMessage
};
string Username = _config["MailSettings:Username"];
string Password = _config["MailSettings:Password"];
var port = Convert.ToInt32(_config["MailSettings:Port"]);
using var client = new SmtpClient();
client.Connect(_config["MailSettings:Host"], port, false);
client.Authenticate(Username, Password);
try
{
client.Send(message);
client.Disconnect(true);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return Task.CompletedTask;
}
I think this is the part that saved the day:
message.Body = new TextPart("html")
{
Text = htmlMessage
};

Basic Auth to Receive Token in Spring Security

I am implementing a RESTful API where the user must authenticate. I want the user to POST their credentials in order to receive a JSON web token (JWT), which is then used for the remainder of the session. I have not found any good sources of information to set this up. In particular, I'm having trouble with the filter. Does anybody have any information or tutorials to help me set this up?
The people at Stormpath have quite a straightforward solution for achieving Oauth. Please take a look at Using Stormpath for API Authentication.
As a summary, your solution will look like this:
You will use the Stormpath Java SDK to easily delegate all your user-management needs.
When the user presses the login button, your front end will send the credentials securely to your backend-end through its REST API.
By the way, you can also completely delegate the login/register/logout functionality to the Servlet Plugin. Stormpath also supports Google, Facebook, LinkedIn and Github login.
Your backend will then try to authenticate the user against the Stormpath Backend and will return an access token as a result:
/**
* Authenticates via username (or email) and password and returns a new access token using the Account's ApiKey
*/
public String getAccessToken(String usernameOrEmail, String password) {
ApiKey apiKey = null;
try {
AuthenticationRequest request = new UsernamePasswordRequest(usernameOrEmail, password);
AuthenticationResult result = application.authenticateAccount(request);
Account account = result.getAccount();
ApiKeyList apiKeys = account.getApiKeys();
for (ApiKey ak : apiKeys) {
apiKey = ak;
break;
}
if (apiKey == null) {
//this account does not yet have an apiKey
apiKey = account.createApiKey();
}
} catch (ResourceException exception) {
System.out.println("Authentication Error: " + exception.getMessage());
throw exception;
}
return getAccessToken(apiKey);
}
private String getAccessToken(ApiKey apiKey) {
HttpRequest request = createOauthAuthenticationRequest(apiKey);
AccessTokenResult accessTokenResult = (AccessTokenResult) application.authenticateApiRequest(request);
return accessTokenResult.getTokenResponse().getAccessToken();
}
private HttpRequest createOauthAuthenticationRequest(ApiKey apiKey) {
try {
String credentials = apiKey.getId() + ":" + apiKey.getSecret();
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Content-Type", new String[]{"application/x-www-form-urlencoded"});
headers.put("Authorization", new String[]{"Basic " + Base64.encodeBase64String(credentials.getBytes("UTF-8"))});
Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
parameters.put("grant_type", new String[]{"client_credentials"});
HttpRequest request = HttpRequests.method(HttpMethod.POST)
.headers(headers)
.parameters(parameters)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Then, for every authenticated request, your backend will do:
/** This is your protected API */
public void sayHello(String accessToken) throws OauthAuthenticationException {
try {
if (verify(accessToken)) {
doStartEngines(); //Here you will actually call your internal doStartEngines() operation
}
} catch (OauthAuthenticationException e) {
System.out.print("[Server-side] Engines not started. accessToken could not be verified: " + e.getMessage());
throw e;
}
}
private boolean verify(String accessToken) throws OauthAuthenticationException {
HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
OauthAuthenticationResult result = application.authenticateOauthRequest(request).execute();
System.out.println(result.getAccount().getEmail() + " was successfully verified");
return true;
}
private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) {
try {
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Authorization", new String[]{"Bearer " + token});
HttpRequest request = HttpRequests.method(HttpMethod.GET)
.headers(headers)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
All this will not need any special Spring Security configuration, this is plain Java code that you can run in any framework.
Please take a look here for more information.
Hope that helps!
Disclaimer, I am an active Stormpath contributor.
Here's a working sample code from Spring Security OAuth github.
https://github.com/spring-projects/spring-security-oauth/tree/master/tests/annotation/jwt
You probably don't even need to mess with the filters as shown in the above example. If you've custom needs, please post some sample code.

How to setup auth token security for WebAPI requests?

In following this tutorial (modifying it to use an application-based auth string rather than their user model), have the following TokenValidationAttribute defined and set this attribute on WebAPI controllers in order to verify that the API request came within my web application:
public class TokenValidationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
string token;
try
{
token = actionContext.Request.Headers.GetValues("Authorization-Token").First();
}
catch (Exception)
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
{
Content = new StringContent("Missing Authorization-Token")
};
return;
}
try
{
var crypto = new SimpleCrypto.PBKDF2(); // type of encryption
var authPart = ConfigurationManager.AppSettings["AuthorizationTokenPart"];
var authSalt = GlobalVariables.AuthorizationSalt;
var authToken = GlobalVariables.AuthorizationToken;
if (authToken == crypto.Compute(authPart, authSalt))
{
// valid auth token
}
else
{
// invalid auth token
}
//AuthorizedUserRepository.GetUsers().First(x => x.Name == RSAClass.Decrypt(token));
base.OnActionExecuting(actionContext);
}
catch (Exception ex)
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
{
Content = new StringContent("Unauthorized User")
};
return;
}
}
}
In my login class, I have the following method defined that returns a User object if valid:
private User IsValid(string username, string password)
{
var crypto = new SimpleCrypto.PBKDF2(); // type of encryption
using (var db = new DAL.DbContext())
{
var user = db.Users
.Include("MembershipType")
.FirstOrDefault(u => u.UserName == username);
if (user != null && user.Password == crypto.Compute(password, user.PasswordSalt))
{
return user;
}
}
return null;
}
As you can see, the user login validation method doesn't make a WebAPI call that would be to ~/api/User (that part works).
1) How do I generate a request with with auth token (only site-generated API requests are valid)? These could be direct API calls from code-behind, or JavaScript-based (AngularJS) requests to hydrate some objects.
2) I'm not entirely clear on what base.OnActionExecuting(actionContext); . What do I do if the token is valid/invalid?
i think the best practices to send authorization header is by added it on request header
request.Headers.Add("Authorization-Token",bla bla bla);
you can create webrequest or httprequest
maybe you should start from http://rest.elkstein.org/2008/02/using-rest-in-c-sharp.html
or http://msdn.microsoft.com/en-us/library/debx8sh9%28v=vs.110%29.aspx.
in my opinion in order to create proper login security and request you should apply a standard such as openid or oauth
cheers
I did something like this, LoginSession contains my token and is static (in my case its a shared service (not static))
public HttpClient GetClient()
{
var client = new HttpClient
{
Timeout = new TimeSpan(0, 0, 2, 0),
BaseAddress = new Uri(GetServiceAddress())
};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
if (LoginSession.Token != null)
{
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", String.Format("Bearer {0}", LoginSession.Token.AccessToken));
}
return client;
}
notice this line:
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", String.Format("Bearer {0}", LoginSession.Token.AccessToken));