Extending Active Directory Membership Provider - asp.net-membership

I have an ASP.NET web site that will use Active Directory to store Users.
There is a requirement to allow users to use their emails as username.
Active directory will not allow characters like "#" in the usernames.
I created a class to extend the ActiveDirectoryMembershipProvider; It converts usernames from (user#domain.com to user_x0040_domain.com ) before calling the base class functions.
example:
public override bool ValidateUser(string username, string password)
{
string encodedUsername = this.Encode(username);
return base.ValidateUser(encodedUsername, password);
}
The Problem is that in the MembershipUser does not allow changing the username.
How can I handle overriding the methods that return MembershipUser?
Like MembershipUser GetUser(string username, bool userIsOnline)

I suppose you could do this overriding the MembershipUser returned by the Active Directory provider, something like this:
public class MyActiveDirectoryMembershipProvider : ActiveDirectoryMembershipProvider
{
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
ActiveDirectoryMembershipUser user = (ActiveDirectoryMembershipUser)base.GetUser(providerUserKey, userIsOnline);
if (user == null)
return null;
return new MyActiveDirectoryMembershipUser(user);
}
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
{
MembershipUserCollection newColl = new MembershipUserCollection();
foreach (ActiveDirectoryMembershipUser user in base.FindUsersByName(usernameToMatch, pageIndex, pageSize, out totalRecords))
{
newColl.Add(new MyActiveDirectoryMembershipUser(user));
}
return newColl;
}
// TODO: check other methods to override
}
public class MyActiveDirectoryMembershipUser : ActiveDirectoryMembershipUser
{
private string _userName;
public override string UserName
{
get
{
return _userName;
}
}
public MyActiveDirectoryMembershipUser(ActiveDirectoryMembershipUser user)
{
// TODO: do your decoding stuff here
_userName = MyDecode(user.Email);
}
}
NOTE: you will need to ensure all methods that return a user are overriden. It also has a some performance impact on collection methods, because you'll need to duplicate the collection (as I have shown in the sample).

Related

Mediator Api call failing

I'm trying to make a simple request using mediator and .net core. I'm getting an error that I am not understanding. All I'm trying to do is a simple call to get back a guid.
BaseController:
[Route("api/[controller]/[action]")]
[ApiController]
public class BaseController : Controller
{
private IMediator _mediator;
protected IMediator Mediator => _mediator ?? (_mediator = HttpContext.RequestServices.GetService<IMediator>());
}
Controller:
// GET: api/Customer/username/password
[HttpGet("{username}/{password}", Name = "Get")]
public async Task<ActionResult<CustomerViewModel>> Login(string username, string password)
{
return Ok(await Mediator.Send(new LoginCustomerQuery { Username = username,Password = password }));
}
Query:
public class LoginCustomerQuery : IRequest<CustomerViewModel>
{
public string Username { get; set; }
public string Password { get; set; }
}
View Model:
public class CustomerViewModel
{
public Guid ExternalId { get; set; }
}
Handler:
public async Task<CustomerViewModel> Handle(LoginCustomerQuery request, CancellationToken cancellationToken)
{
var entity = await _context.Customers
.Where(e =>
e.Username == request.Username
&& e.Password == Encypt.EncryptString(request.Password))
.FirstOrDefaultAsync(cancellationToken);
if (entity.Equals(null))
{
throw new NotFoundException(nameof(entity), request.Username);
}
return new CustomerViewModel
{
ExternalId = entity.ExternalId
};
}
This is the exception I am getting:
Please let me know what else you need to determine what could be the issue. Also, be kind I have been away from c# for a while.
Thanks for the info it was the missing DI. I added this
// Add MediatR
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));
services.AddMediatR(typeof(LoginCustomerQueryHandler).GetTypeInfo().Assembly);
and we are good to go.

UserManager in ApiController

In my project HttpContext is a member of Controller and I can use it in AccountController : Controller. But I can't access an information about current user in ApiController in contraction like
public class AccountController : ApiController
{
public UserManager<ApplicationUser> UserManager { get; private set; }
private IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.Current.GetOwinContext().Authentication;
}
}
}
So how to write custom ApiController right?
In the method below user variable shows me null on breakpoint. How can I retrive current user if I know that hi is logined?
public IHttpActionResult GetUser(int id)
{
var manager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
var userid = User.Identity.GetUserId();
var user = manager.FindById(userid);
var data = new Person {Name = user.UserName, Age = 99};
return Ok(data);
}
From within any controller method you can do this.GetRequestContext().User to get the currently authenticated user. The static HttpContext.Current is not supported by WebApi.
manager.FindById(userid) retrieves a user from the database as opposed to the current . To get the current user, simply access the User property within your ApiController:
public class MyApiController : ApiController
{
IPrincipal GetCurrentUser(){
return User;
}
}
This may help you:
protected string UserId { get { return User.Identity.GetUserId(); } }

