DotNetOpenAuth: Want to access username while storing Nonce - c#

I am using DotNetOpenAuth 4.0.20926 and trying to implement an OAuth2 based Authentication server with Db Nonce provider.
For some purpose I want to access username in NonceStore's StoreNonce function while processing the GetToken request.
I am not getting a way to retrieve Username in that call.
How can I solve this problem?
Hey Andrew thanks for your reply and DotNetOpenAuth.
My GetToken Method is like this
public ActionResult Token()
{
string userName = "";
//Want to fetch username here
//Using username here
var result = this.authorizationServer.HandleTokenRequest(this.Request);
return result.AsActionResult();
}
And I want to fetch the username before calling HandleTokenRequest.
Is there any Message Parser or Helper method to fetch the username from the request data / Code value .

As you've observed, the interface does not pass the username into the StoreNonce method. So the only way you may possibly be able to get the username would be for you to discover what it is first, before you instantiate your INonceStore instance, and pass it to that nonce store first, so that later when StoreNonce is invoked, it already knows the username.
That said, I believe any design where storing and checking a nonce requires the username needs some rethinking. Not only is it a mixing of concerns that otherwise should remain separate, you may be limiting yourself going forward or even introducing security holes.

Related

Asp.net Core Email confirmation sometimes says InvalidToken

I am using asp.net core identity 2.1 and i am having a random issue with email confirmation, which while email confirmation sometimes says result.Error = InvalidToken. The token is also not expired.
Note: We are using multiple servers, and we have also stored our keys in one place so that all the servers use the same keys.
Code snippet for email confirmation.
Email Confirmation
var confCode = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new
{
userId = user.Id,
code = WebUtility.UrlEncode(confCode)
}, protocol: HttpContext.Request.Scheme);
string confirmationEmailBody = string.Format(GetTranslatedResourceString("ConfirmationEmailBody"), "<a href='" + callbackUrl + "'>") + "</a>";
Verification of token
public async Task<bool> ConfirmEmailAsync(string userId, string code)
{
if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(code))
return false;
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return false;
var result = await _userManager.ConfirmEmailAsync(user, code).ConfigureAwait(false);
if (!result.Succeeded)
result = await _userManager.ConfirmEmailAsync(user, WebUtility.UrlDecode(code)).ConfigureAwait(false);
return result.Succeeded;
}
Invalid Token
The below token is encoded twice but we handle that situation
CfDJ8HYrrpCgcr5GvrItPOWapXRy8WF8odd%252BVKuDup7buRsl1x4agRpfgQlEIPWiBqM0Wuilu9tCv5l%252B3lNaAb89%252Fi%252B4k0y%252FH0jdXAbabz0%252FXDGA0eUrmcKdIsDFNuXeyP5ezTVmTx8t0ky9xCTXaKLAfvTsCJviETk5Ag9JbUs3l3%252BnUon6fyYOHsslJI5VKLqhMM0Sm%252BW1EE%252B%252FPEJ%252BXcn%252FPS1My%252BI1lExuF1R1hFEZScEsUCG%252Bx%252BVIFB9bzs1IoLC%252Baw%253D%253D
Any help will be appreciated, Thank you!
This problem seems to be basic Query String Related issue.
There are no pointers in your question about sample expected value and sample actual value. Hence I will not be able to provide you exact answer here. But below two are the pointers which will certainly resolve this issue.
There can be two issues:
Issue 1: Original Base-64 is not restored after HtmlDecode/UrlDecode
These tokens are encoded as base 64 strings which may contain characters like '+'.
They are sent to server.
Then server tries to perform HtmlDecode operation on this string, to remove the characters which were actually present in original base 64 token.
E.g. '+' is replaced by empty string.
So, the token generated after WebUtility.HtmlDecode is invalid. That's why you get the invalid token error
How to check this ? You can debug and see what is the value after HtmlDecode and what is expected value. If they are differing then this is root cause.
Issue 2: Query string not correctly formed
Multiple key value pairs in query strings are joined using '&' character.
e.g. key1=value1&key2=value2
But some times instead of & , its encoded version & comes in the query string.
e.g. key1=value1&key2=value2
The .Net server would not be able to parse query string correctly if this is the case.
How to check this ? You can use directly read raw query string from HttpContext or HttpRequest using QueryString property and check if this is the case. If it is then you can either change your client to send appropriate query string (more logical and maintainable) or write some code to correct it on server side.
These pointers should help you to resolve the issue.
your request for email conformation will gives you response as userId and Your Private key but your token method should be different function like token refresh, you need to add some conditions like if token has expired then refresh token
This may not be the perfect answer, but if you just need an urgent fix and less headache, just generate a shorter disaster free token/code.
services.AddIdentity<ApplicationUser, ApplicationRole>(options => {
options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
}).AddDefaultTokenProviders()
.AddEntityFrameworkStores<YourDbContext>();
You should decode the confirmation code prior to passing it into the _userManager.ConfirmEmailAsync(user, code).ConfigureAwait(false) method.
You have URL encoded the confirmation code that you use in the callBackUrl; you should use WebUtility.UrlDecode(code) to decode it before attempting to use it.
I think the user creation process is taking too much time
Before you are clicking confirm
Make sure you check database that user is created
Check confirm email is false in sql table
You do not need to solve this problem using identity server.
When a user register add two column in your user table. One for verification and others for IsVerified. In verification token column add a Guid. Then generate a link with this Guid. When a user clicks this link then you get the Guid inside a controller. Then get this user using this column, then set IsVerified column to true and delete your Guid column. And your user is now successfully verified.
If your encoded code contains '==' in the end. i.e after urlencode or base64 encode if the code comes out like this "cm9vdA==".
decoding this will not give you the exact encoded string and will result in an invalid code.
So while generating the token check if the encoded value ends with "==". If it does generate another token and the problem will be solved.

