create principle / httpcontextbase.User from users ID - asp.net

I am using cors and asp.net membership to manage security for an API. However in some cases, the server may need to speak to our api, on behalf of the client. As in UI mvc project code behind > API.
Because the server, not authorised client would be making this call, the asp.net cookie would not be woking or picked up.
I have overloaded AuthorizeCore in order to check to see if there is a token:
if(httpContext.Request.Headers["x-access-token"] != null)
{
// this authorization is from token, rather than cookie
var accessToken = httpContext.Request.Headers["x-access-token"];
var security = new Security();
var decrypted = JsonConvert.DeserializeObject<TokenModel>(security.Decrypt(accessToken));
var clientip = GetClientIp(httpContext.Request);
if(httpContext.Request.Headers["x-client-ip"] == null)
{
return false;
}
if (httpContext.Request.Headers["x-client-ip"] != decrypted.Ip)
{
return false;
}
if (!IsSecretValid(decrypted))
{
return false;
}
MembershipUser u = Membership.GetUser(decrypted.UserId);
}
What I am asking is, How do I convert the membership into a Principle, in order to then let the rest of the code for roles etc to work.
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
{
return false;
}
Is this even possible, and if so how.

sorry, found a way through deep thought:
httpContext.User = new GenericPrincipal(new GenericIdentity(u.UserName), System.Web.Security.Roles.GetRolesForUser(u.UserName));
This should then enable my controller actions to pick up userid etc if needed.

Related

How to properly implement authorization code flow in .NET?

I am trying to properly implement Authorization Code flow for a 3rd party REST api for my users to use. However, I am not sure if I am doing it correctly with the redirections. I am storing the Authorization Tokens to Users in the database.
public async Task<IActionResult> Create(int id, string code)
{
var userId = _userManager.GetUserId(User);
var token = _userService.GetById(userId).AccessToken;
var tokenExpiration = _userService.GetById(userId).AccessTokenExpiration;
if (token == null || (DateTime.Now > tokenExpiration))
{
if (code != null)
{
await _trustapApi.GetToken(userId, "http://localhost:58409/Post/Create/" + id, code);
} else
{
var url = await _trustapApi.GetAuthCode("http://localhost:58409/Post/Create/" + id);
return Redirect(url);
}
}
}
This is the code I have at the beginning of all API methods. However, I feel like this is redundant. Are there any tutorials or tips on how to properly implement this flow into a .NET project?

MSAL sign out does not appear to clear cache

