someone knows how can I delete a group from LDAP using java? and how is the best way to verify is this group is empty?
Thanks,
LDAP operations maps to JNDI api. According to the specification available here: http://docs.oracle.com/javase/tutorial/jndi/ldap/operations.html, you can use following method:
void destroySubcontext(String name) throws NamingException
Which should destroy the named context and remove it from the namespace.
Quote from the documentation below:
"This method is idempotent. It succeeds even if the terminal atomic name is not bound in the target context, but throws NameNotFoundException if any of the intermediate contexts do not exist.
In a federated naming system, a context from one naming system may be bound to a name in another. One can subsequently look up and perform operations on the foreign context using a composite name. However, an attempt destroy the context using this composite name will fail with NotContextException, because the foreign context is not a "subcontext" of the context in which it is bound. Instead, use unbind() to remove the binding of the foreign context. Destroying the foreign context requires that the destroySubcontext() be performed on a context from the foreign context's "native" naming system.
Parameters:
name - the name of the context to be destroyed; may not be empty"
Use the UnboundID LDAP SDK to establish a connection to the server, then create a delete request specifying the DN of the group to delete. Transmit the delete request to the server and interpret the response.
DeleteRequest deleteRequest =
new DeleteRequest("cn=entry to delete,dc=example,dc=com");
try
{
LDAPResult deleteResult = connection.delete(deleteRequest);
System.out.println("The entry was successfully deleted.");
}
catch (LDAPException le)
{
System.err.println("The delete operation failed.");
}
If the LDAP client wishes to "empty" the group, which I take to mean "delete all attributes in the entry, LDIF can be constructed to remove all values of an attribute:
##
## assume 'member' is the attribute that whose values are members:
##
dn: cn=group1,ou=group,dc=example,dc=com
changetype: modify
replace: member
'Replace' with no value deletes all values of the member attribute whether any values exist or not. 'Delete' with no value deletes all values, but there must be at least one to delete.
Generally speaking, if there is choice, the UnboundID LDAP SDK should used instead of JNDI.
see also
LDAP: Mastering Search Filters
LDAP: Search best practices
LDAP: Programming practices
Related
I am very new to Springboot and Spring Data JPA and working on a use case where I am required to create users in different databases.
The application will receive 2 inputs from a queue - username and database name.
Using this I have to provision the given user in the given database.
I am unable to understand the project architecture.
Since the query I need to run will be of the format - create user ABC identified by password;
How should the project look like in terms of model class, repositories etc? Since I do not have an actual table against which the query will be run, do I need a model class since there will be no column mappings happening as such.
TLDR - Help in architecturing Springboot-Spring Data JPA application configured with multiple data sources to run queries of the format : create user identified by password
I have been using this GitHub repo for reference - https://github.com/jahe/spring-boot-multiple-datasources/blob/master/src/main/java/com/foobar
I'll be making some assumptions here:
your database of choice is Oracle, based on provided syntax: create user ABC identified by password
you want to create and list users
your databases are well-known and defined in JNDI
I can't just provide code unfortunately as setting it up would take me some work, but I can give you the gist of it.
Method 1: using JPA
first, create a User entity and a corresponding UserRepository. Bind the entity to the all_users table. The primary key will probably be either the USERNAME or the USER_ID column... but it doesn't really matter as you won't be doing any insert into that table.
to create and a user, add a dedicated method to your own UserRepository specifying the user creation query within a #NativeQuery annotation. It should work out-of-the-box.
to list users you shouldn't need to do anything, as your entity at this point is already bound to the correct table. Just call the appropriate (and already existing) method in your repository.
The above in theory covers the creation and listing of users in a given database using JPA.
If you have a limited number of databases (and therefore a limited number of well-known JNDI datasources) at this point you can proceed as shown in the GitHub example you referenced, by providing different #Configuration classes for each different DataSource, each with the related (identical) repository living in a separate package.
You will of course have to add some logic that will allow you to appropriately select the JpaRepository to use for the operations.
This will lead to some code duplication and works well only if the needs remain very simple over time. That is: it works if all your "microservice" will ever have to do is this create/list (and maybe delete) of users and the number of datasources remains small over time, as each new datasource will require you to add new classes, recompile and redeploy the microservice.
Alternatively, try with the approach proposed here:
https://www.endpoint.com/blog/2016/11/16/connect-multiple-jpa-repositories-using
Personally however I would throw JPA out of the window completely as it's anything but easy to dynamically configure arbitrary DataSource objects and reconfigure the repositories to work each time against a different DataSource and the above solution will force you to constant maintenance over such a simple application.
What I would do would be sticking with NamedParameterJdbcTemplate initialising it by using JndiTemplate. Example:
void createUser(String username, String password, String database) {
DataSource ds = (new JndiTemplate()).lookup(database);
NamedParameterJdbcTemplate npjt = new NamedParameterJdbcTemplate();
Map<String, Object> params = new HashMap<>();
params.put("USERNAME", username);
params.put("PASSWORD", password);
npjt.execute('create user :USERNAME identified by :PASSWORD', params);
}
List<Map<String, Object>> listUsers() {
DataSource ds = (new JndiTemplate()).lookup(database);
NamedParameterJdbcTemplate npjt = new NamedParameterJdbcTemplate();
return npjt.queryForList("select * from all_users", new HashMap<>());
}
Provided that your container has the JNDI datasources already defined, the above code should cover both the creation of a user and the listing of users. No need to define entities or repositories or anything else. You don't even have to define your datasources in a spring #Configuration. The above code (which you will have to test) is really all you need so you could wire it in a #Controller and be done with it.
If you don't use JNDI it's no problem either: you can use HikariCP to define your datasources, providing the additional arguments as parameters.
This solution will work no matter how many different datasources you have and won't need redeployment unless you really have to work on its features. Plus, it doesn't need the developer to know JPA and it doesn't need to spread the configuration all over the place.
I have tried to use OACC framework
createResource("USER", "domain1","kim")
USER : resourceClass
domain1 : domain
kim : value to be stored (externalId)
Sorry if arguments order are mismatched
again I have called for :
createResource("USER", "domain2","kim")
in this case, the system conflicts to store the same name , logically yes, externalId can't be same.
But how can we store the real values into this, a normal Resource instantiate will result in its own ID.
Is there any api to "getRoles" if I pass in a UserName ?
A multi-tenant application will have (users/roles/permission) per domain, 1 user can exist in multiple domains !!
But how can we store the real values into this, a normal Resource instantiate will result in its own ID.
As you noticed, the createResource() method can accept a String externalId parameter, which has to be a globally unique string identifier for the new resource. "Globally unique" here means unique across all domains and resource classes.
The externalId is useful to reference OACC resources by an identifier from your application domain, without having to use or store the unique resourceId OACC generates and returns from createResource().
One way to use non-unique application domain identifiers as external IDs would be to prefix identifiers with an appropriate classifier to make them unique within OACC. Such a prefix could simply be composed of the resource class, domain, or both. To use your example:
createResource("USER", "domain1", "user.domain1.kim");
createResource("USER", "domain2", "user.domain2.kim");
Is there any api to "getRoles" if I pass in a UserName ?
In OACC you can model role assignment by having one resource "inherit" all permissions from another resource by granting it the *INHERIT permission. In other words, there is no explicit concept of roles within OACC and hence no dedicated method to "getRoles".
In any case, the best practice for authorizations is to check against permissions, not against role membership.
For auditing or administrative purposes, if you do need to find the resources a specific user inherits permissions from, OACC provides query methods such as getResourcesByResourcePermissions(). If, for example, all your "roles" were modeled as resources of the resource class ROLE, you could find the ones your user inherits with the following call:
getResourcesByResourcePermissions(userResource,
"ROLE",
ResourcePermissions
.getInstance(ResourcePermissions.INHERIT));
I am developing in Java using Spring for my company. We are developing an application that we have a local LDAP server. The LDAP server will be used to fetch information. However, we do not want the user of the application to know the LDAP structure/schema. This is because the customer/user will have their own LDAP server with their own LDAP structure/schema.
For example, the customer/user will fetch information through a user interface by providing the LDAP server details that will be used to conect to the LDAP server. Once connected, they will be able to fetch information by executing a query. Now, they will not know information about the LDAP structure. The code that will be written, will be done by executing the user query. If the query is run, then it will return that information, otherwise it will give an Exception.
The problem that I am facing is that:
When you use Spring LDAP, there is something called AttributesMapper and ContextMapper. In order to use this, I have to pass in a strongly typed object. So for example:
public class EmployeeAttributesMapper implements AttributesMapper {
public EmployeeAttributesMapper() {
}
/**
* This method maps the Employee Entity to data stored in the LDAP Server through a Attribute.
* #param attrs the name of the Attribute to get
* #return the Employee Entity.
*/
public Object mapFromAttributes(Attributes attrs) throws NamingException {
Employee employee = new Employee();
employee.setFirstName((String) attrs.get("cn").get());
return employee;
}
}
The above code when executed depending on the query, will fetch information only about the cn attribute and nothing else. Is there something else that doesn't require an strongly typed object?
I am not sure what to do.
For example, to search for all employees:
public List getAllEmployees() {
return ldapTemplate.search("", "(objectclass=person)", new EmployeeContextMapper());
}
This will return all the employees but only set the cn attributes. But, on the customer LDAP server they may not have the attribute called cn.
What is the best way to do this? Our code that we write, acts as a proxy between the user interface and the customer LDAP server.
The simplest answer is to abstract the intended use of attributes to the attribute type, which is an OID or an alias. For example, map "Name" to the cn (common name) attribute alias, "First Name" to the givenName attribute, "Last Name" to the sn attribute, and so forth. IETF has many RFCs which describe attributes that have been recommended for use with LDAP directory server databases. inetOrgPerson (RFC2798) is a good example.
If the presentation is separated from the implementation correctly, users need never know that the data comes from an LDAP directory server at all, not to mention what the attribute names are.
In a JPA app I have a scenario in which the app is to
list all accounts the given user is authorized to withdraw from
I have the Account entity and a many-to-many table that lists what authorizations each user has on each account – to implement the above scenario, the app currently just inner-joins the two tables – which is quite quick.
Now, I was planning to add an explicit authorization layer (based on apache shiro / spring security / other) to insulate authorization-related logic from the rest of the code, but...
There are some 10k Accounts in the database and the "average" user is granted "deposit" on all of them, "view" on one half of them and "withraw" on just a few.
Does any security framework allow to implement this scenario efficiently?
Ie: is any of them able to "decorate" a JPA query of the type "select a from Account a" (or the equivalent SQL) and thus get the list of accounts without loading all user grants from the database, and by all means, without having to retrieve all accounts?)
Have a look at Apache Shiro.
It allows you to pull in the User authorization once and cache it for the duration of the session. In addition, if all users can VIEW all ACCOUNTS then you wouldn't need to explicitly define this which would significantly reduce the overhead.
If your solution requires realtime access handlers Shiro has a way to reset the Permissions dynamically during runtime too.
Shiro allows you to implement a typical RBAC and define permissions like this:
domain:action:instance
So in your case permissions might look like this for a user:
account:deposit:* // deposit all accounts
account:view:1111
account:view:2222
account:view:3333 // view on these accounts
account:withdraw:5555
account:withdraw:6666 // withdraw on these accounts
In code you can then do something like this:
if (SecurityUtils.getSubject().isPermitted("account:withdraw:"+account.getAccountNumber() ) {
// handle withdraw
}
Shiro also has annotation driven permissions for additional abstraction.
EDIT
The Shiro permissions is the end result, not where you start. I used a set of tables representing mappings of the user-to-role and role-to-permission along with other mappings to instance. After AuthN its usually a simple set of queries indexed by the User PK to build up the data structures needed to render the permissions.
I have a hope that this is one of the possibilities to implement your requirement with Spring-Security.
Write custom org.springframework.security.acls.Permission like
ViewAccount,DepositToAccount,WithDrawFromAccount
Write custom
org.springframework.security.access.PermissionEvaluator Override
hasPermission(Authentication userAuthentication,Object
accountObject,Object oneOfThePermission) to check if the user has
the defined permission on the accountObject
Get reference to JPA
EntityManager in your custom evaluator and cross check/verify in DB
with user_id,permission_id,account_id
If the user is 'root' you can
staight away return true for hasPermission without verifying with
DB.
Annotate your service calls with
#PreAuthorize("isAuthenticated() and hasPermission(#accountArgument,
'respectivePermission')")
Refer link for custom implementations of Permission & PermissionEvaluator
If you are using EclipseLink there are a few features for this,
one is the #AdditionalCriteria annotation that allow a filter to be applied to all queries for a class,
http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_additionalcriteria.htm#additionalcriteria
another is EclipseLink's support for Oracle VPD (row level security in the database),
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Auditing
and finally EclipseLink supports SessionEvents that can allow filter to be appended to any query execution,
http://www.eclipse.org/eclipselink/api/2.4/org/eclipse/persistence/sessions/SessionEventAdapter.html#preExecuteQuery%28org.eclipse.persistence.sessions.SessionEvent%29
Why am I receiving the exception below if the type of both entities is PersistentLogin? I thought that would mean they are in the same entity group, but I guess that is an incorrect assumption. Any ideas how to fix this?
This is the code:
// the class is marked with #Transactional
#Override
public final void removeUserTokens(final String username) {
final Query query = entityManager.createQuery(
"SELECT p FROM PersistentLogin p WHERE username = :username");
query.setParameter("username", username);
for (Object token : query.getResultList()) {
entityManager.remove(token);
}
}
This is the exception:
Caused by: javax.persistence.PersistenceException: Illegal argument
at org.datanucleus.jpa.NucleusJPAHelper.getJPAExceptionForNucleusException(NucleusJPAHelper.java:260)
at org.datanucleus.jpa.EntityTransactionImpl.commit(EntityTransactionImpl.java:122)
at org.datanucleus.store.appengine.jpa.DatastoreEntityTransactionImpl.commit(DatastoreEntityTransactionImpl.java:50)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
... 42 more
Caused by: java.lang.IllegalArgumentException: can't operate on multiple entity groups in a single transaction. found both Element {
type: "PersistentLogin"
name: "1WfCYx8bmwUGkjzP2PpmFA=="
}
and Element {
type: "PersistentLogin"
name: "SfI0P8RVBjTvu0WHMSuaVA=="
}
Same entity group means that the entities have a common parent entity.
Two top-level entities are never in the same entity group.
Any ideas how to fix this?
The easiest way is to relax the transaction requirements. In your case that would mean deleting the PersistentLogin entities one by one (best effort loop, delete as much as you can, retry on errors, no guarantee of atomicity).
If you wanted to put the PersistentLogin for the same user in the same entity group, you would need to make rather big changes to your data model, with uncertain impact on overall performance.
With non-relational databases, you have to code your application without relying on transactions on the data store. They just do not support them to the extent that we have become used to.
First, read carefully the following docs, especially the section "Using Cross-Group Transactions"
http://code.google.com/appengine/docs/java/datastore/transactions.html
Information on what a cross-group transaction is:
http://code.google.com/appengine/docs/java/datastore/overview.html#Cross_Group_Transactions
Note: You can run a transaction over at most 5 different groups!
For your production appengine, you must enable "High Replication Datastore" in your appengine dashboard and you must enable "Cross-group (XG) transactions" in your source code, jdoconfig.xml, or persistence.xml
For your development appengine server, you must ensure that you simulate high-replication datastore. This is described here
Note: if you launch appengine dev server commandline, do not forget to add the high replication datastore option:
~/appengine-java-sdk-1.6.2.1/bin/dev_appserver.sh
--jvm_flag=-Ddatastore.default_high_rep_job_policy_unapplied_job_pct=20
--address=0.0.0.0 --port=8888 --disable_update_check .
We struggled some time with this while developing the Rogerthat Platform (code worked in production and in Eclipse, but not when dev_appserver.sh is executed commandline) so we thought it was worth sharing.