public bool IsUserGroupMember(string user, string unit)
{
bool member = false;
try
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
string[] groups = unit.Split(',');
foreach (string word in groups)
{
GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, word);
if (grp != null)
{
foreach (Principal p in grp.GetMembers(true))
{
if (p.SamAccountName == user)
{
member = true;
grp.Dispose();
ctx.Dispose();
return member;
}
}
}
else
{
grp.Dispose();
ctx.Dispose();
return member;
}
}
}
catch (COMException)
{
return member;
}
return member;
}
I'm using the method above to find if a user is member of a group in Active Directory, recursively. It works well..although sometimes I get a weird exception.
Specified method is not supported.
foreach (Principal p in grp.GetMembers(true)) is red (sorry I can't upload a picture of the exception). The weirdest thing is that it seems to be thrown randomly, and if I refresh the page it works well..
I tried to find a solution on the Internet but no happy news for now..
You should do this the other way around: get the user and then the authorization groups that this user is a member of - this call (.GetAuthorizationGroups on the UserPrincipal) already is searching the groups recursively for you!
public bool IsUserGroupMember(string user, string unit)
{
bool isMember = false;
try
{
// put the PrincipalContext in a using(..) block - then it's
// automatically, safely and properly disposed of at the end
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// get the user
UserPrincipal up = UserPrincipal.FindByIdentity(ctx, user);
if(up != null)
{
// get the authorization groups for the user
// this call is *RECURSIVELY* enumerating all groups
// that this user is a member of
var authGroups = up.GetAuthorizationGroups();
// now that you have the groups - just determine if the user
// is a member of the group you're looking for......
}
}
}
catch (COMException comEx)
{
isMember = false;
}
return isMember;
}
I finally ended up with a solution!
I just had to add my domain name, as follow:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "MyDomain");
It solved the problem right away!
And about the slowness..I used cookies, following this link.
Related
I am implementing CoinPayments IPN in my application and I have trouble with passing data to the method that take their Callback. I have tried like everything I could find: TempData, SessionVariables, tried to implement it somewhere in forms and maybe Request it but that didn`t work for me. So I also tried to implement it with Global static variables. And it worked! But then came another issue: if more than one user were to buy something from website at the same time or even in between any callbacks their data will get mixed. So here I am, trying again to make Session Variables work and have no clue why they are not working as I used them before. Probably what I can think of is that because its a callback from CoinPayments and I handle something wrongly.
Here is the code I have right now: Tho I tried different variations like implementing Session in Get Payment method. Now I ended up with it and it still comes out as null in POST METHOD.
Class for handling Session Variables:
public static class MyGlobalVariables
{
public static int TokenChoice
{
get
{
if (System.Web.HttpContext.Current.Session["TokenChoice"] == null)
{
return -1;
}
else
{
return (int)System.Web.HttpContext.Current.Session["TokenChoice"];
}
}
set
{
System.Web.HttpContext.Current.Session["TokenChoice"] = value;
}
}
public static int PaymentChoice
{
get
{
if (System.Web.HttpContext.Current.Session["PaymentChoice"] == null)
{
return -1;
}
else
{
return (int)System.Web.HttpContext.Current.Session["PaymentChoice"];
}
}
set
{
System.Web.HttpContext.Current.Session["PaymentChoice"] = value;
}
}
public static string CurrentUser
{
get
{
System.Web.HttpContext.Current.Session["CurrentUser"] = System.Web.HttpContext.Current.User.Identity.Name;
return (string)System.Web.HttpContext.Current.Session["CurrentUser"];
}
}
}
Class that returns view where you click on CoinPayments button:
public ActionResult Payment(int tokenChoice, int paymentChoice)
{
ViewBag.Payment = paymentChoice;
MyGlobalVariables.PaymentChoice = paymentChoice;
MyGlobalVariables.TokenChoice = tokenChoice;
return View();
}
Callback class that handles Callback from CoinPayments:
[HttpPost]
public ActionResult Payment()
{
NameValueCollection nvc = Request.Form;
var merchant_id = id;
var ipn_secret = secret;
var order_total = MyGlobalVariables.PaymentChoice;
if (String.IsNullOrEmpty(nvc["ipn_mode"]) || nvc["ipn_mode"] != "hmac")
{
Trace.WriteLine("IPN Mode is not HMAC");
return View();
}
if (String.IsNullOrEmpty(HTTP_HMAC))
{
Trace.WriteLine("No HMAC signature sent");
return View();
}
if (String.IsNullOrEmpty(nvc["merchant"]) || nvc["merchant"] != merchant_id.Trim())
{
Trace.WriteLine("No or incorrect Merchant ID passed");
return View();
}
//var hmac = hash_hmac("sha512", request, ipn_secret.Trim());
var txn_id = nvc["txn_id"];
var item_name = nvc["item_name"];
var item_number = nvc["item_number"];
var amount1 = nvc["amount1"];
var amount2 = float.Parse(nvc["amount2"], CultureInfo.InvariantCulture.NumberFormat);
var currency1 = nvc["currency1"];
var currency2 = nvc["currency2"];
var status = Convert.ToInt32(nvc["status"]);
var status_text = nvc["status_text"];
Trace.WriteLine(status);
if (currency1 != "USD") {
Trace.WriteLine("Original currency mismatch!");
return View();
}
if (Convert.ToInt32(amount1) < Convert.ToInt32(order_total))
{
Trace.WriteLine("Amount is less than order total!");
return View();
}
if (status >= 100 || status == 2) {
using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
{
var account = dc.Users.Where(a => a.Username == MyGlobalVariables.CurrentUser).FirstOrDefault();
if (account != null && account.Paid == 0)
{
Trace.WriteLine("Payment Completed");
Trace.WriteLine("Tokens to add: " + MyGlobalVariables.TokenChoice);
account.Tokens += MyGlobalVariables.TokenChoice;
account.Paid = 1;
dc.Configuration.ValidateOnSaveEnabled = false;
dc.SaveChanges();
}
}
} else if (status < 0)
{
Trace.WriteLine(
"payment error, this is usually final but payments will sometimes be reopened if there was no exchange rate conversion or with seller consent");
} else {
using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
{
var account = dc.Users.Where(a => a.Username == MyGlobalVariables.CurrentUser).FirstOrDefault();
if (account != null)
{
account.Paid = 0;
dc.Configuration.ValidateOnSaveEnabled = false;
dc.SaveChanges();
}
}
Trace.WriteLine("Payment is pending");
}
return View();
}
As you can see there are only 3 variables I need to handle.
Also someone might ask why I use Session Variable for Current.User?
Well for some reason Callback method can not read Current.User as it return null. And well... nothing really changed as for now.
If you have ever experienced something like that or can find an issue I would be so thankful since I wasted already over 2 days on that issue.
EDIT:
After some testing I found out variables works fine if I run Post method on my own. So the problem is with handling callback from CoinPayments. Is there a specific way to deal with this?
I'm wondering how I could get a list of members of an AD group.
Checking if an entered password of a user is correct works perfectly fine. For this I'm using Novell's Ldap.NetStandard:
private bool IsUserValid(string userName,string userPassword)
{
try{
using (var connection = new LdapConnection { SecureSocketLayer = false })
{
connection.Connect("test.local", LdapConnection.DEFAULT_PORT);
connection.Bind(userDn, userPassword);
if (connection.Bound)
{
return true;
}
}
}
catch (LdapException ex)
{
Console.WriteLine(ex.Massage);
}
return false;
}
What I want now is something like this:
bool isUserInGroup("testUser","testGroup");
The problem is I can't get my method working:
public bool IsUserMemberOfGroup(string userName,string groupName)
{
var ldapConn = GetConnection();
var searchBase = "";
var filter = $"(&(objectClass=group)(cn={groupName}))";
var search = ldapConn.Search(searchBase, LdapConnection.SCOPE_BASE, filter, null, false);
while (search.hasMore())
{
var nextEntry = search.next();
if (nextEntry.DN == userName)
return true;
}
return false;
}
What ever I'm doing, I'm not getting back any value from my Ldap.Search()...
Now there is an implementation of System.DirectoryServices.AccountManagement for .NET Core 2. It is available via nuget.
With this package you are able to things like that:
using (var principalContext = new PrincipalContext(ContextType.Domain, "YOUR AD DOMAIN"))
{
var domainUsers = new List<string>();
var userPrinciple = new UserPrincipal(principalContext);
// Performe search for Domain users
using (var searchResult = new PrincipalSearcher(userPrinciple))
{
foreach (var domainUser in searchResult.FindAll())
{
if (domainUser.DisplayName != null)
{
domainUsers.Add(domainUser.DisplayName);
}
}
}
}
This performs a search for the user in your domain.Nearly the same is possible for searching your group. The way I used to search my AD (description in my question) is now obsolet:
Checking if an entered password of a user is correct works perfectly
fine. For this I'm using Novell's Ldap.NetStandard:
How about:
HttpContext.User.IsInRole("nameOfYourAdGroup");
(namespace System.Security.Claims)
I have been facing this problem with assigning users to a proper role. The code looks just fine, but in reality half of the users gets a proper role, the other half stays without a role at all. Here is the method which does it:
public IdentityResult RefreshUserGroupRoles(long? userId)
{
if (userId == null) throw new ArgumentNullException(nameof(userId));
var user = _userManager.FindById(userId.Value);
if(user == null)
{
throw new ArgumentNullException(nameof(userId));
}
// Remove user from previous roles:
var oldUserRoles = _userManager.GetRoles(userId.Value);
if (oldUserRoles.Count > 0)
{
_userManager.RemoveFromRoles(userId.Value, oldUserRoles.ToArray());
}
// Find the roles this user is entitled to from group membership:
var newGroupRoles = this.GetUserGroupRoles(userId.Value);
// Get the damn role names:
var allRoles = _roleManager.Roles.ToList();
var addTheseRoles = allRoles.Where(r => newGroupRoles.Any(gr => gr.AppRoleId == r.Id));
var roleNames = addTheseRoles.Select(n => n.Name).ToArray();
//_db.Database.CurrentTransaction.Commit();
// Add the user to the proper roles
var transaction = _db.Database.BeginTransaction();
IdentityResult result;
try
{
result = _userManager.AddToRoles(userId.Value, roleNames);
transaction.Commit();
_db.DbContextTransactionAu.Commit(); //This is for Audit
}
catch (Exception)
{
transaction.Rollback();
throw;
}
_db.DbContextTransactionAuDispose?.Dispose();
return result;
}
public IEnumerable<AppGroupRole> GetUserGroupRoles(long userId)
{
var userGroups = this.GetUserGroups(userId).ToList();
if (userGroups.Count == 0) return new Collection<AppGroupRole>().AsEnumerable();
var userGroupRoles = new List<AppGroupRole>();
foreach(var group in userGroups)
{
userGroupRoles.AddRange(group.AppRoles.ToArray());
}
return userGroupRoles;
}
Any idea what could be wrong?
I'm having some trouble with Sqlite in memory.
I have a class that has a CPF field - similar to US' SSN. As a bussiness rule, the CPF must be unique in the system.
So I've decided to make a check on the class that has this field. Now maybe there's code smell here: I check with the ORM if this is a Conflicting CPF.
private CPF cpf;
public virtual CPF CPF
{
get { return cpf; }
set
{
if (this.ormCreated) //Do not check if it is loaded from the DB. Otherwise, it loops, generating a StackOverflow exception
{
cpf = value;
}
else
{
this.setNewCpf(value);
}
}
}
private void setNewCpf(CPF newCpf)
{
if (this.cpf == newCpf)
{
return;
}
if (Helper.Orm.IsConflictingCpf(newCpf))
{
throw new ConflictingCpfException();
}
else
{
cpf = newCpf;
}
}
And here is the implementation, on the ORM Helper class.
bool OrmHelper.IsConflictingCpf(CPF cpf)
{
int? cpfNumber = cpf.NumeroSemDV;
if (cpfNumber.HasValue)
{
var teste = findByCpfNumber<Client>(cpf);
return
(
findByCpfNumber<Client>(cpf) != null ||
findByCpfNumber<Adversary>(cpf) != null
);
}
else
{
//CPFSemDV = Nullable
return false;
}
}
private PersonType findByCpfNumber<PersonType> (CPF cpf) where PersonType : PessoaFisica
{
int? cpfNumber = cpf.NumeroSemDV;
using (var session = this.NewSession())
using (var transaction = session.BeginTransaction())
{
try
{
var person = session.Query<PersonType>()
.Where(c => c.CPF.NumeroSemDV == cpfNumber)
.FirstOrDefault<PersonType>();
return person;
}
catch (Exception) { transaction.Rollback(); }
finally
{
session.Close();
}
}
return null;
}
The problem happens in my tests. I'm using FluentNHibernate and In memory SQLite.
protected override FluentConfiguration PersistenceProvider
{
get
{
return Fluently
.Configure()
.Database(
SQLiteConfiguration
.Standard
.InMemory()
.ShowSql()
);
}
}
Here is the failing test.
protected override void Given()
{
base.Given();
var clients = new List<Client>();
Client client1 = new Client("Luiz Angelo Heinzen")
{
Capaz = true,
CPF = new CPF(18743509),
eMail = "lah#furb.br"
};
session.Save(client1);
session.Evict(client1);
}
[Then]
public void Motherfaker()
{
Client fromDb;
var clientsFromDb = session.Query<Client>()
.Where(c => c.eMail == "lah#furb.br");
fromDb = clientsFromDb.FirstOrDefault<Client>();
Assert.AreEqual(fromDb.FullName, "Luiz Angelo Heinzen");
}
The reason it fails? In the beginning it was failing because the table didn't exist. In memory sqlite destroys the schema on each new session. So I changed the code to return the same session on the NewSession(). But now it fails with a NHibernate exception: Session is closed. I've tested and if change the findByCpfNumber from this
private PersonType findByCpfNumber<PersonType> (CPF cpf) where PersonType : PessoaFisica
{
int? cpfNumber = cpf.NumeroSemDV;
using (var session = this.NewSession())
using (var transaction = session.BeginTransaction())
{
try
{
var person = session.Query<PersonType>()
.Where(c => c.CPF.NumeroSemDV == cpfNumber)
.FirstOrDefault<PersonType>();
return person;
}
catch (Exception) { transaction.Rollback(); }
finally
{
session.Close();
}
}
return null;
}
to this
private PersonType findByCpfNumber<PersonType> (CPF cpf) where PersonType : PessoaFisica
{
int? cpfNumber = cpf.NumeroSemDV;
//using (var session = this.NewSession())
var session = this.NewSession();
using (var transaction = session.BeginTransaction())
{
try
{
var person = session.Query<PersonType>()
.Where(c => c.CPF.NumeroSemDV == cpfNumber)
.FirstOrDefault<PersonType>();
return person;
}
catch (Exception) { transaction.Rollback(); }
finally
{
//session.Close();
this.CloseSession(session);
}
}
this.CloseSession(session);
return null;
}
the error doesn't happen anymore. Obviously, I'd have to implement the CloseSession method. It would close the Session on the Production database and it would do nothing if Sqlite is being used.
But I'd rather configure SQLite in someway that it wouldn't dispose the session. I've read here about release_mode, Pooling and Max Pool atributes. But I can't seem to find it in the FluentNHibernate so can't even test to see if it would work. I have the FluentNHibernate cloned and it seems to set the release_mode set to on_close, but that doesn't help.
I've even tried:
public override ISession NewSession()
{
if (this.session == null)
{
if (sessionFactory == null)
{
CreateSessionFactory();
}
this.session = sessionFactory.OpenSession();
}
if (!session.IsOpen)
{
sessionFactory.OpenSession(session.Connection);
session.Connection.Open();
}
return session;
}
But it keeps telling me that the Session is closed. So, anyone has any suggestions on how to approach this?
Or does this so smelly that's beyond salvation?
I hope this is clear enough. And forgive my mistakes: I'm from Brazil and not a native english speaker.
Thanks,
Luiz Angelo.
i would check for uniqueness when creating CPFs in the system and have an additional Unique constraint in the database to enforce that. Then if you set cascading to none for each reference to CPF (default is none) it is not possible to assigne newly created duplicate CPFs to an Entity and save it without exception, so it can't happen accidently.
I had the same problem. What's happening is that in-memory SQLite will drop the entire schema when the connection is closed. If you create a session that you hold on to for all tests, it will retain the structure for all other sessions.
For code and a fuller explanation, check out this answer: Random error when testing with NHibernate on an in-Memory SQLite db
I'm using ASP.NET Membership. If all I ever care about is whether or not I have a non-null Membership.GetUser(), is there ever a reason to use Request.IsAuthenticated?
During development, I have inadvertently created situations where Request.IsAuthenticated is true, but Membership.GetUser() is null, so I would pass the [Authorize] filter test (which is applied globally, with [AllowAnonymous] applied specifically as required), but fail later on. While this is a situation that would probably not occur in production, I'd still like to account for it.
Given this, would it be appropriate to write a custom filter, say AuthorizeMembership or some such, that checks against Membership.GetUser() rather than Request.IsAuthenticated? Any gotchas to be aware of?
If so, would it also be okay to use that filter to populate a global UserInfo object with the user properties I typically need to process a request? I don't use Membership Profile at all, but manage my user properties independently in a separate application database.
The main different is speed.
The Request.IsAuthenticated is faster and use an internal cache flag, than the Membership.GetUser().
To see why the one is faster than the other I place here the code.
public virtual bool IsAuthenticated
{
get
{
if (this.m_isAuthenticated == -1)
{
WindowsPrincipal principal = new WindowsPrincipal(this);
SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority, new int[] { 11 });
this.m_isAuthenticated = principal.IsInRole(sid) ? 1 : 0;
}
return (this.m_isAuthenticated == 1);
}
}
but the GetUser() have too many calls because actually need more information's to give.
public static MembershipUser GetUser()
{
return GetUser(GetCurrentUserName(), true);
}
private static string GetCurrentUserName()
{
if (HostingEnvironment.IsHosted)
{
HttpContext current = HttpContext.Current;
if (current != null)
{
return current.User.Identity.Name;
}
}
IPrincipal currentPrincipal = Thread.CurrentPrincipal;
if ((currentPrincipal != null) && (currentPrincipal.Identity != null))
{
return currentPrincipal.Identity.Name;
}
return string.Empty;
}
public static MembershipUser GetUser(string username, bool userIsOnline)
{
SecUtility.CheckParameter(ref username, true, false, true, 0, "username");
return Provider.GetUser(username, userIsOnline);
}
internal static void CheckParameter(ref string param, bool checkForNull, bool checkIfEmpty, bool checkForCommas, int maxSize, string paramName)
{
if (param == null)
{
if (checkForNull)
{
throw new ArgumentNullException(paramName);
}
}
else
{
param = param.Trim();
if (checkIfEmpty && (param.Length < 1))
{
throw new ArgumentException(SR.GetString("Parameter_can_not_be_empty", new object[] { paramName }), paramName);
}
if ((maxSize > 0) && (param.Length > maxSize))
{
throw new ArgumentException(SR.GetString("Parameter_too_long", new object[] { paramName, maxSize.ToString(CultureInfo.InvariantCulture) }), paramName);
}
if (checkForCommas && param.Contains(","))
{
throw new ArgumentException(SR.GetString("Parameter_can_not_contain_comma", new object[] { paramName }), paramName);
}
}
}