Netscape LDAP API to get the Maxpagesize from Microsoft AD - ldap

As Microsoft AD has maxpagesize property, which is used to return the max records per page from directory to client. So if we want to fetch more records (than configured to maxpagesize) from Microsoft AD, we need to do pagination.
So to achieve this we wanted to read this value of maxpagesize at client side through Netscape API.
So could you please help us on this. is it really possible otherwise we need to configure the pagesize at UI.
Thanks,
Hrushi

The MaxPageSize is part of the LDAP policy in Active Directory and since Windows Server 2008 R2 or Windows Server 2008 domain controller the hardcoded limits dictate MaxPageSize=20,000 and MaxValRange=5,000.
The value can be read from:
dn: CN=Default Query Policy,CN=Query-Policies,CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=mad,DC=example,DC=com
But Real life is never that simple.
LDAP policies are specified using the lDAPAdminLimits attribute. The lDAPAdminLimits attribute of a queryPolicy object is a multivalued string where each string value encodes a name-value pair. In the encoding, the name and value are separated by an "=". For example, the encoding of the name "MaxActiveQueries" with value "0" is "MaxActiveQueries=0". Each name is the name of an LDAP policy, and the value is a value of that policy.
There can be multiple queryPolicy objects in a forest. A DC determines the queryPolicy object that contains its policies according to the following logic:
If the queryPolicyObject attribute is present on the DC's nTDSDSA
object, the DC uses the queryPolicy object referenced by it.
Otherwise, if the queryPolicyObject attribute is present on the
nTDSSiteSettings object for the site to which the DC belongs, the DC
uses the queryPolicy object referenced by it.
Otherwise, the DC uses the queryPolicy object whose DN is "CN=Default
Query Policy,CN=Query-Policies" relative to the nTDSService object
(for example, "CN=Default Query Policy, CN=Query-Policies,
CN=Directory Service, CN=Windows NT, CN=Services" relative to the
root of the config NC).
And Finally MaxPageSize in Windows Server 2008 and Windows Server 2008 R2 (and I assume later) has a Hardcoded limit which override LDAP policy in Active Directory setting when the policy value should be higher.

Related

bdb_dn2entry("cn=kerberoskdc,cn=config,dc=example,dc=com") Meaning?

What is the meaning of third line. I got this message when I run my openldap server while binding a user.
entry_decode(cn=user,dc=example,dc=com)
5a3fd996 => bdb_search
5a3fd996 bdb_dn2entry("cn=kerberoskdc,cn=config,dc=example,dc=com")
This is slapd requesting its backend to load data corresponding to the distinguished name "cn=kerberoskdc,cn=config,dc=example,dc=com". This happens a lot under the hood when performing ldap opertions, the dn is used as a primary key for fast lookups.
bdb_dn2entry is an internal function used by slapd's backend, it is invoked when ldap operations are performed (you should be able to see which operation triggers the call in the log file where this line appears).
Openldap uses a backend for a normal slapd database. Backends do the
actual work of storing or retrieving data in response to LDAP
requests. Backends may be compiled statically into slapd, or when
module support is enabled, they may be dynamically loaded.
OpenLDAP's bdb abd hdb backends use the Oracle Berkeley DB (BDB)
package to store data.
bdb_dn2entry is a function that actually retrieve data from the database. It is shared with other ldap's backend (not only for bdb/hdb) as it is defined as a function prototype in the header file proto-bdb.h in the source code :
/**
* dn2entry.c
*/
#define bdb_dn2entry BDB_SYMBOL(dn2entry)
int bdb_dn2entry LDAP_P(( Operation *op, DB_TXN *tid,
struct berval *dn, EntryInfo **e, int matched,
DB_LOCK *lock ));
The real action takes place in dn2entry.c :
dn2entry looks up the dn in the cache/indexes and returns the corresponding entry. If the requested DN is not found and matched is TRUE, it returns info for the closest ancestor of the DN. Otherwise EntryInfo e is NULL.

How to change Windows ACL 'Group' with Powershell?

