How can I prevent unauthorized code from accessing my assembly in .NET 2.0? - .net-2.0

In .NET 1.x, you could use the StrongNameIdentityPermissionAttribute on your assembly to ensure that only code signed by you could access your assembly. According to the MSDN documentation,
In the .NET Framework version 2.0 and later, demands for identity
permissions are ineffective if the calling assembly has full trust.
This means that any application with full trust can just bypass my security demands.
How can I prevent unauthorized code from accessing my assembly in .NET 2.0?

As per Eric's suggestion, I solved it by checking the key myself. In the code I want to protect, I add the following call,
EnsureAssemblyIsSignedByMyCompany( Assembly.GetCallingAssembly() );
Then the implementation of that method is
/// <summary>
/// Ensures that the given assembly is signed by My Company or Microsoft.
/// </summary>
/// <param name="assembly"></param>
private static void EnsureAssemblyIsSignedByMyCompany( Assembly assembly )
{
if ( assembly == null )
throw new ArgumentNullException( "assembly" );
byte[] pubkey = assembly.GetName().GetPublicKeyToken();
if ( pubkey.Length == 0 )
throw new ArgumentException( "No public key token in assembly." );
StringBuilder builder = new StringBuilder();
foreach ( byte b in pubkey )
{
builder.AppendFormat( "{0:x2}", b );
}
string pkString = builder.ToString();
if ( pkString != "b77a5c561934e089" /* Microsoft */ &&
pkString != "abababababababab" /* Ivara */ )
{
throw new ArgumentException( "Assembly is not signed by My Company or Microsoft. You do not have permission to call this code." );
}
}
** Names and keys changed to protect the innocent. Any likeness to real names or companies is merely a coincidence.*

See this article:
http://blogs.msdn.com/ericlippert/archive/2008/10/06/preventing-third-party-derivation-part-two.aspx
Particularly this part:
In recent versions of .NET, "full trust means full trust". That is, fully-trusted code satisfies all demands, including demands for things like "was signed with this key", whether it actually was signed or not.
Isn't that a deadly flaw in the security system? No. Fully trusted code always had the ability to do that, because fully trusted code has the ability to control the evidence associated with a given assembly. If you can control the evidence,then you can forge an assembly that looks like it came from Microsoft, no problem. (And if you already have malicious full-trust code in your process then you have already lost -- it doesn't need to impersonate Microsoft-signed assemblies; it already has the power to do whatever the user can do.)
Apparently, the .Net designers felt that this attribute wasn't very effective for full trust code in .Net 1.x either.

As Joel indicated, you are out of luck with regard to CAS. However, you may be able to do the check yourself in any method you need to protect by using Assembly.GetCallingAssembly() to get a reference to the assembly containing the calling code, then check the strong name on that assembly manually.

Related

Convert CodeFluent.Runtime.Utilities.Authenticode.FindSuitableCertificate to C#

