0

I'm using JRuby 9.0.5.0 in order to be able to invoke Ruby scripts from Java. I'd like to pass a char array containing a password to a Ruby script, but apparently I'm doing something wrong as my script only works if I use a normal string.

script.rb contains the following function:

def action(user, password)

From Java, I can normally invoke this function, but I only get the the expected result (i.e. no exception) if password is a String:

ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine jruby = m.getEngineByName("jruby");

...

jruby.put("user", "TestUser");
jruby.put("password", "xyz!"); // I'd like to pass "xyz!" as a char array.

// Call the script. Works as expected because password is a String.
String result = (String)jruby.eval("action($user, $password)");

My first attempt was to try to pass the password like this:

char[] password = { 'x', 'y', 'z', '!' };
jruby.put("password", password);
...

but this resulted in the exception

NoMethodError: undefined method `encoding' for char[x, y, z, !]@30abf79c:# encode_utf16le at .../jruby-9.0.5.0/lib/ruby/gems/shared/gems/rubyntlm-0.6.0/lib/net/ntlm/encode_util.rb:42

I get the same error if I try to set the password explicitly in the script.rb itself like this, just for testing:

pwd = ['x', 'y', 'z', '!'].to_s
# use pwd inside the script ...

Next, I tried to force UTF-8 encoding like this:

pwd = ['x', 'y', 'z', '!'].to_s
pwd = pwd.force_encoding("UTF-8")
# use pwd inside the script ...

which resulted in a different error originating from the gem used inside the script, i.e. an authorization error. The same happens if I use "UTF-16".

Could it be that that the Ruby gem used by the script itself, i.e. the internal function call using the password, by itself only works with strings of a specific encoding? Or am I doing something else wrong? I know hardly anything about Ruby and am simply trying to glue this together.

w128
  • 4,680
  • 7
  • 42
  • 65

2 Answers2

1

The solution is to use password.to_a.pack('U*') inside the Ruby script.

Java:

char[] password = { 'x', 'y', 'z', '!' };
jruby.put("password", password); // jruby is of type ScriptEngine

Ruby script.rb:

password_to_use = password.to_a.pack('U*')
w128
  • 4,680
  • 7
  • 42
  • 65
0

~~['x','y','z','!'].to_java(:char) converts the Ruby Array into a Java char[]~~

char[] password = { 'x', 'y', 'z', '!' };
jruby.put("password", new String(password)); // jruby is of type ScriptEngine
kares
  • 7,076
  • 1
  • 28
  • 38
  • Thanks, but I'm trying to achieve the reverse, i.e. convert Java's char[] into a Ruby string. – w128 May 06 '16 at 11:15
  • ... and what's wrong with the standard Java String API for that? – kares May 06 '16 at 16:25
  • kares, if you're referring to the Java's String type, what's wrong is that it's bad practice to use it for passwords and similar sensitive data due to its immutability and other reasons. See http://stackoverflow.com/questions/8881291/why-is-char-preferred-over-string-for-passwords-in-java – w128 May 06 '16 at 16:28
  • The updated solution you propose would work, but is not recommended in this case as it creates a new instance of immutable string in memory and you can't control when it's cleared by GC, unlike `char[]`. – w128 May 06 '16 at 16:32
  • you will eventually need it as a Ruby String ... so you're really just playing yourself smart (want save you much at all). if its ascii just convert to a `byte[]` array than. also the lifespan of a `new String()` and `new char[]` would be around the same in terms of GC! – kares May 06 '16 at 16:35
  • Sure it will save you _some_ compared to plain string, if nothing else it prevents someone from accidentally dropping the plain text password into a log file in my Java code, or finding sensitive info in a memory dump. With char[] you can control the duration for which you want the data to actually be present. Except if what you mean is that JRuby will internally create a String anyway and is the solution thus perfectly equivalent - but is this really the case? Also, I need it to be Unicode, not just ASCII. – w128 May 06 '16 at 16:39
  • Btw, perhaps it should be noted that my original question omits the code that clears the password array immediately after use, as it's not relevant to the question. With String, you can't do such thing and are completely dependent on the GC. – w128 May 06 '16 at 16:47