Problem:
I need to limit access to a WCF service using only Windows account settings. I have a WCF service with security binding element 'clientCredentialType' set to 'Windows'. Can't change this setting. If I understand correctly, anyone with an authentic windows account is authorized as long as they meet the authorization rules set by the file (EXE) that is hosting that WCF service. So I went into Powershell and queried the settings for that service:
Get-Acl MYSERVICE.exe | Format-List
says:
Path : Microsoft.PowerShell.Core\FileSystem::C:\Program Files (x86)\Blah\Server\MYSERVICE.exe
Owner : BUILTIN\Administrators
Group : MYDOMAIN\Domain Users
Access : NT AUTHORITY\SYSTEM Allow FullControl
BUILTIN\Administrators Allow FullControl
BUILTIN\Users Allow ReadAndExecute, Synchronize
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow ReadAndExecute, Synchronize
Audit :
Sddl : O:BAG:DUD:AI(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;0x1200a9;;;BU)(A;ID;0x1200a9;;;AC)
Every user in my domain seems to have access.
Question, how do I change 'MYDOMAIN\Domain Users' to a different group in my domain so that every domain user (in that group) does not have access?
I have been able to change the list of accounts and their permissions under 'Access' like this:
$perm = "My Other Domain Group","FullControl","Allow"
$rule=New-Object System.Security.AccessControl.FileSystemAccessRule $perm
$myservice_acl.SetAccessRule($rule)
And can presumably explicitly deny or grant access but how do I change the group it inherits from? Or is this the correct approach?
The Windows Security Descriptor(SD) is broken up into four primary parts:
Owner
Group (or Primary Group)
Discretionary Access Control List (DACL)
System Access Control List (SACL)
The Primary Group part of the SD is ignored and has been ignored since Windows 2000 and was preserved for backwards compatability with POSIX operating systems. https://technet.microsoft.com/en-us/library/cc961983.aspx
For your case, the only two fields to concern yourself with are the Owner and the DACL.
The Owner has implicit Full Control over the Securable Object.
The DACL is a list of Access Control Entries (ACEs) which defines Security Identifiers (SIDs or trustees) that have a level of access rights defined.
In other words, if you are concerned about the SD on your service binary, check the owner and all members of the DACL but not the Primary Group.
https://technet.microsoft.com/en-us/library/cc961983.aspx
https://technet.microsoft.com/en-us/library/cc781716(v=ws.10).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/aa379563(v=vs.85).aspx
EDIT: For the sake of completeness, the SACL is a list of ACEs (trustees and access rights) but instead of governing control, it controls who is audited and for what type of behavior.
Group: The security group of the owner.
only users in following groups are able to reach folder\object:
NT AUTHORITY\SYSTEM Allow FullControl,
BUILTIN\Administrators Allow FullControl,
BUILTIN\Users Allow ReadAndExecute, Synchronize,
you should check only access property to add/remove/query who has access to the folder\file
Domain users have access via the local group BUILTIN\Users (joining a computer to a domain automatically adds the group DOMAIN\Domain Users to the group BUILTIN\Users on the joining host). The group property of the security identifier has nothing to do with the access.
If you want to prevent access by domain users in general and allow just a particular domain group you'd remove the DOMAIN\Domain Users ACE and add an ACE for the desired group:
$ace = $myservice_acl.Access |
Where-Object { $_.IdentityReference -eq 'DOMAIN\Domain Users' }
$myservice_acl.RemoveAccessRule($ace)
$ace = New-Object Security.AccessControl.FileSystemAccessRule ('DOMAIN\Other Group', 'FullControl', 'Allow')
$myservice_acl.AddAccessRule($ace)
Set-Acl -AclObject $myservice_acl -Path ...
If you just want to deny access to a particular user you could also create a deny ACE for that user. However, mixing permissions like that tends to become pretty messy pretty fast, so I wouldn't recommend going this route.

LDAP Authentication failed: Invalid Credentials