MVC3 - Unity/Unit of Work Pattern and Webservice implementation

I am a newbie to with unity and unit of work pattern and I am trying to write a code, which connects to my webservice and does all the work.
Everything goes well until I use the Database but I get lost when I try to use the webservice.
I have wasted my 2 precious days, searching every single possible article related to it and applying it to my code, but no luck till date.
I know, by writing connection string to web.config and calling it in dbcontext class controller will connect to the required database, but I am not connecting to any database, so what changes I need to do in web/app.config. Also, even if I write my connection logic in dbcontext constructor, it still searches and fills the dbcontext with sql server details. I presume thats happening because I am using DBSet.
Guys, you are requested to have a look at my code, I have done and show me some hope that I can do it. Let me know, if you want any other info related to the code that you want to see.
thanks
DBCONTEXT
public class CVSContext : DbContext
{
public DbSet<CVSViewModel> CVS { get; set; }
public DbSet<Contact> Contacts { get; set; }
public DbSet<Account> Accounts { get; set; }
public CVSContext()
{
//CRM Start
var clientCredentials = new System.ServiceModel.Description.ClientCredentials();
clientCredentials.UserName.UserName = "";
clientCredentials.UserName.Password = "";
var serviceProxy = new Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy(new Uri("http://Organization.svc"), null, clientCredentials, null);
serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
HttpContext.Current.Session.Add("ServiceProxy", serviceProxy);
//CRM End
}
}
GENERIC REPOSITORY
public class GenericRepository<TEntity> where TEntity : class
{
internal CVSContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(CVSContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
}
UNIT OF WORK
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
}
public interface IDALContext : IUnitOfWork
{
ICVSRepository CVS { get; set; }
IContactRepository Contacts { get; set; }
//IAccountRepository Accounts { get; set; }
}
public class DALContext : IDALContext
{
private CVSContext dbContext;
private ICVSRepository cvs;
private IContactRepository contacts;
// private IAccountRepository accounts;
public DALContext()
{
dbContext = new CVSContext();
}
public ICVSRepository CVS
{
get
{
if (cvs == null)
cvs = new CVSRepository(dbContext);
return cvs;
}
set
{
if (cvs == value)
cvs = value;
}
}
public IContactRepository Contacts
{
get
{
if (contacts == null)
contacts = new ContactRepository(dbContext);
return contacts;
}
set
{
if (contacts == value)
contacts = value;
}
}
public int SaveChanges()
{
return this.SaveChanges();
}
public void Dispose()
{
if(contacts != null)
contacts.Dispose();
//if(accounts != null)
// accounts.Dispose();
if(dbContext != null)
dbContext.Dispose();
GC.SuppressFinalize(this);
}
}
SERVICE
public interface ICVSService
{
Contact CreateContact(Guid contactName, string productName, int price);
List<CVSViewModel> GetCVS();
List<Contact> GetContacts();
List<Account> GetAccounts();
}
public class CVSService : ICVSService, IDisposable
{
private IDALContext context;
public CVSService(IDALContext dal)
{
context = dal;
}
public List<CVSViewModel> GetCVS()
{
return context.CVS.All().ToList();
}
public List<Contact> GetContacts()
{
return context.Contacts.All().ToList();
}
public List<Account> GetAccounts()
{
return context.Accounts.All().ToList();
}
public Contact CreateContact(Guid contactName, string accountName, int price)
{
var contact = new Contact() { ContactId = contactName };
var account = new Account() { ContactName = accountName, Rent = price, Contact = contact };
//context.Contacts.Create(contact);
context.SaveChanges();
return contact;
}
public void Dispose()
{
if (context != null)
context.Dispose();
}
}
CONTROLLER
public ActionResult Index()
{
ViewData.Model = service.GetContacts();
return View();
}
It's all about proper abstractions. The common abstraction that is used between some data source (could be a db or ws) is the Repository pattern, or at a higher level the Unit of Work pattern. In fact Entity Framework DbContext is an implementation of the Unit of Work pattern, but it is tailored for databases. You can't use to communicate with a web service.
In that case you will have to write your own IRepository<T> abstraction and have a database specific implementation that uses a DbContext under the covers and a web service specific implementation that wraps a web service client proxy under the covers.
However, when your application gets more complex, you often find yourself wanting to have some sort of transaction like behavior. This is what the Unit of Work pattern if for: it presents a business transaction. Using the unit of work pattern to wrap multiple WS calls however, will get painful very soon. It's a lot of work to get right and in that case you will be much better of using a message based architecture.
With a message based architecture you define a single atomic operation (a business transaction or use case) as a specific message, for instance:
public class MoveCustomerCommand
{
public int CustomerId { get; set; }
public Address NewAddress { get; set; }
}
This is just an object (DTO) with a set of properties, but without behavior. Nice about this is that you can pass these kinds of objects over the wire using WCF or any other technology or process them locally without the need for the consumer to know.
Take a look at this article that describes it in detail. This article builds on top of that model and describes how you can write highly maintainable WCF services using this model.

