From 77a0649b7fd517a4f5e419c613f7bf42291e7b76 Mon Sep 17 00:00:00 2001 From: Martin Goik <goik@hdm-stuttgart.de> Date: Thu, 15 Jan 2015 11:59:16 +0100 Subject: [PATCH] Additional sub sections for exercises --- Sda1/sda1.xml | 836 +++++++++++++++++++++++++------------------------- 1 file changed, 424 insertions(+), 412 deletions(-) diff --git a/Sda1/sda1.xml b/Sda1/sda1.xml index 0941356b0..dcaf0057a 100644 --- a/Sda1/sda1.xml +++ b/Sda1/sda1.xml @@ -11415,292 +11415,304 @@ public class SimpleRead { </callout> </calloutlist> - <qandaset defaultlabel="qanda" xml:id="quandaentry_JdbcTypeConversion"> + <para>We now present a series of exercises thereby exploring important + aspects of <xref linkend="glo_JDBC"/> read access.</para> + + <section xml:id="sectGetterTypeConversion"> <title>Getter methods and type conversion</title> - <qandadiv> - <qandaentry> - <question> - <para>Apart from type mappings the <trademark - xlink:href="http://electronics.zibb.com/trademark/jdbc/29545026">JDBC</trademark> - access methods like <link - xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getString(int)">getString()</link> - may also be used for type conversion. Modify <xref - linkend="listingJdbcRead"/> by:</para> + <qandaset defaultlabel="qanda" + xml:id="quandaentry_JdbcTypeConversion"> + <qandadiv> + <qandaentry> + <question> + <para>Apart from type mappings the <xref + linkend="glo_JDBC"/> access methods like <link + xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getString(int)">getString()</link> + may also be used for type conversion. Modify <xref + linkend="listingJdbcRead"/> by:</para> - <itemizedlist> - <listitem> - <para>Read the database attribute <code>id</code> by <link - xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getString(java.lang.String)">getString(String)</link>.</para> - </listitem> + <itemizedlist> + <listitem> + <para>Read the database attribute <code>id</code> by + <link + xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getString(java.lang.String)">getString(String)</link>.</para> + </listitem> - <listitem> - <para>Read the database attribute nickname by <link - xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getInt(java.lang.String)">getInt(String)</link>.</para> - </listitem> - </itemizedlist> + <listitem> + <para>Read the database attribute nickname by <link + xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getInt(java.lang.String)">getInt(String)</link>.</para> + </listitem> + </itemizedlist> - <para>What do you observe?</para> - </question> + <para>What do you observe?</para> + </question> - <answer> - <para>Modifying our iteration loop:</para> + <answer> + <para>Modifying our iteration loop:</para> - <programlisting language="none">// Step 4: Dataset iteration + <programlisting language="none">// Step 4: Dataset iteration while (data.next()) { System.out.println(data.<emphasis role="bold">getString</emphasis>("id") <co - linkends="jdbcReadWrongType-1" - xml:id="jdbcReadWrongType-1-co"/> + linkends="jdbcReadWrongType-1" + xml:id="jdbcReadWrongType-1-co"/> + ", " + data.<emphasis role="bold">getInt</emphasis>("nickname") <co - linkends="jdbcReadWrongType-2" - xml:id="jdbcReadWrongType-2-co"/> + linkends="jdbcReadWrongType-2" + xml:id="jdbcReadWrongType-2-co"/> + ", " + data.getString("birthdate")); }</programlisting> - <para>We observe:</para> + <para>We observe:</para> - <calloutlist> - <callout arearefs="jdbcReadWrongType-1-co" - xml:id="jdbcReadWrongType-1"> - <para>Calling <link - xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getString(int)">getString()</link> - for a database attribute of type INTEGER does not cause - any trouble: The value gets silently converted to a string - value.</para> - </callout> + <calloutlist> + <callout arearefs="jdbcReadWrongType-1-co" + xml:id="jdbcReadWrongType-1"> + <para>Calling <link + xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getString(int)">getString()</link> + for a database attribute of type INTEGER does not cause + any trouble: The value gets silently converted to a + string value.</para> + </callout> - <callout arearefs="jdbcReadWrongType-2-co" - xml:id="jdbcReadWrongType-2"> - <para>Calling <link - xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getInt(java.lang.String)">getInt(String)</link> - for the database field of type CHAR yields an (expected) - Exception:</para> - </callout> - </calloutlist> + <callout arearefs="jdbcReadWrongType-2-co" + xml:id="jdbcReadWrongType-2"> + <para>Calling <link + xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getInt(java.lang.String)">getInt(String)</link> + for the database field of type CHAR yields an (expected) + Exception:</para> + </callout> + </calloutlist> - <programlisting language="none">Exception in thread "main" java.sql.SQLException: Invalid value for getInt() - 'Jim' + <programlisting language="none">Exception in thread "main" java.sql.SQLException: Invalid value for getInt() - 'Jim' at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073) ...</programlisting> - <para>We may however provide <quote>compatible</quote> data - records:</para> + <para>We may however provide <quote>compatible</quote> data + records:</para> - <programlisting language="none">DELETE FROM Friends; + <programlisting language="none">DELETE FROM Friends; INSERT INTO Friends VALUES (1, <emphasis role="bold">'31'</emphasis>, '1991-10-10');</programlisting> - <para>This time our application executes perfectly - well:</para> + <para>This time our application executes perfectly + well:</para> - <programlisting language="none">1, 31, 1991-10-10</programlisting> + <programlisting language="none">1, 31, 1991-10-10</programlisting> - <para>Conclusion: The <trademark - xlink:href="http://electronics.zibb.com/trademark/jdbc/29545026">JDBC</trademark> - driver performs a conversion from a string type to an integer - similar like the <link - xlink:href="http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#parseInt(java.lang.String)">parseInt(String)</link> - method.</para> - - <para>The next series of exercises aims on a more powerful - implementation of our person data insertion application in - <xref linkend="exerciseInsertLoginCredentials"/>.</para> - </answer> - </qandaentry> - </qandadiv> - </qandaset> + <para>Conclusion: The <xref linkend="glo_JDBC"/> driver + performs a conversion from a string type to an integer + similar like the <link + xlink:href="http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#parseInt(java.lang.String)">parseInt(String)</link> + method.</para> + + <para>The next series of exercises aims on a more powerful + implementation of our person data insertion application in + <xref linkend="exerciseInsertLoginCredentials"/>.</para> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + </section> - <qandaset defaultlabel="qanda" xml:id="quandaentry_HandlingNull"> + <section xml:id="sectHandlingNullValues"> <title>Handling NULL values.</title> - <qandadiv> - <qandaentry> - <question> - <para>The attribute <code>birthday</code> in our database - table Friends allows <code>NULL</code> values:</para> + <qandaset defaultlabel="qanda" xml:id="quandaentry_HandlingNull"> + <qandadiv> + <qandaentry> + <question> + <para>The attribute <code>birthday</code> in our database + table Friends allows <code>NULL</code> values:</para> - <programlisting language="none">INSERT INTO Friends VALUES + <programlisting language="none">INSERT INTO Friends VALUES (1, 'Jim', '1991-10-10') ,(2, <emphasis role="bold"> NULL</emphasis>, '2003-5-24') ,(3, 'Mick', '2001-12-30');</programlisting> - <para>Starting our current application yields:</para> + <para>Starting our current application yields:</para> - <programlisting language="none">1, Jim, 1991-10-10 + <programlisting language="none">1, Jim, 1991-10-10 2, null, 2003-05-24 3, Mick, 2001-12-30</programlisting> - <para>This might be confuses with a person having the nickname - <quote>null</quote>. Instead we would like to have:</para> + <para>This might be confuses with a person having the + nickname <quote>null</quote>. Instead we would like to + have:</para> - <programlisting language="none">1, Jim, 1991-10-10 + <programlisting language="none">1, Jim, 1991-10-10 2, -Name unknown- , 2003-05-24 3, Mick, 2001-12-30</programlisting> - <para>Extend the current code of - <classname>sda.jdbc.intro.SimpleRead</classname> to produce - the above result in case of nickname <code>NULL</code> - values.</para> + <para>Extend the current code of + <classname>sda.jdbc.intro.SimpleRead</classname> to produce + the above result in case of nickname <code>NULL</code> + values.</para> - <para>Hint: Read the documentation of <link - xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#wasNull()">wasNull()</link>.</para> - </question> + <para>Hint: Read the documentation of <link + xlink:href="http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#wasNull()">wasNull()</link>.</para> + </question> - <answer> - <para>A possible implementation is being given in - <classname>sda.jdbc.intro.v1.SimpleRead</classname>.</para> - </answer> - </qandaentry> - </qandadiv> - </qandaset> + <answer> + <para>A possible implementation is being given in + <classname>sda.jdbc.intro.v1.SimpleRead</classname>.</para> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + </section> - <qandaset defaultlabel="qanda" xml:id="exerciseInsecureAuth"> + <section xml:id="sectUserAuthStrategy"> <title>A user authentication <quote>strategy</quote></title> - <qandadiv> - <qandaentry> - <question> - <para>Our current application for entering <code>Person</code> - records lacks authentication: A user simply connects to the - database using credentials being hard coded in a properties - file. A programmer suggests to implement authentication based - on the following extension of the <code>Person</code> - table:</para> - - <programlisting language="none">CREATE TABLE Person ( + <qandaset defaultlabel="qanda" xml:id="exerciseInsecureAuth"> + <qandadiv> + <qandaentry> + <question> + <para>Our current application for entering + <code>Person</code> records lacks authentication: A user + simply connects to the database using credentials being hard + coded in a properties file. A programmer suggests to + implement authentication based on the following extension of + the <code>Person</code> table:</para> + + <programlisting language="none">CREATE TABLE Person ( name char(80) NOT NULL ,email CHAR(20) NOT NULL UNIQUE ,login CHAR(10) UNIQUE -- login names must be unique -- ,password CHAR(20) );</programlisting> - <para>On clicking <quote>Connect</quote> a user may enter his - login name and password, <quote>fred</quote> and - <quote>12345678</quote> in the following example:</para> + <para>On clicking <quote>Connect</quote> a user may enter + his login name and password, <quote>fred</quote> and + <quote>12345678</quote> in the following example:</para> - <figure xml:id="figLogin"> - <title>Login credentials for database connection</title> + <figure xml:id="figLogin"> + <title>Login credentials for database connection</title> - <mediaobject> - <imageobject> - <imagedata fileref="Ref/Screen/login.screen.png" - scale="90"/> - </imageobject> - </mediaobject> - </figure> + <mediaobject> + <imageobject> + <imagedata fileref="Ref/Screen/login.screen.png" + scale="90"/> + </imageobject> + </mediaobject> + </figure> - <para>Based on these input values the following SQL query is - being executed by a <classname>java.sql.Statement</classname> - object:</para> + <para>Based on these input values the following SQL query is + being executed by a + <classname>java.sql.Statement</classname> object:</para> - <programlisting language="none">SELECT * FROM Person WHERE login='<emphasis - role="bold">fred</emphasis>' and password = '<emphasis - role="bold">12345678</emphasis>'</programlisting> + <programlisting language="none">SELECT * FROM Person WHERE login='<emphasis + role="bold">fred</emphasis>' and password = '<emphasis + role="bold">12345678</emphasis>'</programlisting> - <para>Since the login attribute is UNIQUE we are sure to - receive either 0 or 1 dataset. Our programmer proposes to - grant login if the query returns at least one dataset.</para> + <para>Since the login attribute is UNIQUE we are sure to + receive either 0 or 1 dataset. Our programmer proposes to + grant login if the query returns at least one + dataset.</para> - <para>Discuss this implementation sketch with a colleague. Do - you think this is a sensible approach? <emphasis - role="bold">Write down</emphasis> your results.</para> - </question> + <para>Discuss this implementation sketch with a colleague. + Do you think this is a sensible approach? <emphasis + role="bold">Write down</emphasis> your results.</para> + </question> - <answer> - <para>The approach is essentially unusable due to severe - security implications. Since it is based on - <classname>java.sql.Statement</classname> rater than on - <classname>java.sql.PreparedStatement</classname> objects it - is vulnerable to SQL injection attacks. A user my enter the - following password value in the GUI:</para> - - <programlisting language="none">sd' OR '1' = '1</programlisting> - - <para>Based on the login name <quote>fred</quote> the - following SQL string is being crafted:</para> - - <programlisting language="none">SELECT * FROM Person WHERE login='fred' and password = 'sd' OR <emphasis - role="bold">'1' = '1'</emphasis>;</programlisting> - - <para>Since the WHERE clause's last component always evaluates - to true, all objects from the <code>Person</code> relation are - returned thus permitting login.</para> - - <para>The implementation approach suffers from a second - deficiency: The passwords are stored in clear text. If an - attacker gains access to the <code>Person</code> table he'll - immediately retrieve the passwords of all users. This problem - can be solved by storing hash values of passwords rather than - the clear text values themselves.</para> - </answer> - </qandaentry> - </qandadiv> - </qandaset> + <answer> + <para>The approach is essentially unusable due to severe + security implications. Since it is based on + <classname>java.sql.Statement</classname> rater than on + <classname>java.sql.PreparedStatement</classname> objects it + is vulnerable to SQL injection attacks. A user my enter the + following password value in the GUI:</para> + + <programlisting language="none">sd' OR '1' = '1</programlisting> + + <para>Based on the login name <quote>fred</quote> the + following SQL string is being crafted:</para> + + <programlisting language="none">SELECT * FROM Person WHERE login='fred' and password = 'sd' OR <emphasis + role="bold">'1' = '1'</emphasis>;</programlisting> + + <para>Since the WHERE clause's last component always + evaluates to true, all objects from the <code>Person</code> + relation are returned thus permitting login.</para> + + <para>The implementation approach suffers from a second + deficiency: The passwords are stored in clear text. If an + attacker gains access to the <code>Person</code> table he'll + immediately retrieve the passwords of all users. This + problem can be solved by storing hash values of passwords + rather than the clear text values themselves.</para> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + </section> - <qandaset defaultlabel="qanda" xml:id="exerciseHashTraining"> + <section xml:id="sectPasswordsHashed"> <title>Passwords and hash values</title> - <qandadiv> - <qandaentry> - <question> - <para>In exercise <xref linkend="exerciseInsecureAuth"/> we - discarded the idea of clear text passwords in favour of - password hashes. In order to avoid Rainbow cracking so called - salted hashes are superior. You should read <uri - xlink:href="https://www.heckrothindustries.co.uk/articles/an-introduction-to-password-hashes">https://www.heckrothindustries.co.uk/articles/an-introduction-to-password-hashes</uri> - for overview purposes. The article contains further references - on the bottom of the page.</para> - - <para>With respect to an implementation <uri - xlink:href="http://stackoverflow.com/questions/2860943/suggestions-for-library-to-hash-passwords-in-java#11038230">http://stackoverflow.com/questions/2860943/suggestions-for-library-to-hash-passwords-in-java</uri> - provides a simple example for:</para> + <qandaset defaultlabel="qanda" xml:id="exerciseHashTraining"> + <qandadiv> + <qandaentry> + <question> + <para>In exercise <xref linkend="exerciseInsecureAuth"/> we + discarded the idea of clear text passwords in favour of + password hashes. In order to avoid Rainbow cracking so + called salted hashes are superior. You should read <uri + xlink:href="https://www.heckrothindustries.co.uk/articles/an-introduction-to-password-hashes">https://www.heckrothindustries.co.uk/articles/an-introduction-to-password-hashes</uri> + for overview purposes. The article contains further + references on the bottom of the page.</para> + + <para>With respect to an implementation <uri + xlink:href="http://stackoverflow.com/questions/2860943/suggestions-for-library-to-hash-passwords-in-java#11038230">http://stackoverflow.com/questions/2860943/suggestions-for-library-to-hash-passwords-in-java</uri> + provides a simple example for:</para> - <itemizedlist> - <listitem> - <para>Creating a salted hash from a given password - string.</para> - </listitem> + <itemizedlist> + <listitem> + <para>Creating a salted hash from a given password + string.</para> + </listitem> - <listitem> - <para>Verify if a hash string matches a given clear text - password.</para> - </listitem> - </itemizedlist> + <listitem> + <para>Verify if a hash string matches a given clear text + password.</para> + </listitem> + </itemizedlist> - <para>The example uses an external library. On <productname - xlink:href="http://www.ubuntu.com">Ubuntu</productname> Linux - this may be installed by issuing <command>aptitude</command> - <option>install</option> - <option>libcommons-codec-java</option>. On successful install - the file - <filename>/usr/share/java/commons-codec-1.5.jar</filename> may - be appended to your <envar>CLASSPATH</envar>.</para> - - <para>You may as well use <uri - xlink:href="http://crackstation.net/hashing-security.htm#javasourcecode">http://crackstation.net/hashing-security.htm#javasourcecode</uri> - as a starting point. This example works standalone without - needing an external library. Note: Tis example produces - different (incompatible) hash values.</para> - - <para>Create a simple main() method to experiment with the two - class methods.</para> - </question> + <para>The example uses an external library. On <productname + xlink:href="http://www.ubuntu.com">Ubuntu</productname> + Linux this may be installed by issuing + <command>aptitude</command> <option>install</option> + <option>libcommons-codec-java</option>. On successful + install the file + <filename>/usr/share/java/commons-codec-1.5.jar</filename> + may be appended to your <envar>CLASSPATH</envar>.</para> + + <para>You may as well use <uri + xlink:href="http://crackstation.net/hashing-security.htm#javasourcecode">http://crackstation.net/hashing-security.htm#javasourcecode</uri> + as a starting point. This example works standalone without + needing an external library. Note: Tis example produces + different (incompatible) hash values.</para> + + <para>Create a simple main() method to experiment with the + two class methods.</para> + </question> - <answer> - <para>Starting from <uri - xlink:href="http://stackoverflow.com/questions/2860943/suggestions-for-library-to-hash-passwords-in-java#11038230">http://stackoverflow.com/questions/2860943/suggestions-for-library-to-hash-passwords-in-java</uri> - we create a slightly modified class - <classname>sda.jdbc.intro.auth.HashProvider</classname> - offering both hash providing <coref - linkend="hashProviderMethod"/> and verifying <coref - linkend="hashVerifyMethod"/> methods:</para> - - <programlisting language="none">package sda.jdbc.intro.auth; + <answer> + <para>Starting from <uri + xlink:href="http://stackoverflow.com/questions/2860943/suggestions-for-library-to-hash-passwords-in-java#11038230">http://stackoverflow.com/questions/2860943/suggestions-for-library-to-hash-passwords-in-java</uri> + we create a slightly modified class + <classname>sda.jdbc.intro.auth.HashProvider</classname> + offering both hash providing <coref + linkend="hashProviderMethod"/> and verifying <coref + linkend="hashVerifyMethod"/> methods:</para> + + <programlisting language="none">package sda.jdbc.intro.auth; ... public class HashProvider { ... /** Computes a salted PBKDF2 hash of given plaintext password suitable for storing in a database. */ public static <emphasis role="bold">String getSaltedHash</emphasis> <co - xml:id="hashProviderMethod"/>(char [] password) { + xml:id="hashProviderMethod"/>(char [] password) { byte[] salt; try { salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen); @@ -11716,7 +11728,7 @@ public class HashProvider { /** Checks whether given plaintext password corresponds to a stored salted hash of the password. */ public static <emphasis role="bold">boolean check</emphasis> <co - xml:id="hashVerifyMethod"/>(char[] password, String stored){ + xml:id="hashVerifyMethod"/>(char[] password, String stored){ String[] saltAndPass = stored.split("\\$"); if (saltAndPass.length != 2) return false; @@ -11725,15 +11737,15 @@ public class HashProvider { } ...}</programlisting> - <para>We may test the two class methods - <methodname>sda.jdbc.intro.auth.HashProvider.getSaltedHash(char[])</methodname>(...) - and - <methodname>sda.jdbc.intro.auth.HashProvider.check(char[],String)</methodname> - by a separate driver class. Notice the <quote>$</quote> sign - <coref linkend="saltPwhashSeparator"/> separating salt and - password hash:</para> + <para>We may test the two class methods + <methodname>sda.jdbc.intro.auth.HashProvider.getSaltedHash(char[])</methodname>(...) + and + <methodname>sda.jdbc.intro.auth.HashProvider.check(char[],String)</methodname> + by a separate driver class. Notice the <quote>$</quote> sign + <coref linkend="saltPwhashSeparator"/> separating salt and + password hash:</para> - <programlisting language="none">package sda.jdbc.intro.auth; + <programlisting language="none">package sda.jdbc.intro.auth; public class TestHashProvider { @@ -11742,109 +11754,112 @@ public class TestHashProvider { final String hash = <emphasis role="bold">HashProvider.getSaltedHash(clearText)</emphasis>; System.out.println("Hash:" + hash); if (HashProvider.check(clearText, <co - xml:id="saltPwhashSeparator"/> + xml:id="saltPwhashSeparator"/> "<emphasis role="bold">HwX2DkuYiwp7xogm3AGndza8DKRVvCMntxRvCrCGFPw=</emphasis>$<emphasis - role="bold">6Ix11yHNB4uPZuF2IQYxVV/MYragJwTDE33OIFR9a24=</emphasis>")) { + role="bold">6Ix11yHNB4uPZuF2IQYxVV/MYragJwTDE33OIFR9a24=</emphasis>")) { System.out.println("hash matches"); } else { System.out.println("hash does not match"); ...</programlisting> - </answer> - </qandaentry> - </qandadiv> - </qandaset> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + </section> - <qandaset defaultlabel="qanda" xml:id="exerciseInsertLoginCredentials"> + <section xml:id="guiAuthenticateTheRealMcCoy"> <title>Gui authentication: The real McCoy</title> - <qandadiv> - <qandaentry> - <question> - <para>We now implement a refined version to enter - <code>Person</code> records based on the solutions of two - related exercises:</para> + <qandaset defaultlabel="qanda" + xml:id="exerciseInsertLoginCredentials"> + <qandadiv> + <qandaentry> + <question> + <para>We now implement a refined version to enter + <code>Person</code> records based on the solutions of two + related exercises:</para> - <glosslist> - <glossentry> - <glossterm><xref - linkend="exercisefilterUserInput"/></glossterm> + <glosslist> + <glossentry> + <glossterm><xref + linkend="exercisefilterUserInput"/></glossterm> - <glossdef> - <para>Avoiding SQL injection by sanitizing user - input</para> - </glossdef> - </glossentry> + <glossdef> + <para>Avoiding SQL injection by sanitizing user + input</para> + </glossdef> + </glossentry> - <glossentry> - <glossterm><xref - linkend="exerciseSqlInjectPrepare"/></glossterm> + <glossentry> + <glossterm><xref + linkend="exerciseSqlInjectPrepare"/></glossterm> - <glossdef> - <para>Avoiding SQL injection by using - <classname>java.sql.PreparedStatement</classname> - objects.</para> - </glossdef> - </glossentry> - </glosslist> + <glossdef> + <para>Avoiding SQL injection by using + <classname>java.sql.PreparedStatement</classname> + objects.</para> + </glossdef> + </glossentry> + </glosslist> - <para>A better solution should combine both techniques. - Non-vulnerability a basic requirement. Checking an E-Mail for - minimal conformance is an added value.</para> + <para>A better solution should combine both techniques. + Non-vulnerability a basic requirement. Checking an E-Mail + for minimal conformance is an added value.</para> - <para>In order to address authentication the relation Person - has to be extended appropriately. The GUI needs two additional - fields for login name and password as well. The following - video demonstrates the intended behaviour:</para> + <para>In order to address authentication the relation Person + has to be extended appropriately. The GUI needs two + additional fields for login name and password as well. The + following video demonstrates the intended behaviour:</para> - <figure xml:id="videoConnectAuth"> - <title>Intended usage behaviour for insertion of data - records.</title> + <figure xml:id="videoConnectAuth"> + <title>Intended usage behaviour for insertion of data + records.</title> - <mediaobject> - <videoobject> - <videodata fileref="Ref/Video/connectauth.mp4"/> - </videoobject> - </mediaobject> - </figure> + <mediaobject> + <videoobject> + <videodata fileref="Ref/Video/connectauth.mp4"/> + </videoobject> + </mediaobject> + </figure> - <para>Don't forget to use password hashes like those from - <xref linkend="exerciseHashTraining"/>. Due to their length - you may want to consider the data type - <code>TEXT</code>.</para> - </question> + <para>Don't forget to use password hashes like those from + <xref linkend="exerciseHashTraining"/>. Due to their length + you may want to consider the data type + <code>TEXT</code>.</para> + </question> - <answer> - <para>In comparison to earlier versions it does make sense to - add some internal container structures. First we note, that - each GUI input field requires:</para> + <answer> + <para>In comparison to earlier versions it does make sense + to add some internal container structures. First we note, + that each GUI input field requires:</para> - <itemizedlist> - <listitem> - <para>A label like <quote>Enter password</quote>.</para> - </listitem> + <itemizedlist> + <listitem> + <para>A label like <quote>Enter password</quote>.</para> + </listitem> - <listitem> - <para>A corresponding field object to hold user entered - input.</para> - </listitem> + <listitem> + <para>A corresponding field object to hold user entered + input.</para> + </listitem> - <listitem> - <para>A validator checking for correctness of entered - data.</para> - </listitem> + <listitem> + <para>A validator checking for correctness of entered + data.</para> + </listitem> - <listitem> - <para>A label or text field for warning messages in case - of invalid user input.</para> - </listitem> - </itemizedlist> + <listitem> + <para>A label or text field for warning messages in case + of invalid user input.</para> + </listitem> + </itemizedlist> - <para>First we start by grouping label <coref - linkend="uiuLabel"/>, input field's verifier <coref - linkend="uiuVerifier"/> and the error message label <coref - linkend="uiuErrmsg"/> in - <classname>sda.jdbc.intro.auth.UserInputUnit</classname>:</para> + <para>First we start by grouping label <coref + linkend="uiuLabel"/>, input field's verifier <coref + linkend="uiuVerifier"/> and the error message label <coref + linkend="uiuErrmsg"/> in + <classname>sda.jdbc.intro.auth.UserInputUnit</classname>:</para> - <programlisting language="none">package sda.jdbc.intro.auth; + <programlisting language="none">package sda.jdbc.intro.auth; ... public class UserInputUnit { @@ -11858,11 +11873,11 @@ public class UserInputUnit { errorMessage = new JLabel(); } ...</programlisting> - <para>The actual GUI text field is being defined <coref - linkend="verfierGuiField"/> in class - <classname>sda.jdbc.intro.auth.InputVerifierNotify</classname>:</para> + <para>The actual GUI text field is being defined <coref + linkend="verfierGuiField"/> in class + <classname>sda.jdbc.intro.auth.InputVerifierNotify</classname>:</para> - <programlisting language="none">package sda.jdbc.intro.auth; + <programlisting language="none">package sda.jdbc.intro.auth; ... public abstract class InputVerifierNotify extends InputVerifier { @@ -11872,40 +11887,41 @@ public abstract class InputVerifierNotify extends InputVerifier { public InputVerifierNotify(final JTextField field, final String errorMessage) { ...</programlisting> - <para>We need two field verifier classes being derived from - <classname>sda.jdbc.intro.auth.InputVerifierNotify</classname>:</para> + <para>We need two field verifier classes being derived from + <classname>sda.jdbc.intro.auth.InputVerifierNotify</classname>:</para> - <glosslist> - <glossentry> - <glossterm><classname>sda.jdbc.intro.auth.RegexpVerifier</classname></glossterm> + <glosslist> + <glossentry> + <glossterm><classname>sda.jdbc.intro.auth.RegexpVerifier</classname></glossterm> - <glossdef> - <para>This one is well known from earlier versions and - is used to validate text input fields by regular - expressions.</para> - </glossdef> - </glossentry> + <glossdef> + <para>This one is well known from earlier versions and + is used to validate text input fields by regular + expressions.</para> + </glossdef> + </glossentry> - <glossentry> - <glossterm><classname>sda.jdbc.intro.auth.InputVerifierNotify</classname></glossterm> + <glossentry> + <glossterm><classname>sda.jdbc.intro.auth.InputVerifierNotify</classname></glossterm> - <glossdef> - <para>This verifier class is responsible for comparing - our two password fields to have identical values.</para> - </glossdef> - </glossentry> - </glosslist> + <glossdef> + <para>This verifier class is responsible for comparing + our two password fields to have identical + values.</para> + </glossdef> + </glossentry> + </glosslist> - <para>All these components get assembled in - <classname>sda.jdbc.intro.auth.InsertPerson</classname>. We - remark some important points:</para> + <para>All these components get assembled in + <classname>sda.jdbc.intro.auth.InsertPerson</classname>. We + remark some important points:</para> - <programlisting language="none">package sda.jdbc.intro.auth; + <programlisting language="none">package sda.jdbc.intro.auth; ... public class InsertPerson extends JFrame { ... // GUI attributes for user input final UserInputUnit name = <co linkends="listingInsertUserAuth-1" - xml:id="listingInsertUserAuth-1-co"/> + xml:id="listingInsertUserAuth-1-co"/> new UserInputUnit( "Name", new RegexpVerifier(new JTextField(15), "^[^;'\"]+$", "No special characters allowed")); @@ -11913,8 +11929,8 @@ public class InsertPerson extends JFrame { // We need a reference to the password field to avoid // casting from JTextField later. private final JPasswordField passwordField = new JPasswordField(10); <co - linkends="listingInsertUserAuth-2" - xml:id="listingInsertUserAuth-2-co"/> + linkends="listingInsertUserAuth-2" + xml:id="listingInsertUserAuth-2-co"/> private final UserInputUnit password = new UserInputUnit( "Password", @@ -11924,11 +11940,11 @@ public class InsertPerson extends JFrame { new UserInputUnit( "repeat pass.", new EqualValueVerifier <co linkends="listingInsertUserAuth-3" - xml:id="listingInsertUserAuth-3-co"/> (new JPasswordField(10), passwordField, "Passwords do not match")); + xml:id="listingInsertUserAuth-3-co"/> (new JPasswordField(10), passwordField, "Passwords do not match")); private final UserInputUnit [] userInputUnits = <co - linkends="listingInsertUserAuth-4" - xml:id="listingInsertUserAuth-4-co"/> + linkends="listingInsertUserAuth-4" + xml:id="listingInsertUserAuth-4-co"/> {name, email, login, password, passwordRepeat}; ... private void userLoginDialog() {...} @@ -11939,8 +11955,8 @@ public class InsertPerson extends JFrame { add(databaseFieldPanel); for (UserInputUnit unit: userInputUnits) { <co - linkends="listingInsertUserAuth-5" - xml:id="listingInsertUserAuth-5-co"/> + linkends="listingInsertUserAuth-5" + xml:id="listingInsertUserAuth-5-co"/> databaseFieldPanel.add(unit.label); databaseFieldPanel.add(unit.verifier.field); databaseFieldPanel.add(unit.verifier.validationLabel); @@ -11949,8 +11965,8 @@ public class InsertPerson extends JFrame { @Override public void actionPerformed(ActionEvent e) { if (inputValuesAllValid()) { if (persistenceHandler.add( <co - linkends="listingInsertUserAuth-6" - xml:id="listingInsertUserAuth-6-co"/> + linkends="listingInsertUserAuth-6" + xml:id="listingInsertUserAuth-6-co"/> name.getText(), email.getText(), login.getText(), @@ -11958,15 +11974,15 @@ public class InsertPerson extends JFrame { clearMask(); ...} private void clearMask() { <co linkends="listingInsertUserAuth-7" - xml:id="listingInsertUserAuth-7-co"/> + xml:id="listingInsertUserAuth-7-co"/> for (UserInputUnit unit: userInputUnits) { unit.verifier.field.setText(""); unit.verifier.clear(); } } private boolean inputValuesAllValid() {<co - linkends="listingInsertUserAuth-8" - xml:id="listingInsertUserAuth-8-co"/> + linkends="listingInsertUserAuth-8" + xml:id="listingInsertUserAuth-8-co"/> for (UserInputUnit unit: userInputUnits) { if (!unit.verifier.verify(unit.verifier.field)){ return false; @@ -11976,68 +11992,70 @@ public class InsertPerson extends JFrame { } }</programlisting> - <calloutlist> - <callout arearefs="listingInsertUserAuth-1-co" - xml:id="listingInsertUserAuth-1"> - <para>All GUI related stuff for entering a user's - name</para> - </callout> + <calloutlist> + <callout arearefs="listingInsertUserAuth-1-co" + xml:id="listingInsertUserAuth-1"> + <para>All GUI related stuff for entering a user's + name</para> + </callout> - <callout arearefs="listingInsertUserAuth-2-co" - xml:id="listingInsertUserAuth-2"> - <para>Password fields need special treatment: - <code>getText()</code> is superseded by - <code>getPassword()</code>. In order to avoid casts from - <classname>javax.swing.JTextField</classname> to - <classname>javax.swing.JPasswordField</classname> we - simply keep an extra reference.</para> - </callout> + <callout arearefs="listingInsertUserAuth-2-co" + xml:id="listingInsertUserAuth-2"> + <para>Password fields need special treatment: + <code>getText()</code> is superseded by + <code>getPassword()</code>. In order to avoid casts from + <classname>javax.swing.JTextField</classname> to + <classname>javax.swing.JPasswordField</classname> we + simply keep an extra reference.</para> + </callout> - <callout arearefs="listingInsertUserAuth-3-co" - xml:id="listingInsertUserAuth-3"> - <para>In order to check both password fields for identical - values we need a different validator - <classname>sda.jdbc.intro.auth.EqualValueVerifier</classname> - expecting both password fields in its constructor.</para> - </callout> + <callout arearefs="listingInsertUserAuth-3-co" + xml:id="listingInsertUserAuth-3"> + <para>In order to check both password fields for + identical values we need a different validator + <classname>sda.jdbc.intro.auth.EqualValueVerifier</classname> + expecting both password fields in its + constructor.</para> + </callout> - <callout arearefs="listingInsertUserAuth-4-co" - xml:id="listingInsertUserAuth-4"> - <para>All 5 user input elements get grouped by an array. - This allows for iterations like in <coref - linkend="listingInsertUserAuth-7-co"/> or <coref - linkend="listingInsertUserAuth-8-co"/>.</para> - </callout> + <callout arearefs="listingInsertUserAuth-4-co" + xml:id="listingInsertUserAuth-4"> + <para>All 5 user input elements get grouped by an array. + This allows for iterations like in <coref + linkend="listingInsertUserAuth-7-co"/> or <coref + linkend="listingInsertUserAuth-8-co"/>.</para> + </callout> - <callout arearefs="listingInsertUserAuth-5-co" - xml:id="listingInsertUserAuth-5"> - <para>Adding all GUI elements to the base pane in a - loop.</para> - </callout> + <callout arearefs="listingInsertUserAuth-5-co" + xml:id="listingInsertUserAuth-5"> + <para>Adding all GUI elements to the base pane in a + loop.</para> + </callout> - <callout arearefs="listingInsertUserAuth-6-co" - xml:id="listingInsertUserAuth-6"> - <para>Providing user entered values to the persistence - provider.</para> - </callout> + <callout arearefs="listingInsertUserAuth-6-co" + xml:id="listingInsertUserAuth-6"> + <para>Providing user entered values to the persistence + provider.</para> + </callout> - <callout arearefs="listingInsertUserAuth-7-co" - xml:id="listingInsertUserAuth-7"> - <para>Whenever a dataset has been successfully sent to the - database we have to clean our GUI to possibly enter - another record.</para> - </callout> + <callout arearefs="listingInsertUserAuth-7-co" + xml:id="listingInsertUserAuth-7"> + <para>Whenever a dataset has been successfully sent to + the database we have to clean our GUI to possibly enter + another record.</para> + </callout> - <callout arearefs="listingInsertUserAuth-8-co" - xml:id="listingInsertUserAuth-8"> - <para>Thanks to our grouping aggregation of individual - input GUI field validation states becomes easy.</para> - </callout> - </calloutlist> - </answer> - </qandaentry> - </qandadiv> - </qandaset> + <callout arearefs="listingInsertUserAuth-8-co" + xml:id="listingInsertUserAuth-8"> + <para>Thanks to our grouping aggregation of individual + input GUI field validation states becomes easy.</para> + </callout> + </calloutlist> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + </section> <section xml:id="sectArchitectSecurityConsiderations"> <title>Architectural security considerations</title> @@ -12094,20 +12112,17 @@ PersistenceHandler.password=<emphasis role="bold">XYZ</emphasis> <co </section> <section xml:id="sectRelationadatal2Xml"> - <title>Converting relational data to XML</title> + <title>Reversing <xref linkend="glo_XML"/> to Rdbms</title> <qandaset defaultlabel="qanda" xml:base="qandaRelationaldata2Xml" xml:id="qandaRelationaldata2Xml"> - <title>Reversing Xml to Rdbms exercise</title> - <qandadiv> <qandaentry> <question> - <label>Exporting RDBMS data to XML.</label> - <para>Reverse exercise <xref linkend="qandaXmldata2relational"/> to read Rdbms data via - JDBC and export corresponding XML data using Jdom.</para> + <xref linkend="glo_JDBC"/> and export corresponding XML data + using Jdom.</para> </question> <answer> @@ -12119,22 +12134,19 @@ PersistenceHandler.password=<emphasis role="bold">XYZ</emphasis> <co </section> <section xml:id="sda1SaxRdbms"> - <title>SAX and RDBMS</title> + <title>Generating HTML from XML and Rdbms data using SAX and <xref + linkend="glo_JDBC"/>.</title> <qandaset defaultlabel="qanda" xml:id="exercise_saxAttrib"> - <title>Reading XML attributes</title> - <qandadiv> <qandaentry xml:id="saxRdbms"> <question> - <label>SAX processing with RDBMS access.</label> - <para>Implement the example given in <xref linkend="saxRdbmsAccessPrinciple"/> to produce the output sketched in <xref linkend="saxPriceOut"/>. You may start by implementing <emphasis>and testing</emphasis> the following - methods of a RDBMS interfacing class using <trademark - xlink:href="http://electronics.zibb.com/trademark/jdbc/29545026">JDBC</trademark>:</para> + methods of a RDBMS interfacing class using <xref + linkend="glo_JDBC"/>:</para> <programlisting language="none">package sax.rdbms; -- GitLab