How to change Windows ACL 'Group' with Powershell? - wcf

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.

Related

Keycloak cannot propagate user-group mappings from LDAP into user-group mappings

I am trying to setup User Federation from a LDAP server to Keycloak. I managed to import all the users and groups respectively from LDAP server, however, the user-group (group tab in Users section) doesn’t show the actual mapped groups, although I can see those users presenting in the groups listed in Members tab in Groups section…
I went through all article in Keycloak forum/Jira ticket/Mail list and I did find a ticket describing the exact issue that I am experiencing now (https://lists.jboss.org/pipermail/keycloak-user/2018-February/013076.html) and Marek has also replied to that as well, however, I still couldn't figure out what configuration I set incorrectly just by the information provided in the post.
Could anyone please help me out? Thanks ahead!
User-Group
Group
User Configuration
Group Mapper Configuration
Thanks,
Chance
Looks like the issue was in LDAP server. The problem only exists when I import the users from FreeIPA DB. However, when I try to federate to an AD server, the user-group information just comes along with the users without any additional modification!
Below is the configuration I have used in the successful case. Hopefully it will help others who encounter with a similar issue. Thanks everyone for the attention.
[User Federation Provider Settings]
Enabled: ON (Default)
Console Display Name :
Priority: 0 (Default)
Import Users : ON (Default)
Edit Mode : READ_ONLY
Sync Registrations : OFF (Default)
Vendor : Active Directory (This is important. Once I switch to AD, instead of FreeIPA, the issue is gone)
Username LDAP attribute: sAMAccountName
RDN LDAP attribute : cn
UUID LDAP attribute : objectGUID
User Object Classes : person, organizationalPerson, user (You should check what Object Class the server is currently configured and adjust accordingly)
Connection URL : ldap://:389 (If you are using ldaps, the port is 636)
Users DN : <the scope includes all your users you would like to import, e.g. OU=User,DC=example,DC=com)
Bind Type: simple
Enable StartTLS: OFF (Default)
Bind DN:
Bind Credential:
Custom User LDAP Filter: <You can leave it blank if you don't want to filter. However, if you would like to filter something, for example, users from a specific group, you can run a filter such as (&(objectClass=user)(memberof:1.2.840.113556.1.4.1941:=CN=,OU=,DC=example,DC=com)) >
Search Scope: Subtree (It the users after under one level of Users DN, you can choose "One level" option)
Validate Password Policy: OFF (Default)
Trust Email: OFF (Default)
Use Truststore SPI: Only for ldaps
Connection Pooling: On
The rest of setting leave it blank.
You need to configure a group-ldap-mapper as well
[Group Mapper]
Name:
Mapper Type: group-ldap-mapper
LDAP Groups DN : <Where are the groups of this tree saved. For example, OU=Group,DC=example,DC=com>
Group Name LDAP Attribute : cn
Group Object Classes : group
Preserve Group Inheritance: ON
Ignore Missing Groups: OFF (Default)
Membership LDAP Attribute : member
Membership Attribute Type: DN
Membership User LDAP Attribute: sAMAccountName
LDAP Filter : <You can leave it blank if you don't want to filter any group>
Mode: READ_ONLY
User Groups Retrieve Strategy: LOAD_GROUPS_BY_MEMBER_ATTRIBUTE
Member-Of LDAP Attribute: memberOf
Mapped Group Attributes:
Drop non-existing groups during sync: ON

How to enable Streamset Mutitenancy using LDAP Authentication

I am using Streamset Data Collector version 3.19.1, currently am trying to integrate Streamset with LDAP server for authentication, I am successful with the integration however we are facing difficulties in configuring the roles and groups like the way it is in File based.
i.e in file based you have three things to configure a)user b)role c) group
<user name>: MD5:<md5-text>, user, <role> [, <additional role>, <additional role>...] [, group:<group>, group:<additional group>...]
if you look at above syntax, there is user name which can be user defined, then there is user which is fixed value, then we have role it can be one of (Admin,Manager,Creator and guest) and last we have group which us again user defined this can be used for Multitenancy.
however now comparing to LDAP configuration provided by streamset we have only following attributes to configure.
<ldap group>:<SDC role>,<additional SDC role>,<additional SDC role>);<ldap group>:<SDC role>,<additional SDC role>...
from above syntax we can see can be configured which is user defined and SDC role which can be one of the following(Admin,Manager,Creator and guest) with this the configuration will look like
DEV:creator;OPS:manager;
how can I configure LDAP rule mapping for group and role, currently i can only map for role in LDAP, requesting anyone to help here, i tried all my best to resolve unfortunately couldnt find any solution.
You can use the same configuration for groups as well. Following from my environment.
http.authentication.ldap.role.mapping=operators:admin;
To get the groups ldap-login-conf needs to be configured like following:-
roleBaseDn="OU=operations,OU=test_groups,OU=groups,OU=sdc,DC=example,DC=COM"
roleNameAttribute="cn"
roleMemberAttribute="member"
roleObjectClass="group"
roleFilter="member={dn}";

Netscape LDAP API to get the Maxpagesize from Microsoft AD

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.

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.

data realted access in authenciation

I am build a web application,and there are some operations is protected for identified people.
I use the sping security for access control,however I have no idea how to control them when deep to the data level.
For exmaple,there are two operation list and edit operation.
Both the administrator of the company and the administrator of one department can access these operations,but the data they can 'list' or 'edit' are not the same.
administrator of the company can get access to all the data of the company while administrator of one department can only get access to the data of his/her department.
So I wonder what is the best practice to implement these requirements?
Most easy method - use PostFilter annotation on service layer.
#Transactional(readonly=true)
#PostFilter("hasPermission(filterObject, 'edit')")
List<DepartamentData> getDepartamenData();
#Transactional
#PreAuthorize("hasPermission(#data, 'edit')")
List<DepartamentData> editDepartamenData(DepartamentData data);
Or another example:
#Transactional(readonly=true)
#PostFilter(
" hasRole('company_admin')" +
"|| (hasRole('departament_admin') && filterObject.departament.equals(principal.departament))")
List<DepartamentData> getDepartamenData();