Retrieve a complex object from ActionParameters

I am working on an MVC project where controller actions deal with Assets. Different controllers take in the assetId parameter in different way: Some controllers simply get int assetId, other int id, and other using a complex object AssetDTO dto (which contains a property that holds the assetId)
I am writing an ActionFilter that is added to the action method and is provided with the actionParameter name where I can get the asset value.
Action Method:
[AssetIdFilter("assetId")]
public ActionResult Index(int assetId)
{
...
}
The attribute is defined as:
public class AssetIdFilterAttribute : ActionFilterAttribute
{
public string _assetIdParameterKey { get; set; }
public AssetIdFilterAttribute (string assetIdParameterKey)
{
_assetIdParameterKey = assetIdParameterKey;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
int assetId;
if (Int32.TryParse(filterContext.ActionParameters[_assetIdParameterKey].ToString(), out assetId))
{
......
}
}
This works as expected, but will only work when the assetId is provided as a primitive. I am not sure what to do when the assetId is provided within a complex object into the action method.
Will I need to parse each object differently depending on the type? I am hoping I can specify some kind of dot-notation in the AssetIdFilter to tell it where the assetId is located: dto.assetId
Any way I can use dynamics? or reflection?? ect.???
and here dynamic comes to the rescue.you can change the actionFilterAttribute to be :
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
dynamic assetIdHolder = filterContext.ActionParameters[_assetIdParameterKey];
if (assetIdHolder.GetType().IsPrimitive)
{
//do whatever with assetIdHolder
}
else
{
//do whatever with assetIdHolder.assetId
}
}
cheers!
Well, yes, you answered your question. One way would be to use dot notation:
//simple case:
[AssetId("id")]
public ActionResult Index(string id) {
//code here
}
//complex case:
[AssetId("idObj", AssetIdProperty = "SubObj.id")]
public ActionResult index(IdObject idObj) {
//code here
}
And AssetIdAttribute is as follows:
public class AssetIdAttribute : ActionFilterAttribute
{
public string _assetIdParameterKey { get; set; }
public string AssetIdProperty { get; set; }
public AssetIdFilterAttribute(string assetIdParameterKey)
{
_assetIdParameterKey = assetIdParameterKey;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
int assetId;
var param = filterContext.ActionParameters[_assetIdParameterKey];
int.TryParse(GetPropertyValue(param, this.AssetIdProperty).ToString(), out assetId);
//you code continues here.
}
private static string GetPropertyValue(object souce, string property)
{
var propNames = string.IsNullOrWhiteSpace(property) || !property.Contains('.') ? new string[] { } : property.Split('.');
var result = souce;
foreach (var prop in propNames)
{
result = result.GetType().GetProperty(prop).GetValue(result);
}
return result.ToString();
}
}
The code does not have null checks when calling ToString and when calling GetProperty though. Also, it does not check the success of TryParse. Please apply these corrections when used.
Maybe this code could be written using dynamic, but at the end dynamic usage is compiled into object using reflection (something like what I have done here), thus no big difference to me.
Also, maybe it would be more clear to have a parameter like "idObj.SubObj.id", but that again depends on the preference, and the code will become a little bit more complex.

Validating the user with Membership Provider

I'm customizing a form of validation of the users in my application Asp.net MVC 3.
How can I implement the method ValidateUser?
My problem is the password for the MembershipUser class (which I also customize) has a Password property.
I'm using EF CodeFirst .. following code:
MembershipUser
public class User : MembershipUser
{
public User(string username, object providerUserKey, string email, string passwordQuestion, bool isApproved,
bool isLockedOut)
: base("", username, providerUserKey, email, passwordQuestion, "", isApproved, isLockedOut, DateTime.Now, DateTime.MinValue,
DateTime.Now, DateTime.MinValue, DateTime.MinValue)
{
}
}
MembershipProvider
public class UserProvider : MembershipProvider
{
public override bool ValidateUser(string email, string password)
{
var bytes = new ASCIIEncoding().GetBytes(password);
var encryptedPassword = EncryptPassword(bytes);
using (var db = new DataContext())
{
var user = from u in db.Users
where u.Email == email
/* How to compare password? */
}
}
}
Please, is there a complete article with the implementation of this class?
I have not got a complete example but will this not work for you?
public class UserProvider : MembershipProvider
{
public override bool ValidateUser(string email, string password)
{
var bytes = new ASCIIEncoding().GetBytes(password);
var encryptedPassword = EncryptPassword(bytes);
var user = db.Users.FirstOrDefault(x =>
x.EmailAddress == emailAddress && x.Password == encryptedPassword);
return user != null;
}
}

Resources