Accessing nested LDAP roles in Oracle Internet Directory (OID) within Grails and SpringSecurity - grails

In our LDAP directory, we have users, who are mapped to groups. Those groups may be mapped to other groups. For example:
cn=group1,cn=groups,dc=example,dc=com
uniquemember cn=user1,cn=user,dc=example,dc=com
cn=group2,cn=groups,dc=example,dc=com
uniquemember cn=user2,cn=user,dc=example,dc=com
uniquemember cn=group1,cn=user,dc=example,dc=com
So User1 belongs to Group1, but User2 belongs to Group2, which in turn belongs to Group1
Within Grails, User1 has authority to Group1, but User2 only has authority to Group2. From what I've seen, there is no way to cause it to recursively look at the tree. Realistically, I probably only need a 2 level hierarchy, but even that doesn't seem to work.
I'm attempting to work through the Custom UserDetailsContextManager to see if I can iterate over the initial results and re-query LDAP by group, but I thought I'd see if there was an easier/better way.

You probably already saw this, but this is from the documentation:
// If you don't want to support group membership recursion (groups in groups), then use the following setting
// grails.plugins.springsecurity.ldap.authorities.groupSearchFilter = 'member={0}' // Active Directory specific
// If you wish to support groups with group as members (recursive groups), use the following
grails.plugins.springsecurity.ldap.authorities.groupSearchFilter = '(member:1.2.840.113556.1.4.1941:={0})' // Active Directory specific
http://grails-plugins.github.com/grails-spring-security-ldap/docs/manual/guide/2.%20Usage.html

Oracle OID has a product-specific extension for traversing the hierarchy, known as CONNECT_BY, which has LDAP OID 2.16.840.1.113894.1.8.3 . You can add this as a request control to ask the server to connect/follow hierarchies according to an attribute you specify. This can be done using both a Java LDAP client program, or using something like OpenLDAP ldapsearch, although the set-up is a little tricky.
If you want to use Java to follow the hierarchy, this page contains a sample program which shows how to setup the required javax.naming.ldap.Control implementation class, in this case named ConnectByControl.
You can also perform this sort of hierarchical search using ldapsearch, but it requires some preparation and implied understanding of the required control value, as the value is concatenated then base64-encoded. The value is in two-parts - the follow-me depth (0=unlimited), followed by the connect-by attribute name (in this case, uniquemember is the desired name). Set the baseDN in your query to the entry where you want to start the hierarchical search.
ldapsearch -H ldap://myoidserver.mycompany.com:389 -e 2.16.840.1.113894.1.8.3=MBECAQAEDHVuaXF1ZW1lbWJlcg== -b cn=some_group_containing_groups_nested_by_uniquemember,cn=some_groups,dc=mycompany,dc=com "(objectClass=*)" dn uniquemember
The -e 2.16.840.1.113894.1.8.3= adds the CONNECT_BY request control. The value, MBECAQAEDHVuaXF1ZW1lbWJlcg==, is ASN.1 BER-encoded then base64-encoded value 0uniquemember, for the depth and attribute-name mentioned above. This will print first the dn for cn=some_group_containing_groups_nested_by_uniquemember,... and its direct (user) uniquemembers, then each uniquemember will be "connected" or followed. If that entry itself has a set of uniquemember, i.e. it is a nested group, the process will continue until leaf/user entries are reached that have no nested uniquemembers.

Related

Can I remove the unique constrain for error "Asset/Device with such name already exists."

We are using open source Thingsboard for our IOT platform. One project has 100K devices/assets, and we have a tree structure for the assets/devices for example state -> county -> city, etc. Each county, we have an administrator who is responsible for asset/device creation. Frequently they use the same name for asset or device. Currently, Thingsboard doesn't allow duplicated name for asset/device. If we use the same name, we will get error messages
Asset with such name already exists
or
Device with such name already exists
We are thinking to remove this unique constrain but not sure if there is any side effect. Thanks.
It is not recommended to remove the unique constraint, but there may be workarounds:
Make the names unique, e.g. by concating the structure in the Tree for unique names (State_County_City_Device) or use the Device ID as name. In the Dashboards you can utilize the Label Field for a friendly-name.
See issue here: https://github.com/thingsboard/thingsboard/issues/4439

How to do User Impersonation in Apache Sling or Jackrabbit Oak?