I'm trying to convert Dim certificate As X509Certificate2 = CodeFluent.Runtime.Utilities.Authenticode.FindSuitableCertificate() from VB.Net to C# and I know that it's X509Certificate2 AuthenticodeCert = CodeFluent.Runtime.Utilities.Authenticode.FindSuitableCertificate();
The problem is that in C# it produces a ArgumentNullException, but works in VB.Net.
X509Certificate2 AuthenticodeCert = Authenticode.FindSuitableCertificate(); // Problem
// Check if there is a Certificate in the Certificate Store that can signs code.
if (Authenticode.CanSignCode(AuthenticodeCert) == true) // Problem ArgumentNullException
{// Bla, Bla}
Any help would be Appreciated. Thanks.
I figured it out.
X509Certificate2 AuthenticodeCert = new X509Certificate2("PFX_Private_Key", "Password");
The only problem is if it returns null then I hit an error. The only remedying it seems for that was to Try Catch. Anyone know a better way to code for the null value?
Thanks.
The CodeFluent.Runtime library is a .Net framework library independant of the calling language. It is itself implemented in C# .
So I suspect your issue is not related to the language you use, but the local machine certificate stores or the executing user that are different.
The default FindSuitableCertificate looks into the My certificate store for Current User.
There is another more advanced signature you can use if the signing certificate installed on the machine is installed somewhere else instead :
/// <summary>
/// Finds a suitable certificate for authenticode signing.
/// </summary>
/// <param name="storeName">The store name.</param>
/// <param name="storeLocation">The store location.</param>
/// <param name="thumbPrint">The optional thumbprint. May be null.</param>
/// <returns>A certificate instance or null if not found.</returns>
public static X509Certificate2 FindSuitableCertificate(StoreName storeName, StoreLocation storeLocation, string thumbPrint)

How do I get current user in .NET Core Web API (from JWT Token)

After a lot of struggling (and a lot of tuturials, guides, etc) I managed to setup a small .NET Core REST Web API with an Auth Controller issuing JWT tokens when stored username and password are valid.
The token stores the user id as sub claim.
I also managed to setup the Web API to validate those tokens when a method uses the Authorize annotation.
app.UseJwtBearerAuthentication(...)
Now my question:
How do I read the user id (stored in the subject claim) in my controllers (in a Web API)?
It is basically this question (How do I get current user in ASP .NET Core) but I need an answer for a web api. And I do not have a UserManager. So I need to read the subject claim from somewhere.
The accepted answer did not work for me. I'm not sure if that's caused by me using .NET Core 2.0 or by something else, but it looks like the framework maps the Subject Claim to a NameIdentifier claim. So, the following worked for me:
string userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
Note that this assumes the Subject sub Claim is set in the JWT and its value is the user's id.
By default, the JWT authentication handler in .NET will map the sub claim of a JWT access token to the System.Security.Claims.ClaimTypes.NameIdentifier claim type. [Source]
There is also a discussion thread on GitHub where they conclude this behavior is confusing.
You can use this method:
var email = User.FindFirst("sub")?.Value;
In my case I'm using the email as a unique value
It seems a lot of people are looking at this question so I would like to share some more information I learned since I asked the question a while back.
It makes some things more clear (at least for me) and wasn't so obvious (for me as .NET newbie).
As Marcus Höglund mentioned in the comments:
It should be the same for "web api"..In ASP.NET Core Mvc and Web Api are merged to use the same controller.
That's definitely true and absolutely correct.
Because it is all the same across .NET and .NET Core.
Back than I was new to .NET Core and actually the full .NET world. The important missing information was that in .NET and .NET Core all the authentication can be trimmed down to System.Security.Claims namespace with its ClaimsIdentity, ClaimsPrinciple and Claims.Properties. And therefore it is used in both .NET Core controller types (API and MVC or Razor or ...) and is accessible via HttpContext.User.
An important side note all of the tutorials missed to tell.
So if you start doing something with JWT tokens in .NET don't forget to also get confident with ClaimsIdentity, ClaimsPrinciple and Claim.Properties. It's all about that. Now you know it. It was pointed out by Heringer in one of the comments.
ALL the claim based authentication middlewares will (if correctly implemented) populate the HttpContext.User with the claims received during authentication.
As far as I understand now this means one can safely trust on the values in the HttpContext.User. But wait a bit to know what to mind when selecting middleware. There are a lot of different authentication
middleware already available (in addition to .UseJwtAuthentication()).
With small custom extension methods you can now get the current user id (more accurate the subject claim) like that
public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value; }
Or you use the version in the answer of Ateik.
BUT WAIT: there is one strange thing
The next thing that confused me back than: according to the OpenID Connect spec I was looking for "sub" claim (the current user) but couldn't find it. Like Honza Kalfus couldn't do in his answer.
Why?
Because Microsoft is "sometimes" "a bit" different. Or at least they do a bit more (and unexpected) things. For example the official Microsoft JWT Bearer authentication middleware mentioned in the original question.
Microsoft decided to convert claims (the names of the claims) in all of their official authentication middleware (for compatibility reasons I don't know in more detail).
You won't find a "sub" claim (though it is the single one claim specified by OpenID Connect). Because it got converted to these fancy ClaimTypes. It's not all bad, it allows you to add mappings if you need to map different claims into a unique internal name.
Either you stick with the Microsoft naming (and have to mind that when you add/use a non Microsoft middleware) or you find out how to turn the claim mapping of for the Microsoft middleware.
In case of the JwtBearerAuthentication it is done (do it early in StartUp or at least before adding the middleware):
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
If you want to stick with the Microsoft namings the subject claim (don't beat me, I am not sure right now if Name is the correct mapping):
public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase))?.Value; }
Note that the other answers use the more advanced and way more convenient FindFirst method. Though my code samples show it without those you may should go with them.
So all your claims are stored and accessible (via one name or the other) in the HttpContext.User.
But where is my token?
I don't know for the other middleware but the JWT Bearer Authentication allows to save the token for each request. But this needs to be activated (in StartUp.ConfigureServices(...).
services
.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options => options.SaveToken = true);
The actual token (in all it's cryptic form) as string (or null) can then be accessed via
HttpContext.GetTokenAsync("Bearer", "access_token")
There has been an older version of this method (this works for me in .NET Core 2.2 without deprecated warning).
If you need to parse and extract values from this string may the question How to decode JWT token helps.
Well, I hope that summary helps you too.
If you use Name to store the ID here:
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
In each controller method you can get the ID of the current user by:
var claimsIdentity = this.User.Identity as ClaimsIdentity;
var userId = claimsIdentity.FindFirst(ClaimTypes.Name)?.Value;
I used the HttpContext and it works well:
var email = string.Empty;
if (HttpContext.User.Identity is ClaimsIdentity identity)
{
email = identity.FindFirst(ClaimTypes.Name).Value;
}
you can do this using.
User.Identity.Name
In my case I set ClaimTypes.Name to unique user email before JWT token generation:
claims.Add(new Claim(ClaimTypes.Name, user.UserName));
Then I stored unique user id to ClaimTypes.NameIdentifier:
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
Then in the controller's code:
int GetLoggedUserId()
{
if (!User.Identity.IsAuthenticated)
throw new AuthenticationException();
string userId = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;
return int.Parse(userId);
}
Mine worked using the following code in .net core 5 web api
User.Claims.First(x => x.Type == "id").Value;
asp.net core identity get user id
public async Task<IActionResult> YourMethodName()
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier) // will give the user's userId
var userName = User.FindFirstValue(ClaimTypes.Name) // will give the user's userName
ApplicationUser applicationUser = await _userManager.GetUserAsync(User);
string userEmail = applicationUser?.Email; // will give the user's Email
}
.net core identity get user id
public static class ClaimsPrincipalExtensions
{
public static T GetLoggedInUserId<T>(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
if (typeof(T) == typeof(string))
{
return (T)Convert.ChangeType(loggedInUserId, typeof(T));
}
else if (typeof(T) == typeof(int) || typeof(T) == typeof(long))
{
return loggedInUserId != null ? (T)Convert.ChangeType(loggedInUserId, typeof(T)) : (T)Convert.ChangeType(0, typeof(T));
}
else
{
throw new Exception("Invalid type provided");
}
}
public static string GetLoggedInUserName(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirstValue(ClaimTypes.Name);
}
public static string GetLoggedInUserEmail(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirstValue(ClaimTypes.Email);
}
}