We have Xamarin forms app integrated with azure authentication using MSAL. When we log out we are removing the accounts from the PCA and the code was executed without having any issue. But on the subsequent login, it is getting authenticated without even entering the credentials. It is logging in with previously entered credentials. Looks like the cache is not getting cleared properly.
private async void AuthenticateUser()
{
App.Scopes = new string[] { "<client_id>" + "/.default" };
var redirectUri = "msal<clientId>" + "://auth";
if (Device.RuntimePlatform == Device.iOS)
{
App.PCA = PublicClientApplicationBuilder.Create("<client_id>")
.WithIosKeychainSecurityGroup("<package_name>")
.WithRedirectUri(redirectUri)
.Build();
}
else
{
App.PCA = PublicClientApplicationBuilder
.Create(CommonHelper.ClientId)
.WithRedirectUri(redirectUri)
.Build();
}
var accounts = await App.PCA.GetAccountsAsync();
var uid = new UserIdentifier("<user_name>", UserIdentifierType.OptionalDisplayableId);
AuthenticationResult authResult;
try
{
while (accounts.Any())
{
await App.PCA.RemoveAsync(accounts.First());
accounts = (await App.PCA.GetAccountsAsync()).ToList();
}
var firstAccount = accounts.FirstOrDefault();
authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)
.ExecuteAsync();
ProceedToLogin(authResult.AccessToken);
}
catch (MsalUiRequiredException mex)
{
try
{
authResult = await App.PCA.AcquireTokenInteractive(App.Scopes)
.WithParentActivityOrWindow(App.ParentWindow)
.WithLoginHint("<user_name>")
.WithUseEmbeddedWebView(true)
.ExecuteAsync();
ProceedToLogin(authResult.AccessToken);
}
catch (Exception ex)
{
Log(ex);
}
}
}
Please find the code below which will execute during the logout.
public void Logout(string authority)
{
if (App.PCA == null)
{
App.Scopes = new string[] { "<client_id>" + "/.default" };
var redirectUri = "msal<azure_client_id>://auth";
App.PCA = PublicClientApplicationBuilder.Create("<client_id>")
.WithIosKeychainSecurityGroup("<package_name>")
.WithRedirectUri(redirectUri)
.Build();
}
var accounts = App.PCA.GetAccountsAsync().Result;
if (accounts != null)
{
while (accounts.Any())
{
App.PCA.RemoveAsync(accounts.First());
accounts = App.PCA.GetAccountsAsync().Result;
}
}
}
Also, we tried with the below code to clear the cookies. It was working fine in lower versions but again the issue is happening from iOS 14.6 and above.
var cookieStorage = NSHttpCookieStorage.SharedStorage;
foreach (var cookie in cookieStorage.Cookies)
{
cookieStorage.DeleteCookie(cookie);
}
Try adding the following line
.WithPrompt(Prompt.ForceLogin);
Example
PublicClientApplicationBuilder.Create("<client_id>")
.WithIosKeychainSecurityGroup("<package_name>")
.WithRedirectUri(redirectUri)
.WithPrompt(Prompt.ForceLogin);
.Build();
As far as I understand this from my own implementation of MSAL in .NET this is working as expected, I'm not sure how well this carries over to Xamarin. When you log a user out of they will no longer be authenticated against your application, but will keep authentication to Microsoft. When you send an unauthenticated user to the Microsoft endpoint to log back in to your application (as in your screenshot) Microsoft correctly identifies that they are still logged in to their Microsoft account, however that account is not logged in to your application. At this point Microsoft offers the list you see giving the option to use the authenticated account or choose a different one to use sign in to your application.
Their are two levels in play when authenticating against MS, authentication against MS and authentication against your application. Your application can only clear authentication against itself, not Microsoft which lets user stay logged into to other MS services (Outlook etc).

How can you use Auth0 with existing ASP.NET Core Identity database?

