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

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

Related

/users/{userId}/onlineMeetings - create meeting with application token

I have a proxy application that would create for every user365 the onlinemeeting,
So I have read this:
documentation update in march
and it seems that for each user in azure, I have to run a powershell command to allow my application to generate a meeting.
in the example there is this policy with 3 parameter (in the doc explain two parameter) so I'm so confuse:
New-CsApplicationAccessPolicy -Identity Test-policy -AppIds "ddb80e06-92f3-4978-bc22-a0eee85e6a9e", "ccb80e06-92f3-4978-bc22-a0eee85e6a9e", "bbb80e06-92f3-4978-bc22-a0eee85e6a9e" -Description "description here"
It seems that a policy needs to be created first....
And then the policy has to be associated with each user... one at a time....
Isn't there something global for all users?
Let me explain better: once the application type permissions are activated on
OnlineMeetings.Read.All OnlineMeetings.ReadWrite.All
why do I need to do anything else?
In other API (like create calendar event for example here) the policy rule is not necessary... but is necessary only the permission API
I have solve:
There are a -Global parameter that When you use this cmdlet without specifying a user identity, the policy applies to all users in your tenant, except any that have an explicit policy assignment. To skip a warning when you do this operation, specify this parameter.
Grant-CsApplicationAccessPolicy -PolicyName "ASimplePolicy" -Global

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.

Store user passwords in plain text in OpenLDAP server

I am using OpenLDAP provided in osixia/openldap docker image (https://github.com/osixia/docker-openldap) but it is storing all passwords hashed.
Normally it will be desirable but I am planning to hash passwords on front end (with salting and MD5) so no person in the organization never gets to see the users passwords, but when I try saving them they are hash again, I have not find a way to prevent this behavior.
I try deleting (using user cn=admin,cn=config) an entry that comes with the image called cn={4}ppolicy,cn=schema,cn=config which I think may be the culprit but ldapdelete returns Server is unwilling to perform (53).
Any help is deeply appreciated.
If you store the password in plain text you can retrieve them in plain text.
You just need to check in the ACL that the user you use to read them have the correct rights to do it.
The password policy entry you are talking about is just a schema definition which allows you to define a password policy but does not enforce anything. (The 53 error is because you can't remove a schema from a running OpenLDAP to prevent removing a schema which could be used by an entry)
According to what I can see in github about the docker image you use, the ACL used is :
olcAccess: to attrs=userPassword,shadowLastChange
by self write
by dn="cn=admin,{{ LDAP_BASE_DN }}" write
by anonymous auth
by * none
Which means that only the user himself or the admin account can read the password field userPassword
It is this ACL that you need to modify to suit your needs. The ACL should be located here :
dn: olcDatabase={1}{{ LDAP_BACKEND }},cn=config

How to delete assets/participants using REST API on Hyperledger Composer?

I have deployed my business network using composer-rest-server and am able to call the API using postman.
For now I have hard coded ID's for participants/assets, so I cannot make another POST call as objects with the ID already exist.
Where can I delete the existing participants/assets? On composer playground there was a delete button on the testing page that provided this functionality.
If you are using POSTMAN, you can use the DELETE request to remove your test data.
Using the Trade sample from the Composer tutorials, you would use the following curl command to remove the Commodity COAL:
curl -X DELETE --header 'Accept: application/json' 'http://localhost:3000/api/Commodity/COAL'
If you want to remove all the data in you Business Network, you could investigate the composer network reset command. (described here in the Composer docs.)
using javascript composer-client you can do the following:
const { BusinessNetworkConnection } = require('composer-client');
const participantRegistry = await BusinessNetworkConnection.getParticipantRegistry(registry name space, type);
await participantRegistry.remove(registry name space#participantId);
const assetRegistry = await BusinessNetworkConnection.getAssetRegistry(registry name space);
await assetRegistry.remove(registry name space#asset id);
or even you can perform more
await assetRegistry.removeAll(registry name space);
however before deleting participant from registry you should revoke the bounded identity to it by doing the following:
const IdentityRevoke = require('composer-cli').Identity.Revoke;
let options = {
card: 'admin#tutorial-network',
identityId: 'f1c5b9fe136d7f2d31b927e0dcb745499aa039b201f83fe34e243f36e1984862'
};
IdentityRevoke.handler(options);
you can find more information in the documentation about revoking identity in the following link
Since you have deployed the API, use its Swagger interface to look at what you can do. It is a RESTful api which means each endpoint accepts the HTTP verbs that make sense for it.
Each asset and participant endpoint, for example, accepts DELETE requests where all you have to do is pass the ID of the entity you want to delete.
You can issue POST requests to create new data and PUT requests to update the data.
One thing to be aware of is that each request will create a new block on the ledger. DELETE doesn't mean the previous block disappears, it simply means it's in a deleted state and your block count keeps increasing for each transaction you issue.
If you want to run tests and make sure your assets get created properly then you can start using the feature files, there is a sample feature to get you started. It uses a specific composer cucumber package, you can see that if you look inside the package.json. This would be the preferred method to run tests, as this isn't a normal environment where you create test data and then delete it, you have to be careful as your block count will keep increasing.

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

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.

Resources