.Net Core 2.0 Web API using JWT - Adding Identity breaks the JWT authentication

(Edit - Found proper fix! see below)
OK - this is my first attempt at .Net Core 2.0 and authentication, though I've done things with Web API 2.0 in the past, and have worked fairly extensively on various MVC and Webforms ASP projects over the last couple of years.
I'm trying to create a Web API ONLY project using .Net Core. This will form the back end of a multi-tenant application for producing some reports, so I need to be able to authenticate users. It seems the usual approach is to use JWT - first authenticate the user to generate a token, then pass that to the client to use on every API request. Data will be stored and retrieved using EF Core.
I followed this post for a basic way to get this set up, and I managed to get this to work ok - I have a controller which accepts a username/password and returns a token if valid, and some Authorization policies set up based on the claims.
The next thing I need is to actually manage the users/passwords/etc. I thought I'd just use .Net Core Identity for this as that way I would have lots of ready-made code for worry about users/roles, passwords etc. I was using custom User class and UserRole classes which derived from the standard IdentityUser and IdentityRole classes, but I've since reverted to the standard ones now.
The problem I have is that I can't quite figure out how to add identity & register all the various Services (rolemanager, usermanager, etc) without also breaking the authentication - basically as soon as I add this line to my Startup.ConfigureServices class:
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<MyContext>();
It all goes wrong, and I can no longer see any claims when I receive a request, so all the policies just lock down and you can't get to anything.
If I don't have those lines, then I end up with errors related to UserManager, RoleManager, UserStore etc. all not being registered for DI.
So... how (if it's possible) can I register Identity and hook it up to the Context correctly, but avoid/Remove any changes to the actual Authorisation mechanism?
I've looked around a fair bit online, but a lot of this has changed since .Net Core 1.x so a lot of the tutorials etc. aren't really valid any more.
I'm not intending this API application to have any front-end code, so I don't need any cookie authentication for forms or anything for now.
Edit
ok, I've now found that in this code setting up the JWT authentication in the Startup.ConfigureServices() method:
services.AddAuthentication(
JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
>>breakpoint>>> options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "Blah.Blah.Bearer",
ValidAudience = "Blah.Blah.Bearer",
IssuerSigningKey =
JwtSecurityKey.Create("verylongsecretkey")
};
});
If I put a breakpoint at the line indicated (via ">>breakpoint>>>") then it gets hit when I don't add the lines to add identity services, but if I do add those lines then it never gets hit. This is true no matter where in the method I put the services.AddIdentity() call. I get that this is simply a lambda so it's getting executed at a later point, but is there any way I can get the AddIdentity stuff to NOT set up Authentication, or make the code immediately remove it? I assume at some point there's some code which elects to not run the Lambda for config I've set there as the Identity stuff has already set it...
Thanks for reading all that if you have :)
EDIT - Found an answer
ok, I eventually found this GH issue which is basically exactly this problem:
https://github.com/aspnet/Identity/issues/1376
Basically what I had to do was twofold:
Ensure that the call to services.AddIdentity<IdentityUser, IdentityContext() was made first
Change the call to add auth from:
services.AddAuthentication(
JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
...
To:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
...
This does annoyingly result in a cookie being created, but this isn't then used for authentication as far as I can tell - it's purely using the bearer token on requests to controllers/actions which have [Authorize(Policy = "Administrator")] or similar set at least.
I need to test more, and I'll try to come back here an update this if I find it is not working in some way.
(Edited - put proper solution in as an answer now)
I eventually put together the solution, so on the suggestion of user alwayslearning I've edited my post and I'm putting this in as an actual answer.
ok, This can be done properly. First, you need to use the Authentication options I pointed out in my edit above - that's fine.
Then you need to useservices.AddIdentityCore<TUser>() rather than services.AddIdentity<TUser>(). This however, doesn't add a whole bunch of things for role management, and is apparently lacking the proper constructor to give it the type of Role you want to use. This means that in my case I had to do this:
IdentityBuilder builder = services.AddIdentityCore<IdentityUser>(opt =>
{
opt.Password.RequireDigit = true;
opt.Password.RequiredLength = 8;
opt.Password.RequireNonAlphanumeric = false;
opt.Password.RequireUppercase = true;
opt.Password.RequireLowercase = true;
}
);
builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
builder
.AddEntityFrameworkStores<MyContext>();
//.AddDefaultTokenProviders();
builder.AddRoleValidator<RoleValidator<IdentityRole>>();
builder.AddRoleManager<RoleManager<IdentityRole>>();
builder.AddSignInManager<SignInManager<IdentityUser>>();
Having done that, the next thing is to make sure that when validating a user login (prior to sending a token), you make sure to use the SignInManager method CheckPasswordSignInAsync and not PasswordSignInAsync:
public async Task<IdentityUser> GetUserForLogin(string userName, string password)
{
//find user first...
var user = await _userManager.FindByNameAsync(userName);
if (user == null)
{
return null;
}
//validate password...
var signInResult = await _signInManager.CheckPasswordSignInAsync(user, password, false);
//if password was ok, return this user.
if (signInResult.Succeeded)
{
return user;
}
return null;
}
if you use the PasswordSignInAsync method then you'll get a runtime error re. No IAuthenticationSignInHandler being configured.
I hope this helps someone at some point.
I have extracted the AddIdentity code from github and created an extension method based on it that doesn't add the default Cookie Authenticator, It's now pretty similar to the built in AddIdentityCore but can accept IdentityRole.
/// <summary>
/// Contains extension methods to <see cref="IServiceCollection"/> for configuring identity services.
/// </summary>
public static class IdentityServiceExtensions
{
/// <summary>
/// Adds the default identity system configuration for the specified User and Role types. (Without Authentication Scheme)
/// </summary>
/// <typeparam name="TUser">The type representing a User in the system.</typeparam>
/// <typeparam name="TRole">The type representing a Role in the system.</typeparam>
/// <param name="services">The services available in the application.</param>
/// <returns>An <see cref="IdentityBuilder"/> for creating and configuring the identity system.</returns>
public static IdentityBuilder AddIdentityWithoutAuthenticator<TUser, TRole>(this IServiceCollection services)
where TUser : class
where TRole : class
=> services.AddIdentityWithoutAuthenticator<TUser, TRole>(setupAction: null);
/// <summary>
/// Adds and configures the identity system for the specified User and Role types. (Without Authentication Scheme)
/// </summary>
/// <typeparam name="TUser">The type representing a User in the system.</typeparam>
/// <typeparam name="TRole">The type representing a Role in the system.</typeparam>
/// <param name="services">The services available in the application.</param>
/// <param name="setupAction">An action to configure the <see cref="IdentityOptions"/>.</param>
/// <returns>An <see cref="IdentityBuilder"/> for creating and configuring the identity system.</returns>
public static IdentityBuilder AddIdentityWithoutAuthenticator<TUser, TRole>(this IServiceCollection services, Action<IdentityOptions> setupAction)
where TUser : class
where TRole : class
{
// Hosting doesn't add IHttpContextAccessor by default
services.AddHttpContextAccessor();
// Identity services
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
services.TryAddScoped<UserManager<TUser>>();
services.TryAddScoped<SignInManager<TUser>>();
services.TryAddScoped<RoleManager<TRole>>();
if (setupAction != null)
{
services.Configure(setupAction);
}
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}
}
Now you can use the above code normally from a WebApi project like so
.AddIdentityWithoutAuthenticator<User, IdentityRole>()

Not allowed to use reflection in asp.net mvc2 running on a secure server?

I'm trying to deploy a web site on a secure server, but I'm having problems with reflection.
I guess this have something to do with security, but I'm not quite sure.
The error occurs when doing Assembly.GetTypes()
ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.]
System.Reflection.Module._GetTypesInternal(StackCrawlMark& stackMark) +0
System.Reflection.Assembly.GetTypes() +105
If I just ignore these exceptions and continue to load from assemblies, nothing is loaded. Seems like I'm not allowed to do this for any assemblies at all. When I run in a non secure webserver, everything works ok. I don't know much about IIS, mvc or .net security policies, so any help in the right direction would be greatly appreciated.
Heres the code causing the exception:
private static IEnumerable<IModule> GetModules()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in assembly.GetTypes()) // <--- This one throws
{
var moduleType = type.GetInterface(typeof(IModule).Name);
if (moduleType != null)
{
IModule module = null;
try
{
module = (IModule)Activator.CreateInstance(type, null);
}
catch (ReflectionTypeLoadException ex)
{
// GetInterface() get's all interfaces with the same
// name, so we'll just skip those who isn't ours
logger.Warn("Could not load module", ex);
}
if( module != null)
yield return module;
}
}
}
}
I found the error. It's not related to HTTP/HTTPS at all.
This post helped me on track http://forums.asp.net/t/1196710.aspx
Some assemblies in a dependant module didn't get copied to the output folder. My development machine and the test server has these in GAC, so everything works there.
I added these components explicitly, and now everything works.
Thanks for your time