Or more specifically:
Given I am signed in as the 'admin' user, and I want to to impersonate a user 'testSiteUser'
Given the 'testSiteUser' node (rep:User) does not have a protected String[] property called rep:impersonators set with a value containing admin
How do to update the protected property rep:impersonators such that it contains admin?
Once the user node has this set, I'm confident that setting a cookie sling.sudo should allow user impersonation.
What I have tried so far..
curl -F:name=testSiteUser -Fpwd=testSiteUser
-FpwdConfirm=exampleSiteUser
-F'rep:impersonators'=admin
-F'rep:impersonators'#TypeHint='String[]'
-u admin:admin
http://localhost:8080/system/userManager/user.create.html
Which responds with 500
javax.jcr.nodetype.ConstraintViolationException: Attempt to set an
protected property rep:impersonators
According to the JCR Spec
16.3.12 Interaction with Protected Properties
Many features of JCR expose repository metadata as protected properties defined by mixin node types. For example, locking status is exposed by the properties jcr:lockOwner and jcr:lockIsDeep defined by mix:lockable. Changes to protected properties can only be made indirectly through a feature-specific API (for example, Node.lock), not through a generic write method like Node.setProperty. Such changes are not governed by the jcr:modifyProperties privilege, but rather by the particular feature-specific privilege, for example, jcr:lockManagement (see ยง16.2.3 Standard Privileges).
Perhaps the only way is to write my own Java code as shown below, but I'm pretty sure there should be a REST API to do this...
Authorizable authorizable = userManager.getAuthorizable(user.getId());
Principal admin = userManager.getAuthorizable("admin").getPrincipal();
jackrabbitUser = (User) authorizable;
Impersonation impersonation =jackrabbitUser.getImpersonation();
impersonation.grantImpersonation(admin);
Basically rep:impersonators is a read only property that is managed "indirectly through a feature-specific API" What is the API and procedure to do user impersonations using Apache Sling or Jackrabbit Oak?
I understood your question, that you want to add an impersonator via a REST-call.
As you already found, all security related properties are protected. So they can only be manipulated via API-calls - and not directly written to.
But AEM already has a lot specialized REST-API's for its own user interface. To find them you should first perform the desired action on the normal AEM UI. Then check with the browser network inspector, which http-request was made by the browser.
In your case go to the classic user manager (http://localhost:4502/useradmin).
There you find the curl:
curl 'http://localhost:4502/home/users/J/JfiFIrTqxwUamu2BvWj-' \
-u admin:admin \
-F_charset_=utf-8 \
-FmemberAction=sudoers \
-FmemberEntry=alex
In the example I added for user alex2 the impersonator alex. So alex can impersonate to alex2.
For the user alex you need the repository-path, which is encrypted meanwhile for security reasons. But this path is easy to find with the querybuilder. As example the following query:
http://localhost:4502/bin/querybuilder.json?path=%2fhome%2fusers&property=rep%3aauthorizableId&property.value=alex2&type=rep%3aUser
or via the querybuilder UI http://localhost:4502/libs/cq/search/content/querydebug.html
path=/home/users
type=rep:User
property=rep:authorizableId
property.value=alex2

Jenkins integration with AD

I am working on integrating a new Jenkins instance with AD. I have installed the required plugins. When I try to add a domain, it asks for info such as domain name, domain controller, etc.
I am not fully clear on the BindDN field. If I leave it blank and test the domain, it throws this warning
Leaving blank Bind DN means that any operation performed will use anonymous binding. Keep in mind that this is not recommended as some servers do not allow it by default.
I then provided a user account in BindDN which exists in the domain. Now on testing the domain, it is throwing this error log:
DC_Name:389
java.net.UnknownHostException: DC_Name
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
Pls share some inputs to complete the integration with AD.
There is information provided in the Jenkins wiki page for the AD plugin, as well as some ldap tools to help diagnose.
<DOMAIN_NAME> -> Domain Name: support-cloudbees.com
<searchbase> -> Organization Unit we want to look into.
In the example, it is OU=Support, DC=support-cloudbees, DC=com
<binddn> -> Bind DN.
In the example, CN=felix, OU=Support, DC=support-cloudbees, DC=com
<passwd> -> Bind Password
<userid> -> User we want to look for. We can look for the managerDN itself or for a different user on the tree.
In the example, this can be set-up for example to CN=felix, OU=Support, DC=support-cloudbees, DC=com.
As described here,
The Bind DN is comprised of the user and the location of the user in
the LDAP directory tree. Each element of the Distinguished Name is
pointed out: The first part is the user CN=user1. The second part is
the container CN=Users. The third part is the domain DC=example and
DC=com
Did you correctly specify "the location of the user in the LDAP tree" ? The error appears to be with a DC value.
Ours is in the form:
cn=<Acct Name>, ou=<some_value>, ou=<some_value>, dc=<some_value>, dc=<some_value>
YMMV. Try use the ldap tools mentioned to validate.

Access Control: Database Fortify

We ran the Fortify scan and had some Access Control: Database issues. The code is getting the textbox value and setting it to a string variable. In this case, it's passing the value from the TextBox to the stored procedure in a database. Any ideas on how I can get around this Access Control: Database issue?
Without proper access control, the method ExecuteNonQuery() in DataBase.cs
can execute a SQL statement on line 320 that contains an attacker-controlled primary
key, thereby allowing the attacker to access unauthorized records.
Source: Tool.ascx.cs:591 System.Web.UI.WebControls.TextBox.get_Text()
rptItem.FindControl("lblClmInvalidEntry").Visible = false;
ToolDataAccess.UpdateToolData(strSDN, strSSNum, strRANC, strAdvRecDate, strAdvSubDate, strClmRecDate, strClmAuth, strClmSubDate, strAdvAuth, txtNoteEntry.Text);
Sink: DataBase.cs:278
System.Data.SqlClient.SqlParameterCollection.Add()
// Add parameters
foreach (SqlParameter parameter in parameters)
cmd.Parameters.Add(parameter);
The point of "Access Control: Database" is where it isn't being specific enough in the query and so could potentially allow a user to see information that they're not supposed to.
An easy example of this vulnerability would be a payroll database where there is a textbox that says the ID of the employee and gives their salary, this could potentially allow the user to change the ID and see the salary of other employees.
Another example where this is often intended functionality is in a website URL where the product ID is used in a parameter, meaning a user could go through every product you have on your site. But as this only allows users to see information they're supposed to be able to, it's not particularly a security issue.
For instance:
"SELECT account_balance FROM accounts WHERE account_number = " + $input_from_attacker + ";"
// even if we safely build the query above, preventing change to the query structure,
// the attacker can still send someone else's account number, and read Grandma's balance!
As this is pretty context based, it's difficult to determine statically so there are lots of examples where Fortify may catch this but it's actually intended functionality. That's not to say the tool is broken, it's just one of the limitations of static analysis and depending on what your program is supposed to be doing it may or may not be intended.
If this is intended to work like this, then I would suggest auditing it as not an issue or suppressing the issue.
If you can see that this is definitely an issue and users can see information that they shouldn't be able to, then the stored procedure needs to be more specific so that users can only see information they should be able to. However SCA will likely still pick this up in a latter scan so you would still then need to audit it as fixed and no longer an issue.

Error configuring the requestmap in spring security core for grails

In my system, I have numerous roles assigned to the users (lets assume 3 for now ROLE_ADMIN, ROLE_USER, ROLE_SERVICES). In one of my controllers (lets assume SearchController that we have three actions serviceIndex{}, userIndex{} and adminIndex{}), I want users of any role to be able to access two of the actions (the first two). For the final action, I want to restrict the action against a user of single role type (lets say ROLE_USER) but allow access to users of other roles (i.e. to ROLE_ADMIN, ROLE_SERVICE. I have something like the following in my requestmap table.
config_attribute ----------------------------------------------------------->url
ROLE_ADMIN,ROLE_SERVICE,ROLE_USER ------------------------------> /search/serviceIndex
ROLE_ADMIN,ROLE_SERVICE,ROLE_USER-------------------------------> /search/userIndex
ROLE_ADMIN,ROLE_SERVICE -----------------------------------------> /search/adminIndex
Since the third rule states that the url '/search/adminIndex' is not accessible to ROLE_USER, the user with that role should have been denied the authorization to access the url. But, the user can still access the url. What is the correct configuration. I did try someting like /search/adminIndex/**, but that doesn't work either. On a side note, none of the urls will have suffixes furthermore but I would still like to prevent access if users manipulate the url like adding suffixes like /search/userIndex/56a just in case.
Regards,
dipess
Since the plugin iterates through the rules and applies the first one that matches the current URL, I would set the adminIndex first and then have a catchall for anything else.
ROLE_ADMIN,ROLE_SERVICE /search/adminIndex
ROLE_ADMIN,ROLE_SERVICE,ROLE_USER /search/**

Resources