In Gforge, when a new user tries to log in; the user is automatically registered by fetching data from LDAP. It works fine for other users but one particular user is not able to log in and gets the error LDAP Authentication failed: Invalid Credentials . I don't understand what could be the issue? Could you please help?
This is the search function I am using.
ldap_bind($ldap, $dn, $pw)
$dn = ldap_get_dn($ldap, $entry);
$entry = ldap_first_entry($ldap,$res);
$res=ldap_search($ldap, $sys_ldap_base,$sys_ldap_id_attribute . '=' . $id,
array());
If it works for some users but not for one specific user, then it's something to do with the LDAP configuration, or with the characters in that user's ID or pwd.
Is the failing user in a different org/OU? Do they have accent characters in their username or password? These things can cause compatibility issues between GForge and the LDAP server.
Does this user have a much longer user name than other users? There is a GForge config setting called "usernameregex" that governs the complexity and length of allowed user names. Even though LDAP logins result in automatic account creation, the validation of the user's unix name might fail due to the regex in place. The error noted above could certainly be the catch-all message when this happens.
The default setting is "^[a-z0-9_.-]{3,15}$". You can change the upper length limit by changing the 15 to something else. The unix_name field in the GForge database is TEXT, so it can be extremely long (1GB?).
In GForge 6.3.x and earlier, you can find that setting in /etc/gforge/gforge.conf. Change the value and then update the system using:
cd /opt/gforge/bin && php create_config_cache.php
In GForge 6.4 and later, you can use the gf-config utility to set the value. It will take effect right away:
/opt/gforge/bin/gf-config set "usernameregex" "new regex value"

Freeradius users operators

I faced with one issue, which I can't understand in Freeradius users file.
My goal is just authenticate external user "shad" with password "test".
I added line in /etc/raddb/users the following line:
shad Cleartext-Password == "test"
Result was Reject. If I change "==" operator to ":=" Authentication is successful.
So my question is the following:
Why I can't use "==" operator while FreeRadius documentation tells:
"Attribute == Value
As a check item, it matches if the named attribute is present in the request, AND has the given value."
And one more question.
In some resourses I faced with such lines:
shad Auth-Type := Local, User-Password == "test"
I tried and it doesn't work. Responce is Reject with log:
[pap] WARNING! No "known good" password found for the user. Authentication may fail because of this.
How the users file works
For the answer below, pairs is referring to Attribute Value Pairs (AVPs), that is, a tuple consisting of an attribute an operator and a value.
There are three lists of attribute(s) (pairs) that are accessible from the users file. These are bound to the request the server is currently processing, and they don't persist across multiple request/response rounds.
request - Contains all the pairs from the original request received from the NAS (Network Access Server) via the network.
control - Initially contains no pairs, but is populated with pairs that control how modules process the current request. This is done from the users file or unlang (the FreeRADIUS policy language used in virtual servers).
reply - Contains pairs you want to send back to the NAS via the network.
The users file module determines the list it's going to use for inserting/searching, by where the pair is listed in the entry, and the operator.
The first line of the entry contains check pairs that must match in order for the entry to be used. The first line also contains control pairs, those you want to be inserted into the control list if all the check pairs match.
Note: It doesn't matter which order the pairs are listed in. control pairs will not be inserted unless all the check pairs evaluate to true.
check and control pairs are distinguished by the operator used. If an assignment operator is used i.e. ':=' or '=' then the pair will be treated as a control pair. If an equality operator such as '>', '<', '==', '>=', '<=', '=~' is used, the pair will be treated as a check pair.
Subsequent lines in the same entry contain only reply pairs. If all check pairs match, reply pairs will be inserted into the reply list.
Cleartext-Password
Cleartext-Password is strictly a control pair. It should not be present in any of the other lists.
Cleartext-Password is one of a set of attributes, which should contain the 'reference' (or 'known good') password, that is, the local copy of the users password. An example of another pair in this set is SSHA-Password - this contains a salted SHA hash of the users password.
The reference password pairs are searched for (in the control list) by modules capable of with authenticating users using the 'User-Password' pair. In this case that module is 'rlm_pap'.
User-Password
User-Password is strictly a request pair. It should not be present in any of the other lists.
User-Password is included in the request from the NAS. It contains the plaintext version of the password the user provided to the NAS. In order to authenticate a user, a module needs to compare the contents of User-Password with a control pair like Cleartext-Password.
In a users file entry when setting reference passwords you'll see entries like:
my_username Cleartext-Password := "known_good_password"
That is, if the username matches the value on the left (my_username), then insert the control pair Cleartext-Password with the value "known_good_password".
To answer the first question the reason why:
shad Cleartext-Password == "test"
Does not work, it is because you are telling the files module to search in the request list, for a pair which does not exist in the request list, and should never exist in the request list.
You might now be thinking oh, i'll use User-Password == "test" instead, and it'll work. Unfortunately it won't. If the password matches then the entry will match, but the user will still be rejected, see below for why.
Auth-Type
Auth-Type is strictly a control pair. It should not be present in any of the other lists.
There are three main sections in the server for dealing with requests 'authorize', 'authenticate', 'post-auth'.
authorize is the information gathering section. This is where database lookups are done to authorise the user, and to retrieve reference passwords. It's also where Auth-Type is determined, that is, the type of authentication we want to perform for the user.
Authenticate is where a specific module is called to perform authentication. The module is determined by Auth-Type.
Post-Auth is mainly for logging, and applying further policies, the modules run in Post-Auth are determined by the response returned from the module run in Authenticate.
The modules in authorize examine the request, and if they think they can authenticate the user, and Auth-Type is not set, they set it to themselves. For example the rlm_pap module will set Auth-Type = 'pap' if it finds the User-Password in the request.
If no Auth-Type is set the request will be rejected.
So to answer your second question, you're forcing pap authentication, which is wrong, you should let rlm_pap set the Auth-Type by listing pap after the files module in the authorize section.
When rlm_pap runs in authenticate, it looks for a member of the set of 'reference' passwords described above, and if it can't find one, it rejects the request, this is what's happening above.
There's also a 'magic' Auth-Type, 'Accept', which skips the authenticate section completely and just accepts the user. If you want the used to do cleartext password comparison without rlm_pap, you can use:
shad Auth-Type := Accept, User-Password == "test"

