2

I'm building a MATLAB application that authenticates a user's credentials. I want to read in his password, and I want to hide his typed credentials somehow.

Some constraints:

  • I have to account for windows as well as linux/mac users.
  • I can't be assured of any programs (perl/python/VBS) in the user system.

Here's what I've tried:

Straight-up GUIDE

Works, but not an option as the user is likely to be running matlab in -nodesktop (or -nodisplay) mode.

MATLAB + Java

console.readPassword. This messes up my terminal horribly.

system() calls

Essentially I call bash or dos scripts based on OS.

I have the following call for linux/mac:

[status cred] = system('stty -echo; read cred; stty echo;echo ""; echo "$cred"');

This is supposed to pick up the user credentials and dump that on to 'cred'. I've checked that it works in the regular terminal, but executing it in MATLAB causes nothing to be output, and a Ctrl-C is required to bring back the >> prompt.

MATLAB Perl

The Windows MATLAB packages Perl, as pointed out in comments. I tried the following snippet:

use Term::ReadKey;
use Term::ReadLine;
ReadMode('noecho');
$yesnoline = Term::ReadLine->new("foo");
$pass = $yesnoline->readline();
printf "$pass";
ReadMode('restore');

And then called it as [result status] = perl('my_perl.pl'). Works great on Linux. On Windows:

res =

GetConsoleMode failed, LastError=|6| at ReadKey.pm line 264.

sta =

 9

My searches so far suggest that it's a problem related to the packaged version of perl for windows.

Any idea what's happening in the above approaches?