Secure WebApi concept

How about this system. I need some comments and maybe critical security part for this.
System which I use is maybe little bit complicated but 100% custom and should be good. This is a system for custom authentication in sending request to Asp.NET
WebApi
System works with sending 2 request
Everything what you need is 2 pairs of data. 1st one is public and 2nd one is secret.
Second pair of data be must be known to both sides (sender and receiver)
public: ApiKey and RequstID where ApiKey is "normal" and requstID have to be unique always;
secret: UserName and Password (both side have to know these data)
Sender:
Send 1st request with 3 parameters: 1st= ApiKey, 2nd=RequstID, 3rd=Hash(ApiKey+RequestID+USerName+Pass)
Server:
Read RequstID
Read ApiKey and get data about users UserName and Pass for this ApiKey
From the own side: Hash(ApiKey+RequestID+USerName+Pass)
Check is Hash from Sender same us from Server
If is False:
BadRequest - or whatever...
if is True
Before all - Create on database on table for collect data about request.
This is table with columns (e.g.):
ID(autoincrement), RequstID, Token, TokenValidateDateTime
Before create new row, check is there already this RequestID and if there is return BadRequest.
If there is not - make new row.
RequstID is RequstID from request;
Token - Generate token (e.g. Guid.NewGuid().ToString());
TokenValidateDateTime= DateTime.Now.AddMinutes(2) - or some other value ...
In response for the first request send back this this Token (from item 2)
In the second request, Sender have to use AGAIN same RequstID and Token (from response before)
Server will check
Combination RequstID and Token
Token validation (depend on current date time);
Is everything is OK, user is validated
if is not - BadRequest, or whatever
Any suggestions or comments are welcome :)
It sounds similar to traditional website username / password authentication which returns a session cookie.
But you're also including a api key & request id and a hash. The hash won't add to much value unless there's a shared salt, as once someone works out your hashing technique it will be vulnerable to dictionary attacks.
Also generating a Guid token isn't "cryptographically secure", it is designed to be unique but it's often based upon the system clock meaning it is predictable.
Building bespoke security mechanisms are generally unadvised; doing bespoke encryption is defiantly a "no no" (which you aren't doing as far as I'm aware). Bespoke authentication is probably less risky, but seeing as there are many frameworks already existing that have been critiqued by security experts I'd suggest researching if any of those suit first.
I'd recommend looking at asp.net core's security options: https://learn.microsoft.com/en-us/aspnet/core/security/?view=aspnetcore-2.1

How to invalidate tokens after password change

