Problem
I want to see if user "john" is in group "Calltaker". I can't seem to get the syntax right on my search filter to check for a specific user in a specific group. I can list all users in a group to verify the desired user is there.
Questions
What is the right syntax for a ldap search filter to determine if a specific user is in a specific group(in Tivoli Access Manager)?
What should I check on the returned LDAPEntry object given by that search string to see that the user is, or isn't, in the group?
Info
john is defined in "cn=users,dc=ldap,dc=net"
Calltaker is defined in "cn=groups,dc=ldap,dc=net"
I'm querying against TAM's ldap, from java
Using the searchfilter to be "cn=Calltaker" I can print out the search results such that calling nextEntry.toString contains the list of users. See Example 1 below
Here's a few searchfilters I've tried that don't work (aka searchResults.next() throws an error):
(&(objectclass=groupOfUniqueName)(uniquemember=uid="+ username + ",cn=groups,dc=ldap,dc=net))
(&(objectclass=groupOfUniqueName)(uniquemember=uid="+ username + ",cn=users,dc=ldap,dc=net))
(uniquemember=uid="+ username + ",cn=users,dc=ldap,dc=net)
Example 1) only search group, using searchFilter="cn=Calltaker", verify it contains users:
System.out.println(nextEntry.toString()); //added newlines for readability
nextEntry:
LDAPEntry:
cn=Calltaker,cn=groups,dc=ldap,dc=net;
LDAPAttributeSet:
LDAPAttribute: {type='objectclass', values='groupOfUniqueNames','top'}
LDAPAttribute: {type='uniquemember',
values=
'uid=placeholder,cn=users,dc=ldap,dc=net',
'secAuthority=default',
'uid=john,cn=users,dc=ldap,dc=net',
'uid=sally,cn=users,dc=ldap,dc=net', ....etc
Code:
public boolean isUserInGroup(username){
boolean userInGroup = false;
String loginDN = "uid=" + admin_username + "," + "cn=users,dc=ldap,dc=net";
String searchBase = "cn=groups,dc=ldap,dc=net";
int searchScope = LDAPConnection.SCOPE_SUB;
searchFilter = "(&(objectclass=ePerson)(uniquemember=uid="+ username + ",cn=users,dc=ldap,dc=net))";
//Connect
LDAPConnection lc = connect(hosts);
lc.bind(LDAPConnection.LDAP_V3, loginDN, admin_password.getBytes("UTF8"));
lc.getAuthenticationDN();
LDAPSearchResults searchResults = lc.search(searchBase,
searchScope,
searchFilter,
null, // return all attributes
false); // return attrs and values
while (searchResults.hasMore()) {
LDAPEntry nextEntry = null;
try {
nextEntry = searchResults.next();
} catch (LDAPException e) {
// Exception is thrown, go for next entry
if (e.getResultCode() == LDAPException.LDAP_TIMEOUT || e.getResultCode() == LDAPException.CONNECT_ERROR)
break;
else
continue;
}
//TODO some check to verify nextEntry shows the user in the group
userInGroup = true;
LDAPAttributeSet attributeSet = nextEntry.getAttributeSet();
Iterator<LDAPAttribute> allAttributes = attributeSet.iterator();
while (allAttributes.hasNext()) {
LDAPAttribute attribute = (LDAPAttribute) allAttributes.next();
String attributeName = attribute.getName();
System.out.println("found attribute '" + attributeName + "' with value '" + attribute.getStringValue() + "'");
}
}
lc.disconnect();
return userInGroup;
}
** EDIT **
Implemented answer from EJP, changed searchBase to include group
Code that works:
private static final String admin_username = "foo";
private static final String[] hosts = new String[]{"foohost.net"};
public boolean isUserInGroup(String username, String group){
boolean userInGroup = false;
String loginDN = "uid=" + admin_username + "," + "cn=users,dc=ldap,dc=net";
String searchBase = "cn=" + group + "," + "cn=groups,dc=ldap,dc=net";
int searchScope = LDAPConnection.SCOPE_SUB;
searchFilter = "(&(objectclass=groupOfUniqueNames)(uniquemember=uid="+ username + ",cn=users,dc=ldap,dc=net))";
//Connect
LDAPConnection lc = connect(hosts);
lc.bind(LDAPConnection.LDAP_V3, loginDN, admin_password.getBytes("UTF8"));
lc.getAuthenticationDN();
LDAPSearchResults searchResults = lc.search(searchBase,
searchScope,
searchFilter,
null, // return all attributes
false); // return attrs and values
while (searchResults.hasMore()) {
LDAPEntry nextEntry = null;
try {
nextEntry = searchResults.next();
} catch (LDAPException e) {
// Exception is thrown, go for next entry
if (e.getResultCode() == LDAPException.LDAP_TIMEOUT || e.getResultCode() == LDAPException.CONNECT_ERROR)
break;
else
continue;
}
//A result was found, therefore the user is in the group
userInGroup = true;
}
lc.disconnect();
return userInGroup;
}
What is the right syntax for a ldap search filter to determine if a specific user is in a specific group(in Tivoli Access Manager)?
Either of the filters you used, but the objectClass to search on is groupofUniqueNames (plural).
What should I check on the returned LDAPEntry object given by that search string to see that the user is, or isn't, in the group?
Nothing. He will be, otherwise the group won't be returned in the search. All you need to do is check that the search result is non-empty.
Here's a few searchfilters I've tried that don't work (aka searchResults.next() throws an error):
Throws what error?
(&(objectclass=groupOfUniqueName)(uniquemember=uid="+ username + ",cn=groups,dc=ldap,dc=net))
Nothing wrong with this except for groupOfUniqueName. You should use search filter arguments like {0} rather than building them into the search string.
(&(objectclass=groupOfUniqueName)(uniquemember=uid="+ username + ",cn=users,dc=ldap,dc=net))
This one will search the cn=users subtree for a group. It won't work unless you have groups under cn=users, which doesn't seem likely.
(uniquemember=uid="+ username + ",cn=users,dc=ldap,dc=net)
This will select non-groups. You don't want that: you need the objectClass part.
Related
I have a String SELECT *FROM USERS WHERE ID = '#userid#' AND ROLE = '#role#'
Now i have replace any string between #...# , with a actual value .
Expected output SELECT *FROM USERS WHERE ID = '4' AND ROLE = 'Admin'
This replace will happen from a method , i have written this logic
public String replaceQueryKeyWithValueFromKeyValues(String query, int reportId) {
try {
REPMReportDao repmReportDao = new REPMReportDao();
int Start = 0;
int end;
if (query.contains("#")) {
boolean specialSymbolFound = false;
for (int i = 0; i < query.length(); i++) {
if (query.charAt(i) == '#') {
if (!specialSymbolFound) {
Start = i + 1;
specialSymbolFound = true;
} else {
specialSymbolFound = false;
end = i;
query = query.replace(query.substring(Start - 1, end + 1), repmReportDao.getReportManagerKeyValue(query.substring(Start - 1, end + 1).replaceAll("#", ""), reportId));
}
}
}
return query;
} else {
return query;
}
} catch (Exception e) {
logger.log(Priority.ERROR, e.getMessage());
return e.getMessage();
}
}
It works fine , but in the case if a single '#' symbol exist instead of start and end it will fail.
Like :
SELECT *FROM USERS WHERE emailid = 'xyz#gmail.com' AND ROLE = '#role#'
Here it should replace the only role '#role#' and should left email as it is.
Expected Output => SELECT *FROM USERS WHERE emailid = 'xyz#gmail.com' AND ROLE = 'Admin'
Complete example with mocked data returned by getReportManagerKeyValue:
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StackOverflow54842971 {
private static Map<String, String> map;
public static void main(String[] args) {
// preparing test data
map = new HashMap<>();
map.put("role", "Admin");
map.put("userid", "666");
// original query string
String query = "SELECT * FROM USERS WHERE ID = '#userid#' AND emailid = 'xyz#gmail.com' AND ROLE = '#role#' ";
// regular expression to match everything between '# and #' with capture group
// omitting single quotes
Pattern p = Pattern.compile("'(#[^#]*#)'");
Matcher m = p.matcher(query);
while (m.find()) {
// every match will be replaced with value from getReportManagerKeyValue
query = query.replace(m.group(1), getReportManagerKeyValue(m.group(1).replaceAll("#", "")));
}
System.out.println(query);
}
// you won't need this function
private static String getReportManagerKeyValue(String key) {
System.out.println("getting key " + key);
if (!map.containsKey(key)) {
return "'null'";
}
return map.get(key);
}
}
It's considered very bad practice to use string substitution to generate database queries, because you leave your code open to SQL Injection attacks. I can't tell from the small code sample you've provided, but the vast majority of large-scale Java projects use the Spring Framework, which allows you to use either JdbcTemplate or (my preference) NamedParameterJdbcTemplate. Both will allow you to substitute variables in a safe manner.
I need some guidance on my current obstacle with this application. If you can point me in the right direction will help. Basically I have twitter like application with a sql database storing the "tweets" and the users data.The user's nickname always start with a "#". Now everything is working but i need to add the functionality that if I send a twit and "mentioned" a user, meaning I add #nickname , then that person I mentioned should see it on his messages. I think I can figure it out, but i'm just confused on how to get started, specifically when I'm getting the "tweet" how can I find a "#" and return the word that contains the "#" ? The next step should probably be to see if that nickname exists and find the userID by the nickname and update their messages? Please help me out.
This is what I'm trying.. not working..
HttpSession session = request.getSession();
String tweet = request.getParameter("tweet");
ArrayList<User> x= new ArrayList<User>();
for(int i = 0; i < x.size(); i++){
String alias = x.get(i).getAlias();
if(tweet.contains(alias)){
try {
int uid= getUseridByNickName(alias);
Twit t = new Twit();
t.setMentionedUserID(uid);
} catch (SQLException ex) {
Logger.getLogger(TwitServlet.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
To get the username of the mentioned users you could simply use the indexOf method:
String s = "#user1 #user2 some text";
ArrayList<String> users = new ArrayList<>();
int index = s.indexOf("#");
while(index != -1) {
users.add(s.substring(index + 1, s.indexOf(" ", index)));
index = s.indexOf("#", index + 1);
}
users.stream().forEach(System.out::println);
Note that this method will work only if the username is followed by a space, otherwise the username will also contain the text between the "#" and the first space it founds (e.g. the tweet "#user1, some text" will return "user1,")
I have an API in which I am doing my own validation for certain input parameters. For example -
public Builder(int clientId) {
TestUtils.assertNonNegative(clientId, "ClientId");
this.clientId = clientId;
}
public Builder setUserId(String userid) {
TestUtils.assertNotNull(userid, "UserId");
this.userid = userid;
return this;
}
And my assertNonNegative and assertNotNull method in TestUtils class is like this -
public static void assertNonNegative(int val, String attr) {
if (val <= 0) {
s_logger.logError("Attribute = ", attr, " Value = ", val, " error=", attr, " cannot be negative or zero");
throw new IllegalArgumentException(attr + " cannot be negative or zero");
}
}
public static void assertNotNull(String value, String key) {
if (value == null || value.isEmpty()) {
s_logger.logError("Key = ", key, " Value = ", value, " error=", key,
" cannot be NULL or empty String");
throw new IllegalArgumentException(key + " cannot be null OR empty");
}
}
I am wondering is there any validation API available in any open source projects which I can use to substitute the above internal method I have? If yes, can anyone provide an example how would I achieve this? I still need to throw the same message back as an IllegalArgumentException
I dont understand why would you use an external API tu achieve a nullOrEmpty or a non-negative number validation but...
If you would like to verifiy an id of a user in a database directly in you Java app
This might interest you to learn:
http://www.mkyong.com/java/how-to-send-http-request-getpost-in-java/
Use a bit of PHP and verify if the user is in the database.
if(isset($_GET['idcmd']))
{
switch($_GET['idcmd'])
{
case 1:
if(isset($_POST['iduser']))
{
$sql= "SELECT idUser FROM users WHERE idUser=:iduser ";
$result = $db_conn->prepare($sql);
$result->bindParam(":iduser" ,$_POST['iduser']);
$result->execute();
$num=$result->fetchColumn();
if($num > 0){
echo "cool";
}else{
echo "nocool";
}
}
break;
}
}
Now if you make a POST request to the url www.mydomain.com/myapi.php?idcmd=1 and get the response cool, it means that the user is in database.
I hope it helps.
I'm trying to get all the users of a DL using below code.The code is working as expected. However, I'm not able to get AD usernames for some users. Ex. First row of the o/p has username rkama but not the second row. Is this LDAP data issue or is there a different way to get user name/email address in a DL.
O/p
Entry is : CN=Ay\,Ram(rkama),OU=Site-SJN,OU=Accounts_User,DC=corp,DC=XXX,DC=com
Entry is : CN=Wang\,Peter(),OU=Site-SJN,OU=Accounts_User,DC=corp,DC=XXX,DC=com
public ArrayList<String> getAllDLs(String dlname) throws NamingException {
ArrayList<String> dls = new ArrayList<String>();
String attributes[] = { "member", "displayName" };
createDLContext();
SearchControls ctrl = new SearchControls();
ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
ctrl.setReturningAttributes(attributes);
String search = "(&(objectClass=group)((sAMAccountName="+dlname+"*)))";
NamingEnumeration enumeration = dlContext.search("", search, ctrl);
while (enumeration.hasMoreElements()) {
SearchResult result = (SearchResult) enumeration.next();
System.out.println("Found match & result is : " + result);
NamingEnumeration<?> n2 = result.getAttributes().get("member").getAll();
while (n2 != null && n2.hasMore()) {
String dlList = (String) n2.next();
System.out.println("Entry is : " + dlList);
}
}
dlContext.close();
return dls;
}
I think you need to escape the \ character. Have a look at http://www.rlmueller.net/CharactersEscaped.htm
The member element only contains a DN for the user, this is not the username or password of the account, but a value that can be put back into the search to get the user information (including cn - the name of the user, and sAMAccountName - the userid of the user).
So you need to feed the dlList value into a second search (cleanly) e.g.
NamingEnumeration searchResult = dlContext.search("", "(dn={1})", new Object[]{ dlList }, ctrl);
Trying to construct the search with a simple string like "(&(objectClass=group)((sAMAccountName="+dlname+"*)))" will yield problems because the elements of the returned string will need to be escaped before putting it into the search (the \ for example).
I am able to get the iterations under the project object. Now how do I get the iteration I need under that project and then drill down to the stories in that iteration using the JAVA toolkit?
https://sandbox.rallydev.com/slm/webservice/v2.0/project/7191194697/iterations
Given a project:
String projectRef = "/project/1234";
You may scope your requests as follows:
iterationRequest.setProject(projectRef);
or
storyRequest.setProject(projectRef);
If you scoped a story request to a project, then you may query on stories by traversing Iteration.Name if you know the iteration already:
storyRequest.setQueryFilter(new QueryFilter("Iteration.Name", "=", "my Iteration 1"));
Here is a more complex example that returns stories assigned to iterations that fall within the timbox of a specific release. If, for example, you have 4 iterations per release, this code will return stories assigned to all four iterations.
If you code against the sandbox, replace the value in the host variable accordingly.
public class FindIterationsByReleaseDateAndStories {
public static void main(String[] args) throws URISyntaxException, IOException {
String host = "https://rally1.rallydev.com";
String username = "user#co.com";
String password = "secret";
String projectRef = "/project/12352608219";
String applicationName = "Find Iterations by Release Dates and Stories";
RallyRestApi restApi = null;
try {
restApi = new RallyRestApi(
new URI(host),
username,
password);
restApi.setApplicationName(applicationName);
System.out.println(restApi.getWsapiVersion());
QueryRequest releaseRequest = new QueryRequest("Release");
releaseRequest.setFetch(new Fetch("ReleaseStartDate", "ReleaseDate"));
releaseRequest.setScopedDown(false);
releaseRequest.setScopedUp(false);
releaseRequest.setProject(projectRef);
releaseRequest.setQueryFilter(new QueryFilter("Name", "=", "r1"));
QueryResponse releaseQueryResponse = restApi.query(releaseRequest);
int numberOfReleasesInProject = releaseQueryResponse.getTotalResultCount();
System.out.println(numberOfReleasesInProject);
JsonObject releaseJsonObject = releaseQueryResponse.getResults().get(0).getAsJsonObject();
System.out.println(releaseJsonObject.get("ReleaseStartDate"));
System.out.println(releaseJsonObject.get("ReleaseDate"));
String rsd = releaseJsonObject.get("ReleaseStartDate").getAsString();
String rd = releaseJsonObject.get("ReleaseDate").getAsString();
QueryRequest iterationRequest = new QueryRequest("Iteration");
iterationRequest.setFetch(new Fetch("Name","StartDate","EndDate"));
iterationRequest.setScopedDown(false);
iterationRequest.setScopedUp(false);
iterationRequest.setProject(projectRef);
iterationRequest.setQueryFilter(new QueryFilter("StartDate", ">=", rsd).and(new QueryFilter("EndDate", "<=", rd)));
QueryResponse iterationQueryResponse = restApi.query(iterationRequest);
int numberOfIteraitons = iterationQueryResponse.getTotalResultCount();
System.out.println("numberOfIteraitons " + numberOfIteraitons);
if(numberOfIteraitons >0){
for (int i=0;i<numberOfIteraitons;i++){
JsonObject iterationJsonObject = iterationQueryResponse.getResults().get(i).getAsJsonObject();
String iterationName = iterationJsonObject.get("Name").getAsString();
System.out.println("iteration: " + iterationName);
QueryRequest storyRequest = new QueryRequest("HierarchicalRequirement");
storyRequest.setProject(projectRef);
storyRequest.setFetch(new Fetch(new String[] {"Name", "FormattedID","ScheduleState"}));
storyRequest.setLimit(1000);
storyRequest.setScopedDown(false);
storyRequest.setScopedUp(false);
storyRequest.setQueryFilter(new QueryFilter("Iteration.Name", "=", iterationName));
QueryResponse storyQueryResponse = restApi.query(storyRequest);
System.out.println("Number of stories in " + iterationName + " :" + storyQueryResponse.getTotalResultCount());
for (int j=0; j<storyQueryResponse.getResults().size();j++){
JsonObject storyJsonObject = storyQueryResponse.getResults().get(j).getAsJsonObject();
System.out.println("Name: " + storyJsonObject.get("Name") + " FormattedID: " + storyJsonObject.get("FormattedID") + " ScheduleState: " + storyJsonObject.get("ScheduleState"));
}
}
}
}
finally{
if (restApi != null) {
restApi.close();
}
}
}
}
UPDATE: as far as your question in the comment, the code above is equivalent of
https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement?query=((Iteration.Name = i1) AND (Project = /project/12352608219))
There are other ways to achive the same result. Iteration name may not be unique, hence the second condition by project ref. In the code the request's project is set first, that's why the query itself uses one condition, but effectively there are two. If you know your iteration's ref, or ObjectID then the same result will be returned from (Iteration = /iteration/123456789), and there is no need to filter by project since a reference or ObjectID are unique.
WS API doc is interactive.Test your queries in WS API and copy the resulting query URLs from the address bar if you want to see how queries are formed:
-Query in the context of the intended object: click on the work item type in the Object Model, e.g. Defect or HierarchicalRequirement before typing your query in the query box.
-Enter a query in a box, e.g (Iteration.Name = i1)
-Click on Query button
-Results are displayed in the window from which you can copy query URL from address bar of your browser.