Asked  8 Months ago    Answers:  5   Viewed   38 times

I am running a network. Here I have a domain controller (DC) I just installed IIS6 , PHP and Mysql on it. every thing is working fine.:)

Now I want to bring up a script on this local website. The first problem is that I want to detect which one of network users (active directory users) are logged in with PHP. I mean it is enough for me when the user is logged in to windows there is no need for another authentication.

I was wondering if I could just use a function or something... that its output is the AD username and user group.

 Answers

34

If you've set IIS to authenticate users one or more of these should contain the username:

$_SERVER['LOGON_USER']
$_SERVER['AUTH_USER']
$_SERVER['REDIRECT_LOGON_USER']
$_SERVER['REDIRECT_AUTH_USER']
Wednesday, March 31, 2021
 
Sagar
answered 8 Months ago
11

As you run it from server itself, and you just want to read I would try to use :

...
if(ldap_bind($ldap))
...

According to PHP documentation if bind_rdn and bind_password are not specified, an anonymous bind is attempted.

Then if your anonymous logon is refused (this should not be, because running under IIS on the server your code is at least executed as a domain user) you will find there how to enable anonymous LDAP binds to Windows Server. This used to work forme on W2K8, Inever test it on W2K12.

Saturday, May 29, 2021
 
BrunoRamalho
answered 5 Months ago
92

It does seem that there is no way of converting the username format without involving a query to Active Directory. Since that is the case there is no need to create WindowsPrincipal for checking the group membership since that would probably need yet another connection to AD.

By using the System.DirectoryServices.AccountManagement namespace you can both get the UPN of the user and check the group membership.

string accountName = @"DOMAINuser";
var groupNames = new[] { "DOMAINDomain Users", "DOMAINGroup2" }; // the groups that we need to verify if the user is member of

// cannot create WindowsIdentity because it requires username in form user@domain.com but the passed value will be DOMAINuser.
using (var pc = new PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Domain, Environment.UserDomainName))
{
    using (var p = UserPrincipal.FindByIdentity(pc, accountName))
    {
        // if the account does not exist or is not an user account
        if (p == null)
            return new string[0];

        // if you need just the UPN of the user, you can use this
        ////return p.UserPrincipalName;

        // find all groups the user is member of (the check is recursive).
        // Guid != null check is intended to remove all built-in objects that are not really AD gorups.
        // the Sid.Translate method gets the DOMAINGroup name format.
        var userIsMemberOf = p.GetAuthorizationGroups().Where(o => o.Guid != null).Select(o => o.Sid.Translate(typeof(NTAccount)).ToString());

        // use a HashSet to find the group the user is member of.
        var groups = new HashSet<string>(userIsMemberOf, StringComparer.OrdinalIgnoreCase);
        groups.IntersectWith(groupNames);

        return groups;
    }
}
Friday, July 23, 2021
 
bumperbox
answered 3 Months ago
68

Well, I managed to figure out the issue:

PrincipalContext domainContext = new PrincipalContext(ContextType.Domain,domain);

domainContext.ValidateCredentials(userName, password, 
    ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);

By specifying the ContextOptions in the ValidateCredentials method (instead of in the constructor), this allowed me to avoid having to specify a DN for a container object.

UPDATE:

Although I should clarify that after further experimentation, I found that any queries derived from this PrincipalContext object takes place UN-encrypted.

Apparently, when the ContextOptions are set in ValidateCredentials, those options are only used for that specific call of ValidateCredentials. But here's where it gets strange...

So, I wanted to have my queries to the AD server take place encrypted as well. Example query:

UserPrincipal p = UserPrincipal.FindByIdentity(
    domainContext, IdentityType.SamAccountName, userName);
var groups = p.GetGroups();
foreach (GroupPrincipal g in groups) { /* do something */ }

The above code gets a list of all the Groups that the user belongs to, but it happens in the clear (unencrypted). So after much fiddling, I discovered that the DN never needs to be set.

PrincipalContext domainContext = new PrincipalContext(ContextType.Domain,domain,
    null,ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);

I found that I could set the container object (DN) to null. And this works fine. Setting it to an empty string ("") results in an exception of some unknown type, so don't think you can give it an empty string.

And here's the weird part. You'd think that setting the SecureSocketLayer option in the PrincipalContext would mean that you don't have to explicitly set it when you use VerifyCredentials. But I found that if I didn't set it in the VerifyCredentials part, the authentication would fail, but the queries (like in the example to the Groups) still takes place encrypted.

Maybe I just don't fully understand AD authentication and queries yet, but that seems like odd behavior to me.

Tuesday, July 27, 2021
 
Jauco
answered 3 Months ago
43

So, first, as a heads up, do realize that fileName.getBytes() as you have there gets the bytes of the filename, not the file itself.

Second, reading inside the docs of FileReader:

The constructors of this class assume that the default character encoding and the default byte-buffer size are appropriate. To specify these values yourself, construct an InputStreamReader on a FileInputStream.

So, sounds like FileReader actually isn't the way to go. If we take the advice in the docs, then you should just change your code to have:

String fileName = getFileNameToReadFromUserInput();
FileInputStream is = new FileInputStream(fileName);
InputStreamReader isr = new InputStreamReader(is, getCorrectCharsetToApply());
BufferedReader buffReader = new BufferedReader(isr);

and not try to make a FileReader at all.

Thursday, July 29, 2021
 
Fanda
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share