How to know strong name of GWT serialization policy at the time of host page generation?

There is an excellent article describing a way to embed GWT RPC payload into the host page. A key element is missing there is how to know Strong Name of RPC serialization policy at run time.
Strong Name is computed at the compile time, put into the client and obfurscated. Strong name is sent to the server with RPC request as described here. What would you suggest to make this parameter available at the time of host page generation?
I have integrated GWT with spring with a custom SerializationPolicyProvider where I always had to rename <strong name>.gwt.rpc file and hard code the name in my custom SerializationPolicyProvider class. I got work around by looking at GWT docs. Strong Name is MD5 hash with length of 32. Each time RPC call is made to Spring based Controller's method: public String processCall(String payload), I parse the payload using following code to get strong name:
String strongName = null;
if(payload!=null){
StringTokenizer tokens = new StringTokenizer(payload,String.valueOf(AbstractSerializationStream.RPC_SEPARATOR_CHAR));
while(tokens.hasMoreTokens()){
String s = tokens.nextToken();
if(s.length() == 32){
strongName = s;
break;
}
}
}
Then in your SerializationPolicyProvider impl class use following:
to get SerializationPolicy:
return SerializationPolicyLoader.loadFromStream(servletContext.getResourceAsStream(moduleBaseURL+"/"+strongName+"gwt.rpc");
One solution seems to be using compiler -gen option. Get _Proxy.java from compiler output and extract SERIALIZATION_POLICY from it.