I am working on an API that uses JWT token auth. I've created some logic behind it to change user password with a verification code & such.
Everything works, passwords get changed. But here's the catch:
Even if the user password has changed and i get a new JWT token when authenticating...the old token still works.
Any tip on how i could refresh/invalidate tokens after a password change?
EDIT: I've got an idea on how to do it since i've heard you can't actually invalidate JWT tokens.
My idea would be to create a new user column which has something like "accessCode" and store that access code in the token. Whenever i change the password i also change accessCode (something like 6 digit random number) and i implement a check for that accessCode when doing API calls (if the accesscode used in the token doesnt match the one in the db -> return unauthorized).
Do you guys think that would be a good approach or is there some other way ?
The easiest way to revoke/invalidate is probably just to remove the token on the client and pray nobody will hijack it and abuse it.
Your approach with "accessCode" column would work but I would be worried about the performance.
The other and probably the better way would be to black-list tokens in some database. I think Redis would be the best for this as it supports timeouts via EXPIRE so you can just set it to the same value as you have in your JWT token. And when the token expires it will automatically remove.
You will need fast response time for this as you will have to check if the token is still valid (not in the black-list or different accessCode) on each request that requires authorization and that means calling your database with invalidated tokens on each request.
Refresh tokens are not the solution
Some people recommend using long-lived refresh tokens and short-lived access tokens. You can set access token to let's say expire in 10 minutes and when the password change, the token will still be valid for 10 minutes but then it will expire and you will have to use the refresh token to acquire the new access token. Personally, I'm a bit skeptical about this because refresh token can be hijacked as well: http://appetere.com/post/how-to-renew-access-tokens and then you will need a way to invalidate them as well so, in the end, you can't avoid storing them somewhere.
ASP.NET Core implementation using StackExchange.Redis
You're using ASP.NET Core so you will need to find a way how to add custom JWT validation logic to check if the token was invalidated or not. This can be done by extending default JwtSecurityTokenHandler and you should be able to call Redis from there.
In ConfigureServices add:
services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect("yourConnectionString"));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.SecurityTokenValidators.Clear();
// or just pass connection multiplexer directly, it's a singleton anyway...
opt.SecurityTokenValidators.Add(new RevokableJwtSecurityTokenHandler(services.BuildServiceProvider()));
});
Create your own exception:
public class SecurityTokenRevokedException : SecurityTokenException
{
public SecurityTokenRevokedException()
{
}
public SecurityTokenRevokedException(string message) : base(message)
{
}
public SecurityTokenRevokedException(string message, Exception innerException) : base(message, innerException)
{
}
}
Extend the default handler:
public class RevokableJwtSecurityTokenHandler : JwtSecurityTokenHandler
{
private readonly IConnectionMultiplexer _redis;
public RevokableJwtSecurityTokenHandler(IServiceProvider serviceProvider)
{
_redis = serviceProvider.GetRequiredService<IConnectionMultiplexer>();
}
public override ClaimsPrincipal ValidateToken(string token, TokenValidationParameters validationParameters,
out SecurityToken validatedToken)
{
// make sure everything is valid first to avoid unnecessary calls to DB
// if it's not valid base.ValidateToken will throw an exception, we don't need to handle it because it's handled here: https://github.com/aspnet/Security/blob/beaa2b443d46ef8adaf5c2a89eb475e1893037c2/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs#L107-L128
// we have to throw our own exception if the token is revoked, it will cause validation to fail
var claimsPrincipal = base.ValidateToken(token, validationParameters, out validatedToken);
var claim = claimsPrincipal.FindFirst(JwtRegisteredClaimNames.Jti);
if (claim != null && claim.ValueType == ClaimValueTypes.String)
{
var db = _redis.GetDatabase();
if (db.KeyExists(claim.Value)) // it's blacklisted! throw the exception
{
// there's a bunch of built-in token validation codes: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/7692d12e49a947f68a44cd3abc040d0c241376e6/src/Microsoft.IdentityModel.Tokens/LogMessages.cs
// but none of them is suitable for this
throw LogHelper.LogExceptionMessage(new SecurityTokenRevokedException(LogHelper.FormatInvariant("The token has been revoked, securitytoken: '{0}'.", validatedToken)));
}
}
return claimsPrincipal;
}
}
Then on your password change or whatever set the key with jti of the token to invalidate it.
Limitation!: all methods in JwtSecurityTokenHandler are synchronous, this is bad if you want to have some IO-bound calls and ideally, you would use await db.KeyExistsAsync(claim.Value) there. The issue for this is tracked here: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/468 unfortunately no updates for this since 2016 :(
It's funny because the function where token is validated is async: https://github.com/aspnet/Security/blob/beaa2b443d46ef8adaf5c2a89eb475e1893037c2/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs#L107-L128
A temporary workaround would be to extend JwtBearerHandler and replace the implementation of HandleAuthenticateAsync with override without calling the base so it would call your async version of validate. And then use this logic to add it.
The most recommended and actively maintained Redis clients for C#:
StackExchange.Redis (also used on stackoverflow) (Using StackExchange.Redis in a ASP.NET Core Controller)
ServiceStack.Redis (commercial with limits)
Might help you to choose one: Difference between StackExchange.Redis and ServiceStack.Redis
StackExchange.Redis has no limitations and is under the MIT license.
So I would go with the StackExchange's one
The simplest way would be: Signing the JWT with the users current password hash which guarantees single-usage of every issued token. This is because the password hash always changes after successful password-reset.
There is no way the same token can pass verification twice. The signature check would always fail. The JWT's we issue become single-use tokens.
Source- https://www.jbspeakr.cc/howto-single-use-jwt/
The following approach brings together the best of each approach proposed previously:
Create the column "password_id" in the "user" table.
Assign a new UUID to "password_id" when creating a user.
Assign a new UUID to "password_id" every time the user changes his password.
Sign the authorization JWTs using the "password_id" of the respective user.
If more performance is needed, simply store the "password_id" of the users in Redis.
Advantages of this approach:
If a user changes his password all JWTs existing up to that moment will automatically become invalid forever.
It does not matter if a user changes his password to an old one.
It is not necessary to store the JWTs in the server side.
It is not necessary to add any extra data in the JWT payload.
The implementation using Redis is very simple.

Where to store data in WCF request

I'm using a custom username and password validation for my WCF security. Now i would like to store the username during the request so that i can access it later in the method that is called. How do i do that?
Some sample code to describe my problem:
public class CustomUserValidator : UserNamePasswordValidator
{
public override void Validate(string username, string password)
{
if (username == "aaa" && password == "bbb")
{
// store username where i can get it in method called later.
return;
}
throw new SecurityTokenException("Unknown Username or Password");
}
}
Now the method that is being called:
public void WebServiceMethod()
{
Database.User.Single(c => c.Username == /* username from above */);
}
BR
Andreas
You would typically do this by issuing a custom "principal", which is done via IAuthorizationPolicy; IIRC, the username is made available to the auth-policy via the evaluation-context parameter. A general walkthrough to custom principals in WCF is here, however you may need to experiment a bit in Evaluate to find the incoming username in the evaluation context. In particular, if any of the keys is a "claims" dictionary, look at that. And look at the .Claims on the evaluation context - you should find a "claim" in their issued by CustomUserValidator with the username in it.
I have, however, done exactly what you describe in a previous job - and IIRC it worked fine, using the above page as my starting point.
Once you have issued a principal, it will be available, as normal, via:
string cn = Thread.CurrentPrincipal.Identity.Name;
To store data of any kind through a single WCF request, Darin Dimitrov suggests hooking up a simple IExtension<> helper class to the current OperationContext here: Where to store data for current WCF call?

Generate a client-specific verification number for a web service

I have a web service that is outward-facing, however I need to generate a verification system to ensure that a request came from a valid client.
Let's say the original web service is defined as follows:
[OperationContract]
public void Service.RequestMethod (string clientId, int reqNumber,
string reqText)
{
// do stuff with the parameters
}
I want to make sure that the request actually came from the client specified by the clientId parameter.
My current plan is to add another parameter to the method signature, giving a checksum of sorts.
[OperationContract]
public void Service.RequestMethod (string clientId, int reqNumber,
string reqText, string reqChecksum)
{
// verify reqChecksum, then
// do stuff with the parameters
}
I need a function that verifies that the checksum was calculated by the approved client. It should be calculated on the reqNumber and reqText parameters as well as a client-specific "password" known by both client and server.
In effect, it should be:
private bool VerifyChecksum(int reqNumber, string reqText,
string clientPassword, string reqChecksum)
{
// hash reqNumber, reqTxt, and clientPassword
// ensure it matches reqChecksum
}
Does anyone have any suggestions for this hashing function or the model as a whole?
It needs to be message-specific, client-specific, and hard to guess (high entropy).
You're probably looking for some kind of MAC. Something like MD5 for the hash. The whole idea of MD5 is that you apply it to "some" data and get a value. As long as the "some data" part is not known to everyone, it's almost impossible to reproduce the value.
Why not use one of the standard web services authentication methods? You'll have a choice of well-known and widely implemented solutions and won't muddy up your interface by trying to pass both parameters and authentication information.
You might still have an authorization problem if an authenticated client can pass more than one 'clientId', but again there are plenty of known solutions to this and it's entirely on your side. E.g., you could go as far as an ACL implementation that lists all acceptable (userId, clientId, methodname) combinations and forbids everything else.

Categories