I would like to use JNDI to look up Kerberos SRV records in a local network. I try to guess the local domain in hopefully clever ways. If that fails I would like to look up the plain entry, e.g. _kerberos._tcp without any suffix and rely on the DNS domain search list to find the right entry. This works on Windows with nslookup -type=srv _kerberos._tcp and Linux with host -t srv _kerberos._tcp. The domain example.test is appended and the entry is found.
Here is an example program to do DNS lookups via JNDI:
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class JndiDnsTest {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: " + JndiDnsTest.class.getName() +
" name record-types...");
return;
}
String name = args[0];
String[] recordTypes = new String[args.length - 1];
System.arraycopy(args, 1, recordTypes, 0, args.length - 1);
Hashtable<String, String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
try {
DirContext ctx = new InitialDirContext(env);
Attributes dnsQueryResult = ctx.getAttributes(name, recordTypes);
if (dnsQueryResult == null) {
System.out.println("Not found: '" + name + "'");
}
for (String rrType: recordTypes) {
Attribute rr = dnsQueryResult.get(rrType);
if (rr != null) {
for (NamingEnumeration<?> vals = rr.getAll(); vals.hasMoreElements();) {
System.out.print(rrType + "\t");
System.out.println(vals.nextElement());
}
}
}
} catch (NamingException e) {
e.printStackTrace(System.err);
}
System.out.println("\nThe DNS search list:");
for (Object entry: sun.net.dns.ResolverConfiguration.open().searchlist()) {
System.out.println(entry);
}
System.out.println("\nsun.net.spi.nameservice.domain = " +
System.getProperty("sun.net.spi.nameservice.domain"));
}
}
It appears to me that JNDI only does one lookup for the direct name. No entry is found where above commands succeed. It seems it does not use the DNS search list. Its contents are printed correctly at the bottom, though.
On the other hand the Networking properties documentation says that
If the sun.net.spi.nameservice.domain property is not defined then the provider will use any domain or domain search list configured in the platform DNS configuration.
(The property is not set.) The Java version is Sun Java 1.6.0_20.
Does JNDI use the DNS search list or not?
It's a known bug - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6427214
Related
I have a problem while creating a Java bot for Discord. I decided to make a command for it to kick players from the server. But I ran into difficulties.
Here's a code :
package com.company;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import java.util.List;
import java.util.Objects;
public class KickComm extends ListenerAdapter {
public void onGuildMessageReceived(GuildMessageReceivedEvent event) {
String[] args = event.getMessage().getContentRaw().split("\\s+");
List<Member> mentionedMembers = event.getMessage().getMentionedMembers();
Member target = mentionedMembers.get(0);
if(args[0].equalsIgnoreCase(Main.prefix + "kick"))
{
if (args.length < 2) { //TODO NOT WORK
EmbedBuilder NoUser = new EmbedBuilder();
NoUser.setColor(0xff3923);
NoUser.setTitle("\uD83D\uDD34You need to add a <#username> and <reason>");
NoUser.setFooter("Usage: " + Main.prefix + "kick <#username> <reason>.",
Objects.requireNonNull(event.getMember()).getUser().getAvatarUrl());
event.getChannel().sendMessage(NoUser.build()).queue();
NoUser.clear();
}
else if (args.length < 3) { //WORK
EmbedBuilder NoReason = new EmbedBuilder();
NoReason.setColor(0xff3923);
NoReason.setTitle("\uD83D\uDD34You need to add a <reason>.");
NoReason.setFooter("Usage: " + Main.prefix + "kick <#username> <reason>.",
Objects.requireNonNull(event.getMember()).getUser().getAvatarUrl());
event.getChannel().sendMessage(NoReason.build()).queue();
NoReason.clear();
}
else if(!Objects.requireNonNull(event.getMember()).hasPermission(Permission.KICK_MEMBERS) //WORK
&&
!event.getMember().canInteract(target)) {
EmbedBuilder NoPermission = new EmbedBuilder();
NoPermission.setColor(0xff3923);
NoPermission.setTitle("\uD83D\uDD34You don't have permission to use this command.");
NoPermission.setFooter("Usage: " + Main.prefix + "kick <#username> <reason>.",
Objects.requireNonNull(event.getMember()).getUser().getAvatarUrl());
event.getChannel().sendMessage(NoPermission.build()).queue();
NoPermission.clear();
}
else if(mentionedMembers.isEmpty()) { //TODO NOT WORK
EmbedBuilder NoMember = new EmbedBuilder();
NoMember.setColor(0xff3923);
NoMember.setTitle("\uD83D\uDD34I don't see member with this nickname.");
NoMember.setFooter("Usage: " + Main.prefix + "kick <#username> <reason>.",
Objects.requireNonNull(event.getMember()).getUser().getAvatarUrl());
event.getChannel().sendMessage(NoMember.build()).queue();
NoMember.clear();
}
}
}
}
Promlem in two lines :
if (args.length < 2) {
And
else if(mentionedMembers.isEmpty()) {
Most of all, I can't understand why line 1 does not work. When I write the !kick command in the discord, the console displays an error :
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
I don't know why args length is 0, it's very strange.I tried to "if-else-if" to "if", but it doesn't work.I really wanna to continue creating that command, but i don't know what to do.
P.S.:it's not all of code, because i can't progress further due to this error.Sorry for my Google translater english and many thanks
The exception is caused by this line:
Member target = mentionedMembers.get(0);
Your problem here is that not every message may mention a member. Keep in mind you also receive your own messages. If the bot only sends an embed, the content will be empty.
If the content is only whitespace your split("\\s+") will return an empty array. This will cause an ArrayIndexOutOfBoundsException on this line:
if(args[0].equalsIgnoreCase(Main.prefix + "kick"))
I would recommend checking for the length of mentionedMembers and checking for the length of args before trying to access their respective elements.
I have just edited my previous question, and I am providing more details, (hopefully someone would be able to help).
I have a Redis cluster with 1 master and 2 slaves. All 3 nodes are managed by Sentinel. The failover works fine and when the new master is elected, I can write on the new master (from the command line).
Now, I am trying to write a small Java program using Redisson, which ideally should write records into redis, and be able to handle the failover (which it should do as far as I have understood). This is my code until now.
import org.redisson.Redisson;
import org.redisson.RedissonNode;
import org.redisson.api.*;
import org.redisson.api.annotation.RInject;
import org.redisson.config.Config;
import org.redisson.config.RedissonNodeConfig;
import org.redisson.config.SubscriptionMode;
import java.util.Collections;
import java.util.UUID;
public class RedissonTest {
public static class RunnableTask implements Runnable {
#RInject
RedissonClient client;
#Override
public void run(){
System.out.println("I am in ..");
RMap<String, String> map = client.getMap("completeNewMap");
System.out.println("is thread interrupted?? " + Thread.currentThread().isInterrupted());
NodesGroup ngroup = client.getNodesGroup();
Collection<Node> nodes = ngroup.getNodes();
for(Node node : nodes){
System.out.println("Node ip "+ node.getAddr().toString()+" type: "+node.getType().toString());
}
for(int i=0; i < 10000; i++) {
String key = "bg_key_"+String.valueOf(i);
String value = String.valueOf(UUID.randomUUID());
String oldVal = map.get(key);
map.put(key, value);
RBucket<String> bck = client.getBucket(key);
bck.set(value);
System.out.println("I am going to replace the old value " + oldVal + " with new value " + value + " at key "+key);
}
System.out.println("I am outta here!!");
}
}
public static void main(String[] args) {
Config config = new Config();
config.useSentinelServers()
.setMasterName("redis-cluster")
.addSentinelAddress("192.168.56.101:26379")
.addSentinelAddress("192.168.56.102:26379")
.addSentinelAddress("192.168.56.103:26379")
.setPingTimeout(100)
.setTimeout(60000)
.setRetryAttempts(25)
.setReconnectionTimeout(45000)
.setRetryInterval(1500)
.setReadMode(ReadMode.SLAVE)
.setConnectTimeout(20000)
.setSubscriptionMode(SubscriptionMode.MASTER);
RedissonClient client = Redisson.create(config);
RedissonNodeConfig nodeConfig = new RedissonNodeConfig(config);
nodeConfig.setExecutorServiceWorkers(Collections.singletonMap("myExecutor6", 1));
RedissonNode node = RedissonNode.create(nodeConfig);
node.start();
System.out.println("Node address "+node.getRemoteAddress().toString());
RExecutorService e = client.getExecutorService("myExecutor6");
e.execute(new RunnableTask());
e.shutdown();
if(e.isShutdown()) {
e.delete();
}
client.shutdown();
node.shutdown();
System.out.println("Hello World!" );
}
}
Running the code, a couple of things that I don't understand happen.
The first one is:
why redisson recognise my 3 hosts as redis slaves??
why the key value pairs I created are not stored into redis??
The idea is that after I have been able to write into redis, I would start to test the failover killing the master and expecting that the program will manage it and continues to write to the new master, without losing a message(it would be nice to be able to cache the messages while the failover occurs).
What happen with this simple program is that I can write into redis, but when I kill the master, the execution just hangs for a time that seems to be close to the setTimeout and exits without completing the task.
Any suggestion?
You should set retryAttempts parameter big enough to make Redisson survive failover period.
I'm using the Java API for VirtualBox from the SDK version "VirtualBoxSDK-5.1.22-115126" (vboxjws.jar).
I want to get a List of all snapshots belonging to the IMachine object (object representing one virtual machine) that I'm working with.
IMachine has the method findSnapshot(String nameOrId) which returns a snapshot for the given name or UUID. But I want a list of ALL snapshots the machine has...
The command line interface vboxmanage is able to return a list of all snapshots with the command:
vboxmanage snapshot <uuid|vmname> list
(source: https://www.virtualbox.org/manual/ch08.html#idm4900)
So is this method missing in the API by design or have the developers from Oracle just forgotten to implement it? (would proof that they are just human beings too ;))
Snapshots is a tree structure with a root snapshot, from which all other snapshots originate. You could say it is by design the API call does not exists, but you can implement it yourself directly by going through the tree.
This sample will do just that:
import org.virtualbox_5_1.IMachine;
import org.virtualbox_5_1.ISnapshot;
import org.virtualbox_5_1.IVirtualBox;
import org.virtualbox_5_1.VirtualBoxManager;
public class SnapshotList {
private static void printChilds(ISnapshot snapshot) {
System.out.println("\"" + snapshot.getName() + "\" {" + snapshot.getId() + "}");
for (ISnapshot snapChild : snapshot.getChildren()) {
printChilds(snapChild);
}
}
public static void main(String[] args) {
/*
* WebServices info
*/
String wsHost = "http://localhost:18083";
String wsUser = "user";
String wsPass = "password";
if (args.length < 1 || args[0] == null || args[0].length() < 1) {
System.err.println("Specify the VM name/UUID as first parameter");
System.exit(1);
}
String vmName = args[0];
VirtualBoxManager vboxManager = VirtualBoxManager.createInstance(null);
vboxManager.connect(wsHost, wsUser, wsPass);
try {
IVirtualBox vbox = vboxManager.getVBox();
IMachine vm = vbox.findMachine(vmName);
if (vm.getSnapshotCount() < 1) {
System.out.println("The machine + " + vmName + " has no snapshot");
System.exit(0);
}
// The magic is here: null will give you the root snapshot
printChilds(vm.findSnapshot(null));
} finally {
vboxManager.disconnect();
vboxManager.cleanup();
}
}
}
I assume you know how to configure the WS login & password variables or disable authentication on the WebService process.
The doc of IMachine::findSnapshot() explains that null can be used to fetch the root snapshot, from which you can just process the childs:
Returns a snapshot of this machine with the given UUID. A null
argument can be used to obtain the first snapshot taken on this
machine. To traverse the whole tree of snapshots starting from the
root, inspect the root snapshot's ISnapshot::children attribute and
recurse over those children.
I have configured ADDC on windows server 2012 R2 and I have added two users into DC - one is windows 8 and another one is ubuntu.
Windows server 2012 username - DC
Windows 8.1 username - Win
Ubuntu username - Linux
I am trying to achieve this - I want to write java program in ubuntu, that will connect to ADDC and sends back, detailed user information on windows 8.1
My program is like -
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class LdapSearch {
public static void main(String[] args) throws Exception {
Hashtable env = new Hashtable();
String sp = "com.sun.jndi.ldap.LdapCtxFactory";
env.put(Context.INITIAL_CONTEXT_FACTORY, sp);
String ldapUrl = "ldap://server.com, dc=com";
env.put(Context.PROVIDER_URL, ldapUrl);
DirContext dctx = new InitialDirContext(env);
String base = "ou=name";
SearchControls sc = new SearchControls();
String[] attributeFilter = { "cn", "mail" };
sc.setReturningAttributes(attributeFilter);
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(&(sn=W*)(l=Criteria*))";
NamingEnumeration results = dctx.search(base, filter, sc);
while (results.hasMore()) {
SearchResult sr = (SearchResult) results.next();
Attributes attrs = sr.getAttributes();
Attribute attr = attrs.get("cn");
System.out.print(attr.get() + ": ");
attr = attrs.get("mail");
System.out.println(attr.get());
}
dctx.close();
}
I am referring to above program and trying to achieve connection to AD through LDAP java. I dont know how to get ou, cn, etc.. I am very much new to the concepts of LDAP, ADDC.
Any idea on this? Please let me know.
Thanks,
saurabh
I've done a similar scenario in C# so am not sure about the connection settings in Java but as for similarities you should create a directory entry for the LDAP and provide the path, user name and password of authorized user who can access the active directory, i didnt provide DC in the path just the LDAP path and then the query filter parameters that searched based upon user first name was
Filter = "(& (SAMAccountName=" + name + ") (| (&(objectCategory=person)(objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*))) ))";
then it would provide you with an result in an arraylist like object so you would query the rest of information you like by just providing the attribute name, you would find a list of LDAP attributes here
LDAP attributes
I have a Serial-to-USB device with a similarly named device driver in the Windows device manager. The devices do not always grab the same COM port on system boot, so my program needs to identify it on start up.
I've tried using RXTX to enumerate the COM ports on the system, but this didn't work because CommPortIdentifier.getName() simply returns the COM name (eg. COM1, COM2, etc.) I need to acquire either the driver manufacturer name, or the driver name as it appears in the device manager, and associate it with the COM name.
Can this easily be done in Java? (I'd be interested in any 3rd party Java libraries that support this.) Otherwise, how I could begin to accomplish this via the win32 API?
I achieved what I wanted by using the WinRegistry class provided by David in this SO question to obtain the FriendlyName from registry key associated with my USB device. I then parse out the COM number from the friendly name.
Some things to consider:
USB devices are located at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\ in the registry (tested on WinXP, Win7.)
I required the device VID + PID to identify the correct device key (eg. VID_xxxx&PID_xxxx.) Since VID and PID are device specific, this key should be reliable across multiple systems.
The VID_xxxx&PID_xxxx key contains another sub-key with device values. I had some trouble enumerating the sub-keys with WinRegistry, so I hard-coded the sub-key name as a quick hack during development. A much safer solution would search sub-keys to find the correct name.
The device keys exist in the registry regardless of whether the device is currently connected. This code makes the assumption that Windows will update FriendlyName if the device is reconnected to a different COM port. I haven't verified this, but things looked good during use-testing.
Example
String keyPath = "SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_067b&Pid_2303\\";
String device1 = "5&75451e6&0&1";
System.out.println("First COM device: " + getComNumber(keyPath + device1));
Code
import java.util.regex.Pattern;
import java.util.regex.Matcher;
// Given a registry key, attempts to get the 'FriendlyName' value
// Returns null on failure.
//
public static String getFriendlyName(String registryKey) {
if (registryKey == null || registryKey.isEmpty()) {
throw new IllegalArgumentException("'registryKey' null or empty");
}
try {
int hkey = WinRegistry.HKEY_LOCAL_MACHINE;
return WinRegistry.readString(hkey, registryKey, "FriendlyName");
} catch (Exception ex) { // catch-all:
// readString() throws IllegalArg, IllegalAccess, InvocationTarget
System.err.println(ex.getMessage());
return null;
}
}
// Given a registry key, attempts to parse out the integer after
// substring "COM" in the 'FriendlyName' value; returns -1 on failure.
//
public static int getComNumber(String registryKey) {
String friendlyName = getFriendlyName(registryKey);
if (friendlyName != null && friendlyName.indexOf("COM") >= 0) {
String substr = friendlyName.substring(friendlyName.indexOf("COM"));
Matcher matchInt = Pattern.compile("\\d+").matcher(substr);
if (matchInt.find()) {
return Integer.parseInt(matchInt.group());
}
}
return -1;
}
#robjb Your code does not allow for more than one device to be connected. How will the user know the device name? I added to your code thus to return a list of com ports:
ArrayList<String> subKeys = WinRegistry.readStringSubKeys(WinRegistry.HKEY_LOCAL_MACHINE, keyPath);
ArrayList<Integer> comPorts = new ArrayList<Integer>();
for (String subKey : subKeys) {
String friendlyName = getFriendlyName(keyPath + subKey);
if (friendlyName != null && friendlyName.contains("MyDriverName") && friendlyName.contains("COM")) {
int beginIndex = friendlyName.indexOf("COM") + 3 /*length of 'COM'*/;
int endIndex = friendlyName.indexOf(")");
comPorts.add(Integer.parseInt(friendlyName.substring(beginIndex, endIndex)));
}
}
Update: I don't think these are solutions. Why? This information is statically stored in the registry - even when the device is not connected.
Great example, using JNA, here.
The author (Geir Arne Ruud) has released it under Public Domain License.
My example code
public static String getFriendlyName(GoGPSModel model, String name)
{
if(model.getSystem().getOSType() != OSType.Windows32
&& model.getSystem().getOSType() != OSType.Windows64) {
return name;
}
for (DeviceInformation devInfo : infoObjects) {
System.out.println(devInfo.toString());
String friendlyName = devInfo.getFriendlyName();
if(friendlyName != null && !friendlyName.equals("") && friendlyName.contains(name)) {
return devInfo.getManufacturer() + ": " + friendlyName;
}
}
return name;
}