blob: 1df69da35fe0fe7b441673e69393d40ed52727f6 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>NetBeans Platform Login Tutorial</title>
<link rel="stylesheet" type="text/css" href="https://netbeans.org/netbeans.css">
</head>
<body>
<h1>NetBeans Platform Login Tutorial</h1>
<p>This tutorial demonstrates how to create a login form for a NetBeans
Platform application with very simple user and password management.
The login will be implemented with the <tt>DialogDisplayer</tt> class
of the NetBeans APIs.
<p>The dialog that you create in this tutorial will be visible whenever
the user starts the application. The passwords and usernames will be stored
in a preferences file, which is not very safe. Therefore, this tutorial will
provide a solution to encrypt the passwords with "Message-Digest Algorithm 5" (MD5).
MD5 is a cryptographic hash-function invented by Roland L. Rivest.
To use MD5 in our application, the <tt>java.security</tt> package will help us.
<h3>Contents</h3>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr>
<td align="left" valign="top">
<ul>
<li><a href="#installing">Installing The Software</a></li>
<li><a href="#creatingthemodulesuite">Setting Up The Module Suite</a>
<li><a href="#usermanagement">Creating A Simple User And Password Management</a>
<ul>
<li><a href="#optionpanel">Create Option Panel For The User Management</a></li>
<li><a href="#md5">Use MD5 To Encrypt Password</a></li>
<li><a href="#poss">Other Possibilities</a></li>
</ul>
<li><a href="#login">Creating The Login Module</a>
<li><a href="#code">All The Code At Once</a>
<ul><li><a href="#loginform">LoginForm.java</a></li>
<li><a href="#installer">Installer.java</a></li>
<li><a href="#user">UsermanagementPanel.java</a></li>
</ul>
</li>
<li><a href="#nextsteps">Next Steps
</a>
<li><a href="#version">Versioning</a>
</ul></td>
<td width="20"> </td>
<td align="right" valign="top">&nbsp;</td>
</tr>
</tbody></table>
<p>For more information on working with modules, see the <a href="https://platform.netbeans.org/index.html">
NetBeans Development Project home</a> on the NetBeans website. If you have questions, visit the
<a href="http://wiki.netbeans.org/wiki/view/NetBeansDeveloperFAQ">NetBeans Developer FAQ</a> or use the feedback link
at the bottom of this page.</p>
<br />
<!-- ===================================================================================== -->
<h2 class="tutorial"><a name="installing"></a>Installing The Software</h2>
<p>Before you begin, you need to install the following software on your
computer:</p>
<ul>
<li>NetBeans IDE 6.0 (<a href="http://www.netbeans.info/downloads/download.php?a=n&p=1">download</a>)</li>
<li>Java Standard Development Kit (JDK&trade;) version
1.4.2 (<a href="http://java.sun.com/j2se/1.4.2/download.html">download</a>)
or 5.0 (<a href="http://java.sun.com/j2se/1.5.0/download.jsp">download</a>)
or later</li>
</ul>
<br />
<!-- ===================================================================================== -->
<h2 class="tutorial"><a name="creatingthemodulesuite" id="creatingthemodulesuite"></a>Setting Up The Module Suite</h2>
<p>The first thing you have to do is to create a sample project. We will use a Module Suite. Here you can use the wizard that the IDE provides.</p>
<ol>
<li>Choose File &gt; New Project (Ctrl-Shift-N). Under Categories, select NetBeans Modules. Under projects,
select <tt>Module Suite</tt> and click Next.</li>
<li>In the next panel you have to give the suite a proper name, such
as <tt>LoginSuite</tt>, and set the location to any directory on your computer.
Click Finish.
<li>Now the IDE has created an empty suite for you. You can even test it when you right-click the module suite name and choose run. There will start a whole new IDE. But we do not need a complete IDE. So if you like, you can make the start of your application faster by following these few optional steps:
<li>Right-click the module suite name. Choose 'Properties'. Select 'Libraries'. Now you see on the right side a list of 'Platfom Modules'. Deselect all except of 'platform7'. Click OK.</li>
<li>If you run the application again there will only be a window with the essential buttons and menus. It should look like this:
<p><p><img border="1" src="../../images/tutorials/login/1_newapp.png" width="548" height="403"" border="1" alt="System Properties module.">
</ol>
<p><!-- ===================================================================================== -->
<h2><a name="usermanagement" id="usermanagement"></a>Creating A Simple User And Password Management</h2>
<p>To have as little work as possible, we will use some very interesting features of
NetBeans IDE to create our simple user management. This management will only
be able to store one username and one password in a preferences file.
<h3 class="tutorial"><a name="optionpanel" id="optionpanel"></a>Create Option Panel For The User Management</h3>
<p class="tutorial">In this section we will show you how to create an option panel to handle your username and password.</p>
<ol>
<li>At first we create a new module by right-clicking on the Modules folder in our suite and choosing <tt>Add New...</tt>.<br />
<p><img border="1" src="../../images/tutorials/login/2_newmod.png" width="250" height="190" border="1" alt="System Properties module.">
<li>Now a wizard for adding a new module appears. You have to enter a name for your module, for example 'UserManagement'. Click Next.</li>
<li>Change now the Code Base name, so that it fits into your application. Click Finish.</li>
</ol>
<p>After that the NetBeans IDE has created a new module for you. So, now we have to create a so called options panel to easily set our password and username.</p>
<ol>
<li>Right-click on the Source Packages of your new module and select New &gt; Other... .<br />
<p><img border="1" src="../../images/tutorials/login/3_newopt.png" width="350" height="347" border="1" alt="System Properties module.">
<li>A wizard appears and you should select the category 'Module Development' and in the list of filetypes you should select 'Options Panel'. Click Next.</li>
<li>Here we can choose whether we want a whole new panel category or a new panel in the 'Miscellaneous' category. In our case we will use the 'Miscellaneous' one. To complete this task enter a name and a tool tip text. Click Next.<br />
<p><img border="1" src="../../images/tutorials/login/4_optpan.png" width="400" height="75" border="1" alt="System Properties module.">
<li>On this panel you can now choose a class name prefix. I recommend to accept the IDE suggestion. Click Finish.</li>
</ol>
<p>Next there are some files opened by the IDE. For now we only need the <tt>&lt;ClassNamePrefix&gt;Panel.java</tt>. Go to this file and go into the Design-View and follow the instructions below. </p>
<ol>
<li>Use the Palette and add two labels and two textfields.<br />
<p><img border="1" src="../../images/tutorials/login/5_tex.png" width="230" height="101" border="1" alt="System Properties module.">
<li>Then rename the top label to 'Username' and the bottom one to 'Password'. Delete the texts of the textfields and rename the variables to 'user' and 'pass'.</li>
<li>Now go to the Source-View and look for two methods called <tt>load</tt> and <tt>store</tt>. These two methods are used to initialize the textfields and to store changes.</li>
<li>Change the source code of 'store' to the following:<br />
<pre class="examplecode">void store() {
NbPreferences.forModule(UsermanagementPanel.class).put("user", user.getText());
NbPreferences.forModule(UsermanagementPanel.class).put(&quot;pass&quot;, pass.getText());
} </pre>
<br />
With this code a new NetBeans Preferences file is created and the information of the textfields is stored into it with the written keys. Then add imports for <tt>org.openide.util.NbPreferences</tt>.</li>
<li>Now change the source code for 'load' in the following way:<br />
<br />
<pre class="examplecode">void load() {
user.setText(NbPreferences.forModule(UsermanagementPanel.class).get("user", ""));
pass.setText(NbPreferences.forModule(UsermanagementPanel.class).get("pass", ""));
}</pre>
<br />
In that part of the code the NetBeans Preferences are used to fill the textfields.</li>
</ol>
<p>When you start your application you will find your new options panel in 'Tools &gt; Options &gt; Miscellaneous'. You can also enter a password and an username now. When your restart your application you will see that these changes are persistant.<br />
<p><img border="1" src="../../images/tutorials/login/6_opt.png" width="350" height="287" border="1" alt="System Properties module.">
<p>Now our mini user management is complete. We have one user with one password.</p>
<div class="indent"></div>
<h3><span class="tutorial"><a name="md5" id="optionpanel2"></a>Use MD5 To Encrypt Password</span></h3>
<p>Here we will show you the encryption of your password with the MD5 algorithm.</p>
<p>A very good possibility to make your system safer is to encrypt your password with an algorithm called MD5. The 'Message-Digest Algorithm 5' is a cryptographic hash-function that was invented by Roland L. Rivest. To use MD5 in our application we can use some features of Java. The <tt>java.security</tt> package will help us.</p>
<p>But we have a problem with our created options panel. A MD5-Hash cannot be decrypted in a string. It is only possible to compare two MD5 values. So if you want to use this, you have to do some changes on your code in the 'store' method. </p>
<pre class="examplecode">void store() {
NbPreferences.forModule(UsermanagementPanel.class).put("user", user.getText());
if(NbPreferences.forModule(UsermanagementPanel.class).get("pass", "").equals(pass.getText())){
//do nothing with password
} else {
try {
String passwordMD5 = null;
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] tmp = pass.getText().getBytes();
md5.update(tmp);
passwordMD5 = byteArrToString(md5.digest());
NbPreferences.forModule(UsermanagementPanel.class).put("pass", passwordMD5);
} catch (NoSuchAlgorithmException ex) {
Exceptions.printStackTrace(ex);
}
}
}
private static String byteArrToString(byte[] b){
String res = null;
StringBuffer sb = new StringBuffer(b.length * 2);
for (int i = 0; i < b.length; i++){
int j = b[i] & 0xff;
if (j < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(j));
}
res = sb.toString();
return res.toUpperCase();
}</pre>
Your entered password will now be created as a MD5-hash. The second method creates a proper string representation and it is needed to avoid non-printable characters.
<p>&nbsp;</p>
<h3><span class="tutorial"><a name="poss" id="optionpanel3"></a>Other Possibilities</span></h3>
<p>In this section we will show you the encryption of your password with the SHA-1 algorithm.</p>
<p>&nbsp;</p>
<p>Another possibility is to use the SHA-1 instead of the MD5. SHA-1 (secure hash algorithm) was decrypted in 2006 but for our purpose it is safe enough. You just have to do some little changes on the MD5 code shown above. </p>
<pre class="examplecode">void store() {
NbPreferences.forModule(UsermanagementPanel.class).put("user", user.getText());
if(NbPreferences.forModule(UsermanagementPanel.class).get("pass", "").equals(pass.getText())){
//do nothing with password
} else {
try {
String passwordSHA = null;
MessageDigest sha = MessageDigest.getInstance("SHA-1");
byte[] tmp = pass.getText().getBytes();
sha.update(tmp);
passwordMD5 = byteArrToString(sha.digest());
NbPreferences.forModule(UsermanagementPanel.class).put("pass", passwordMD5);
} catch (NoSuchAlgorithmException ex) {
Exceptions.printStackTrace(ex);
}
}
}</pre>
<p>The only real change is to use the java <tt>MessageDigist</tt> to create an instance of a SHA-1 instead of a MD5.</p>
<p>To secure the application a little bit you should save your usernames and passwords somewhere else than in a preferences file. Maybe a database or a file on a safe server will be a better way.</p>
<h2><a name="login" id="login"></a>Creating The Login Module </h2>
<p>Now we are ready to start with the actual login module.</p>
<ol>
<li>First we have to create a new module again, by right-clicking on the 'Modules' folder in the Module Suite. Choose 'Add new...'.</li>
<li>Give the new module a name like 'Login' and click Next.</li>
<li>Change the 'Code Base Name' if it is needed. Click Finish.</li>
<li>When the new module is located in the Projects window, right-click on the 'Source Packages' and choose 'New' &gt; 'Other...'.</li>
<li>In the appearing wizard select 'Module Development' as a category and then 'Module Installer' as file-type. Click Next. </li>
<li>Now you see again which files are changed or created. Click Finish.</li>
</ol>
<p>Now your Projects window should look as follows:<br />
<p><img border="1" src="../../images/tutorials/login/7_loo.png" width="250" height="222" border="1" alt="System Properties module.">
<p>If you open the <tt>Installer.java</tt> you should see this:<br />
<pre>package org.yourorghere.login;
import org.openide.modules.ModuleInstall;
/**
* Manages a module's lifecycle. Remember that an installer is optional and
* often not needed at all.
*/
public class Installer extends ModuleInstall {
@Override
public void restored() {
// By default, do nothing.
// Put your startup code here.
}
}</pre>
</p>
<p>The code that we will write in the <tt>restored()</tt>
method will be called before the application starts. So we will use this to show our login form. But this form has to be created first.</p>
<ol>
<li>Right-click the 'Source Packages' and choose 'New' &gt; 'Other...'.</li>
<li>Select 'Swing GUI Forms' as category and 'JPanel Form' as filetype. Click Next.</li>
<li>Give the form a name like 'LoginFrame' and select the correct package. Click Finish.</li>
<li>If it has not been opened yet, open the LoginFrame and go to the Design-View.</li>
<li>Get two labels, a textfield and a password field.</li>
<li>Name the labels 'Username' and 'Password', delete the text in the fields and rename the variables of the fields to 'user' and 'pass'.</li>
</ol>
<p><img border="1" src="../../images/tutorials/login/8_log.png" border="1" alt="System Properties module.">
<p>Now we can call our <tt>LoginForm</tt> in the <tt>Installer.java</tt>. Go to the Installer.java and add a private field <tt>LoginForm form = new LoginForm()</tt>.</p>
<p>Now we have to call something in the <tt>restored()</tt>method. For our login dialog we will use the <tt>NotifyDescriptor</tt> from the NetBeans API.</p>
<ol>
<li>Add the following code to the <tt>restored()</tt> method in the Installer.java:<br />
<pre>NotifyDescriptor nd = new NotifyDescriptor.Message("Ok");
DialogDisplayer.getDefault().notifyLater(nd);
</pre>
And then fix the imports.</li>
<li>But you will see that the import cannot be fixed. The reason for this is that we must add the specific packages to our project. Right-click the 'Login' module name and choose 'Properties'.</li>
<li>Go to the 'Libraries' category and click 'Add Dependency...'.</li>
<li>In the filter textfield write 'notify'.</li>
<li>Now you will see that there is a 'Dialogs API'. Select it and click OK.</li>
<li>Close the 'Properties' window by clicking OK.</li>
<li>Now try to fix the imports again and you will see that it works.</li>
</ol>
<p>When you start the application you will see that there is a dialog with an 'OK' button in it. This will be the dialog where we will call our LoginForm.<br />
To create a better structure we will create a new method that will be called in the <tt>restored()</tt> method.</p>
<p>We do not want to have a simple dialog, but a diaolg with an 'OK' and a 'Cancel' button. For this purpose we will use the Confirmation method instead of the Message method of the NotifyDescriptor. The changed class Installer should look like this:<br />
<pre>/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.yourorghere.login;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.modules.ModuleInstall;
/**
* Manages a module's lifecycle. Remember that an installer is optional and
* often not needed at all.
*/
public class Installer extends ModuleInstall {
private LoginForm form = new LoginForm();
@Override
public void restored() {
createLoginDialog();
}
private void createLoginDialog(){
NotifyDescriptor nd = new NotifyDescriptor.Confirmation(form, "Login");
DialogDisplayer.getDefault().notifyLater(nd);
}
}
</pre>
</p>
<p>There you see that our 'LoginForm' form is given to the <tt>NotifyDescriptor.Confirmation()</tt> method as a parameter. The second parameter is the title of the dialog window.
If we now look at our created login panel we will see that the NotifyDescriptor has created some buttons for us. That is great but these are not the buttons we actually want.</p>
<p><img border="1" src="../../images/tutorials/login/9_but.png" width="300" height="189" border="1" alt="System Properties module.">
<p>For a login we only want to have an 'OK' and a 'Cancel' button. So we have to create them. This time we cannot use the graphical designer, so we have to code it ourselves which is not as difficult as it maybe sounds. You only have to change our <tt>createLoginDialog()</tt> method.</p>
<pre>private void createLoginDialog(){
JButton ok = new JButton();
ok.setText("OK");
JButton cancel = new JButton();
cancel.setText("Cancel");
cancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//close whole application
}
});
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//authenicate username and password
}
});
NotifyDescriptor nd = new NotifyDescriptor.Confirmation(form, "Login");
nd.setOptions(new Object[]{ok, cancel});
DialogDisplayer.getDefault().notifyLater(nd);
}</pre>
<p>These new changes will create two new buttons and the <tt>setOptions()</tt> method will add them to our NotifyDescriptor. Of course, these buttons do actually nothing. The 'Cancel' button should close the whole application. So we will write an <tt>exit()</tt> method that is called in the <tt>actionPerformed()</tt> method.</p>
<pre>private void exit(){
LifecycleManager.getDefault().exit();
}</pre>
<p>This method will close the application immediately. So when you look at your application closely you will see that we have three buttons. The 'x' is also a button and closes the dialog window, but not the whole application. So we have to listen to an action that closes this dialog. We will do this if we add the following code to our <tt>createLoginDialog()</tt> method. </p>
<pre>nd.addPropertyChangeListener(new PropertyChangeListener(){
public void propertyChange(PropertyChangeEvent evt){
if(NotifyDescriptor.CLOSED_OPTION.equals(evt.getNewValue())){
exit();
}
}
});</pre>
<p>This listener will close the whole application if the dialog is closed in another way than with the 'Cancel' or the 'OK' button.</p>
<p>Now we have to deal with our 'OK' button and what to happen when clicking on it. We will create a new method that we will call <tt>authenticate()</tt>. In this method we need to compare our given passwords and usernames of the formular and the ones of the options panel. For this purpose we will call the <tt>authenticate()</tt> method with two parameters, namely the username and the password of our LoginForm. If we want to do so we need to alter the LoginForm.java and add two getters for the values of the textfields. In this term we must not forget that we need a MD5 compatible form (of course, only when you have added a security mechanism). But our getters should only return a normal string for the username and a char-array from the password field.</p>
<pre>public String getUsername(){
return this.user.getText();
}
public char[] getPassword(){
return this.pass.getPassword();
}</pre>
<p>As mentioned before we now have to create a method called <tt>authenticate()</tt> where we compare usernames and passwords.</p>
<pre>private void authenticate(){<br /> if(NbPreferences.forModule(UsermanagementPanel.class).get(&quot;user&quot;, &quot;&quot;).equals(this.form.getUsername())){<br /> try {<br /> char[] passwordFromForm = null;<br /> char[] passwordFromPref = NbPreferences.forModule(UsermanagementPanel.class).get(&quot;pass&quot;, &quot;&quot;).toCharArray();<br /> <br /> String passwordPref = new String(this.form.getPassword());<br /> MessageDigest <span class="examplecode">md5</span> = MessageDigest.getInstance(&quot;MD5&quot;);<br /> byte[] tmp = passwordPref.getBytes();<br /> <span class="examplecode">md5</span>.update(tmp);<br /> passwordFromForm = byteArrToString(<span class="examplecode">md5</span>.digest()).toCharArray();<br /> int correctCount = 0;<br /> if(passwordFromForm.length != passwordFromPref.length){<br /> exit();<br /> }<br /> for (int i = 0; i &lt; passwordFromPref.length; i++) {<br /> if (passwordFromPref[i] == passwordFromForm[i]) { <br /> correctCount++;<br /> }<br /> }<br /> if (passwordFromPref.length == correctCount) {<br /> //do nothing here<br /> } else {<br /> exit();<br /> }<br /> } catch (NoSuchAlgorithmException ex) {<br /> Exceptions.printStackTrace(ex);<br /> }<br /> } else {<br /> exit();<br /> }<br />}</pre>
<p>In this method the usernames are compared at first. If the username is wrong the password will not be checked at all. If the username is correct then the password will be compared character by character. But at first it has to be converted in a MD5 hash. This works exactly like in the <tt>UsermanagementPanel.java</tt>. We also need the <tt>byteArrToString()</tt> method in this class we have created above.</p>
<p>A problem that might occurs is that the Preference file cannot be read. To get the file access follow these steps.</p>
<ol>
<li>Right-click our 'UserManagement' module and select 'Properties'.</li>
<li>Choose 'API-Versioning' as category.</li>
<li>Select our usermanagement-package as 'Punlic Package'. Click OK.</li>
<li>Right-click the 'Login' module and select 'Properties'.</li>
<li>Choose 'Libraries' as category.</li>
<li>Click 'Add dependency...'.</li>
<li>Search in the filter for 'usermanagement'.</li>
<li>If you find it, select our 'UserManagement' module and click OK.</li>
<li>Click OK.</li>
<li>Open the <tt>UsermanagementPanel.java</tt> and alter the class definition by adding 'public' before the 'final' keyword.</li>
</ol>
<p>Now you should be able to get the correct imports.</p>
<p>If you run the application it should work with your given password.</p>
<h2><a name="code" id="code"></a>All The Code At Once</h2>
<p>&nbsp;</p>
<h3><a name="user" id="user"></a>UsermanagementPanel.java</h3>
<p>In the <tt>UsermanagementPanel.java</tt> we create a panel in the options dialog of the NetBeans Platform to manage our username and password. Most of the code is created by the NetBeans IDE.</p>
<pre>package org.yourorghere.usermanagement;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.openide.util.Exceptions;
import org.openide.util.NbPreferences;
public final class UsermanagementPanel extends javax.swing.JPanel {
private final UsermanagementOptionsPanelController controller;
UsermanagementPanel(UsermanagementOptionsPanelController controller) {
this.controller = controller;
initComponents();
// TODO listen to changes in form fields and call controller.changed()
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/ <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
user = new javax.swing.JTextField();
pass = new javax.swing.JTextField();
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, "Username");
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, "Password");
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(21, 21, 21)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
.add(jLabel2)
.add(jLabel1))
.add(18, 18, 18)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(pass, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 157, Short.MAX_VALUE)
.add(user, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 157, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.addContainerGap()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(jLabel1)
.add(user, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(18, 18, 18)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(jLabel2)
.add(pass, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addContainerGap(35, Short.MAX_VALUE))
);
}// </editor-fold>
void load() {
user.setText(NbPreferences.forModule(UsermanagementPanel.class).get("user", ""));
pass.setText(NbPreferences.forModule(UsermanagementPanel.class).get("pass", ""));
}
private static String byteArrToString(byte[] b){
String res = null;
StringBuffer sb = new StringBuffer(b.length * 2);
for (int i = 0; i < b.length; i++){
int j = b[i] & 0xff;
if (j < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(j));
}
res = sb.toString();
return res.toUpperCase();
}
void store() {
NbPreferences.forModule(UsermanagementPanel.class).put("user", user.getText());
if(NbPreferences.forModule(UsermanagementPanel.class).get("pass", "").equals(pass.getText())){
//do nothing with password
} else {
try {
String passwordMD5 = null;
MessageDigest <span class="examplecode">md5</span> = MessageDigest.getInstance("MD5");
byte[] tmp = pass.getText().getBytes();
<span class="examplecode">md5</span>.update(tmp);
passwordMD5 = byteArrToString(<span class="examplecode">md5</span>.digest());
NbPreferences.forModule(UsermanagementPanel.class).put("pass", passwordMD5);
} catch (NoSuchAlgorithmException ex) {
Exceptions.printStackTrace(ex);
}
}
}
boolean valid() {
// TODO check whether form is consistent and complete
return true;
}
// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JTextField pass;
private javax.swing.JTextField user;
// End of variables declaration
}
</pre>
<h3><a name="loginform" id="loginform"></a>LoginForm.java</h3>
<p>The <tt>LoginForm.java</tt> creates a dialog in which the password and username can be entered to start your application. This class is also quickly created when you use the tools of the NetBeans IDE.</p>
<pre>/*
* LoginForm.java
*
* Created on 03. Dezember 2007, 21:39
*/
package org.yourorghere.login;
/**
*
* @author Christof and Sabine
*/
public class LoginForm extends javax.swing.JPanel {
/** Creates new form LoginForm */
public LoginForm() {
initComponents();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
user = new javax.swing.JTextField();
pass = new javax.swing.JPasswordField();
jLabel1.setText(org.openide.util.NbBundle.getMessage(LoginForm.class, "LoginForm.jLabel1.text")); // NOI18N
jLabel2.setText(org.openide.util.NbBundle.getMessage(LoginForm.class, "LoginForm.jLabel2.text")); // NOI18N
user.setText(org.openide.util.NbBundle.getMessage(LoginForm.class, "LoginForm.user.text")); // NOI18N
pass.setText(org.openide.util.NbBundle.getMessage(LoginForm.class, "LoginForm.pass.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2)
.addComponent(jLabel1))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(pass)
.addComponent(user, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE))
.addContainerGap(31, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(user, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel2)
.addComponent(pass, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(30, Short.MAX_VALUE))
);
}// </editor-fold>
public String getUsername(){
return this.user.getText();
}
public char[] getPassword(){
return this.pass.getPassword();
}
// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JPasswordField pass;
private javax.swing.JTextField user;
// End of variables declaration
}
</pre>
<h3><a name="installer" id="installer"></a>Installer.java</h3>
<p>This class starts the <tt>LoginPanel.java</tt> and handels the response to this dialog. It also takes care about the authentication.</p>
<pre>/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.yourorghere.login;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.swing.JButton;
import org.openide.DialogDisplayer;
import org.openide.LifecycleManager;
import org.openide.NotifyDescriptor;
import org.openide.modules.ModuleInstall;
import org.openide.util.Exceptions;
import org.openide.util.NbPreferences;
import org.yourorghere.usermanagement.UsermanagementPanel;
/**
* Manages a module's lifecycle. Remember that an installer is optional and
* often not needed at all.
*/
public class Installer extends ModuleInstall {
private LoginForm form = new LoginForm();
@Override
public void restored() {
createLoginDialog();
}
private void createLoginDialog(){
JButton ok = new JButton();
ok.setText("OK");
JButton cancel = new JButton();
cancel.setText("Cancel");
cancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
exit();
}
});
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
authenticate();
}
});
NotifyDescriptor nd = new NotifyDescriptor.Confirmation(form, "Login");
nd.setOptions(new Object[]{ok, cancel});
DialogDisplayer.getDefault().notifyLater(nd);
nd.addPropertyChangeListener(new PropertyChangeListener(){
public void propertyChange(PropertyChangeEvent evt){
if(NotifyDescriptor.CLOSED_OPTION.equals(evt.getNewValue())){
exit();
}
}
});
}
private void authenticate(){
if(NbPreferences.forModule(UsermanagementPanel.class).get("user", "").equals(this.form.getUsername())){
try {
char[] passwordFromForm = null;
char[] passwordFromPref = NbPreferences.forModule(UsermanagementPanel.class).get("pass", "").toCharArray();
String passwordPref = new String(this.form.getPassword());
MessageDigest MD5 = MessageDigest.getInstance("MD5");
byte[] tmp = passwordPref.getBytes();
MD5.update(tmp);
passwordFromForm = byteArrToString(MD5.digest()).toCharArray();
int correctCount = 0;
if(passwordFromForm.length != passwordFromPref.length){
exit();
}
for (int i = 0; i < passwordFromPref.length; i++) {
if (passwordFromPref[i] == passwordFromForm[i]) {
correctCount++;
}
}
if (passwordFromPref.length == correctCount) {
//do nothing here
} else {
exit();
}
} catch (NoSuchAlgorithmException ex) {
Exceptions.printStackTrace(ex);
}
} else {
exit();
}
}
private static String byteArrToString(byte[] b){
String res = null;
StringBuffer sb = new StringBuffer(b.length * 2);
for (int i = 0; i < b.length; i++){
int j = b[i] & 0xff;
if (j < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(j));
}
res = sb.toString();
return res.toUpperCase();
}
final private void exit(){
LifecycleManager.getDefault().exit();
}
}
</pre>
<p><div class="feedback-box"><a href="https://netbeans.org/about/contact_form.html?to=3&amp;subject=Feedback: Login Tutorial Tutorial">Send Us Your Feedback</a><br style="clear:both;" />
<!-- ======================================================================================== -->
</div>
<h2><a name="nextsteps"></a>Next Steps</h2>
<p>For more information about creating and developing NetBeans modules, see the following resources:
<ul>
<li><a href="https://netbeans.org/kb/trails/platform.html">Other Related Tutorials</a></li>
<li><a href="https://netbeans.org/download/dev/javadoc/">NetBeans API Javadoc</a></li>
</ul>
<hr>
<!-- ======================================================================================== -->
<h2><a name="version"></a>Versioning </h2>
<p>Christof Höll, Sabine Weiss; Johannes Kepler University Linz, Austria
<table width="76%" border="1">
<tbody>
<tr>
<td>
<div align="left"><b>Version</b></div> </td>
<td>
<div align="left"><b>Date</b></div> </td>
<td>
<div align="left"><b>Changes</b></div></td>
<td>
<div align="left"><b>Open Issues</b></div> </td>
</tr>
<tr>
<td>
1 </td>
<td>
05 January 2008 </td>
<td>
Initial version </td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
</body>
</html>