Vish
  • 2,144
  • 5
  • 25
  • 48
  • 2
    FYI: MATLAB ships with both Java and Perl on all platforms (although Java can be disabled with `-nojvm` startup option) – Amro Aug 10 '12 at 19:11
  • True! Tried this out just now. Works on Linux, but not on Windows, for some reason. Editing my original reply. – Vish Aug 10 '12 at 19:35
  • When you say your code worked on Linux, did you test it with the `-nodisplay` mode or was it from inside the full MATLAB IDE? In the Windows version, I think that MATLAB runs as a GUI program without a console/shell attached at all (for both full and `-nodisplay` modes)... When I tried running the code with the same packaged version of Perl **outside** of MATLAB (`"C:\..\MATLAB\R2012a\sys\perl\win32\bin\perl.exe" my_perl.pl`) it worked fine, which confirms that the issue is only running it from inside MATLAB (as I said, I don't think the *command window* in the IDE is a true "DOS" console) – Amro Aug 11 '12 at 08:45
  • @Amro yes I tested Linux with `-nodisplay`. Right... [I read](http://home.online.no/~pjacklam/matlab/doc/perl/) that the packaged perl might be somewhat stripped-down too. I guess it's not an ideal solution. I'm gonna try Swing next. – Vish Aug 13 '12 at 15:38
  • I suppose you are right (about it being a "lite" version), but still I was able to run your script with that same bundled Perl, only I ran it outside of MATLAB in `cmd.exe` prompt.. Anyway go ahead and try Java Swing, and please let us know what you come up with. This was definitely an interesting question :) – Amro Aug 13 '12 at 18:05
  • 1
    haha, it's strange this hasn't been discussed properly here (or anywhere) before. My quest took me across continents of programming languages and I now have some basic Java knowledge as a result! Thanks a lot for your help - Swing did it! Posting my reply. – Vish Aug 13 '12 at 18:58
  • You might be interested in reading this other question as well: [Determine if Matlab has a display available](http://stackoverflow.com/q/6754430/97160) – Amro Aug 13 '12 at 19:56
  • Ah, yeah, I know how to query for display - but thanks, I'll take a look. Currently trying to rework the java code into what I need it to do. – Vish Aug 13 '12 at 20:31

2 Answers2

1

I suggest that you detect Windows installation (ispc), and handle them differently than Unix-like systems, by creating a MATLAB GUI or something similar..

Here is one possible solution for Windows using .NET Windows Forms from inside MATLAB:

function pass = getPasswordNET()
    %# password return value
    pass = '';

    %# hidden figure used to wait for button press
    fig = figure('Visible','off', ...
        'IntegerHandle','off', 'HandleVisibility','off');

    %# create and show the Windows Forms GUI
    [handles,lh] = InitializeComponents();
    handles.frm.Show();

    %# block execution until figure is closed
    waitfor(fig)

    %# remove the listeners
    delete(lh);

    return;

    %# create GUI
    function [handles,lh] = InitializeComponents()
        %# import assembly
        NET.addAssembly('System.Windows.Forms');

        %# form
        frm = System.Windows.Forms.Form();
        frm.SuspendLayout();

        %# textbox
        tb = System.Windows.Forms.TextBox();
        tb.Dock = System.Windows.Forms.DockStyle.Fill;
        tb.Text = '';
        tb.PasswordChar = '*';
        tb.MaxLength = 14;

        %# button
        bt = System.Windows.Forms.Button();
        bt.Dock = System.Windows.Forms.DockStyle.Bottom;
        bt.Text = 'Submit';

        %# setup the form
        frm.Text = 'Password';
        frm.ClientSize = System.Drawing.Size(250, 40);
        frm.Controls.Add(tb);
        frm.Controls.Add(bt);
        frm.ResumeLayout(false);
        frm.PerformLayout();

        %# add event listeners
        lh(1) = addlistener(bt, 'Click', @onClick);
        lh(2) = addlistener(frm, 'FormClosing', @onClose);

        %# return handles structure
        handles = struct('frm',frm, 'tb',tb, 'bt',bt);
    end

    %# event handlers
    function onClick(~,~)
        %# get password from textbox
        pass = char(handles.tb.Text);

        %# close form
        handles.frm.Close();
    end
    function onClose(~,~)
        %# delete hidden figure (to unblock and return from function)
        close(fig)
    end
end

I tested the above on my machine, and it worked even when MATLAB was started in headless mode:

matlab.exe -nodesktop -noFigureWindows

then called it as:

>> pass = getPasswordNET()
pass =
secret_password

screenshot

It should be straightforward to do something similar in Java using Swing's JPasswordField

Amro
  • 123,847
  • 25
  • 243
  • 454
  • That definitely works, Amro, thanks! I still want the user experience to be seamless across platforms, so I'll try the JPasswordField approach with MATLAB Java next. – Vish Aug 13 '12 at 13:09
  • @Vish: I think a **GUI** approach is your best bet at a cross-platform solution; the shell/command prompt are quite different that all other solutions proposed here (Python's `getpass`, Perl's `Term`, or Java's `System.console`) were not consistent and none seamlessly worked on my Win installation... Since a Java GUI is the only common thing across Win/Mac/Linux, it is the way to go. If a display is not available, I say you fallback to the normal prompt in MATLAB. – Amro Aug 13 '12 at 17:49
  • Thanks Amro and @mutzmatron for your replies - as it turns out, I heavily modified the Swing example for my own purposes. It will have to do, as it works well on Windows and Linux. – Vish Aug 13 '12 at 21:16
  • @Vish: my pleasure. I found a couple of nice submissions on FEX that also do the job: two based on Java Swing [`passwordEntryDialog`](http://www.mathworks.com/matlabcentral/fileexchange/19729-passwordentrydialog) and [`uicomponent`](http://www.mathworks.com/matlabcentral/fileexchange/14583-uicomponent-expands-uicontrol-to-all-java-classes) (those are really excellent as their show how to properly incorporate Java components in existing MATLAB figures), and the other purely implemented in MATLAB [`login`](http://www.mathworks.com/matlabcentral/fileexchange/8499-login) – Amro Aug 14 '12 at 01:48
  • Thanks! I have already cobbled together something that works, but it's nice to know there are alternatives! – Vish Aug 14 '12 at 15:10
0

Java getPassword

I haven't yet managed to get the getPassword approach to return the console to the normal state - I'm assuming your code looks something like:

import java.lang.*
cs = System.console()
a = cs.readPassword()

Could you confirm this?

Python solution

If the solution has to be multi-platform, and you don't mind Python being a dependency, I would suggest writing a very simple python script and using this with a Matlab system call, something like

file: usergetpass.py

import getpass
import os
os.sys.stdout.write(getpass.getpass())

then in matlab

[status,pass] = system('python usergetpass.py');

You would then have to (trivially) parse pass though, the actual password is contained on line 3 of pass.

So you could put the above into your own mini matlab function,

function out = getpass()
[status, pass] = system('python usergetpass.py');
out = pass(13:end-1);

Note: I can use this because the password always occurs at that point in the pass variable.

jmetz
  • 12,144
  • 3
  • 30
  • 41
  • I guess the user system would need python right? Just revised my post to contain that tidbit of info. – Vish Aug 10 '12 at 19:02
  • mutzmatron, I believe that was what my java snippet must have looked like - can't seem to find it in my activity log. If you want to recover from a terminal mess-up (and are in `-nodesktop` on Linux), Ctrl-z followed by fg is a quick-fix :) – Vish Aug 10 '12 at 19:50
  • @mutzmatron: the Python version does not work as expected. It simply waits indefinitely without any prompts shown... (I had to end the call with Ctrl+C). I am using WinXP with the latest MATLAB version, and Python 2.6 installed from the official Windows binaries – Amro Aug 11 '12 at 08:52
  • @mutzmatron: as for the Java version, `System.console()` simply returns an empty matrix (of size 0x0), and the next line fails. Again this is because the JVM is started as a background job with no console attached (thus the call [returns](http://docs.oracle.com/javase/6/docs/api/java/io/Console.html) `null`) – Amro Aug 11 '12 at 08:56
  • @Amro: I'm afraid I can't comment - both work fine on my Ubuntu box, can't test them on Windows at the moment but in principle both approaches should be portable - significantly more so than using the **.NET** framework. – jmetz Aug 13 '12 at 14:57
  • @Amro: does it really return an empty? On MATLAB+Linux: `import java.lang.*; ob = System.console; ob` `java.io.Console@c3014` – Vish Aug 13 '12 at 15:25
  • @Amro: Also the OP stated that the user would be using `-nodesktop` **not** `-nojvm` - perhaps this was your mistake wrt console? – jmetz Aug 13 '12 at 15:41
  • @Vish: yes I'm sure, on MATLAB+Windows `java.lang.System.console` simply returns an empty matrix (which I assume corresponds to Java null value). @mutzmatron: I tested it with the full MATLAB IDE started normally (Either way that wouldn't matter, as `-nojvm` has no effect on Windows, and Java support is always available). I think neither of our solutions are truly portable (using the shell or command prompt), the best thing to do is to use a GUI to ask the user for the password (IMO Java GUI is the way to go since its available on all platforms) ... – Amro Aug 13 '12 at 17:56
  • 1
    ... After all, the entire MATLAB IDE and all figures are built on top of Java – Amro Aug 13 '12 at 18:10
  • @Amro: Good to know about the console issue - and while I agree in general about using the GUI there are clear cases where this may just not be feasible due to complexity, such as cross-platform ssh access to a server running matlab, and it seems suspicious that the System.console is behaving in this way - that should ideally be the simplest solution. – jmetz Aug 13 '12 at 19:02
  • @mutzmatron: the whole concept of SSH and X11-Forwarding is foreign to Windows.. When connecting to a remote Windows server running MATLAB (in a university environment for example), people usually use remote desktop (RDP), so a display is obviously available. If the server is running Linux, then one has the option of either SSH with no display, or SSH with X11-tunnelling (or any other protocols similar to RDP) which provides a display. – Amro Aug 13 '12 at 20:02
  • 1
    @mutzmatron: ... So a good solution would use GUI as default and detect when no display is available, which should only happen when SSH'ing to a Linux/Mac box, in which case any of the proposed solutions for console would do Perl/Python/Java – Amro Aug 13 '12 at 20:03