Which parameter is used for authentication in LDAP

In case of LDAP authenticaion, what are the parameters that are generally used for authentication. I guess using DN would be a headache for users logging in via ldap because it is too large to remember.
How is the option of using uid or sAMAccountName for authentication where in my implementation, I retrieve the dn of the corresponding uid or sAMAccountName and proceed to authentication.
Am I going the right track?
In LDAP, a connection or session can be authenticated. When an LDAP client makes a new connection to an LDAP directory server, the connection has an authorization state of anonymous. The LDAP client can request that the authorization state be changed by using the BIND request.
A BIND request has two forms: simple and SASL. Simple uses a distinguished name and a password, SASL uses one of a choice of mechanisms, for example, PLAIN, LOGIN, CRAM-MD5, DIGEST-MD5, GSSAPI, and EXTERNAL - all of which except for GSSAPI and EXTERNAL are too weak to use in production scenarios or mission-critical areas.
To Use the simple BIND, construct a BIND request and transmit it to the LDAP directory server. The LDAP directory server will respond with a BIND response in which is contained a result code. The result code is an integer, anything other zero indicates that the BIND request failed. If the result code is zero, the BIND request succeeded and the session authorization state has been changed to that of the distinguished name used in the BIND request.
Each subsequent BIND request on the same connection/session causes the authorization state to be set to anonymous and each successive successful BIND request on the same connection/session causes the authorization state to be set to the authorization state associated with the authentication ID, which is the distinguished name in the case of the simple BIND, but might be something else entirely where SASL is used - modern professional quality servers can map the incoming names to different DNs.
Whichever language is used, construct a BIND request, transmit it to the server, and interpret the response.
Update:
If the distinguished name is not known, or is too cumbersome (often the case with web application users who don't know how they are authenticated and would not care if they did know), the LDAP application should search the directory for the user. A successful search response always contains the distinguished name, which is then used in a simple BIND.
The search contains at a minimum, the following:
base object: a distinguished name superior to the user, for example, dc=example,dc=com
a scope: base level, one level below base, or subtree below base. For example, if users are located subordinate to ou=people,dc=example,dc=com, use base object ou=people,dc=example,dc=com and a scope of one-level. These search parameters find entries like: uid=user1,ou=people,dc=example,dc=com
a filter: narrows down the possible search results returned to the client, for example (objectClass=inetOrgPerson)
a list of requested attributes: the attributes from an entry to return to the client. In this case, use 1.1, which means no attributes and returns on the DN (distinguished name), which is all that is required for the simple BIND.
see also
the links in the about section here
LDAP servers only understand LDAP queries; they don't have "usernames" like you and I are used to.
For LDAP, to authenticate someone, you need to send a distinguished name of that person's (or entity's) entry in LDAP; along with their password.
Since you mentioned sAMAccountName I am assuming you are working with Active Directory. Active Directory allows anonymous binds - this means you can connect to it without providing any credentials; but cannot do any lookups without providing credentials.
If you are using python-ldap and Cython (and not IronPython which has access to the various .NET APIs that make this process very easy); then you follow these steps.
Typically you use a pre-set user that has appropriate rights to the tree, and connect to the directory with that user first, and then use that user's access for the rest of the authentication process; which generally goes like this:
Connect to AD with the pre-set user.
Query active directory with the pre-set user's credentials and search for the distinguished name based on the sAMAccountName that the user will enter as their "username" in your form.
Attempt to connect again to Active Directory using the distinguished name from step 2, and the password that the user entered in their form.
If this connection is successful, then the user is authenticated.
So you need two main things:
The login attribute (this is the "username" that LDAP understands)
A LDAP query that fetches information for your users
Following is some rough code that can do this for you:
AD_USER = 'your super user'
AD_PASSWORD = 'your super user password'
AD_BIND_ATTR = 'userPrincipalName' # this is the "login" for AD
AD_URL = "ldap://your-ad-server"
AD_DN = "DC=DOMAIN,DC=COM"
AD_LOGIN_ATTR = 'sAMAccountName' # this is what you user will enter in the form
# as their "login" name,
# this is what they use to login to Windows
# A listing of attributes you want to fetch for the user
AD_ATTR_SEARCH = ['cn',
'userPrincipalName',
'distinguishedName',
'mail',
'telephoneNumber','sAMAccountName']
def _getbinduser(user):
""" This method returns the bind user string for the user"""
user_dn = AD_DN
login_attr = '(%s=%s)' % (AD_LOGIN_ATTR,user)
attr_search = AD_ATTR_SEARCH
conn = ldap.initialize(AD_URL)
conn.set_option(ldap.OPT_REFERRALS,0)
conn.set_option(ldap.OPT_PROTOCOL_VERSION,3)
try:
conn.bind(AD_USER,AD_PASSWORD)
conn.result()
except:
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
# Exit the script and print an error telling what happened.
sys.exit("LDAP Error (Bind Super User)\n ->%s" % exceptionValue)
try:
result = conn.search_s(user_dn,
ldap.SCOPE_SUBTREE,
login_attr, attr_search)
except:
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
# Exit the script and print an error telling what happened.
sys.exit("LDAP Error (Search)\n ->%s" % exceptionValue)
# Return the user's entry from AD, which includes
# their 'distinguished name'
# we use this to authenticate the credentials the
# user has entered in the form
return result[0][1]
def authenticate(user,password):
bind_attr = AD_BIND_ATTR
user_dn = AD_DN
login_attr = '(%s=%s)' % (AD_LOGIN_ATTR,user)
data = _getbinduser(user)
if len(data) == 1:
return None
# Information we want to return from the directory
# for each user, season to taste.
info = {}
info['name'] = data['cn'][0]
info['email'] = data['mail'][0]
try:
info['phone'] = data['telephoneNumber'][0]
except KeyError:
info['phone'] = 'Not Available'
conn = ldap.initialize(Config.AD_URL)
conn.set_option(ldap.OPT_REFERRALS,0)
conn.set_option(ldap.OPT_PROTOCOL_VERSION,3)
try:
# Now we have the "bind attribute" (LDAP username) for our user
# we try and connect to see if LDAP will authenticate
conn.bind(data[bind_attr][0],password)
conn.search(user_dn,ldap.SCOPE_SUBTREE,login_attr,None)
conn.result()
return info
except (ldap.INVALID_CREDENTIALS,ldap.OPERATIONS_ERROR):
return None
One small expansion on Terry's excellent comment. If you store all your users in the same part of the DIT, and use the same attribute to identify them, you can programmatically construct the DN, rather than searching for it.