I'm working on Auth0 integration for an application. I have an existing application that uses ASP.NET Core Identity and a SQL Database currently with the usual tables (AspNetUsers, AspNetRoles, etc).
The problem is that Auth0 currently has custom database templates for working with ASP.NET Membership Provider (MVC3 Universal Providers, and MVC4 Simple Membership) database, but not ASP.NET Core Identity. Since I don't know exactly how to code the Password Hashing necessary to be compatible with my ASP.NET Core Identity database, this is a big problem.
Does anyone have an example of Auth0 custom database scripts for working with an existing ASP.NET Core Identity database? Or, at least the hashing algorithm used to code it myself?
For more info, the ASP.NET Core Identity database has a AspNetUsers table with the following columns that would be of interest for this integration:
Id (PK, nvarchar, not null)
Email (nvarchar, null)
PasswordHash (nvarchar, null)
SecurityStamp (nvarchar, null)
UserName (nvarchar, not null)
Just to be clear, I'm asking about how to setup the Custom Database scripts within the Auth0 configurations written in JavaScript; not the ASP.NET web app code. The web app is pretty straight forward according to the docs to get setup. It's just the Auth0 built-in custom database templates don't include an example to use for the ASP.NET Core Identity database schema and password hashing.
Any help would be greatly appreciated!
You need to figure out the hashing algorithm used and modify the scripts they have in the templates, using the Auth0 documentation too, to get it correct. You can find code for the algorithm in the aspnet-identity-pw project.
Here's a sample Login database action script for Auth0 that works with an ASP.NET Core Identity 2.0 database stored in Azure SQL Database:
function login (username, password, callback) {
var Connection = require('tedious#1.11.0').Connection;
var Request = require('tedious#1.11.0').Request;
var TYPES = require('tedious#1.11.0').TYPES;
var connection = new Connection({
userName: configuration.db_username + '#' + configuration.db_server,
password: configuration.db_password,
server: configuration.db_server, //'dbserver.database.windows.net',
options: {
database: configuration.db_database,
encrypt: true
}
});
connection.on('debug', function(text) {
// if you have connection issues, uncomment this to get more detailed info
//console.log(text);
}).on('errorMessage', function(text) {
// this will show any errors when connecting to the SQL database or with the SQL statements
//console.log(JSON.stringify(text));
});
connection.on('connect', function (err) {
if (err) {
console.log('error: ' + JSON.stringify(err));
return callback(err);
}
getMembershipUser(username, function(err, user) {
if (err) {
return callback(err); // this will return a 500
}
if (!user.profile) {
return callback(); // this will return a 401
}
validatePassword(password, user.password.hash, function(err, isValid) {
if (!isValid) {
return callback(); // unauthorized
}
callback(null, user.profile);
});
});
});
// Membership Provider implementation used with ASP.NET Core Identity database
/**
* getMembershipUser
*
* This function gets a username or email and returns a user info, password hashes and salt
*
* #usernameOrEamil {[string]} the username or email, the method will do a query
* on both with an OR
* #callback {[Function]} first argument will be the Error if any, and second
* argument will be a user object
*/
function getMembershipUser(usernameOrEmail, callback) {
var user = {};
var query =
'SELECT Id, UserName, Email, PasswordHash, SecurityStamp from AspNetUsers ' +
'WHERE UserName = #UserName';
var getMembershipQuery = new Request(query);
getMembershipQuery.addParameter('UserName', TYPES.VarChar, usernameOrEmail);
getMembershipQuery.on('row', function (fields) {
user.profile = {};
user.password = {};
for(var f in fields) {
var item = fields[f];
if (item.metadata.colName === 'Id') {
user.profile.user_id = item.value;
} else if (item.metadata.colName === 'UserName') {
user.profile.nickname = item.value;
} else if (item.metadata.colName ==='Email') {
user.profile.email = item.value;
} else if (item.metadata.colName ==='PasswordHash') {
user.password.hash = item.value;
}
}
//console.log('User: ' + JSON.stringify(user));
callback(null, user);
});
connection.execSql(getMembershipQuery);
}
/**
* validatePassword
*
* This function gets the password entered by the user, and the original password
* hash and salt from database and performs an HMAC SHA256 hash.
*
* #password {[string]} the password entered by the user
* #originalHash {[string]} the original password hashed from the database
* (including the salt).
* #return {[bool]} true if password validates
*/
function validatePassword(password, originalHash, callback) {
aspnet_identity_pw.validatePassword(password, originalHash, function(result, isValid) {
console.log('Is Password Valid: ' + isValid);
callback(null, isValid);
});
}
var aspnet_identity_pw = {
validatePassword: function(password, hashedPassword, callback) {
// Original Source:
// https://github.com/Syncbak-Git/aspnet-identity-pw/blob/master/lib/aspnet-identity-pw.js
// https://www.npmjs.com/package/aspnet-identity-pw
// There were some slight modifications to make it run well in Auth0
var done = false;
var error = null;
var result = null;
if(!hashedPassword) {
if(callback) {
callback(null, false);
}
return false;
}
if(!password) {
error = new Error("Password is required.");
if(callback) {
callback(error);
return;
}
throw error;
}
var src = new Buffer(hashedPassword, 'base64');
if(src.length !== 49 || src[0] !== 0) {
return false;
}
var salt = new Buffer(16);
src.copy(salt, 0, 1, 17);
var bytes = new Buffer(32);
src.copy(bytes, 0, 17, 49);
var hashed = crypto.pbkdf2Sync(password, salt, 1000, 32, 'sha1');
result = true;
for(var i = 0; i < 32; i++) {
if(bytes[i] !== hashed[i]) {
result = false;
break;
}
}
done = true;
if(callback) {
callback(null, result);
}
if(!callback) {
throw 'callback required!';
}
}
};
}
This took what seemed like forever to get fully figured out. Especially to get the password hashing algorithm coded, until stumbling upon the js project listed with the code for it.
Hope this helps others!

how use sessions and store value in a session and use for login sysytem

i am trying to create an custom login process and for this a want use sessions but i cant find any source for that how i can use sessions in asp.net MVC please guide me how i can use sessions i just check from them that user log out or not so he can be able to access on dashboard without log in again. thanks in advance.
Session["user"] = profile.userName;
var admin = db.userProfiles.Where(x => x.userName == user.userName && x.password == user.password && x.admin==1).FirstOrDefault();
if(admin==null)
{
if (Session["user"] != null)
{
ViewBag.userName = user.userName;
return View();
}
else
{
return RedirectToAction("login");
}
}
else
{
if (Session["user"] != null)
{
return RedirectToAction("index");
}
else
{
return RedirectToAction("login");
}
You're reinventing the wheel. Have you considered using the built-in Identity and authentication schemes?
Create an ASP.NET Core app with user data protected by authorization
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/secure-data
Building a simple ToDo application with ASP.NET Identity and associating Users with ToDoes
https://blogs.msdn.microsoft.com/webdev/2013/10/20/building-a-simple-todo-application-with-asp-net-identity-and-associating-users-with-todoes/

How can I authorize a SignalR Hub using Azure Mobile Apps Authentication

I have my mobile app using Facebook Auth through azure. The auth works fine for the ApiControllers with the [MobileApiController] flag.
I can't seem to find how to make my SignalR Hub authorize - the Authorize attribute blocks access from users. All the articles I have found seem to be old and using the deprecated Azure Mobile Services which is different and not compatible.
I have configured my SignalR client to connect as long-polling with the x-zumo-auth header set.
I ended up making a custom SignalR authentication attribute. Code below for anyone else interested.
public class HubAuthorizeAttribute : AuthorizeAttribute
{
public HubAuthorizeAttribute()
{
}
public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
{
var owinContext = request.GetHttpContext().GetOwinContext();
ClaimsPrincipal claimsPrincipalFromToken;
var options = Startup.AuthenticationOptions;
string tokenFromHeader = request.Headers[AppServiceAuthenticationHandler.AuthenticationHeaderName];
if (!string.IsNullOrEmpty(tokenFromHeader))
{
bool claimsAreValid = options.TokenHandler.TryValidateLoginToken(tokenFromHeader, options.SigningKey, options.ValidAudiences, options.ValidIssuers, out claimsPrincipalFromToken);
if (claimsAreValid)
{
var identity = claimsPrincipalFromToken.Identity as ClaimsIdentity;
request.Environment["server.User"] = new ClaimsPrincipal(identity);
return true;
}
}
return false;
}
public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod)
{
var connectionId = hubIncomingInvokerContext.Hub.Context.ConnectionId;
// check the authenticated user principal from environment
var environment = hubIncomingInvokerContext.Hub.Context.Request.Environment;
var principal = environment["server.User"] as ClaimsPrincipal;
if (principal != null && principal.Identity != null && principal.Identity.IsAuthenticated)
{
// create a new HubCallerContext instance with the principal generated from token
// and replace the current context so that in hubs we can retrieve current user identity
hubIncomingInvokerContext.Hub.Context = new HubCallerContext(new ServerRequest(environment), connectionId);
return true;
}
else
{
return false;
}
}
}

Resources