tag:blogger.com,1999:blog-71837737010176559632024-03-12T20:45:08.526-04:00Expert Oracle and Java SecurityProgramming Secure Oracle Database Applications with JavaDavid Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-7183773701017655963.post-37678516746306809222014-02-23T21:47:00.001-05:002014-02-23T21:47:14.811-05:00HTML Forms With Single Text Input - Fail!<span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">This is probably old news, but I learned the hard way.<br>I have some simple forms with tables, select lists, buttons and in three cases, just a single text field. I needed to validate the text field, so I added a javascript onChange function. All my buttons have onClick functions. But, if the user enters characters (that need validation) in the text field and hits the {Enter} key, none of my validation took place. </span><div><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">I tried a dozen different approaches then did a Google search. It turns out that the specification for HTML was modified with this requirement -- <br>If a form has a single text input field, then the {Enter} key acts as a form submit().<br>No, it doesn't go through your field onChange method, nor through your focused button onClick method. It goes straight to form submit.<br><br>Naturally, the solution is to put your form validation in a form onSubmit method.<br>But, why is bypassing all other controls / validation perceived as a "convenience"?<br>Here's a simplified example (save as html and load in Your browser). <br>To see the difference when there are more than one text field, uncomment the second one and reload.<br><br><HTML><br><HEAD><br><!-- Active content stripped --><br></HEAD><br><BODY><br><FORM NAME='myForm' onsubmit='return validateForm(this);'><br><INPUT TYPE='text' NAME='inText' onChange='tryValidate()' /><br><INPUT TYPE='button' VALUE='Change' onClick='tryValidate()' /><br><br><!--<br><INPUT TYPE='text' /><br>// --><br><br></FORM><br></BODY><br></HTML></span></div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com1tag:blogger.com,1999:blog-7183773701017655963.post-29734380642495631922013-11-10T08:11:00.001-05:002014-02-26T14:02:56.676-05:00Java Cross-Site Request Forgery (CSRF) Remedy, and Reverse Proxy
Considerations<div>Recently, an application that I wrote and support got scanned by a more sophisticated web application security tool, and it revealed some issues. One of the issues was in regard to “Cross-Site Request Forgery”. Basically, Cross-Site Request Forgery (I’m going to abbreviate this as CSRF) means that data is being submitted to your application by a form that was not generated by your application. For example, a hacker might save the source of your web page and form and submit the form from their saved version.</div><div><br></div><div>If an authenticated web application user (I assume you are authenticating your users) submits valid data (I assume you are validating the data) from a form that you didn’t originate, there should be no problem, right? Valid user and valid data should be OK, right?</div><div><br></div><div>In reality, the examples of where this exploit has been used are the justification for preventing it. I'll describe one CSRF attack vector. You may be authenticated to use my application, and you may load a page in your browser that has NOT come from me. If that page has a couple features, we will both be upset: (1) perhaps the page has been maliciously coded to emulate a page delivered by my application and submits some valid data, and (2) that data performs some valid function that you have not approved, like transferring money to a hacker. That kind of potential scenario, and others like it should motivate us to keep CSRF from succeeding in our applications. </div><div><br></div><div>Additionally, if there is a chance that bad data might seep through your server-side validation or that an authenticated user might be spoofed or that you just need to pass intense application security scanning that is going to reveal CSRF vulnerabilities, then there are a couple things you can do to prevent CSRF.</div><div><br></div><div>But first, let me take a minute to talk about server names. Often a server will have multiple names: an official name and one or more DNS aliases. Most likely, one of the DNS aliases, if they exist, is what users will browse to in the URL -- that gives you flexibility to move an alternate system into place (physically or logically) as that same DNS alias, without having to change all your URLs. In addition, you may have more elaborate access to your corporate servers from the Internet through reverse proxies that may sit on the boundary of your intranet. In that case, the proxy server may rewrite both the header of the request and the referrer. So there are four name types: 1) the machine name, 2) a DNS name, 3) a potentially rewritten referrer name, and 4) a potentially rewritten header "server" name. <span style="font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;"> How should we use each of these? In the simplest arrangement, all of these will be the same.</span></div><div><span style="font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;"><br></span></div><div>The machine name (hostSrvrName in the code below) should be used for anything that applies to everything being served from that specific server, even when served at URLs using potentially different DNS aliases. I choose to name my authentication cookies with the machine name so that other applications can share the authentication. Our nonce cookie is not quite of that type, it is specific to our application forms, at present, but could be made into a general service for the entire server. We can get the machine name (which only needs to be read once) from an InetAddress class, through a static initializer block outside the doGet(), doPost() and other methods, like this:</div><div><br></div><div> private static boolean isDebug = true;</div><div> private static String applName = "myapp";</div><div> private static String defaultNetworkName = "org.com";</div><div> private static String defaultServerName = "myappsrv" </div><div> + "." + defaultNetworkName;</div><div> private static String hostSrvrName = null; </div><div> private static InetAddress[] hostAddresses = null;</div><div> static { </div><div> try {</div><div> try { </div><div> hostSrvrName = InetAddress.getLocalHost().getHostName() </div><div> + "." + defaultNetworkName;</div><div> } catch( Exception y ) {} </div><div> if( hostSrvrName == null ) hostSrvrName = defaultServerName;</div><div> hostAddresses = InetAddress.getAllByName( hostSrvrName ); </div><div> } catch( Exception x ) {} </div><div> } </div><div> // This is what we will see in the request at the server</div><div> // It may be rewritten to the client</div><div> private static String reverseProxyName = "access" </div><div> + "." + defaultNetworkName;</div><div><br></div><div>The first thing you can do is what I would term as “poor-man’s CSRF prevention.” Basically, you check to assure the referrer in the html header is what you expect. Note that if you are using a reverse proxy, the proxy will occur as the referrer name; so in addition to your web app server, you will need to allow that host name as a referrer. In a Java servlet, this test might look like the following (note that the standard parameter name “referer” is misspelled).</div><div><br></div><div> // A reverse proxy may rewrite the header server name</div><div> String rqstSrvrName = request.getServerName();</div><div> if( rqstSrvrName == null ) rqstSrvrName = hostSrvrName;</div><div> // The referrer is important to us!</div><div> // That should be the name of the server that the client addresses</div><div> // If it is acceptable, we will reflect that back to the client</div><div> String referrer = request.getParameter( "referer" );</div><div> // If the request or referrer server name equals</div><div> // our standard reverse proxy server name,</div><div> // then set the referrer to the reverse proxy</div><div> // else assure the referrer is this host</div><div> String referrerName = rqstSrvrName;</div><div> <span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);"><font>// May have remnant referrer on a GET - use request server</font> </span></div><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);"><font> </font><font><b>if</b></font><font>( referrer != </font><font><b>null</b></font><font> &&</font> <br><font> ! request.getMethod().equals( </font><font>"GET"</font><font> ) ) </font><br><font> {</font> </span><div> int start = referrer.indexOf( "//" ) + 2;</div><div> int end = referrer.indexOf( "/", start );</div><div> referrerName = referrer.substring( start, end );</div><div> }</div><div> if( rqstSrvrName.equals( reverseProxyName ) </div><div> || referrerName.equals( reverseProxyName ) ) </div><div> {</div><div> referrerName = reverseProxyName;</div><div> } else {</div><div> // Test if the server name from the referrer or request header</div><div> // Has one of the same addresses as our host (DNS alias)</div><div> boolean isThisAddr = false;</div><div> try {</div><div> InetAddress referInetAddr = </div><div> InetAddress.getByName( referrerName );</div><div> String requestAddr = referInetAddr.getHostAddress();</div><div> // InetAddresses are keyed by IP Address, so may not work</div><div> // With hosts with multiple network homes (cards or VPNs)</div><div> if( hostAddresses != null ) </div><div> for( InetAddress iAddr: hostAddresses ) {</div><div> if( iAddr.getHostAddress().equals( requestAddr ) ) {</div><div> isThisAddr = true;</div><div> break;</div><div> }</div><div> }</div><div> } catch( Exception x ) {}</div><div> // Referrer may also be another acceptable host</div><div><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);"><font> </font><font><b>if</b></font><font>( referrerName.equalsIgnoreCase( </font><font>"<a href="http://menu.org.com/" x-apple-data-detectors="true" x-apple-data-detectors-type="link" x-apple-data-detectors-result="0">menu.org.com</a>"</font><font> ) ) isThisAddr = </font><font><b>true</b></font><font>;</font> <br><font> </font><font><b>if</b></font><font>( referrerName.equalsIgnoreCase( </font><font>"<a href="http://lookup.org.com/" x-apple-data-detectors="true" x-apple-data-detectors-type="link" x-apple-data-detectors-result="1">lookup.org.com</a>"</font><font> ) ) isThisAddr = </font><font><b>true</b></font><font>;</font> <br><font> </font><font><b>if</b></font><font>( referrerName.equalsIgnoreCase( </font><font>"<a href="http://test.org.com/" x-apple-data-detectors="true" x-apple-data-detectors-type="link" x-apple-data-detectors-result="2">test.org.com</a>"</font><font> ) ) isThisAddr = </font><font><b>true</b></font><font>;</font></span></div><div> if( ! isThisAddr ) {</div><div> System.out.println( "Referrer Problem coming from: " + </div><div> clientIP + ", Referrer: " + referrer );</div><div> throw new ServletException();</div><div> }</div><div> }</div><div> if( isDebug ) {</div><div> System.out.println( "hostSrvrName: " + hostSrvrName );</div><div> System.out.println( "rqstSrvrName: " + rqstSrvrName );</div><div> System.out.println( "referrerName: " + referrerName );</div><div> }</div><div><br></div><div>The DNS name (or machine name if no DNS aliases are used) will usually appear in all the places we might look for the server name: the URL, the referrer and the header for each client request coming to the server. We can't really enforce security around the server name in the URL; it is just the address where someone found us. Once they find us, however, we can enforce security around the server name in the referrer, as shown above, and in the header. If these are not what we are expecting, we should reject the request or fix the server name. In particular, we need a good server name to use for the cookie Domain. You can provide a cookie to the browser using any Domain, but since you want the browser to return it, the cookie Domain setting needs to match the target server of THE CLIENT request. From the other side of a reverse proxy, your best bet for a working cookie Domain is the server name that the client places in the request referrer. But if there is no referrer, the acceptable server name in the request object should be used.</div><div><br></div><div>If that is the poor-man’s solution, what does the wealthy Java programmer do? Well, he can stamp every web page he delivers with a random value and validate the value when that web page is submitted. If the random value is stored in a session cookie, then it will be returned only with valid requests. We will see how I implemented that solution.</div><div><br></div><div>There are several places where a per-page random value can be stored, and we are going to place that value in three of them: the web page form, a web page cookie and in the server-side session for that client. There are a couple scenarios where we can be assured that CSRF has not occurred – when all the stored values are null (that would be the first request for this client session), or when all the stored values are equal. One more instance where we do not flag the submission as a potential CSRF is when the request is coming from an http GET and has no form – we will be pretty strict about that exception. This would only be something we need to deal with when the client has an existing session for this application and then clicks on a link (GET request) for the same application.</div><div><br></div><div>To test whether a form has been submitted, and a form is the only way our per-page random value will be returned, we check the method of the request. If it is a GET request, then there is no form. But that is not a sufficient reason to throw open the gate. We need to assure that the client is not submitting unexpected data in the GET (in the URL). However, we may want to submit some data through a GET request, and we need to test for each valid GET. In this example, the request is a “form” submission (and will need to include a valid per-page random value) unless it meets these criteria: It is a GET request and has no data parameters or has one data parameter that is “reload”.</div><div><br></div><div> // Anchor tags into myapp (isForm = false) don't have nonce. </div><div> // Flush has one parameter, otherwise zero. </div><div> boolean isForm = true;</div><div> String doFlush = request.getParameter( "reload" );</div><div> if( request.getMethod().equals( "GET" ) ) {</div><div> @SuppressWarnings("rawtypes")</div><div> Map pMap = request.getParameterMap();</div><div> if( pMap.size() == 0 ) isForm = false;</div><div> else if( pMap.size() == 1 && doFlush != null ) isForm = false;</div><div> }</div><div><br></div><div>Here is a fun word to say, and one that technically fits this scenario: “nonce”, or “number used once”. We will deliver a nonce with each web page and validate it with each form submittal.</div><div><br></div><div> // On forms, check nonce</div><div> if( isForm ) {</div><div> boolean isNonceOK = </div><div> checkNonceCookie( hostSrvrName, request, response );</div><div> // Need to set cookie before throw Exception if( ! isNonceOK )</div><div> setNonceCookie( hostSrvrName, referrerName, request, response);</div><div> if( ! isNonceOK ) { </div><div> System.out.println( "Nonce Problem coming from: " + </div><div> clientIP );</div><div> throw new ServletException();</div><div> }</div><div> } <span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);"><font><b>else</b></font><font> <i>setNonceCookie</i>( </font><font><i>hostSrvrName</i></font><font>, referrerName, request, response);</font></span></div><div><br></div><div>In my application coding, I normally log the exception where it happens, then throw an application-specific Exception (not shown in the code above), and simply pass that along in any other methods, finally catching it at the doPost() or doGet() method in order to return an error page with a form and nonce of its own. For that reason, before I throw the exception, I set a new nonce value to be sent with the Error page. I will plan to provide the details of that process in another blog message.</div><div><br></div><div>Note that even if we are not coming from a form, we need to set a nonce cookie in the form we will be returning.</div><div><br></div><div>There are two methods that I will describe here, checkNonceCookie() and setNonceCookie(). Let me explain the set method first. Here is the basic code:</div><div><br></div><div> // The nonce cookie is intended to avoid Cross-Site Request Forgery</div><div> private static SecureRandom rand = new SecureRandom();</div><div> static {</div><div> rand.nextLong();</div><div> rand.nextLong();</div><div> }</div><div> private static void setNonceCookie(</div><div> String hostSrvrName, String referrerName,</div><div> HttpServletRequest request, HttpServletResponse response )</div><div> {</div><div> try {</div><div> String randNonce = String.valueOf( rand.nextLong() );</div><div> String encodedNonce = encode( randNonce );</div><div> HttpSession session = request.getSession(true);</div><div> session.setAttribute( "nonce", encodedNonce );</div><div> request.setAttribute( "nonce", encodedNonce );</div><div> // We encrypt the nonce value and place it in the cookie so that</div><div> // a hacker may not generate a cookie and matching form nonce</div><div> // (can't spoof our cookie)</div><div> String cryptNonce =</div><div> getCryptResult( hostSrvrName, encodedNonce, request );</div><div> // Cookie class does not support Expires date - manually one hour</div><div> SimpleDateFormat cookieDateFormat = new SimpleDateFormat(</div><div> "EEE, dd-MMM-yyyy HH:mm:ss" );</div><div> // Set the formatter timezone so the numeric value</div><div> // matches "GMT" in the cookie</div><div> cookieDateFormat.setTimeZone( TimeZone.getTimeZone("GMT") );</div><div> Date cookieDate = new Date();</div><div> cookieDate = new Date( cookieDate.getTime() + 60L * 60L * 1000L);</div><div> String expiresDate = cookieDateFormat.format( cookieDate );</div><div> // Perhaps use defaultNetworkName as Domain to permit this cookie</div><div> // for all hostnames in network</div><div> // including DNS aliases and reverse proxy header rewrites</div><div> String mCookieString = applName + "_nonce_" + hostSrvrName + "="</div><div> + cryptNonce + "; Path=/; Domain="</div><div> //+ defaultNetworkName + "; Expires=" + expiresDate</div><div> + referrerName + "; Expires=" + expiresDate</div><div> + " GMT; Secure; HttpOnly";</div><div> response.addHeader( "Set-Cookie", mCookieString );</div><div> } catch (Exception x) {</div><div> System.out.println( "setNonceCookie: " + x.toString() );</div><div> }</div><div> }</div><div><br></div><div>Observe that we are encrypting the nonce value, using a method that I often employ (shown below) so that the cookie cannot be easily spoofed – a cookie and matching nonce would be difficult for a hacker to generate. We don’t want to be totally dependent on a “difficulty”, so any matching nonce value from a form and from a cookie will need to also match a value that we set in the server-side session. Notice in the code above that in addition to creating the cookie and setting it in the header, we also set the session attribute, “nonce” with that value and the request attribute, “nonce” with that value. One common practice for placing the nonce value in an html form is by using Java Server Pages (JSPs) and perhaps the JSP Standard Tag Library (JSTL) core functions to get the value from the request attribute. Here is an example JSP snippet:</div><div><br></div><div><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %></div><div>…</div><div><FORM NAME='mForm' METHOD=POST />'></div><div><INPUT TYPE='hidden' NAME='nonce' VALUE='<c:out value="${nonce}" />' /></div><div><INPUT TYPE='submit' VALUE='Retry' /></div><div></FORM></div><div><br></div><div>Those three value settings (the form, the cookie and the session) will be compared in the checkNonceCookie() method. If they are all blank, or if they all match, then a legitimate form is being submitted. In certain circumstances (occasionally from a reverse proxy) a cookie will be returned even though a new browser session has been established, so there is no form or session nonce. So for that reason, just check if those two are blank and ignore the cookie. Here’s the code:</div><div><br></div><div> private static boolean checkNonceCookie( String hostSrvrName,</div><div> HttpServletRequest request, HttpServletResponse response )</div><div> {</div><div> boolean rtrnBool = true;</div><div> try {</div><div> <span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);"><font>HttpSession session = request.getSession(</font><font><b>true</b></font><font>);</font> </span></div><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);"><font> Object sessNonceObj = session.getAttribute( </font><font>"nonce"</font><font> );</font> <br><font> </font><font>// If user leaves page up, will have form <u>nonce</u> and cookie, but no session</font> <br><font> </font><font>// So don't do anything (ignore all input), just display start page</font> <br><font> </font><font><b>if</b></font><font>( sessNonceObj == </font><font><b>null</b></font><font> || sessNonceObj.toString().equals(</font><font>""</font><font>)) {</font> <br><font> </font><font><b>if</b></font><font>( </font><font><i>isDebug</i></font><font> ) System.</font><font><i>out</i></font><font>.println( </font><br><font> </font><font>"Going to Start: "</font><font> + request.getRemoteUser() );</font> <br><font> request.setAttribute( </font><font>"goToStart"</font><font>, </font><font>"true"</font><font> );</font> <br><font> </font><font><b>return</b></font><font> </font><font><b>true</b></font><font>;</font> <br><font> }</font> <br><font> String formNonce = request.getParameter( "</font><font>nonce"</font><font> );</font> <br><font> String cookieCryptNonce = </font><font><b>null</b></font><font>;</font> <br><font> String cookie = request.getHeader(</font><font>"cookie"</font><font>) + </font><font>";"</font><font>;</font></span><div> // TEMPORARY ONLY</div><div> ////if( isDebug ) System.out.println( "cookie: " + cookie );</div><div> int start = cookie.indexOf( applName + "_nonce_" +</div><div> hostSrvrName + "=" );</div><div> if (-1 < start) { // cookie exists</div><div> int end = cookie.indexOf( ";", start );</div><div> String nonceCookie = cookie.substring( start, end );</div><div> start = nonceCookie.indexOf( "=" );</div><div> cookieCryptNonce = nonceCookie.substring( start + 1 );</div><div> }</div><div> if( isDebug ) {</div><div> System.out.println( "sessNonceObj: " + </div><div> (String)sessNonceObj );</div><div> System.out.println( "formNonce: " + formNonce );</div><div> System.out.println( "cookieCryptNonce: " + </div><div> cookieCryptNonce );</div><div> }</div><div> rtrnBool = false; // if exception is thrown - this is returned</div><div> if( ! formNonce.equals( (String)sessNonceObj ) ) return false;</div><div> String cryptNonce = getCryptResult( hostSrvrName,</div><div> (String)sessNonceObj, request );</div><div> if( isDebug ) System.out.println( "cryptNonce: " + cryptNonce );</div><div> if( cryptNonce.equals( cookieCryptNonce ) ) return true;</div><div> return false;</div><div> } catch( Exception x ) {</div><div> System.out.println( "checkNonceCookie: " + x.toString() );</div><div> return rtrnBool;</div><div> }</div><div> }</div><div><br></div><div>In checkNonceCookie(), above we get the encrypted value that we stored in the cookie, then we encrypt the values again. We compare the cookie value with the newly encrypted value.</div><div>My code for the getCryptResult() method is like the following. It creates an encrypted value that is also rather specific to the client browser. Also, to get the encrypted value into a representation that is easily included in a web page, we encode it. I’ll also show a Hex encoding method that I’ve published in a previous blog post; although, I have a hardened version I present in my book, Expert Oracle and Java Security.</div><div><br></div><div> // Requires Java Cryptography Extension (JCE)</div><div> // Unlimited Strength Jurisdiction Policy Files 6</div><div> private static byte[] salt = { (byte) 0x8d, (byte) 0xc8, (byte) 0xdf,</div><div> (byte) 0x65, (byte) 0xb4, (byte) 0x94, (byte) 0x43, (byte) 0x8e };</div><div> private static int itCount = 24;</div><div> private static PBEParameterSpec pbeParamSpec = new</div><div> PBEParameterSpec( salt, itCount );</div><div> private static SecretKeyFactory keyFac;</div><div> private static Cipher pbeCipher;</div><div> private static String algorithm = "PBEWithSHA1AndDESede";</div><div> static {</div><div> try {</div><div> keyFac = SecretKeyFactory.getInstance( algorithm );</div><div> algorithm = keyFac.getAlgorithm();</div><div> pbeCipher = Cipher.getInstance( algorithm );</div><div> } catch (Exception x) {}</div><div> }</div><div> static String getCryptResult( String srvrName, String randNonce,</div><div> HttpServletRequest request ) </div><div> {</div><div> String rtrnString = "";</div><div> try {</div><div> PBEKeySpec pbeKeySpec =</div><div> new PBEKeySpec(randNonce.toCharArray());</div><div> SecretKey pbeKey;</div><div> String clearText = request.getRemoteAddr().substring(0, 10)</div><div> + request.getHeader( "profile" )</div><div> + randNonce + srvrName</div><div> + request.getHeader( "user-agent" );</div><div> byte[] bytesOfMessage = clearText.getBytes( "UTF-8" );</div><div> MessageDigest md = MessageDigest.getInstance( "MD5" );</div><div> byte[] thedigest = md.digest( bytesOfMessage );</div><div> byte[] cryptText;</div><div> synchronized( pbeCipher ) {</div><div> pbeKey = keyFac.generateSecret( pbeKeySpec );</div><div> pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);</div><div> cryptText = pbeCipher.doFinal( thedigest );</div><div> }</div><div> rtrnString = encode( cryptText );</div><div> } catch (Exception x) {}</div><div> return rtrnString;</div><div> }</div><div><br></div><div> static String encode( byte[] bytes ) {</div><div> StringBuffer sBuf = new StringBuffer();</div><div> try {</div><div> for( byte b: bytes ) {</div><div> sBuf.append( String.format( "%02X", b ) );</div><div> }</div><div> } catch( Exception x ){}</div><div> return sBuf.toString();</div><div> }</div><div><br></div><div>Note that this blog site and my book, Expert Oracle and Java Security, will give you further tools for your application security efforts.</div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com1tag:blogger.com,1999:blog-7183773701017655963.post-8934458650094678782013-11-02T08:11:00.001-04:002013-11-02T08:20:24.546-04:00Secure Quick Real Login in Java<span style="background-color: rgba(255, 255, 255, 0);">I </span><span style="background-color: rgba(255, 255, 255, 0); -webkit-text-size-adjust: auto; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;">am all for pushing the envelope in computer security; however, I don’t live on the bleeding edge. I am a security practitioner and implementor. I like currently deployed encryption technologies. It is the failure to encrypt and the failure to protect that really gets me upset.</span><br><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">Recently, the Secure Quick Reliable Login (SQRL) protocol (or should I say process) has been getting a fair amount of press. I had some initial doubts. After reviewing the various blogs and security newsgroups, I believe that the basic technical premise may be critically flawed. It is primarily the concept embodied in this phrase from the SQRL website that causes concern: “The primary enabling feature of the SQRL system's underlying crypto technology is its ability to use the randomly distributed arbitrary output of the 256-bit SHA256 hash function as its private key.” What Steve Gibson seems to be saying is that SQRL will calculate a value based on a master key and site address to use as the private key. From that calculated private key, SQRL purports to calculate a consistent public key to be used for asymmetrical encryption and identity (authentication). That's far from standard practice in public key cryptography.</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">In any case, in the meantime, I decided to demonstrate an implementation of something like SQRL (just the guts) without some of the technological blood and hype. This uses currently existing and readily accessible technologies to accomplish the PRIMARY features of SQRL -- web application authentication. I call this Secure Quick Real Login (SQReaL).</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">I don’t want to delve into discussions of the philosophy of application authentication, mobile device security or privacy security data protection. If you are not taking the basic steps of backing up your mobile device, setting a device timeout and login password, etc. then there is no security system that can protect you. I’m also not persuaded that there is more value in this than in regular username / password authentication, nor that it bests other authentication services. Perhaps to attain a consistent, protected anonymous persona, this might be a good authentication mechanism, if that even makes sense.</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">So what limited features does SQReaL attempt to implement?</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">1) A master key, stored on the device that provides (access to) private / public key pairs</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">2) Site-specific private / public key pairs that are consistent across sessions (hence, can be used for identity)</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">3) Encryption of a challenge code with the private key that can be decrypted by the authentication service using the public key that is delivered with the encrypted challenge code</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">And, no rocket science is required.</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">This is a quick implementation using code that I’ve published elsewhere, including my book, Expert Oracle and Java Security. For ease of discussion, I’m storing all the data in files. On the application server, you would want to use a database. I’m also using Triple-DES for encrypted local storage and RSA for public / private keys. I’m not trying to persuade anyone that this is a superior set of algorithms – they are just common, available and quick enough for this demonstration.</span></p><p></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">On a practical issue with SQRL, to change Master Keys in SQReaL, you simply move the Site Key Store into memory, change the DES Cipher to use the new Master Key and serialize the Site Key Store back to storage.</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">Here is SQReaL:</span></p><p style="font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;"><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">// David Coffin, 11/02/2013</span></font></p><p><font style="font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif; -webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">// Requires Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6</font></p><p><span style="background-color: rgba(255, 255, 255, 0); -webkit-text-size-adjust: auto; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;">// Installed in every JRE and JDK/jre</span></p><p><span style="-webkit-text-size-adjust: auto; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;">package dac;</span></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.io.ByteArrayOutputStream;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.io.File;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.io.FileInputStream;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.io.FileOutputStream;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.io.ObjectInputStream;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.io.ObjectOutputStream;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.io.Serializable;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.math.BigInteger;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.security.Key;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.security.KeyFactory;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.security.KeyPair;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.security.KeyPairGenerator;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.security.SecureRandom;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.security.interfaces.RSAPublicKey;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.security.spec.RSAPublicKeySpec;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.util.HashMap;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import java.util.Map;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import javax.crypto.Cipher;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import javax.crypto.CipherInputStream;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import javax.crypto.CipherOutputStream;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import javax.crypto.SecretKey;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import javax.crypto.SecretKeyFactory;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import javax.crypto.spec.PBEKeySpec;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">import javax.crypto.spec.PBEParameterSpec;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">/*</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * The difficult (mis-)conception in the SQRL description comes in these words:</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * "The primary enabling feature ... is its ability to use ... as its private key"</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * Simply put, SQRL portends to use a calculated value AS the private key</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * And to calculate a public key from that value to be used for asymmetrical encryption</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * That is not done</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * Here is a solution which uses a secure local data store of fixed key pairs</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * That are designated for use with specific URL hosts.</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * Note that the Master key has nothing to do with generation of site keys, </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * but is used for security of the store</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * And, likewise, the site URL is not used for generation of the site key, </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * but is used as the index for the key store value</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> */</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">public class SQReaL {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static boolean isTest = false;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static String masterKeyLocation = "C:/dac/Master.ser";</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static String publicKeyLocation = "C:/dac/Public.ser";</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> public static void main(String[] args) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> SQReaL.ReturnValues returnValues = getReturnValues( "http://try.this.one/", "abcdefghijk" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Modulus: " + returnValues.sitePublicModulus );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Exponent: " + returnValues.sitePublicExponent );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Encrypted: " + returnValues.encryptedChallengeCode );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "User: " + serverIdentifyUser( </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.sitePublicModulus, returnValues.sitePublicExponent ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Decrypted: " + serverDecryptChallengeCode(</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.sitePublicModulus, returnValues.sitePublicExponent,</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.encryptedChallengeCode ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "----------------" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Next will use same site key (modulus and exponent) but different challenge</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues = getReturnValues( "http://try.this.one/", "1abcdefghijk" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Modulus: " + returnValues.sitePublicModulus );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Exponent: " + returnValues.sitePublicExponent );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Encrypted: " + returnValues.encryptedChallengeCode );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "User: " + serverIdentifyUser(</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.sitePublicModulus, returnValues.sitePublicExponent ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Decrypted: " + serverDecryptChallengeCode(</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.sitePublicModulus, returnValues.sitePublicExponent,</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.encryptedChallengeCode ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "----------------" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Next will use different site key, but same challenge - should be encrypted differently</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues = getReturnValues( "http://try.this.two/", "1abcdefghijk" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Modulus: " + returnValues.sitePublicModulus );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Exponent: " + returnValues.sitePublicExponent );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Encrypted: " + returnValues.encryptedChallengeCode );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Note that for this test, we are acting like a single server application</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // So since we passed a different URL, we will have a different key</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // And we will report this as a different user</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "User: " + serverIdentifyUser(</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.sitePublicModulus, returnValues.sitePublicExponent ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "Decrypted: " + serverDecryptChallengeCode(</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.sitePublicModulus, returnValues.sitePublicExponent,</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.encryptedChallengeCode ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> System.out.println( "----------------" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static String masterKey = null;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> /**</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * The sitePublicKey (since using RSA, the key is a modulus and exponent)</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * is returned to the host and is used for two processes:</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * 1) To identify me uniquely (should never change) - lack of randomness needed for identity</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * 2) To decrypt the challenge code - assures that I have the matching public key</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * Note that the algorithm must be common between the client and server</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * Returning as Strings for inclusion in html post, or other</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> * Using my encode() method for value obfuscation</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> */</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> public class ReturnValues {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String sitePublicModulus;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String sitePublicExponent;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String encryptedChallengeCode;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static Map<String,KeyPubPriv> keyStore = null;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> public static ReturnValues getReturnValues( String hostUR, String challengeCode ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> SQReaL sqrl = new SQReaL();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return sqrl.calcReturnValues( hostUR, challengeCode );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private ReturnValues calcReturnValues( String hostUR, String challengeCode ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> ReturnValues returnValues = new ReturnValues();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> getMasterKey();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> KeyPubPriv sitepair = getSiteKeyPair( hostUR );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // encode() for return, but don't store encoded</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.encryptedChallengeCode =</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> encodeBytes( getEncryptedChallengeCode( sitepair.privateKey, challengeCode ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.sitePublicModulus = sitepair.publicKey.getModulus().toString();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> returnValues.sitePublicExponent = sitepair.publicKey.getPublicExponent().toString();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> x.toString();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return returnValues;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Synchronized in order to keep masterKeyFile access limited to one thread at a time</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static synchronized void getMasterKey() throws Exception {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( masterKey != null ) return;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> ObjectInputStream oIn = null;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> ObjectOutputStream oOut = null;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> File masterKeyFile = new File( masterKeyLocation );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( masterKeyFile.exists() ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oIn = new ObjectInputStream( new FileInputStream( masterKeyFile ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> masterKey = (String)oIn.readObject();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oIn.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } else {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut = new ObjectOutputStream( new FileOutputStream( masterKeyFile ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // No need to recreate this, so just use random values</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String newMasterKey = "";</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // 32 bytes is 256 bits</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> for( int i = 0; i < 32; i++ ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // I want printable ASCII characters (32 to 126) only</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> newMasterKey += (char)( rand.nextInt( 126 - 32 ) + 32 );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> masterKey = new String( newMasterKey );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.writeObject( masterKey );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.flush();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "master Key: " + masterKey );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> x.printStackTrace();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> throw x;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } finally {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( oOut != null ) oOut.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( oIn != null ) oIn.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static byte[] salt = { (byte) 0x7f, (byte) 0xd7, (byte) 0xef, </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> (byte) 0x59, (byte) 0xd2, (byte) 0x74, (byte) 0x54, (byte) 0x7a }; </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static int itCount = 18; </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, itCount);</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static SecretKeyFactory keyFac;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static Cipher pbeCipher;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static String algorithm = "PBEWithSHA1AndDESede";</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> static {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> keyFac = SecretKeyFactory.getInstance(algorithm);</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> algorithm = keyFac.getAlgorithm();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> pbeCipher = Cipher.getInstance( algorithm );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch (Exception x) {}</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Synchronized in order to keep publicKeyFile access limited to one thread at a time</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Synchronized method instead of blocks to assure we retain all keyStore updates</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> @SuppressWarnings("unchecked")</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static synchronized KeyPubPriv getSiteKeyPair( String hostUR ) throws Exception {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> KeyPubPriv sitePair = new KeyPubPriv();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> ObjectInputStream oIn = null;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> ObjectOutputStream oOut = null;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> File publicKeyFile = new File( publicKeyLocation );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> PBEKeySpec pbeKeySpec = new PBEKeySpec(masterKey.toCharArray());</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( keyStore == null ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( publicKeyFile.exists() ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oIn = new ObjectInputStream( </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> new CipherInputStream( new FileInputStream( publicKeyFile ), pbeCipher ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> keyStore = (HashMap<String,KeyPubPriv>)oIn.readObject();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "entry count: " + keyStore.size() );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oIn.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> else keyStore = new HashMap<String,KeyPubPriv>();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( keyStore.containsKey( hostUR ) ) </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> sitePair = keyStore.get( hostUR );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> else {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> sitePair = makeRSAKeyPair();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> keyStore.put( hostUR, sitePair );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut = new ObjectOutputStream( </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> new CipherOutputStream( new FileOutputStream( publicKeyFile ), pbeCipher ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.writeObject( keyStore );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.flush();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> x.printStackTrace();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> throw x;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } finally {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( oOut != null ) oOut.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( oIn != null ) oIn.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return sitePair;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static int keyLengthRSA = 1024;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static SecureRandom rand = new SecureRandom();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> static {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> rand.nextLong();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> rand.nextLong();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static KeyPubPriv makeRSAKeyPair() throws Exception {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> KeyPubPriv sitePair = new KeyPubPriv();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> KeyPairGenerator generator = KeyPairGenerator.getInstance( "RSA" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> generator.initialize( keyLengthRSA, rand );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> KeyPair pair = generator.generateKeyPair();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> sitePair.privateKey = pair.getPrivate();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> sitePair.publicKey = ( RSAPublicKey )pair.getPublic();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> throw x;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return sitePair;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static Cipher cipherRSA;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> static {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> cipherRSA = Cipher.getInstance( "RSA" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ) {}</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private byte[] getEncryptedChallengeCode( Key privateKey, String challengeCode ) </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> throws Exception</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> byte[] encryptedBytes = new byte[0];</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> cipherRSA.init( Cipher.ENCRYPT_MODE, privateKey );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> byte[] challengeCodeBytes = challengeCode.getBytes();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "clear String: " + challengeCode );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "clear bytes: " + new String( challengeCodeBytes ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> encryptedBytes = cipherRSA.doFinal( challengeCodeBytes );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "encrypted bytes: " + new String( encryptedBytes ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return encryptedBytes;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static String userIDLocation = "C:/dac/UserID.ser";</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static Map<String,UserClass> userStore = null; </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static int userNo = 0;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Synchronized in order to keep userIDFile access limited to one thread at a time</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Synchronized method instead of blocks to assure we retain all userID updates</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // Preferably, in your web app server, you would store the userIDs in a database</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> @SuppressWarnings("unchecked")</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static synchronized String serverIdentifyUser( </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String sitePublicModulus, String sitePublicExponent ) </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> UserClass thisUser = new UserClass();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> ObjectInputStream oIn = null;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> ObjectOutputStream oOut = null;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String userID = sitePublicModulus + "/" + sitePublicExponent;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> File userIDFile = new File( userIDLocation );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( userStore == null ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( userIDFile.exists() ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oIn = new ObjectInputStream( new FileInputStream( userIDFile ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> userStore = (HashMap<String,UserClass>)oIn.readObject();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> userNo = userStore.size();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "user count: " + userNo );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oIn.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> else userStore = new HashMap<String,UserClass>();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( userStore.containsKey( userID ) ) { </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> thisUser = userStore.get( userID );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( thisUser.name.startsWith( "New User ") )</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> thisUser.name = thisUser.name.substring( 4 );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } else {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> thisUser.userID = userID;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> thisUser.name = "New User " + userNo;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> userNo++;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> userStore.put( userID, thisUser );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut = new ObjectOutputStream( new FileOutputStream( userIDFile ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.writeObject( userStore );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.flush();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> oOut.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> x.printStackTrace();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } finally {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( oOut != null ) oOut.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( oIn != null ) oIn.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception y ) {}</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return thisUser.name;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static String serverDecryptChallengeCode( String sitePublicModulus, </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String sitePublicExponent, </span></font><span style="-webkit-text-size-adjust: auto; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;">String encryptedChallengeCode )</span></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> byte[] encryptedBytes = decodeByteString( encryptedChallengeCode );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "decoded encrypted bytes: " + new String( encryptedBytes ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return serverDecryptChallengeCode( sitePublicModulus, sitePublicExponent, encryptedBytes );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static String serverDecryptChallengeCode( String sitePublicModulus, </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String sitePublicExponent, </span></font><span style="-webkit-text-size-adjust: auto; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;">byte[] encryptedBytes )</span></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String decryptedChallengeCode = "";</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> BigInteger modulus = new BigInteger( sitePublicModulus );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> BigInteger exponent = new BigInteger( sitePublicExponent );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> RSAPublicKeySpec keySpec = new RSAPublicKeySpec( modulus, exponent );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> KeyFactory kFactory = KeyFactory.getInstance( "RSA" );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> RSAPublicKey extRSAPubKey = ( RSAPublicKey )kFactory.generatePublic( keySpec );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> cipherRSA.init( Cipher.DECRYPT_MODE, extRSAPubKey );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> encryptedBytes = cipherRSA.doFinal( encryptedBytes );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "decrypted bytes: " + new String( encryptedBytes ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> decryptedChallengeCode = new String( encryptedBytes );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> if( isTest ) System.out.println( "decrypted String: " + decryptedChallengeCode );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> x.printStackTrace();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return decryptedChallengeCode;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> static String encodeBytes( byte[] bytes ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> StringBuffer sBuf = new StringBuffer();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> for( byte b: bytes ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> sBuf.append( String.format( "%02X", b ) );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ){}</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return sBuf.toString();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> static byte[] decodeByteString( String byteString ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> ByteArrayOutputStream out = new ByteArrayOutputStream(); </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String byteChars;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> int byteVal;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> for( int i = 0; i < byteString.length(); i++ ) {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> byteChars = byteString.substring( i, i+2 );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> i++;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> //if( isTest ) System.out.println( byteChars );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> // radix 16 is Hex</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> byteVal = Integer.parseInt( byteChars, 16 );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> out.write( byteVal );</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception x ){</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } finally {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> try {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> out.flush();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> out.close();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> } catch( Exception y ) {}</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> return out.toByteArray();</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> }</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">}</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">class KeyPubPriv implements Serializable {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static final long serialVersionUID = 1L;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> RSAPublicKey publicKey;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> Key privateKey; </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">}</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"><br></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">class UserClass implements Serializable {</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> private static final long serialVersionUID = 1L;</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String userID = "";</span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;"> String name; </span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="background-color: rgba(255, 255, 255, 0); -webkit-text-size-adjust: auto;"></span></font></p><p><font face="Helvetica Neue Light, HelveticaNeue-Light, helvetica, arial, sans-serif"><span style="-webkit-text-size-adjust: auto;">}</span></font></p><div><br></div><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);"><br></span></p>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-16327947959321863112013-10-26T23:15:00.001-04:002013-10-26T23:35:19.358-04:00Java Synchronization and Concurrency Across Multiple JVMs, Multiple
Computers, Part 2<div><span style="font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;">I’m going to add a couple asides to this blog entry. One of them is at the end, and details an additional consideration for the synchronization discussed in “Part 1” – reading the shared file, in addition to writing to it. But before we get started with “Java Synchronization Across JVMs, Part 2”, I want to describe Flag Passing in general. You will still use this general Flag Passing when sharing files on remote systems (not by drive mapping, a network path or a file:// URL), for instance by SFTP. This is not even near “real-time” file sharing, and should be considered “scheduled” or “periodic” file sharing.</span></div><div><span style="font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;"><br></span></div><div>Our sample scenario is that one system (SOURCE) creates files and a second system (TARGET) processes those files, then deletes them. When SOURCE creates a file, we will have it also create or update a file named “mark.mark”. When TARGET connects (periodically) to SOURCE, the first thing TARGET will do is check for a file named “mark.mark” and get the date of the file. Then TARGET will read and delete all files with modification dates before the date of “mark.mark”. The date of the file “mark.mark” is the flag we are passing. This is just one example of Flag Passing, but it helps us get our bearing for the following discussion.</div><div><br></div><div>When I was in high school in the 1970’s, my dad was stationed overseas in a relatively remote location with the US Air Force. He called home every week, and it went like this. He would say “Hello, I love you. Over.” And somewhere, somebody switched something so that we could reply. At the end of our greetings, we said “Over” and dad could start talking again. If we failed to say “Over”, then we would sit there with silence until we remembered. It was like a conversation on a Citizens Band radio with a couple major differences: 1) there was a guy in the middle making a change to allow conversation to flow in the opposite direction, and 2) it was a conversation between only two parties (unless the NSA was listening in.) Let me call this kind of coordination “flag passing”, since I don’t know a more technical term (perhaps semaphores or signaling).</div><div><br></div><div>Those conversations with my dad are the analogue, except for the middle-man, of another way to do Java (or any program) synchronization across operating environments. (Actually, the analogy has several applications, but it also breaks down pretty quickly. However, I like the recollection, so I’ll leave it in here.) In this blog discussion, the presence of a file IS the flag that indicates something is available to be processed.</div><div><br></div><div>In this discussion, we are going to examine the case where multiple files (of the same name) are created, and a separate process (perhaps in a separate JVM) deals with the file and deletes it, when it appears. First we will consider the case where the file is created by only one “Talker” and in all this blog we are limiting this discussion to the case where there is only one “Listener” dealing with the file. The next case, which is really the base solution, is when there are multiple “Talkers”, actually one or more. This first case does not use file locking, and it is inherently faulty – we only present it here in order to examine the problem.</div><div><br></div><div>The OneTalker class writes some output to a file named “message.txt”. Before the file is written, OneTalker checks to see if the file already exists. If it exists, then the Listener has not yet read, processed and deleted the file, so we sit and wait (sleep) until the file does not exist. Then we simply write and close the file. There is nothing inherently “exclusive” about this process, and therein lies the problem (discussed below). Note that there is no added value in having OneTalker sleep for a second while waiting for the existing file to disappear. We could write that loop like this: while(outFile.exists()){}</div><div><br></div><div>public class OneTalker {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>public static void main(String[] args) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Set true to sleep forever (practically) with file open</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>boolean testNoClose = false;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>BufferedOutputStream out = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// This loop is for demo purposes - 5 iterations</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>for( int i = 0; i < 5; i++ ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>File outFile = new File( "C:\\dac\\message.txt" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Listener has not picked up previous file</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( outFile.exists() ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Thread.sleep( 1000 );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}<span class="Apple-tab-span" style="white-space:pre"> </span></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.out.println( "New File" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>out = new BufferedOutputStream( </div><div> new FileOutputStream( outFile ) );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Handle data as byte array - most flexible</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>String newString = "message: " + i;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>byte[] outBytes = newString.getBytes();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>out.write( outBytes, 0, outBytes.length );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>out.flush();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( testNoClose ) Thread.sleep( <a href="tel:1000000000" x-apple-data-detectors="true" x-apple-data-detectors-type="telephone" x-apple-data-detectors-result="0">1000000000</a> );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>out.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Space out the messages - 10 seconds</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Thread.sleep( 10000 );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception x ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>x.printStackTrace();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} finally {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( out != null ) out.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception y ) {}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.exit(0);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div>}</div><div><br></div><div>In the examples in this blog discussion, I am writing and reading byte arrays. Unless you are always writing a line of text with a line-end (for example; carriage return / line feed) , as in Part 1 of this blog topic -- the centralized log file, then writing byte arrays is preferred. [One exception is when you are writing and reading serialized objects.]</div><div><br></div><div>For testing purposes, we have a “for” loop that runs through five iterations of the file creation process. Then to get a little reality “feel”, we sleep for ten seconds between iterations. Note the Boolean, testNoClose – we will discuss how to use that below.</div><div><br></div><div>The Listener code, OneListener checks to see if the file exists, and if so, processes the file and then deletes it. Again, there is nothing exclusive in this process, and if the file is currently being written, two problems will occur: 1) the current partial file will be read, and 2) the file will not be deleted. Normally, with this test code, the time required to write or read the file is so short that it would be difficult to experience the problem, but you should never code for “best-case-scenario”. Instead, as a secure programmer you need to see the potential problem and code for it (which we will do).</div><div><br></div><div>You can test for this problem by setting the boolean, testNoClose in OneTalker to true. This will create the file and then go into a long sleep without closing the file. In that state, when you run OneListener, the same (partial) file will be read and processed repeatedly, and you will see that the file does not get deleted.</div><div><br></div><div>public class OneListener {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>public static void main(String[] args) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>BufferedInputStream in = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Same number loops as Talker</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>for( int i = 0; i < 5; i++ ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>File inFile = new File( "C:\\dac\\message.txt" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Wait for file to appear</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( ! inFile.exists() ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Thread.sleep( 1000 );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// This is where problem may occur – </div><div> // file may be being written</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// In that case, a partial file will be </div><div> // read and delete will fail</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>in = new BufferedInputStream( </div><div> new FileInputStream( inFile ) );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>byte[] inBytes = new byte[2000];</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int readQty;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( (readQty = </div><div> in.read( inBytes, 0, inBytes.length )) > 0 ) </div><div> {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.out.write( inBytes, 0, readQty );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.out.println();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>in.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>inFile.delete();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( inFile.exists() ) </div><div> System.out.println( "Delete failed" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception x ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>x.printStackTrace();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} finally {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( in != null ) in.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception y ) {}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.exit(0);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div>}</div><div><br></div><div>Just for consistency in our demonstration, OneListener has a “for” loop set to consume as many messages as OneTalker will be sending. OneListener also tests to see if a message file exists. If no message file exists, OneListener waits a second (but doesn’t have to) and checks again. When a message file exists, OneListener consumes it then deletes the file. That is another flag of sorts that indicates to OneTalker that he may send another message.</div><div><br></div><div>So let’s fix the problem with OneTalker / OneListener, and expand our scenario. We expand the Talker code in ManyTalker to lock the file while writing. Since we are locking the file, we can assure that only one Talker instance will be writing at any one time – so now we can handle multiple parties writing the file. ManyTalker includes all the same code as OneTalker, with the addition of the FileLock and an extra, labeled RETRY while() loop for handling the FileLock acquisition. Whenever we cannot acquire the lock on the file, or experience an Exception while trying to acquire the lock, we loop to the RETRY label. When we acquire the lock, we break out of the RETRY while() loop and write the file as we did in OneTalker.</div><div><br></div><div>public class ManyTalker {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>public static void main(String[] args) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Set true to sleep forever (practically) with file locked</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>boolean testNoRelease = false;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>FileLock fl = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>BufferedOutputStream out = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// This loop is for demo purposes - 5 iterations</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>for( int i = 0; i < 5; i++ ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>File outFile = new File( "C:\\dac\\message.txt" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>FileOutputStream outFOS = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>RETRY: while( true ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Someone else is writing or reading file</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( outFile.exists() ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> Thread.sleep( 1000 );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}<span class="Apple-tab-span" style="white-space:pre"> </span></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> // In mean time, someone else might </div><div> // create file and get lock</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> outFOS = new FileOutputStream( outFile );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> fl = outFOS.getChannel().tryLock();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> if( fl == null ) continue RETRY;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> // Else I got the lock! </div><div> // Break out of while(true)</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> break;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception z ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> z.printStackTrace();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> continue RETRY;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.out.println( "New File" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>out = new BufferedOutputStream( outFOS );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Handle data as byte array - most flexible</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>String newString = "message: " + i;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>byte[] outBytes = newString.getBytes();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>out.write( outBytes, 0, outBytes.length );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>out.flush();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( testNoRelease ) Thread.sleep( <a href="tel:1000000000" x-apple-data-detectors="true" x-apple-data-detectors-type="telephone" x-apple-data-detectors-result="2">1000000000</a> );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Must release lock before closing stream</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>fl.release();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>out.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Space out the messages - 10 seconds</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Thread.sleep( 10000 );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception x ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>x.printStackTrace();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} finally {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( fl != null ) fl.release();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( out != null ) out.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception y ) {}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.exit(0);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div>}</div><div><br></div><div>Note that the FileLock is acquired on the FileOutputStream. It is an exclusive lock, the only kind we’ve seen so far, using the FileChannel.tryLock() method. As in OneTalker, but in a different order, we encapsulate the FileOutputStream in a BufferedOutputStream for efficiency. Note that the FileLock must be released before you close the stream!</div><div><br></div><div>Finally, we have the ManyListener class, which shares the file lock with ManyTalker. In this case, the name ManyListener may be deceiving. There should only be one Listener class. The reason for that is the way we need to get a lock on the FileInputStream for reading – we pass the start value (0), the length to be read (Long.MAXVALUE) and a Boolean which indicates we are locking the file in “shared” mode. This type of lock will keep any of our ManyTalker instances from acquiring an “exclusive” lock, but another ManyListener instance could also acquire a “shared” lock on this same file – so we should only have one ManyListener instance.</div><div><br></div><div>public class ManyListener {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>public static void main(String[] args) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Set true to sleep forever (practically) with file locked</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>boolean testNoRelease = false;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>BufferedInputStream in = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>FileLock fl = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Same number loops as Talker</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>for( int i = 0; i < 5; i++ ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>File inFile = new File( "C:\\dac\\message.txt" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>FileInputStream inFIS = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>RETRY: while( true ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Someone else is writing or reading file</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( ! inFile.exists() ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> Thread.sleep( 1000 );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> // In mean time, someone else might get lock</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> inFIS = new FileInputStream( inFile );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> // This is a shared lock, </div><div> // required for reading FileInputStream</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> // It will keep Talker from acquiring </div><div> // an exclusive lock</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> fl = inFIS.getChannel().</div><div> tryLock(0, Long.MAX_VALUE, true );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> if( fl == null ) continue RETRY;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> // Else I got the lock! </div><div> // Break out of while(true)</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> break;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception z ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> z.printStackTrace();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> System.exit(0);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> continue RETRY;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>in = new BufferedInputStream( inFIS );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>byte[] inBytes = new byte[2000];</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int readQty;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( ( readQty = </div><div> in.read( inBytes, 0, inBytes.length ) ) > 0 ) </div><div> {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.out.write( inBytes, 0, readQty );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.out.println();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( testNoRelease ) Thread.sleep( <a href="tel:1000000000" x-apple-data-detectors="true" x-apple-data-detectors-type="telephone" x-apple-data-detectors-result="4">1000000000</a> );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Must release lock before closing and deleting</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// OK, since Talker won't write to an existing file</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// And there should only be one Listener!</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>fl.release();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>in.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>inFile.delete();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( inFile.exists() ) </div><div> System.out.println( "Delete failed" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception x ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>x.printStackTrace();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} finally {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( fl != null ) fl.release();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( in != null ) in.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception y ) {}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.exit(0);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div>}</div><div><br></div><div>As a challenge, you might look at my use of the separate “lock.lock” file on which we acquire an exclusive FileLock, in Part 1 of this blog discussion, and use that same locking paradigm to implement a true “ManyListener” – that is, supporting multiple instances of ManyListener. Note that ManyTalker will have to be similarly modified in order to share the FileLock on “lock.lock”. There is a simple alternative modification that can be made to ManyListener – use a RandomAccessFile instead of the FileInputStream / BufferedInputStream combination. When you instantiate the RandomAccessFile, declare the read/write mode (“rw”). Then you can get an exclusive lock (via FileChannel.tryLock()) and read the file. However, there are some efficiency losses in that solution. A picture is worth a thousand words, and so is code, so here is the RandomAccessFile solution.</div><div><br></div><div>public class ManyListener {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>public static void main(String[] args) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Set true to sleep forever (practically) with file locked</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>boolean testNoRelease = true;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>RandomAccessFile in = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>FileLock fl = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>for( int i = 0; i < 5; i++ ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>File inFile = new File( "C:\\dac\\message.txt" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>RETRY: while( true ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( ! inFile.exists() ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> Thread.sleep( 1000 );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> // Note that to get an exclusive lock, </div><div><span class="Apple-tab-span" style="white-space:pre"> </span> // you must open the file for read/write</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> in = new RandomAccessFile(</div><div> "C:\\dac\\message.txt", "rw" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> fl = in.getChannel().tryLock();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> if( fl == null ) continue RETRY;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> break;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception z ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> z.printStackTrace();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> System.exit(0);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> continue RETRY;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>byte[] inBytes = new byte[2000];</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int readQty;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( ( readQty = </div><div> in.read( inBytes, 0, inBytes.length ) ) > 0 ) </div><div> {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.out.write( inBytes, 0, readQty );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.out.println();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( testNoRelease ) Thread.sleep( <a href="tel:1000000000" x-apple-data-detectors="true" x-apple-data-detectors-type="telephone" x-apple-data-detectors-result="5">1000000000</a> );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>fl.release();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>in.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>inFile.delete();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( inFile.exists() ) </div><div> System.out.println( "Delete failed" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception x ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>x.printStackTrace();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} finally {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( fl != null ) fl.release();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( in != null ) in.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception y ) {}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>System.exit(0);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div>}</div><div><br></div><div>For further research, you might try running the pair of ManyTalker and ManyListener with the Boolean “testNoRelease” set to true (in one at a time). You will see how they wait indefinitely for one another to release the lock.</div><div><br></div><div>One more challenge, if you care to extend this, is to consider how these ideas can be adapted to a two-way file exchange where each class both Talks and Listens, synchronously (I speak and you listen, then we switch roles) or asynchronously (I speak, and either you speak or listen, and I might speak again before you reply). I can imagine the code but can’t think of a good application – perhaps “Auto-Chat”.</div><div><br></div><div>Now our second “aside” -- this should have been included in the “Part 1” blog of this discussion. In addition to writing to the centralized log, you may want to read from it and place the output in a report web page. In this case, you should acquire a FileLock on the same file used for writing to the log, as shown in the reportCentralLog() method, below. The only concern here is that, the way this is written, you will retain the lock while you read through the entire file – thus keeping others from writing to the log for an extended period. This is probably not a good idea. Perhaps you should only read the tail end of the file (for example, get the file length (e.g., 50,000) and start reading from an offset 5,000 before the end (e.g., using the byte array reading paradigm, in.read( inBytes, 45000, readQty);) ).</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>private static String reportCentralLog( String message ) </div><div> throws ServletException </div><div> {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>StringBuffer rtrnSB = new StringBuffer();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Need something external to this JVM to test singularity</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>FileOutputStream fos = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>FileLock fl = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>BufferedReader centralIn = null;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>fos = new FileOutputStream( "\\\\server\\dir\\lock.lock" );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>fl = fos.getChannel().tryLock();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// Null when can't get exclusive lock on file</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while (fl == null) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Thread.sleep(1000);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>fl = fos.getChannel().tryLock();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch (Exception v) {}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// At this point, I have exclusive lock on file!</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>centralIn = new BufferedReader( </div><div> new FileReader( "\\\\server\\dir\\central.log" ) );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>// File read (and written) a line at a time</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>String inString;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>while( ( inString = centralIn.readLine() ) != null ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>rtrnSB.append( inString );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception x ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>throw new ServletException( x.toString() );</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} finally {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( centralIn != null ) centralIn.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception y ) {}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>try {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( fl != null ) fl.release();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if( fos != null ) fos.close();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} catch( Exception y ) {}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>return rtrnSB.toString();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><br></div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-68853852538930850912013-10-26T23:12:00.001-04:002013-10-26T23:12:12.837-04:00Coding a Fast Browser Proxy Script<div>Well, I checked Google and wasn’t satisfied that this information was generally available…</div><div><br></div><div>So, I’m reviving some research I did in 2003 that led to significant speed increase in dealing with browser proxy determination. The enterprise environment where you would apply this tactic is one where you have multiple routes to internet and corporate resources, multiple on-site subnets (including non-routed subnets) and varying levels of authentication and html tag filtering that you want to enforce.</div><div>The problem with most example proxy scripts that address these issues is that they use a cookie-cutter approach to determining where to forward a user-entered request. Often they use the most basic approach which is to do a DNS lookup on the hostname and see if it belongs to a specific subnet.</div><div><br></div><div>Eventually, most non-local addresses need to be determined by a DNS lookup, but DNS lookups are costly in time and network resources. It is best to reduce DNS lookups required, or even to eliminate them, where possible.</div><div><br></div><div>One clear example where DNS lookup is not required is where the host name contains the string of your corporate subnet name; for example, apps.org.com contains the subnet name org.com. For that host, the proxy script should return immediately with the directive “DIRECT”, which means don’t go through the proxy.</div><div><br></div><div>But in a large enterprise environment, there may be hosts on the open internet (on a DeMilitarized Zone, DMZ network) that have the same subnet name, like www.org.com. That host will need to be addressed by enterprise workstations, using the proxy script, through a proxy server (and through a router off the enterprise LAN). This test needs to be done before the check described above, where addresses with our enterprise subnet name are directed to be found “DIRECT”.</div><div><br></div><div>Here is the basic script (e.g., proxyscript.pac) to get us this far:</div><div><br></div><div>function FindProxyForURL(url, host)</div><div>{</div><div> var mHost = host.toLowerCase();</div><div><br></div><div> if( (mHost == "public1" ) ||</div><div> (mHost == "public2" ) ||</div><div> (mHost == "public1.org.com") ||</div><div> (mHost == "public2.org.com")</div><div> )</div><div> return "PROXY clearproxy.org.com:8080";</div><div><br></div><div> // dnsDomainIs() resolves upper and lower case domain</div><div> if( dnsDomainIs(host, ".org.com") )</div><div> return "DIRECT";</div><div><br></div><div>This script, so far, does not do any DNS lookups. Notice that the “host” parameter that is being passed to the FindProxyForURL() function is whatever hostname the user enters in the browser address line. For local hosts, the subnet name (“org.com”) does not need to be included, so we represent the host name in our script, both with and without the subnet name. These hosts, since they are ours, might be available through a proxy (e.g., clearproxy) that does not require authentication and perhaps does not do html tag filtering. It is a security measure that is often enforced, that everything within a set of <applet></applet>, <embed></embed>, and/or <object> tags is removed by the proxy before the page is delivered to the client browser.</div><div><br></div><div>There may be some additional hosts on the open internet that belong to our Parent company, for which we also don’t want to do authentication or tag filtering. We can direct the browser to the correct proxy, again without doing a DNS lookup for those specific hosts:</div><div><br></div><div> if( (mHost == "www.parent.com" ) ||</div><div> (mHost == "www.sister.com")</div><div> )</div><div> return "PROXY clearproxy.org.com:8080";</div><div><br></div><div>At this point, we are going to have to do a DNS lookup to get the address of the host. We will then use the host IP address to determine the proxy directive required. If the host IP address is bogus, we simply return the “DIRECT” directive – whether it works for the browser or not.</div><div><br></div><div> var HostIP = "<a href="tel:999.999.999.999" x-apple-data-detectors="true" x-apple-data-detectors-type="telephone" x-apple-data-detectors-result="11">999.999.999.999</a>";</div><div><br></div><div> // First 1 or 2 DNS queries here</div><div> if( isPlainHostName(host) || isResolvable(host) )</div><div> HostIP = dnsResolve(host);</div><div><br></div><div> // On bogus HostIP, or localhost, we are done!</div><div> if( (HostIP == null ) ||</div><div> (HostIP == "999.999.999.999") ||</div><div> (HostIP == "127.0.0.1" ) ||</div><div> (HostIP == "" )</div><div> )</div><div> return "DIRECT";</div><div><br></div><div>Next we want to identify our local, enterprise subnets by IP address, and return the directive “DIRECT”, as in “no proxy required”. We should order this list by likelihood that the browser will be addressing hosts in that subnet, because each test may require a separate DNS query. For example, if our data center is in subnet 111.11.0.0, and our desktop workstations are in subnet 122.22.22.0, then we would list 111.11.0.0 first, since browsers would most likely be addressing hosts in our data center. We also include non-routed subnets, if needed.</div><div><br></div><div> if( isInNet(HostIP, "111.11.0.0" ,"255.255.0.0" ) ||</div><div> isInNet(HostIP, "122.22.22.0" ,"255.255.255.0" ) ||</div><div> isInNet(HostIP, "192.168.0.0" ,"255.255.0.0" ) ||</div><div> isInNet(HostIP, "172.16.0.0" ,"255.240.0.0" ) ||</div><div> isInNet(HostIP, "10.0.0.0" ,"255.0.0.0" )</div><div> )</div><div> return "DIRECT";</div><div><br></div><div>If you deal with users, you will find that some will have a unique need to get to a server on the internet that cannot handle your usual tag filtering. Or perhaps you have some users that need to get to a site (for example a benefits site, like Blue Cross Blue Shield) but who don’t have credentials to authenticate to the proxy. Those kinds of exceptions will require a separate block in your proxy script, like this:</div><div><br></div><div> if( isInNet(HostIP, "33.33.33.0", "255.255.255.0" ) )</div><div> return "PROXY alternateproxy.org.com:8080";</div><div><br></div><div>Finally, you may have several dedicated network routes to corporate subnets (Parent or sister companies) that are not local, for which unique proxy provisions apply (probably no authentication and no tag filtering to resources on those subnets). For those subnets, you will go through an appropriate proxy, and for EVERYTHING ELSE, you will send the browser through your standard proxy.</div><div><br></div><div> if(</div><div> isInNet(HostIP, "144.44.0.0" ,"255.255.0.0" ) ||</div><div> isInNet(HostIP, "155.55.0.0" ,"255.255.0.0" ) ||</div><div> isInNet(HostIP, "166.66.66.0" ,"255.255.255.0" ) ||</div><div> isInNet(HostIP, "177.77.77.77" ,"255.255.255.252")</div><div> )</div><div> return "PROXY parentproxy.org.com:8080";</div><div> else</div><div> return "PROXY externalproxy.org.com:8080";</div><div>}</div><div><br></div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-84311851167620007392013-10-26T22:59:00.001-04:002013-10-26T22:59:38.938-04:00Java Method Access Modifiers<font style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">In talking to my son, Matthew, who is also a Java programmer, I described a simple understanding of the access modifiers applied to methods: default (package), public, private and protected. In summary, I said:</font><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">1) Protected is for situations you will rarely, if ever, encounter – keeping methods from being implemented in a subclass</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">2) Public is for when you write a method that you want everybody to call</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">3) Private is for methods that you only ever want called from this specific class</span></p><p><span style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">4) No-modifier (default or package) is appropriate for almost everything – it allows your method to be called by other classes in your package, but not by other folks’ classes (in other packages)</span></p><p><font style="-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">I mentioned that I had on occasion abused those rules when using classes written by others. A couple times, I created an empty folder hierarchy in my project that mirrored someone else’s package and created my class there so I could use their package-access resources. For example, I once extended sun.net.ftp.TransferProtocolClient, creating my own FTPClient class with the addition of methods to do such things as proxy login, make directory, make path and chmod. That was in 2003, when Sun was pretty strict about the sun.* packages and classes. I just now edited that FTPClient code in Eclipse, referring to a new JDK and found that not only does sun.net.ftp.FtpProtocolException no longer extend IOException (requiring major code updates); but also, I can extend TransferProtocolClient in a different package with no problem. In this case, I no longer need to mirror the original package in order to extend the class – and I conclude that the resources I need to access are no longer package-protected, they are public.</font></p>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-14742616909292530422013-10-12T07:44:00.001-04:002013-10-12T07:44:10.427-04:00New Oracle Installation Lockdown
<br />
<a href="https://www.blogger.com/" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a><a href="https://www.blogger.com/" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a><a href="https://www.blogger.com/" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a><a href="https://www.blogger.com/" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a><span style="font-family: "Arial","sans-serif"; font-size: 10pt;">It is my
standard practice to turn off services and applications which are not needed.
I do this as an administrative account; however, I regularly run as a
non-administrative account, and you should too.</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">1)
Typically, I remove everything from Windows Start Menu /
All Programs / Startup (C:\ProgramData\Microsoft\Windows\Start
Menu\Programs\Startup ).</span> <br />
<o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt; mso-ansi-language: EN-US; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;">2) Then I run the
Registry Editor (regedit.exe) and search for Keys that match the whole string
“run”, as shown below. Search the entire registry (find next from top to
bottom) and comment applications that need not run (some call this stuff
“Crapware”). Typically, I add “x_” in front of the application command,
as shown below. Note that you may need to research each application
listed in order to determine whether or not it is needed on your system.</span><span style="font-family: "Times New Roman","serif"; font-size: 12pt; mso-ansi-language: EN-US; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;"> </span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-pfAcz8QXMIs/Ulk1byiAX_I/AAAAAAAAAMQ/f7c6zUhdtVo/s1600/a.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-pfAcz8QXMIs/Ulk1byiAX_I/AAAAAAAAAMQ/f7c6zUhdtVo/s1600/a.gif" height="196" width="320" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-lSKGXtk0suc/Ulk1iWzzqaI/AAAAAAAAAMY/U7pX06VOcN0/s1600/b.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-lSKGXtk0suc/Ulk1iWzzqaI/AAAAAAAAAMY/U7pX06VOcN0/s1600/b.gif" height="64" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-dOk6O3llseY/Ulk1pcM7xbI/AAAAAAAAAMg/JDi5B1wv1ZE/s1600/c.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-dOk6O3llseY/Ulk1pcM7xbI/AAAAAAAAAMg/JDi5B1wv1ZE/s1600/c.gif" height="34" width="320" /></a></div>
<br />
<span style="font-family: "Times New Roman","serif"; font-size: 12pt; mso-ansi-language: EN-US; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;"></span><br />
<br />
<span style="font-family: "Times New Roman","serif"; font-size: 12pt; mso-ansi-language: EN-US; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;">
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">3)
Finally, I run Computer Management (%windir%\system32\compmgmt.msc
/s) and set any Services that are not needed from “Automatic” to “Manual”
startup.</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">When Oracle
12c is installed, there are several Services that are created, and most of them
are set for “Automatic” startup. On my development workstation, I only
start Oracle as needed (as shown below), but even in production environments,
several of these Services may not be required at all times – they should be
started only as needed.</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-1jJT2IV6-p0/Ulk16DFRcGI/AAAAAAAAAMo/E1A7-YVCwP4/s1600/d.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-1jJT2IV6-p0/Ulk16DFRcGI/AAAAAAAAAMo/E1A7-YVCwP4/s1600/d.gif" height="78" width="320" /></a></div>
<o:p></o:p><br />
</span>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-73233089613847795082013-10-12T07:33:00.001-04:002013-10-12T07:33:18.335-04:00Oracle Create Session Role and Kicking Everybody Off
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">Do not use
the default Oracle role, Connect. Use of that role is deprecated. Instead,
create a role to provide valid users with the Create Session privilege.
(Please refer to my book, “Expert Oracle and Java Security”.) Do
not grant the Create Session privilege directly to users; but rather, grant
them your role. Here is an example:</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">create role
create_session_role not identified;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">grant create
session to create_session_role;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">create user
username identified by userpassword container=CURRENT;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">grant
create_session_role to username;</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">Note that
the qualifier “container=CURRENT” is for Pluggable Database (PDB) instances in
Oracle 12c.</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">You should
ask, “besides adhering to a philosophy or rule of standardization, why should I
use a role for the Create Session privilege? After all, all standard
users need to be able to connect.” In this case, our role is less for
providing a standard grant for users to connect than it is for providing a
mechanism to remove that ability without deleting the users (or shutting down
the listener or database.) Basically, the create_session_role role provides
us a mechanism for kicking everyone off an active Oracle instance.</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">Say, for
example, we have a hundred user accounts, and all have been granted the
create_session_role role. At any time, twenty of those users may be
connected. Now, for some security or administrative reason, we need to
stop all user activity without shutting down the database. First we need
to assure that no one else can connect, and that the current users cannot
reconnect. This is the easy part. We simple revoke the Create Session
privilege from create_session_role.</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">revoke
create session from create_session_role;</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">This does
not also have the effect of breaking the current sessions. Those have
already been “created”; and so for active sessions, the Create Session
privilege has already been used, and is no longer needed. For active
sessions, we need to manually kill them to stop their activity. This
Anonymous PL/SQL Block will kill all active sessions, except the current
session in which it is run.</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">declare</span>
<o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
pragma autonomous_transaction;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
m_sid v$session.SID%TYPE;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
cursor session_cur is</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
select serial#, sid from sys.v$session</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
where type='USER' and not sid = m_sid;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
session_rec session_cur%ROWTYPE;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">begin</span>
<o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
-- Oracle will not let you kill your own current, active session</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
m_sid := SYS_CONTEXT( 'USERENV', 'SID' );</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
open session_cur;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
loop</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
fetch session_cur into session_rec;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
exit when session_cur%NOTFOUND;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
dbms_output.put_line( 'Killing: ' ||</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
session_rec.SID || ', ' ||
session_rec.serial# );</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
execute immediate 'ALTER SYSTEM KILL SESSION ''' ||</span>
<o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
session_rec.SID || ', ' ||
session_rec.serial# || '''';</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
end loop;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">
close session_cur;</span> <o:p></o:p><br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">end;</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">In this
block, we create a cursor (session_cur) of active sessions, selected from
sys.v$session; so this needs to be run by an account with SYS, SYSTEM or DBA
level privileges. We only care about USER sessions. Also, we filter
out the current session by Session ID (SID). We find our current SID from
the USERENV environment of the SYS_CONTEXT context.</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">We loop
through our cursor, getting each record (session_rec) while there are more to
find. We print out a line to DBMS_OUTPUT for each session we are killing.
And we call EXECUTE IMMEDIATE, passing the ALTER SYSTEM command syntax
required to kill each session.</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">So everybody
is kicked off the database, except the current user. And no one may
connect / reconnect. The current user may grant Create Session to any
additional user needed for troubleshooting or research on the current
situation. After the situation is remedied, and normal operations are
restored, users can be permitted to connect once again with a single grant:</span>
<o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">grant create
session to create_session_role;</span> <o:p></o:p><br />
<br />
<span style="font-family: "Arial","sans-serif"; font-size: 10pt;">Now, we are
very glad to have a role to distribute this privilege to all users.</span> <o:p></o:p><br />
David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-9802550117707282222013-10-12T07:20:00.003-04:002013-10-12T07:20:59.456-04:00Java Synchronization and Concurrency Across Multiple JVMs, Multiple Computers
<span style="font-family: Calibri;">It is pretty standard fare for a Java application to
coordinate multiple uses of a single resource by using the “synchronized” key
word.<span style="mso-spacerun: yes;"> </span>But there are times when a single
resource must be used by multiple programs running in separate Java Virtual
Machines (JVMs), perhaps even on different computers.<span style="mso-spacerun: yes;"> </span>Synchronizing use of that resource involves a
bit more planning.<span style="mso-spacerun: yes;"> </span>Let’s look at
single-JVM synchronization first so we can see where, how and why cross-JVM
synchronization may be applied.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Typically, resources like counters and files that are used
by multiple threads (multiple concurrent users) in a web application require
synchronization.<span style="mso-spacerun: yes;"> </span>In a Java Servlet, the
doGet() and doPost() methods are multithreaded.<span style="mso-spacerun: yes;">
</span>Each web browser addressing the web application will have a separate
thread, executing the method independently and concurrently.<span style="mso-spacerun: yes;"> </span>Whenever those methods update a resource that
is declared outside of the method scope, it is a shared resource, and that
update should be synchronized.<o:p></o:p></span></div>
<span style="font-family: Calibri;">There are a couple easy ways to synchronize use of those
resources.<span style="mso-spacerun: yes;"> </span>We can make a method
synchronized so that only one thread can use it at a time – all other threads
will queue up until the synchronized method is available – they will take
turns.<span style="mso-spacerun: yes;"> </span>A second way to synchronize use
of a resource is to update the resource within a synchronized block.<span style="mso-spacerun: yes;"> </span>Let’s look at an example.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> SynchServlet </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> HttpServlet {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> PrintWriter </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">fileOut</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">; </span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Synchronize use
of this!</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> init( ServletConfig
config ) </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">super</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">.init( config );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">fileOut</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> PrintWriter( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"logfile.log"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( Exception x ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throw</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException(
x.toString() );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> destroy(
ServletConfig config ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">fileOut</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.close();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> doGet(
HttpServletRequest req, HttpServletResponse res )</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException,
IOException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><i>logWrite</i>(
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Using
doGet()"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//…</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> doPost(
HttpServletRequest req, HttpServletResponse res )</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException,
IOException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><i>logWrite</i>(
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Using
doPost()"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//…</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> logWrite( String
logEntry ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">fileOut</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println( logEntry );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}<o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="font-family: Calibri;">In this first example, each time a browser calls on the
doGet() and doPost() methods we will write to a log file. We need to have these
threads take turns, so only one thread attempts to write to the file at a time
– if more than one write occurs concurrently, a runtime exception will be
generated.<span style="mso-spacerun: yes;"> </span>The simplest way get the
threads to take turns is to place the actual log file write in a synchronized
method.<span style="mso-spacerun: yes;"> </span>The example logWrite() method is
modified with the “synchronized” key word so that each thread in this web
application (Servlet) will wait until the logWrite() method is available, then
the thread will lock the method for exclusive use until finished.<span style="mso-spacerun: yes;"> </span>After that, the lock will be released, and
the next thread will be able to use the method.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">This synchronized method is static, so the lock is applied
to the SynchServlet class, not to an instance of SynchServlet – that difference
is irrelevant in this case, since there is usually only one instance of a
Servlet.<span style="mso-spacerun: yes;"> </span>However, in most cases, both “static”
and “synchronized” modifiers should be used for a single resource that is
shared within a JVM.<span style="mso-spacerun: yes;"> </span>As a public static
method, you can call it from other classes, and it will enforce the same synchronization
controls, like this:<o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>SynchServlet.<i>logWrite</i>(
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Some
other message"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="font-family: Calibri;">Another way we can synchronize multiple threads using a
shared resource is to put every use of the resource in synchronized blocks.<span style="mso-spacerun: yes;"> </span>The following example shows how we might
implement a doGet() success counter.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> SynchServlet </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> HttpServlet {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">int</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> = 0;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> Object </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> Object();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> doGet(
HttpServletRequest req, HttpServletResponse res )</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException,
IOException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {<span style="mso-tab-count: 1;"> </span></span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">++;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//…<span style="mso-tab-count: 3;"> </span></span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"There are
"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> +
</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 5;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> + </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">" doGet()
successes!"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( Exception x ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">--;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throw</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException(
x.toString() );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}<o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="font-family: Calibri;">Notice in this example that we increment the
doGetSuccessCounter integer in the doGet() method, and we decrement
doGetSuccessCounter in the catch block – just for fun, we do not count a thread’s passage
through doGet() as a “success” if an Exception is thrown.<span style="mso-spacerun: yes;"> </span>Again we want to synchronize use of this
shared resource (it is declared outside the method scope) so that we count and
discount for every thread calling doGet(), without concurrent threads
overwriting one another.<span style="mso-spacerun: yes;"> </span>In addition, we
synchronize around the report of the current value of doGetSuccessCounter so we
are guaranteed to get the current value (after any other lock is released and
we have exclusive access to the integer.)<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Notice that in each case, when we set up the synchronized
block, we specify that the synchronization lock be placed on an object named
synchObject.<span style="mso-spacerun: yes;"> </span>Any Java object can be used
for synchronization locking, but not primitives – that is, we could lock on an
Integer.class instance but not on an int primitive.<span style="mso-spacerun: yes;"> </span>Our example instantiates an object of type
Object named synchObject, and we use it for all the synchronized blocks.<span style="mso-spacerun: yes;"> </span>Synchronized blocks must share the lock on a
single object in order to coordinate their execution – so all our example
synchronized blocks share the lock on synchObject.<span style="mso-spacerun: yes;"> </span>Of all the synchronized blocks on
synchObject, only one at a time may acquire the lock and execute.<span style="mso-spacerun: yes;"> </span>The lock is automatically released at the end
of the synchronized block.<o:p></o:p></span></div>
<span style="font-family: Calibri;">You might observe that we have three separate synchronized
blocks and that we could get rid of all of them if we just make the doGet()
method synchronized.<span style="mso-spacerun: yes;"> </span>I love code
reduction and refactoring, but this is one case where it would be a very bad
plan.<span style="mso-spacerun: yes;"> </span>If we made the doGet() method
synchronized, then only one browser could view our Servlet at a time; also, the
entire doGet() would need to execute before the lock is released.<span style="mso-spacerun: yes;"> </span>You always want to limit the amount of time
and processing that is done in a synchronized block or synchronized method.<span style="mso-spacerun: yes;"> </span>Look back at our examples, at the minimal synchronized
block / method.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Also note that since synchObject is modified with the
“static” keyword, all instances of the SynchServlet class will share the same
lock – that is typically what you want for shared locks within a JVM.<span style="mso-spacerun: yes;"> </span>If you also share the resource in another
class (perhaps another servlet), you would lock on this same static object,
like this:<o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( SynchServlet.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>SynchServlet.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">++;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="font-family: Calibri;">Synchronized methods and synchronized blocks are
foundational concurrency tools.<span style="mso-spacerun: yes;"> </span>There
are a number of other synchronization and concurrency techniques, many
Thread-safe classes and the java.util.concurrent packages that may be also
used.<span style="mso-spacerun: yes;"> </span>All of them deal with
synchronization within a single JVM.<span style="mso-spacerun: yes;">
</span>Probably the clearest example of when all these techniques fall short is
when you are running Java applications on separate computers and need to update
a shared resource, like a file.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Typically, you might run an independent service to update
the shared file.<span style="mso-spacerun: yes;"> </span>You would provide a
network port (or messaging) interface to the service so that all the
applications that update the file can send messages to the service which would
serve as a proxy to update the (shared) file on their behalf.<span style="mso-spacerun: yes;"> </span>Alternatively, you could just update a database using JDBC.<o:p></o:p></span></div>
<span style="font-family: Calibri;">However, it is possible to program synchronization into
applications so that they can share and update a resource, even when running in
separate JVMs.<span style="mso-spacerun: yes;"> </span>In this case, we cannot
share a lock on a Java object by using the synchronized keyword – no objects
are shared between separate JVMs.<span style="mso-spacerun: yes;">
</span>Instead we lock on a file.<span style="mso-spacerun: yes;"> </span>We
depend on the locking mechanisms inherent in the Operating System (OS) filesystem in
order to synchronize our efforts.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Here is an example that shows how code running in separate
JVMs can share updates to a file.<span style="mso-spacerun: yes;"> </span>The
shared file that we are updating is named “central.log”.<span style="mso-spacerun: yes;"> </span>I’m using the escaped double backskash to
indicate the file is found on a fileshare named </span><a href="file://server/dir"><span style="color: blue; font-family: Calibri;">\\server\dir</span></a><span style="font-family: Calibri;">.<span style="mso-spacerun: yes;"> </span>I refer to another file named “lock.lock” on
that same fileshare.<span style="mso-spacerun: yes;"> </span>We will get an
exclusive file lock on the “lock.lock” file before we do any updates to
“central.log”.<span style="mso-spacerun: yes;"> </span>Note that the method,
centralLog() can be included in several applications, running in different
JVMs, perhaps on different servers; and they will all be able to coordinate
updates to the “central.log” file.<o:p></o:p></span></div>
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> SynchServlet </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> HttpServlet {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> init( ServletConfig
config ) </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">super</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">.init( config );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><i>centralLog</i>(
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Starting
SynchServlet"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> centralLog( String
message ) </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Need something
external to this JVM to test singularity</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"> FileOutputStream fos = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span><span style="mso-spacerun: yes;"> </span><span style="mso-tab-count: 1;"> </span>FileLock
fl = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span><span style="mso-spacerun: yes;"> </span><span style="mso-tab-count: 1;"> </span>PrintWriter
centralOut = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 1;"> </span><span style="mso-spacerun: yes;"> </span>fos= </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> FileOutputStream( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"\\\\server\\dir\\lock.lock"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span>fl = fos.getChannel().tryLock();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Null when can't get exclusive lock on
file</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">while</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( fl == </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span><span style="mso-spacerun: yes;"> </span><span style="mso-tab-count: 1;"> </span><span style="mso-spacerun: yes;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span>Thread.<i>sleep</i>(1000);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span>fl
= fos.getChannel().tryLock();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span><span style="mso-tab-count: 1;"> </span><span style="mso-spacerun: yes;"> </span>} </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( Exception v ) {}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// At this point, I have exclusive lock on
file!</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span>centralOut = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> PrintWriter( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"\\\\server\\dir\\central.log"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><span style="mso-spacerun: yes;"> </span>centralOut.println( message );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( Exception x ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throw</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException(
x.toString() );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 1;"> </span>} </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">finally</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 4;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( centralOut != </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> )
centralOut.close();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 2;"> </span>} </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">(Exception y) {}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 4;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( fl != </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) fl.release();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 4;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( fos != </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) fos.close();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 2;"> </span>} </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">(Exception y) {}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}<o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="font-family: Calibri;">There are three classes in the java.io package that can
provide FileChannel objects: FileInputStream, FileOutputStream and
RandomAccessFile.<span style="mso-spacerun: yes;"> </span>In our example, we
instantiate a FileOutputStream on the “lock.lock” file and call getChannel() to
get the FileChannel object.<span style="mso-spacerun: yes;"> </span>There are
several methods to get an exclusive lock on a FileChannel.<span style="mso-spacerun: yes;"> </span>We use the FileChannel.tryLock() method in
our example.<span style="mso-spacerun: yes;"> </span>If tryLock() is
unsuccessful, it returns null, else it returns the associated FileLock
object.<span style="mso-spacerun: yes;"> </span>In our example, we call
tryLock() then test the return value for null.<span style="mso-spacerun: yes;">
</span>If it is null, we sleep for one second then try again, in the while(
null ) loop.<span style="mso-spacerun: yes;"> </span>When the FileLock is not
null, we have an exclusive lock and can update shared resources.<span style="mso-spacerun: yes;"> </span>It is very important that we release the
FileLock.<span style="mso-spacerun: yes;"> </span>For this reason, I have an
independent try/catch block within the finally block that calls the release()
method on the FileLock object.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">I use a separate file, “lock.lock” for the FileLock,
separate from the shared file that applications update, “central.log”.<span style="mso-spacerun: yes;"> </span>We could alternatively establish the FileLock
on the shared file.<span style="mso-spacerun: yes;"> </span>I use a separate
file for locking for a couple reasons: it makes the lock file job more obvious
and explicit, and occasionally the object I’m sharing is not a file. <span style="mso-spacerun: yes;"> </span>I have had to implement this style locking to
accommodate a dedicated, single-user port: for example a serial port server, or
in one bizarre situation, an FTP client that required a fixed port (per
firewall rules), like this:<o:p></o:p></span></div>
<span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//package
org.apache.commons.net.ftp;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">package</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> dac;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
org.apache.commons.net.ftp.*;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
org.apache.commons.net.ftp.parser.*;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> FTPClient </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> FTP {<o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>…</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">int</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> getActivePort() {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">true </span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">) </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">return</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> 11111; </span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// requires <u>ip</u>
/ port filter permission<o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="font-family: Calibri;">Let me mention the limitation of this file locking
strategy.<span style="mso-spacerun: yes;"> </span>It does not work between JVMs
running on different OS architectures.<span style="mso-spacerun: yes;">
</span>If all your JVMs are running on Windows or all your JVMs are running on UNIX,
there is no problem; however, you cannot obtain an exclusive lock on a file
from a Windows computer and have that lock observed on a UNIX computer, nor
vice versa.<span style="mso-spacerun: yes;"> </span>On the bright side, you can
have a JVM on a Windows computer get an exclusive lock on a file that resides on
a UNIX computer, and other Windows JVMs will observe the lock.<span style="mso-spacerun: yes;"> </span>The same is true for JVMs on UNIX obtaining
exclusive locks on files that reside on Windows.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">There is also a risk that while a file is locked, the JVM
may unexpectedly quit without completing the finally block and releasing the
lock.<span style="mso-spacerun: yes;"> </span>And there is a risk that if the
locked file is on a remote computer, there may be a network failure, or the
locking computer may unexpectedly reboot; which could leave the file in a
locked state.<span style="mso-spacerun: yes;"> </span>A key to avoiding this
scenario is to only keep a file locked for the minimum time required.<span style="mso-spacerun: yes;"> </span>Lock it, do your work, unlock it ASAP.<o:p></o:p></span></div>
<span style="font-family: Calibri;">Thus ends part one of this story, Java Synchronization
Across JVMs.<span style="mso-spacerun: yes;"> </span>In part two, I will discuss
flag-passing synchronization.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">The complete code follows:<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">package</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> dac;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
java.io.FileOutputStream;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> java.io.IOException;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> java.io.PrintWriter;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
java.nio.channels.FileLock;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
javax.servlet.ServletConfig;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
javax.servlet.ServletException;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
javax.servlet.http.HttpServlet;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
javax.servlet.http.HttpServletRequest;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> javax.servlet.http.HttpServletResponse;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> SynchServlet </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> HttpServlet {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">final</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">long</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">serialVersionUID</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> = 1L;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> PrintWriter </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">fileOut</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">; </span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Synchronize use
of this!</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">int</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> = 0;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> Object </span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> Object();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><span style="color: #646464; font-family: Consolas; font-size: 10pt;">@Override</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> init(ServletConfig
config) </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">super</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">.init(config);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span><i>centralLog</i>(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Starting
SynchServlet"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">fileOut</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;"> = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> PrintWriter(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"logfile.log"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (Exception x) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throw</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
ServletException(x.toString());</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
destroy(ServletConfig config) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">fileOut</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.close();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><span style="color: #646464; font-family: Consolas; font-size: 10pt;">@Override</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
doGet(HttpServletRequest req, HttpServletResponse res)</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException,
IOException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">++;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span><i>logWrite</i>(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Using
doPost()"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// …</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span><i>logWrite</i>(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"There are
"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> +
</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 6;"> </span>+
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"
doGet() successes!"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"There are
"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> +
</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 6;"> </span>+
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"
doGet() successes!"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (Exception x) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">--;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throw</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
ServletException(x.toString());</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
altGet(HttpServletRequest req, HttpServletResponse res)</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException,
IOException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (SynchServlet.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span>SynchServlet.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">++;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>SynchServlet.<i>logWrite</i>(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Some other
message"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// …</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span><span style="mso-tab-count: 1;"> </span><i>logWrite</i>(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"There are
"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> +
</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 6;"> </span>+
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"
doGet() successes!"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"There are
"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> +
</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 6;"> </span>+
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"
doGet() successes!"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (Exception x) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">synchObject</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">doGetSuccessCounter</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">--;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throw</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
ServletException(x.toString());</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><span style="color: #646464; font-family: Consolas; font-size: 10pt;">@Override</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
doPost(HttpServletRequest req, HttpServletResponse res)</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException,
IOException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span><i>logWrite</i>(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Using
doPost()"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// …</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// synchronized
instance method, not class method (static)</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">synchronized</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> logWrite(String
logEntry) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">fileOut</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println(logEntry);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">private</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> centralLog(String
message) </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throws</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> ServletException {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Need something
external to this JVM to test singularity</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>FileOutputStream
fos = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>FileLock
fl = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>PrintWriter
centralOut = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>fos
= </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> FileOutputStream(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"\\\\server\\dir\\lock.lock"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>fl
= fos.getChannel().tryLock();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Null when can't
get exclusive lock on file</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">while</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (fl == </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 5;"> </span>Thread.<i>sleep</i>(1000);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 5;"> </span>fl
= fos.getChannel().tryLock();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (Exception v) {}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// At this point, I
have exclusive lock on file!</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>centralOut
= </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> PrintWriter(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"\\\\server\\dir\\central.log"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>centralOut.println(message);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (Exception x) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">throw</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
ServletException(x.toString());</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">finally</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (centralOut != </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">) centralOut.close();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (Exception y) {}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (fl != </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">) fl.release();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 4;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (fos != </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">null</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">) fos.close();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 3;"> </span>}
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> (Exception y) {}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 2;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-tab-count: 1;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<o:p><span style="font-family: Calibri;"> </span></o:p></div>
David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com4tag:blogger.com,1999:blog-7183773701017655963.post-40257988878497026822013-10-12T06:58:00.001-04:002013-10-12T06:58:45.492-04:00Cross-Platform Java Details on Compiling and JNA - Getting Extended User Name, Windows and gecos
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">One of the great things about Java is cross-platform runtime
execution of code .<span style="mso-spacerun: yes;"> </span>For example, we can
compile web applications to be run in Tomcat and can run them on both Windows
and UNIX servers.<span style="mso-spacerun: yes;"> </span>In addition to
cross-platform web applications, I write utilities in Java, and I benefit from
cross-platform runtime compatibility.<o:p></o:p></span></div>
<span style="font-family: Calibri;">However, there are some pitfalls to watch out for!<span style="mso-spacerun: yes;"> </span>For one thing, directory structures are
different across platforms.<span style="mso-spacerun: yes;"> </span>On UNIX
systems, directory structures start at the root “/” and get assembled at mount
points.<span style="mso-spacerun: yes;"> </span>For example “/” might be a mount
point for one drive, and “/usr” might be a mount point for a separate
drive.<span style="mso-spacerun: yes;"> </span>On Windows, the directory
structure takes a different form with drive letters mapped to each drive, for
example “C:” is usually the boot drive.<span style="mso-spacerun: yes;">
</span>These generalizations are standard and typical; although, there’s always
a new mousetrap, for better or worse.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Other areas of difference between Windows and UNIX systems
are worth mentioning.<span style="mso-spacerun: yes;"> </span>(1) The classpath
separator character on UNIX is “:” while the classpath separator on Windows is
“;”.<span style="mso-spacerun: yes;"> </span>This is usually not a factor in Java
code, but is a concern for getting your java runtime started.<span style="mso-spacerun: yes;"> </span>(2) The directory (path) separator is forward
slash (“/”) on UNIX and backslash (“\”) on Windows.<span style="mso-spacerun: yes;"> </span>In Java code, it is always good to use the
forward slash (UNIX style) path separator.<span style="mso-spacerun: yes;">
</span>This will be handled correctly on both Windows and UNIX.<span style="mso-spacerun: yes;"> </span>Because the backslash character has dual
meaning (it’s a character and an “escape” character), to use it as a path
separator, you need to double it, like “\\Windows\\System32”.<span style="mso-spacerun: yes;"> </span>(3) The line separator character is different
between UNIX and Windows.<span style="mso-spacerun: yes;"> </span>Windows uses
two characters: carriage return (CR, 0x0D, “\r”) and line feed (LF, 0x0A, “\n”);
while UNIX only uses line feed.<span style="mso-spacerun: yes;"> </span>The IO
and NIO classes in Java which read lines (like
java.io.BufferedReader.readLine()) will accommodate either line separator
syntax, but if you intend to read lines manually (byte by byte) then you will
need to be aware of this difference and handle it accordingly.<o:p></o:p></span></div>
<span style="font-family: Calibri;">Now to the heart of this discussion...<span style="mso-spacerun: yes;"> </span>There are certain aspects of Java that are
not cross-platform capable.<span style="mso-spacerun: yes;"> </span>These are
few, and are not included in the standard Java library packages.<span style="mso-spacerun: yes;"> </span>One thing that is done differently on
different platforms is acquiring the user id and name.<span style="mso-spacerun: yes;"> </span>You can imagine that Windows and UNIX keep
user information in different formats.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">A simple effort can be made to acquire the current userID
from the Java system properties with a simple call like this:<o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;">String userID = System.<i>getProperties</i>().getProperty(
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"user.name"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">This approach is much better than reading the operating
system environment, and I’m almost embarrassed to say that in my almost 2
decades of writing Java, I have done that more than once.<span style="mso-spacerun: yes;"> </span>Here’s an example from code I wrote in 2008:<o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;">Process proc;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">Runtime rt = Runtime.getRuntime();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.arch"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ).equals( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"x86"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) &&</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.name"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ).startsWith( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Windows"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) )</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">{</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>proc = rt.exec( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"cmd /c set"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">} </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">else</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>proc = rt.exec( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"ksh -c set"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">InputStream is =
proc.getInputStream();<o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">int in;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">while</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( ( in = is.read() )
!= -1 <u>)</u> { <o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">// ... parse for User ID</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<o:p><span style="font-family: Calibri;"> </span></o:p><br />
<span style="font-family: Calibri;">But now I know that reading the Java system properties is
cross-platform compatible; whereas, executing a Runtime and getting a Process
to do work or get information is simply a way to turn Java into a scripting
language – it is a role reversal, to be done only when the same job cannot be
done in native Java.<span style="mso-spacerun: yes;"> </span>With that
philosophy, we will promote pure Java solutions for cross-platform tasks.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">So, we are able to get the userID from the Java system
properties, but how good is that?<span style="mso-spacerun: yes;"> </span>It is
not good at all!<span style="mso-spacerun: yes;"> </span>If I take a second before
running the Java code, and set the USERNAME environment variable to something
else (“set USERNAME=fake” on Windows, “export USER=fake” in most UNIX shells),
then the Java system properties will present this miss-set userID as if that
were the real userID.<span style="mso-spacerun: yes;"> </span>Note that this
same frailty (security vulnerability) exists when reading User ID from the
operating system environment settings.<o:p></o:p></span></div>
<span style="font-family: Calibri;">A better way to do this would be to talk directly to the
operating system (Windows or UNIX).<span style="mso-spacerun: yes;">
</span>However, with the Java Virtual Machine (JVM) between your Java code and
the native operating system, this becomes a bit more difficult.<span style="mso-spacerun: yes;"> </span>One way to work around this difficulty in an
enterprise environment is to call on a separate service, like an LDAP directory
service, to provide the information.<span style="mso-spacerun: yes;"> </span>And
Java can readily do that, with sufficient credentials and access, and with the
service available.<span style="mso-spacerun: yes;"> </span>For cross-platform
applications, there will probably be separate directory services available for
each client platform.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">But shouldn’t the local computer be able to tell me what I
want?<span style="mso-spacerun: yes;"> </span>The local machine knows my userID
and already knows or can find out more details about me.<span style="mso-spacerun: yes;"> </span>So our next job will be to have Java talk to
the native operating system.<o:p></o:p></span></div>
<span style="font-family: Calibri;">As I have said, the platform-specific sections of Java are
kept outside of the standard Java library packages, but some are nevertheless
included in the standard distribution library jar files.<span style="mso-spacerun: yes;"> </span>For example, in the rt.jar file that comes
with every Java Runtime Environment (JRE) there is a package named
“com.sun.security.auth.module”.<span style="mso-spacerun: yes;"> </span>You can
tell this package is not a standard Java library, because the name does not
start with “java”, like “java.lang” or “java.util”.<span style="mso-spacerun: yes;"> </span>And it is for this very reason that certain
Integrated Development Environments (IDEs) like Eclipse do not give ready
access to classes in the “com.sun.*” packages, even though they are part of the
standard distribution.<span style="mso-spacerun: yes;"> </span>We will deal with
that.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Let me assume that you are developing code using Eclipse on
a Windows computer.<span style="mso-spacerun: yes;"> </span>The standard JRE
rt.jar library will include a class named
“com.sun.security.auth.module.NTSystem”.<span style="mso-spacerun: yes;">
</span>We will use it to find the current user’s identity like this:<o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;">String userName = (</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
com.sun.security.auth.module.NTSystem()).getName();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">This will generate an error indicator in Eclipse, and will
not be able to be compiled.<span style="mso-spacerun: yes;"> </span>The error
text is “Access restriction: The method getName() from the type NTSystem is not
accessible due to restriction on required library”.<span style="mso-spacerun: yes;"> </span>Basically, the class and method exist, but
you’re not encouraged (or readily permitted) to use them.<span style="mso-spacerun: yes;"> </span>To immediately resolve this problem, you can
go to your Eclipse project Properties and add the local rt.jar file as an
External Jar to your Java Build Path.<span style="mso-spacerun: yes;">
</span>Note that rt.jar is in the default classpath, so once we get Eclipse to
accept and compile the code, there is no problem running it.<span style="mso-spacerun: yes;"> </span>However, as we shall see, that is true only
on a Windows platform.<o:p></o:p></span></div>
<span style="font-family: Calibri;">On a UNIX platform, the standard JRE distribution of rt.jar
does not have the NTSystem.class file at all!<span style="mso-spacerun: yes;">
</span>That makes sense, come to think of it, since NTSystem is not functional
on UNIX (it is not cross-platform compatible).<span style="mso-spacerun: yes;">
</span>As an alternative, in the UNIX JRE, we find this class that did not
exist in the standard Windows JRE,
“com.sun.security.auth.module.UnixSystem”.<span style="mso-spacerun: yes;">
</span>We will use it like this:<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;">String userName = (</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
com.sun.security.auth.module.UnixSystem()).getUsername();</span><o:p></o:p></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">However, now we are faced with another difficulty – that
class doesn’t even exist on the Windows workstation where we are running
Eclipse!<span style="mso-spacerun: yes;"> </span>To remedy this, we need to copy
the rt.jar file from a UNIX computer to our Windows workstation.<span style="mso-spacerun: yes;"> </span>I recommend you rename it on the Windows box
to something like UNIXrt.jar, so it’s clear what it is.<span style="mso-spacerun: yes;"> </span>Then you can add that file as an External Jar
to your Java Build Path in your project Properties.<span style="mso-spacerun: yes;"> </span>Now that’s all well and good, and your code
should be free from reported errors, but there are precautions we need to take.<o:p></o:p></span></div>
<span style="font-family: Calibri;">Unless you are willing to always and only run your code from
your Eclipse environment (not a very cross-platform approach), then you need to
avoid mentioning classes that don’t exist.<span style="mso-spacerun: yes;">
</span>If you run your code on a different Windows machine, or at the command
prompt (without manipulating the classpath to point at the UNIXrt.jar file)
then you will not have access to UnixSystem.class, and it is unmentionable
(else runtime exceptions will ensue.)<span style="mso-spacerun: yes;">
</span>And on a UNIX platform, NTSystem.class is unmentionable.<span style="mso-spacerun: yes;"> </span>So how can you run this code
cross-platform?<span style="mso-spacerun: yes;"> </span>These are the steps we
must take:<o:p></o:p></span><br />
<br />
<div class="MsoListParagraphCxSpFirst" style="margin: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<!--[if !supportLists]--><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">1)</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><!--[endif]--><span style="font-family: Calibri;">Do not import these classes, rather refer to
them with their complete package names, as shown in the code above.<o:p></o:p></span></div>
<br />
<div class="MsoListParagraphCxSpLast" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<!--[if !supportLists]--><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2)</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><!--[endif]--><span style="font-family: Calibri;">Determine what platform you are running on, and
only attempt to execute code specific to that platform.<o:p></o:p></span></div>
<span style="font-family: Calibri;">Here is a model I like to use for separating
platform-specific code.<span style="mso-spacerun: yes;"> </span>I use the Java
System Properties to determine if I’m executing on a Windows box or not, and
call the platform-specific code in an If/else block:<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;">Properties props = System.<i>getProperties</i>();<o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;">String userName;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( (
props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.arch"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ).equals( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"x86"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) ||</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.arch"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ).equals( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"amd64"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) ) &&</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.name"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ).startsWith( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Windows"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) )</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">{</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>userName = (</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> com.sun.security.auth.module.NTSystem()).getName();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">} </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">else</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>userName = (</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> com.sun.security.auth.module.UnixSystem()).getUsername();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">That code model examines two properties, operating system architecture
and name.<span style="mso-spacerun: yes;"> </span>The architecture can be either
“x86” for 32-bit or “amd64” for 64-bit.<span style="mso-spacerun: yes;">
</span>In this case, that is an indication of 32-bit or 64-bit implementation
of Java, not an indication of the CPU type.<span style="mso-spacerun: yes;">
</span>Also, the OS name, for Windows machines, can have several appearances,
but they all start with “Windows”.<o:p></o:p></span></div>
<span style="font-family: Calibri;">I spend a bit of text describing how NTSystem, UnixSystem
and the Java Authentication and Authorization System (JAAS) package operates in
the chapter on Single Sign-On in my book, <i style="mso-bidi-font-style: normal;">Expert
Oracle and Java Security</i>, published by Apress.<span style="mso-spacerun: yes;"> </span>Of course, I recommend that book.<span style="mso-spacerun: yes;"> </span>Also see my current blogs at </span><a href="http://oraclejavasecure.blogspot.com/"><span style="color: #0563c1; font-family: Calibri;">http://oraclejavasecure.blogspot.com/</span></a><span style="font-family: Calibri;">
<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">So what have we done so far?<span style="mso-spacerun: yes;">
</span>We have achieved cross-platform determination of current user identity
from the operating system.<span style="mso-spacerun: yes;"> </span>However, what
if we are really after the user’s name, like “John Doe”?<span style="mso-spacerun: yes;"> </span>Is that a value we can acquire from the local
machine?<span style="mso-spacerun: yes;"> </span>I should hope so, but for this
effort, we will need to talk a bit more intimately with the operating system. <span style="mso-spacerun: yes;"> </span>We will use Java Native Interface (JNI)
programming to accomplish this, and we will use some existing utility code that
was developed to make this effort easy, the Java Native Access (JNA)
packages.<span style="mso-spacerun: yes;"> </span>JNI is used, not to talk to
operating systems, but rather to talk to other programming languages.<span style="mso-spacerun: yes;"> </span>In this case, we will be talking to C
language libraries that have the intimate kind of access to the operating
system that we want to tap into.<o:p></o:p></span></div>
<span style="font-family: Calibri;">To use JNA, you will need to browse to jna.java.net and
download jna-3.3.0.jar and jna-3.3.0-platforms.jar.<span style="mso-spacerun: yes;"> </span>Add these two files as External JAR files to
your Java Build Path in your project Properties.<span style="mso-spacerun: yes;"> </span>These will also need to be included in the
classpath you configure for your java runtime from the command line or a
script.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">As is frequently the case when trying to work well with
other computers or languages, a lowest-common-denominator (LCD) for data
exchange must be established.<span style="mso-spacerun: yes;"> </span>In JNI,
the LCD data exchange is byte arrays.<span style="mso-spacerun: yes;">
</span>Passing arrays of bytes can be easily done, even when both parties do
not have a common understanding of a String.<span style="mso-spacerun: yes;">
</span>So before getting the Windows extended user name via JNA, we define a
byte array (char array) to hold it.<span style="mso-spacerun: yes;"> </span>The
following code passes our char array as the second parameter to the
GetUserNameEx() method of the JNA class, Secur32.<span style="mso-spacerun: yes;"> </span>That method returns the Windows extended user
name in our char array.<span style="mso-spacerun: yes;"> </span>For local use,
we create a String from the char array and trim it to its significant
characters.<o:p></o:p></span></div>
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">char</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">[] name = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">char</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">[100];</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Gets current user extended name</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">com.sun.jna.platform.win32.Secur32.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">INSTANCE</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.GetUserNameEx(</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>com.sun.jna.platform.win32.Secur32.EXTENDED_NAME_FORMAT.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">NameDisplay</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">,</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>name, </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> com.sun.jna.ptr.IntByReference(name.</span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">length</span><span style="color: black; font-family: Consolas; font-size: 10pt;">) );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">userName = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String(name).trim();<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">I wish it were as easy as this to get the extended user name
(“John Doe”) from UNIX and Linux computers, but the classes in the
com.sun.jna.platform package that are specific for UNIX variants do not include
that ability – probably because of the many implementations that would be
required.<o:p></o:p></span></div>
<span style="font-family: Calibri;">However, do not fret.<span style="mso-spacerun: yes;">
</span>Similar C libraries that provide intimate access to UNIX platforms do
exist, and with a little Java tailoring, we can acquire the same level of data
as on Windows.<span style="mso-spacerun: yes;"> </span>Here we will be using
closer-to-the-bone JNI programming, using existing native libraries.<span style="mso-spacerun: yes;"> </span>The JNA package gives us a friendly
interface into those libraries.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Let’s start with the interface between Java and the specific
C Library we want to address.<span style="mso-spacerun: yes;"> </span>This
example configures the interface that is specific to the Oracle Solaris
platform.<span style="mso-spacerun: yes;"> </span>Likely the only change you
will have to make to accommodate other UNIX / Linux variants is in the list of
fields included in the data structure returned from the library.<o:p></o:p></span></div>
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">interface</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> CLibrary </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> Library {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//
Method to shadow C library getpwnam function</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>passwd getpwnam(String username);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//
This matches the struct for passwd on Solaris</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//
Modify to match passwd struct on other platforms</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> passwd </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> Structure {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_name</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_passwd</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">int</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_uid</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">int</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_gid</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_age</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_comment</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_gecos</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_dir</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_shell</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Notice that this interface extends the Library interface,
included in the JNA package.<span style="mso-spacerun: yes;"> </span>In our
extension, we define one method, getpwnam() which shadows a function in the
native C library which returns a data structure representing an entry in the
system passwd datastore.<span style="mso-spacerun: yes;"> </span>On Solaris,
there are nine fields returned in this structure, and the “gecos” field
contains data that is often the user’s name, but can be any text data specific
to the user.<span style="mso-spacerun: yes;"> </span>In my limited research,
I’ve seen that “gecos” stands for “General Electric” so-and-so.<span style="mso-spacerun: yes;"> </span>That’s hard for me to believe, but with other
examples of UNIX utilities named for the initials of their authors, I guess I
shouldn’t be surprised.<span style="mso-spacerun: yes;"> </span>The gecos field
is returned in the seventh field of our passwd.class, which extends the JNA
Structure class.<o:p></o:p></span></div>
<span style="font-family: Calibri;">To use our CLibrary interface, we instantiate a class based
on it by calling the JNA Native.loadLibrary() method.<span style="mso-spacerun: yes;"> </span>We tell that method to load the “c” native
library, which includes the getpwnam function, and to wrap it in our CLibrary
interface.<span style="mso-spacerun: yes;"> </span>At that point we can call the
getpwnam() method we defined in CLibrary.<span style="mso-spacerun: yes;">
</span>Then we can access the pw_gecos member of the passwd instance returned
by that method.<span style="mso-spacerun: yes;"> </span>Note that this function
reads the passwd datastore for a specified userID, so we are passing in the
userID we acquired earlier.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;">CLibrary libc = (CLibrary)Native.<i>loadLibrary</i>(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"c"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">, CLibrary.</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Gets named user gecos field from passwd
struct</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">userName = libc.getpwnam(userName).</span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_gecos</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="font-family: Calibri;">I am including the complete code, below, for a class that
executes cross-platform and acquires the extended username from the native
platform.<span style="mso-spacerun: yes;"> </span>Of course, all the significant
code is shown previously in this article, along with instructions on how to set
up your environment to edit and compile it.<o:p></o:p></span></div>
<span style="font-family: "Calibri","serif"; font-size: 11pt; line-height: 107%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;"><br clear="all" style="mso-special-character: line-break; page-break-before: always;" />
</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">package</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> dac;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
java.util.Properties;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> com.sun.jna.Library;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> com.sun.jna.Native;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">import</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
com.sun.jna.Structure;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
CrossPlatformUserName {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">static</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">void</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> main(String[] args)
{</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>String userName = </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">""</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>Properties props = System.<i>getProperties</i>();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>userName = props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"user.name"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"A: "</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> + userName );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Arch: "</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> + props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.arch"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) +</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">", OS: "</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> + props.getProperty(
</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.name"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//
Some example reports of Arch and OS:</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;"> </span>Arch: amd64, OS: Windows 7</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;"> </span>Arch: x86, OS: Windows Vista</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;"> </span>Arch: <u>sparc</u>, OS: SunOS</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">if</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( (
props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.arch"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ).equals( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"x86"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) ||</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>(props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.arch"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ).equals( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"amd64"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) ) &&</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>props.getProperty( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"os.name"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ).startsWith( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"Windows"</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> ) ) )</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>{</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Eclipse complains:</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Access restriction: The method
getName() from the type NTSystem</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>is not accessible due to restriction on required library</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>C:\dac\java\jdk1.6\jre\lib\rt.jar</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Add that standard rt.jar to
project properties compile build path<o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>to remove the restriction</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>userName = (</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
com.sun.security.auth.module.NTSystem()).getName();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"B: "</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> + userName );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Certain Java Native Access (JNA)
applications are available for</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>various platforms.</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// One will allow us to read the
Users full name from Windows</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Include 2 jar files, download
from jna.java.net, jna-3.3.0.jar</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>and jna-3.3.0-platform.jar</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>as external jars in your project properties, compile build path</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">char</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">[] name = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">char</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">[100];</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Gets current user extended name</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>com.sun.jna.platform.win32.Secur32.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">INSTANCE</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.GetUserNameEx(</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>com.sun.jna.platform.win32.Secur32.EXTENDED_NAME_FORMAT.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">NameDisplay</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">,</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>name,</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
com.sun.jna.ptr.IntByReference(name.</span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">length</span><span style="color: black; font-family: Consolas; font-size: 10pt;">) );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>userName = </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String(name).trim();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"C: "</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> + userName );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>} </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( Throwable t ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println(
t.toString() );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">else</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// ldaplist -l -v passwd $USER | grep gecos:</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Eclipse on Windows machine, accessing
Windows JDK/JRE does not find</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>UnixSystem.class</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Copy rt.jar from a UNIX machine, which
will include UnixSystem</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>then add that rt.jar as an External Jar to your project properties</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Now you will be able to compile on
Windows, even with this reference</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>to a UNIX-specific class. Alternatively, you could create a </span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>local project, with empty UnixSystem class in the same package</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//<span style="mso-spacerun: yes;">
</span>with an empty getUsername() method</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">try</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>userName = </span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>(</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">new</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">
com.sun.security.auth.module.UnixSystem()).getUsername();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"B: "</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> + userName );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 10pt;"><o:p> </o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>CLibrary libc =
(CLibrary)Native.<i>loadLibrary</i>(</span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"c"</span><span style="color: black; font-family: Consolas; font-size: 10pt;">, CLibrary.</span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Gets named user gecos field from passwd
struct</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>userName =
libc.getpwnam(userName).</span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_gecos</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>System.</span><i><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">out</span></i><span style="color: black; font-family: Consolas; font-size: 10pt;">.println( </span><span style="color: #2a00ff; font-family: Consolas; font-size: 10pt;">"C: "</span><span style="color: black; font-family: Consolas; font-size: 10pt;"> + userName );</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>} </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">catch</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;">( Throwable t ) {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>t.printStackTrace();</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;"> </span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>System.<i>exit</i>(0);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">// Create our own platform-specific
library</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span></div>
<b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">interface</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> CLibrary </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> Library {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//
Method to shadow C library getpwname function</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>passwd getpwnam(String username);</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//
This matches the struct for passwd on Solaris</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><span style="color: #3f7f5f; font-family: Consolas; font-size: 10pt;">//
Modify to match passwd struct on other platforms</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">class</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> passwd </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">extends</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> Structure {</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_name</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_passwd</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">int</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_uid</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">int</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_gid</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_age</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_comment</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_gecos</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_dir</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span></span><b><span style="color: #7f0055; font-family: Consolas; font-size: 10pt;">public</span></b><span style="color: black; font-family: Consolas; font-size: 10pt;"> String </span><span style="color: #0000c0; font-family: Consolas; font-size: 10pt;">pw_shell</span><span style="color: black; font-family: Consolas; font-size: 10pt;">;</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;"><span style="mso-spacerun: yes;">
</span>}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
<span style="color: black; font-family: Consolas; font-size: 10pt;">}</span><span style="font-family: Consolas; font-size: 10pt;"><o:p></o:p></span><br />
David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com3tag:blogger.com,1999:blog-7183773701017655963.post-33270723370770359612013-09-27T10:10:00.002-04:002013-09-27T10:16:22.060-04:00Java Version in Oracle 12c<span style="background-color: rgba(255, 255, 255, 0);">Oracle has had an embedded Java Virtual Machine (JVM) for several years, but it has always been a bit behind the current release of Java. Prior to Oracle 11g, Java 1.4 JVM was the latest available and was called the Aurora JVM, in Oracle. In Oracle 11g, finally Java 1.5 JVM was available, and it was based on the Java Security features of that release that I wrote my book, “Expert Oracle and Java Security”. Now the production release of Oracle 12c is available, and the first thing I wanted to know is what version of the JVM was included.</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"><br /></span>
<span style="background-color: rgba(255, 255, 255, 0);">To test what version of Java is available in Oracle 12c, I wrote this small Java class, and a Java Stored Procedure (Function) to encapsulate it.</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"><br /></span>
<span style="background-color: rgba(255, 255, 255, 0);">CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED JSProc AS</span><br />
<span style="background-color: rgba(255, 255, 255, 0);">public class JavaStoredProcedures {</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"> public static String getVersion() {</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"> return System.getProperty("java.version");</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"> }</span><br />
<span style="background-color: rgba(255, 255, 255, 0);">}</span><br />
<span style="background-color: rgba(255, 255, 255, 0);">/</span><br />
<br />
<span style="background-color: rgba(255, 255, 255, 0);"><br /></span>
<span style="background-color: rgba(255, 255, 255, 0);">CREATE OR REPLACE FUNCTION f_get_java_version</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"> RETURN VARCHAR2</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"> AS LANGUAGE JAVA</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"> NAME 'JavaStoredProcedures.getVersion() return java.String';</span><br />
<br />
<span style="background-color: rgba(255, 255, 255, 0);"><br /></span>
<span style="background-color: rgba(255, 255, 255, 0);">Running the Java Stored Procedure, I found that Java 1.6 was available in Oracle 12c. Yay! Even though 1.7 is out and 1.8 is coming soon, new encryption algorithms that I pre-programmed for in the code of my book are now supported with 1.6, along with even more secure algorithms. This is great!</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"><br /></span>
<span style="background-color: rgba(255, 255, 255, 0);">SELECT f_get_java_version FROM DUAL;</span><br />
<span style="background-color: rgba(255, 255, 255, 0);">-- 1.6.0 --</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"><br /></span>
<span style="background-color: rgba(255, 255, 255, 0);">Cleaning up after running my Java Stored Procedure requires removing the function and the Java class. Cleaning up after ourselves is part of good, secure programming.</span><br />
<span style="background-color: rgba(255, 255, 255, 0);"><br /></span>
<span style="background-color: rgba(255, 255, 255, 0);">DROP FUNCTION f_get_java_version;</span><br />
<br />
<span style="background-color: rgba(255, 255, 255, 0);">DROP JAVA SOURCE JSProc;</span><br />
<br />David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com1tag:blogger.com,1999:blog-7183773701017655963.post-63054801489234614342013-09-27T09:55:00.004-04:002013-09-27T09:55:27.832-04:00Oracle 12c Multitenant Architecture OptionThis is a very brief introduction and starter concepts for the Multitenant Architecture option available with Oracle 12c. The idea is that you can host several Oracle instances on a single computer without separate virtual machines and while sharing core Oracle code – no multiple Oracle homes or installation directories.<br />
<br />
This is accomplished by having ONE Container Database (CDB) which should not be used to support your database applications. The CDB supports MANY Pluggable Database (PDB) instances. The PDBs are equivalent to your separate Oracle home / database instances that you’re used to.<br />
<br />
For example, if you elect to use the Multitenant Architecture option when you install Oracle 12c, you will end up with a CDB named “CDB$ROOT” and a PDB named, for example “PDBORCL”. The CDB will be available via the base instance / service name, for example “ORCL”. Normal installation will configure a Service or startup script to start the “ORCL” instance and the Listener. However, the PDB(s) which are configured in the CDB are not started automatically (after a reboot). This we can fix with a startup trigger. Let’s examine these concepts a bit:<br />
<br />
Connect to your Oracle 12c instance (as SYS) and view the containers that are available:<br />
<br />
SELECT CON_ID, NAME, OPEN_MODE FROM V$CONTAINERS;<br />
<br />
You will see something like the following table. The PDB$SEED container is like a template that can be used when creating additional PDBs and when converting stand-alone Oracle instances into PDB containers.<br />
<br />
1 CDB$ROOT READ WRITE<br />
2 PDB$SEED READ ONLY<br />
3 PDBORCL MOUNTED<br />
<br />
There are great resources in the Oracle Documents and on-line that you can use when you go on to create PDBs from scratch, from PDB$SEED or from a clone PDB; when you plug or unplug PDB into or from a CDB; and other CDB / PDB tasks. I will not be discussing those items here.<br />
<br />
You are, by default, in the CDB container, and you can return there from a PDB by setting your container:<br />
<br />
ALTER SESSION SET CONTAINER = CDB$ROOT;<br />
<br />
As I mentioned, after shutdown, the PDBs are not automatically started back up. Use this command to manually change the status of a PDB from “MOUNTED” to “READ/WRITE”:<br />
<br />
ALTER PLUGGABLE DATABASE pdborcl OPEN;<br />
<br />
Typically, we would want to have all our PDB containers opened whenever the CDB is restarted, without manual intervention. We can accomplish this with a startup trigger:<br />
<br />
CREATE OR REPLACE TRIGGER SYS.g_after_startup AFTER STARTUP ON DATABASE<br />
BEGIN<br />
-- Opens all pluggable databases<br />
EXECUTE IMMEDIATE 'ALTER PLUGGABLE DATABASE ALL OPEN';<br />
END;<br />
/<br />
<br />
Before we move on to the PDB, let’s create a user within the CDB in order to demonstrate the naming requirements:<br />
<br />
ALTER SESSION SET CONTAINER = CDB$ROOT;<br />
CREATE USER tuser IDENTIFIED BY tpassword;<br />
<br />
This generates an Oracle error, “ORA-65096: invalid common user or role name”. All non-default users and roles in the CDB require the ugly naming convention prefix “C##”. That helps distinguish items that you will see, merged into every PDB, but that may not exist when the PDB is plugged into a different CDB. Typically, you would not create any items in the CDB – it is a “Container Database”, not a “Central Database”. However, there may be exceptions to that plan, and there will be technical considerations for those exceptions that would need to be addressed and that we will explore here. Let’s create a user and role, using “Common User” naming conventions, in the CDB to use as an example:<br />
<br />
CREATE USER C##tuser IDENTIFIED BY tpassword;<br />
CREATE ROLE C##create_session_role;<br />
GRANT CREATE SESSION TO C##create_session_role;<br />
GRANT C##create_session_role TO C##tuser;<br />
SELECT * FROM ALL_USERS;<br />
<br />
You will see our new user, C##tuser listed, with the designation “YES” in the COMMON column. This user will appear in all PDBs. Observe the data from ALL_USERS in the following commands – again the C##tuser user is listed as a COMMON user, within the PDB. First, we switch containers to the PDB (e.g., pdborcl), still as the SYS user. SYS is a default common user, and many of the “common” SYS views are merged with the “local” SYS views on the PDB.<br />
<br />
ALTER SESSION SET CONTAINER = pdborcl;<br />
SELECT * FROM ALL_USERS;<br />
<br />
The common users exist in the PDB; however, the grants we made above only exist in the CDB! To allow the common user to connect within the PDB, you need similar grants in that container:<br />
<br />
GRANT CREATE SESSION TO C##create_session_role;<br />
GRANT C##create_session_role TO C##tuser;<br />
<br />
There is where it gets a bit convoluted – a system privilege (CREATE SESSION), specific to this PDB, is granted to a common role; and a common role is specifically granted in “this PDB only” to a common user. Alternatively, and I recommend this alternate approach, unless there is some exceptional reason for using a common role, create a local (PDB) role to receive local system privileges. If needed, grant the local role to a common user.<br />
<br />
REVOKE CREATE SESSION FROM C##create_session_role;<br />
REVOKE C##create_session_role FROM C##tuser;<br />
<br />
CREATE ROLE create_session_role;<br />
GRANT CREATE SESSION TO create_session_role;<br />
GRANT create_session_role TO C##tuser;<br />
<br />
You can now connect as this user in both the CDB and the PDB. Note that there will be naming conventions in your connection strings, based on your Listener configuration that may not be consistent. Again, I will direct you to Oracle and on-line sources for configuring your Listener.ora and related files. Here are a couple example connections, using SQLPlus:<br />
<br />
SQLPlus C##tuser@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)<br />
(PORT=1521))(CONNECT_DATA=(SID=orcl)))<br />
<br />
SQLPlus C##tuser@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)<br />
(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdborcl.org.com)))<br />
<br />
OK, now let’s see the limitations of data stored in the CDB, and how it will not be specifically beneficial to our database applications, running from PDBs. We will create a local user while we are in the PDB container, then we will return to the CDB and create a table of data:<br />
<br />
ALTER SESSION SET CONTAINER = pdborcl;<br />
CREATE USER tuser IDENTIFIED BY tpassword;<br />
-- or<br />
-- CREATE USER tuser IDENTIFIED BY tpassword CONTAINER=CURRENT;<br />
GRANT create_session_role TO tuser;<br />
<br />
You could grant system privileges or a role with privileges to tuser in order to create tables, but we will just do this as SYS, for now. Please refer to my book, “Expert Oracle and Java Security” from Apress for a thorough discussion of user and role security.<br />
<br />
ALTER SESSION SET CONTAINER = CDB$ROOT;<br />
ALTER USER c##tuser QUOTA 10M ON USERS;<br />
CREATE TABLE C##tuser.test_table<br />
(text_col VARCHAR2 (256));<br />
/<br />
INSERT INTO C##tuser.test_table<br />
(text_col) VALUES ('test one');<br />
SELECT * FROM C##tuser.test_table;<br />
GRANT SELECT ON C##tuser.test_table TO tuser;<br />
<br />
This last command generates the Oracle error, “ORA-01917: user or role 'TUSER' does not exist”. Here is the first problem with data in the CDB; non-common, PDB users do not exist in the CDB, so they cannot be granted access to data in the CDB. But, hey, the common user, C##tuser exists in the PDB, so let’s just read his data from there:<br />
<br />
ALTER SESSION SET CONTAINER = PDBORCL;<br />
SELECT * FROM C##tuser.test_table;<br />
<br />
This generates the Oracle error, “ORA-00942: table or view does not exist”. The common user account exists in the PDB, and with sufficient grants, the user can connect to the PDB, but his schema and all his data are in the CDB – not available within the PDB. So, let’s try another tack. Let’s create a link in the PDB to access data in the CDB, and try reading data through the link:<br />
<br />
CREATE DATABASE LINK l_cdb_tuser<br />
CONNECT TO C##tuser IDENTIFIED BY tpassword<br />
USING '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)<br />
(PORT=1521))(CONNECT_DATA=(SID=orcl)))';<br />
SELECT * FROM C##tuser.test_table@l_cdb_tuser;<br />
<br />
That worked, so it is possible to read data in the CDB from a user session on the PDB over a database link. Well, that’s no different from reading data over database links to other PDBs or non-Multitenant-Architecture Oracle instances. There is no benefit to placing data in a CDB versus a PDB, and in fact there are strong reasons to argue that it should not be done. You could, but should NOT do that, because the idea behind PDBs is that you can export them from one server and plug them into another server to run there without change. That would hardly work if you were placing central data or code in the CDB.<br />
<br />
Perhaps you can imagine a scenario where all PDBs need to share some centralized data, and that data is different on each server (CDB). In that case, I suggest you do not put data in the CDB; but rather, create a “core” PDB on each CDB to hold that shared data.<br />
<div>
<br /></div>
David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-27114896791996603812013-01-25T08:09:00.001-05:002013-01-25T08:18:59.755-05:00Experian for All or Encrypt Your ArchivesI have just signed up with Experian to have my credit activity monitored. It was free; free that is to all who submitted a South Carolina state tax return in the last fifteen years. If you are attuned to corporate computer security, you probably heard about how a hacker made off with 3.8 million tax returns from the South Carolina Department of Revenue. Anyway, to make good on their after-the-hack responsibility, SCDOR offered free credit monitoring for a year from Experian, and credit resolution for life. Free to individuals, but we South Carolina taxpayers will still be footing the bill; and what is worse, we may be faced with identity theft and credit harm due to this data loss.
<P>
When I was at my dentist recently, he asked if the book I wrote dealt with this, “Expert Oracle and Java Security”. I answered “yes, and it’s too bad Governor Haley didn’t read it before this happened.” Actually the folks who work in SCDOR should have been up on security, not necessarily the Governor; but the Governor has been the spokeswoman for the official response. Unfortunately, she said these things: “The industry standard is most Social Security numbers are not encrypted. A lot of banks don’t encrypt… It’s very complicated. It’s very cumbersome. There’s a lot of numbers involved with it.” So I associate her with the problem.
<P>
The only difficulty with encryption is analysis. I believe that even on a system the size of the South Carolina Revenue system, the analysis should only take a few weeks. To you readers, I want to say that you also have no excuse to delay analyzing your system and then encrypt the sensitive data.
<P>
After discussing encryption in my book -- encryption over the wire, encryption on disk and hardening the encryption process -- I wrote a supplement that deals specifically with encryption of archived data. I proposed a scenario where a corporate policy required deletion of unneeded sensitive data from archive records, and encryption of any remaining sensitive data. I want to share a simplified version with you now. We will use the sample Sales History (SH) schema (the archive of the sample Order Entry (OE) schema) that comes with Oracle 11g. I will be skipping a lot of analysis and further technical information in this article (like single sign-on, 2-factor authentication, key storage and PL/SQL Wrapping) that you can find in my book. Hopefully, you have already mitigated SQL Injection and applied solid database security, also covered in the book.
<P>
To comply with our imaginary corporate data security policy, we will remove the marital status and income level data from our sales history customers archive table. We will retain the customer year of birth data, but we must encrypt it. That was a simple analysis result – your analysis may also be relatively simple. So the difficult part is done! Now the easy part – data expunging and encryption. You can apply these same steps to whatever archive data you are protecting.
<P>
First let’s get the ball rolling by enabling the sample schema and account. We also grant the SH user access to the DBMS_CRYPTO PL/SQL package that comes with Oracle 11g.
<P><PRE>
ALTER USER sh ACCOUNT UNLOCK;
ALTER USER sh IDENTIFIED BY password;
GRANT CREATE SESSION TO sh;
GRANT EXECUTE ON sys.dbms_crypto TO sh;
</PRE><P>
We will start out with a simple procedure which does Passphrase-Based Encryption (PBE); specifically, using the Advanced Encryption Standard (AES) algorithm. In my book, I also cover Public-Key Encryption (PKE) using the RSA algorithm. These are very easy to implement using Oracle 11g.
<P>
As SYS or a DBA user, create the following function in the SH sample schema. This function takes a string and encrypts it with a passphrase which is also passed in. Compare this to the F_MASK() function from “Expert Oracle and Java Security”. There is no rocket science here. The bulk of the code has to do with converting VARCHAR strings to RAW (byte arrays) and handling RAWs, which are needed for encryption. The final call to SYS.DBMS_CRYPTO.ENCRYPT() applies the AES 256-bit algorithm with the specified chaining and padding to the clear data (in RAW form). We use a passphrase and initialization vector (which I’ve assembled as appropriate-length RAWs). The return value is a RAW data value representing the encrypted data.
<P><PRE>
CREATE OR REPLACE FUNCTION sh.encrypt_data(
clear_string VARCHAR2,
pass_phrase VARCHAR2 )
RETURN RAW
AS
clear_raw RAW(32767);
iv RAW(16);
pass_key RAW(32);
crypt_raw RAW(32767) := NULL;
BEGIN
-- Cast to RAW
clear_raw := SYS.UTL_RAW.CAST_TO_RAW(clear_string);
-- Concatenate VARCHAR, cast to RAW, get substring (16)
iv := SYS.UTL_RAW.SUBSTR(
SYS.UTL_RAW.CAST_TO_RAW(pass_phrase||'SufficientLength'), 0, 16 );
-- Concatenate VARCHAR, get hash (16), concatenate RAW (32)
pass_key := SYS.UTL_RAW.CAST_TO_RAW(pass_phrase||'SufficientLength');
pass_key := SYS.DBMS_CRYPTO.HASH( pass_key, SYS.DBMS_CRYPTO.HASH_MD5 );
pass_key := SYS.UTL_RAW.CONCAT( pass_key, pass_key );
crypt_raw := SYS.DBMS_CRYPTO.ENCRYPT( clear_raw,
SYS.DBMS_CRYPTO.ENCRYPT_AES256 + SYS.DBMS_CRYPTO.CHAIN_CBC +
SYS.DBMS_CRYPTO.PAD_PKCS5, pass_key, iv );
RETURN crypt_raw;
END encrypt_data;
</PRE><P>
By the way, until the actual step of encryption (the call to SYS.DBMS_CRYPTO.ENCRYPT()), hardly any computing resources are required. Casting VARCHARs as RAWs and concatenating them or getting substrings are hardly calculations at all. There is one minor calculation of the MD5 hash, but even with that, the compute cost of this function is almost solely the cost of the final encryption effort – no extra overhead.
Test the function by logging in as the SH user and select from the function. This query selects the encrypted form of “this” using the passphrase “that”.
<P><PRE>
SELECT sh.encrypt_data('this','that') FROM DUAL;
</PRE><P>
I’m not going to spend any more words here describing the encryption. In fact, you don’t really need to know how it works, if you know how to use it and what the results are. Contrary to what Governor Haley said, you can encrypt data without a lot of numbers and complexity.
<P>
We are going to clean up the archived customers table, sh.customers. Removing data is the easiest part, and we have already setup the encryption. What we still need is to store the encrypted data; and in encrypted form, the data won’t fit back into the original column. The customer year of birth column is defined as NUMBER(4), and the encrypted form will be RAW(2000). Let’s add a column for the encrypted data:
<P><PRE>
ALTER TABLE sh.customers ADD cust_yob_encr RAW(2000);
</PRE><P>
Now we’re set! There are two steps to the clean-up process: 1) encrypt records when they are inserted or updated, and 2) encrypt preexisting records in the archive. We can automatically handle step (1) with an “on insert” trigger. Execute the following as SYS or a DBA user.
<P><PRE>
CREATE OR REPLACE TRIGGER sh.t_customers_biur BEFORE INSERT OR UPDATE
ON sh.customers FOR EACH ROW
BEGIN
:new.cust_marital_status := '';
:new.cust_income_level := '';
:new.cust_yob_encr := :old.cust_yob_encr;
IF( :new.cust_year_of_birth > 0 )
THEN
:new.cust_yob_encr :=
sh.encrypt_data(TO_CHAR(:new.cust_year_of_birth),
TO_CHAR(:new.cust_id) || 'PPhrase' );
END IF;
:new.cust_year_of_birth := 0;
END;
/
ALTER TRIGGER sh.t_customers_biur ENABLE;
</PRE><P>
As you can see, whenever a row is inserted or updated, we simply set the marital status and income level to blank; then we don’t allow insert of the encrypted year of birth, so we overwrite what’s submitted with what already exists (:new.cust_yob_encr := :old.cust_yob_encr ); then, if a positive unencrypted year of birth is submitted, we encrypt it to store in our new cust_yob_encr column; and finally we set the unencrypted year of birth to zero. Those secure values will be stored in the database instead of the values that were submitted.
<P>
There are two things to note. One is the pass phrase, which we build by concatenating the alphabetic (TO_CHAR()) representation of the customer ID and the string “PPhrase”. The pass phrase can be whatever you want, but once you set it you must not change it; otherwise, you won’t be able to decrypt data that was encrypted with the previous pass phrase. We prepend the pass phrase with the customer ID so that no 2 people with the same birth year will have that same encrypted birth year. Otherwise, while we may not be able to decrypt them, we would still know when people share the same birth year. Why not use a different column to be the pass phrase, like the customer last name? Well, that is not a primary key column (in the oe.customers source table), is not unique, and may change. Again, if the pass phrase changes after we encrypt a value, we will not be able to decrypt it.
<P>
The second thing to note is that this trigger is only protected by belonging to the SH schema. It must not be visible or granted to other users or roles. In this way, only the SH user can see the pass phrase, and can encrypt and decrypt the customers data.
Yes, there is an analogous decrypt function, shown here:
<P><PRE>
CREATE OR REPLACE FUNCTION sh.decrypt_data(
crypt_raw RAW,
pass_phrase VARCHAR2 )
RETURN VARCHAR2
AS
iv RAW(16);
pass_key RAW(32);
clear_raw RAW(32767);
clear_string VARCHAR2(2000) := NULL;
BEGIN
iv := SYS.UTL_RAW.SUBSTR(
SYS.UTL_RAW.CAST_TO_RAW(pass_phrase||'SufficientLength'), 0, 16 );
pass_key := SYS.UTL_RAW.CAST_TO_RAW(pass_phrase||'SufficientLength');
pass_key := SYS.DBMS_CRYPTO.HASH( pass_key, SYS.DBMS_CRYPTO.HASH_MD5 );
pass_key := SYS.UTL_RAW.CONCAT( pass_key, pass_key );
clear_raw := SYS.DBMS_CRYPTO.DECRYPT( crypt_raw,
SYS.DBMS_CRYPTO.ENCRYPT_AES256 + SYS.DBMS_CRYPTO.CHAIN_CBC +
SYS.DBMS_CRYPTO.PAD_PKCS5, pass_key, iv );
clear_string := SYS.UTL_RAW.CAST_TO_VARCHAR2( clear_raw );
RETURN clear_string;
END decrypt_data;
</PRE><P>
Nothing new here, except that we call SYS.DBMS_CRYPTO.DECRYPT() instead of ENCRYPT(). You can test both encryption and decryption as the SH user with the following select query. We use the same passphrase (“that”) for both encryption and decryption, so the result should be the same clear text that we started with (“this”).
<P><PRE>
SELECT sh.decrypt_data(sh.encrypt_data('this','that'),'that') FROM DUAL;
</PRE><P>
Alright, now that we’ve got everything defined, let’s go ahead and expunge and encrypt the existing sensitive data in our sh.customers archive table. We can do that by applying the trigger to each row by causing an update to each row. Execute the following as the SH user.
<P><PRE>
UPDATE sh.customers target
SET target.cust_year_of_birth = (
SELECT source.cust_year_of_birth
FROM sh.customers source
WHERE source.cust_id = target.cust_id
)
WHERE target.cust_year_of_birth > 0;
COMMIT;
</PRE><P>
You should only execute this once. It may take a while (about eight seconds on the 55,500 rows in the sample data on my workstation). Also be aware that this, and every transaction on the sh.customers table, places sensitive data into the redo logs, which must be cleaned up separately.
<P>
Now you can select records from the sh.customers table and verify that the marital status and income level columns are blank, the year of birth column is zero, and our new cust_yob_encr column contains an encrypted value.
<P><PRE>
SELECT * FROM sh.customers;
</PRE><P>
Presumably, since we have retained the customer year of birth, there must be some instance or circumstance in which we need to view it. We can’t simply select it any longer from the sh.customers table, and only the SH user can decrypt the data, so how do we make this data accessible as needed? Well, first we need to do it securely! Whatever method we provide has to be restricted.
<P>
I recommend creating a view of the data that includes the decrypted values. Select on this view should ONLY be granted to those who need it, only when they need it, and only for as long as they need it. Access should be revalidated on a periodic basis. Here is a view that you can define to provide future access to the decrypted data:
<P><PRE>
CREATE OR REPLACE FORCE VIEW sh.v_customers_sensitive
AS SELECT
cust_id, cust_first_name, cust_last_name, cust_gender,
TO_NUMBER( sh.decrypt_data( cust_yob_encr, TO_CHAR(cust_id)|| 'PPhrase' )
) cust_year_of_birth,
cust_marital_status, cust_street_address, cust_postal_code, cust_city,
cust_city_id, cust_state_province, cust_state_province_id, country_id,
cust_main_phone_number, cust_income_level, cust_credit_limit, cust_email,
cust_total, cust_total_id, cust_src_id, cust_eff_from, cust_eff_to, cust_valid
FROM sh.customers;
</PRE><P>
You can select from this view to see the decrypted birth year.
<P><PRE>
SELECT * FROM sh.v_customers_sensitive;
</PRE><P>
Note that the pass phrase, “TO_CHAR(cust_id)|| 'PPhrase'” that we pass to decrypt_data() in this view is the same as what we passed to encrypt_data() in the trigger. One thing that I would like to point out with this approach is that the passphrase is kept separate from the data. Presumably, a backup of the data or even a hacker dump of the table, will not carry with it the trigger and view definition. In that case, the stolen data is encrypted and cannot be read – the thief does not have the pass phrase.
<P>
So we learned a simple method to encrypt data using inherent capabilities of Oracle 11g. We learned how to remove sensitive data from our archives and how to encrypt any sensitive data that we retain. We also learned how to view the decrypted sensitive data securely, as needed. If we have also learned about the need for data protection from the SCDOR hack, and done the analysis, and taken corrective actions, then we may have actually learned our lesson.
David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-25927131814820763962011-11-21T19:20:00.005-05:002011-12-09T21:48:53.711-05:00Source Code For DownloadWe had a bit of a problem coordinating my source code submissions with the Apress web site for the book, so the source code may not have been available for download, for those who looked. Here is another link for the source code:<div><br /></div><div><a href="https://sites.google.com/site/orajavsec/ExpertOracleJavaSecuritySourceCode.zip?attredirects=0">Source Code - 4 MBytes</a></div><div>Updated on 12/09/2011</div><br />In this update I have made all the source available under the GNU General Public License.David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com1tag:blogger.com,1999:blog-7183773701017655963.post-51460099363454290262011-11-04T09:20:00.005-04:002011-11-04T10:56:50.358-04:00The Final SolutionIt will be helpful for those evaluating this book and considering spending their hard-earned cash to acquire a copy, to know what the final solution is -- where this book is going. Some of it is obvious from the title and descriptions on the cover; but I would like to put into just a few paragraphs a description of the security system that we develop in the book.<div><br /></div><div>First let me say that there are only two things required to complete the entire system: download of Oracle 11g Enterprise edition and download of Java Development Kit (JDK) 1.5 or higher. These two downloads are free! All the rest is code that we develop in the book. You will not be burdened by any other application frameworks or ancillary (additional-purchase) applications.</div><div><br /></div><div><span class="Apple-style-span"><b>The Final Solution:</b></span></div><div>Each user has an Oracle account (options are discussed and are possible), identified externally (no password). The user opens a Java application on their computer. The Java application gets the logged-in user ID from NTSystem or UnixSystem (JAAS). Thus begins Single Sign-On. The authenticated user establishes a proxy connection through a centralized access user.</div><div><br /></div><div>The password for the centralized access user is the only password that is exposed in the application. For this user, we define him on a hardened Oracle database instance (as described in the book). He has very little access - just enough to be an application gatekeeper. His password is embedded in the application in encoded form. Various password encryption / hiding / access methods are discussed in the book, but we resolve to an encoded password that is encoded (encrypted) using an obfuscated Java class.</div><div><br /></div><div>The access user determines if a 2-factor authentication code was provided, and if not, Oracle sends a valid for 10-minute, 2-factor code to mobile devices (cell phone SMS or pager) and/or e-mail for the authenticated user. Once the code is received, the user submits the code in a second connection, proxied through the access user. If the application, authenticated user, and 10-minute time to live are all acceptable, a series of encrypted Oracle passwords (connection strings) are returned for use in the application.</div><div><br /></div><div>These passwords are encrypted on disk using DBMS_CRYPTO and a calculated password, specific to the client application. They are decrypted, then reencrypted using session-specific encryption for the current user / application. The session-specific encryption uses random encryption parameters like this: First a public / private RSA key pair is generated and the artifacts of the public key are submitted to Oracle. The Oracle instance generates a DES shared password key using random algorithm parameters (respect the power of random) and transmits the parameters to the client application -- the DES key parameters are encrypted with the RSA public key. Those passwords (connection strings) that Oracle returns to the client application are encrypted with the DES key for decryption as needed.</div><div><br /></div><div>So now the application is free to begin using sensitive Oracle data. One of the encrypted connection strings is decrypted just-in-time, and the authenticated user is validated as a user of that Oracle connection through a secure application procedure. The user must be granted access to proxy through the Oracle user and must be granted the application role required for the connection. It is all very complex, and this brief summary is insufficient (so buy the book, please).</div><div><br /></div><div>When we connected with this new encrypted connection string, and the user was validated for access, a new set of session-specific RSA and DES keys was generated. All sensitive data transferred for use in the application is transferred in encrypted form. We primarily use stored procedures that return result sets (cursors) for queries and stored procedures for data updates.</div><div><br /></div><div>In the last chapter, I provide a GUI interface for bootstrapping the entire security system and then managing users, access, administration, applications and connection strings. If you'd rather build it than buy it, you can have Expert Security using this book. Or if you just want to learn secure programming approaches and the technologies used in commercial products, then this is a good way to get that insight. There is also a Supplement with the source code that provides some further insights and scenarios.</div><div><br /></div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-36148006828173920012011-11-04T06:54:00.012-04:002011-11-12T12:12:05.550-05:00Oracle Security Controversies<div>There are several areas of security that I delve into in the book where I take a contrarian position: Client Wallets, Virtual Private Database and Password-Protected Roles. It is not so much that I oppose using those things; it's just that there are security weaknesses that I believe are unacceptable. There are also some areas that I discuss in the book that need to be considered carefully when used in your Oracle Security scheme, for example Password storage for Data On Disk Encryption.</div><div><br /></div><div><span class="Apple-style-span"><b>Why are Client Wallets bad?</b></span></div><div>Client Wallets are a secure storage file for Oracle account passwords. The wallet file is encrypted with a password, so it cannot be easily deciphered. The algorithm parameters are embedded in Java and DLLs, so they are not beyond attack, but that is not the real problem. The truly scary reality of client wallet files is that if someone gets hold of the file, they can use it to log into Oracle as the target account without any further authentication. Normally these files are stored in user's home directories, and so the assumption is that they are protected by the Operating System file system security; but the wallet is simply a file that can be copied or even e-mailed (by a hacker, administrator or hapless user), or even stolen from backups or archives.</div><div><br /></div><div>One more security lapse that is created by client wallet files is the dependency on SQLnet configuration files for application. An encrypted password in the wallet is tied to an entry in the TNSNames.ora file or equivalent. For example the user mUser on the Oracle instance mOra might have a TNSNames entry mOra_mUser for which a password exists in the client wallet. The obvious security loophole here is that the TNSNames entry can point to ANY oracle instance -- if the Oracle user exists on that instance, the client wallet can be used to log in as that user. In some Oracle instances, mUser may have more privileges or more sensitive data access, and if the user account has the same password on that instance, the wallet can be used to get access, even if that's not the instance for which the wallet entry was created.</div><div><br /></div><div><span class="Apple-style-span"><b>What's wrong with Virtual Private Database?</b></span></div><div>Let me say that there is nothing really wrong with VPD, and it can be configured so that it does enhance security. But the way it is usually defined, it bases security on data. For example: only show the current user rows in the employee table for employees with the same company code as the current user. This is data filtering data -- it is not a basis for security.</div><div><br /></div><div>In the book, I show VPD based on two parameters that are security-related, not data-related: proxy grants and role grants. I also show that without VPD, by limiting grants to the data and limiting grants to stored procedures, you can embed dynamic where clauses (the heart of VPD) into your views and procedures and accomplish the same thing. My argument for doing that is to make the security enforcement obvious and not hidden in policy settings. There is nothing inherently more secure about a policy setting, which can be unset with a single command, than in the application of common security measures.</div><div><br /></div><div><span class="Apple-style-span"><b>My take on Password-Protected Roles.</b></span></div><div>In Oracle 11g, Oracle Corporation has removed the ability to acquire a password-protected role without entering the password, even if the role is a default password. This is a good correction, and my argument is that a role should not be granted if the user should not have access. Then if the user should have access, why is a password required?</div><div><br /></div><div>I realize that some applications acquire the password and then set the role, and the idea is that within the application a user can get the role, but from outside the application, she can not. Well, we have to ask, can she really NOT get the password and get the role? Perhaps not if you are limiting all other clients by Product User Profile. But an impostor application that presents the same Product User Profile (or none) can do whatever the original application does to acquire the role: query a view or execute a procedure or function.</div><div><br /></div><div>In other words, the addition of passwords to roles buys you nothing, but requires more user maintenance and code support. My final analysis is that you should not grant a role to anyone who does not need it all the time, and if you really want to password-protect a role, then make the user enter it -- do not encode the password acquisition.</div><div><br /></div><div><span class="Apple-style-span"><b>Password Storage for Data Encryption on Disk</b></span></div><div>As in the discussion of Client Wallet encryption, here again the algorithms and parameters used for encrypting data using the DBMS_CRYPTO package are codified in Java and DLLs and perhaps wrapped procedures. They can be attacked. But once again, that is not the real problem. The problem is where to store the password.</div><div><br /></div><div>The solution I came up with is to calculate an application-specific password based on identity artifacts from the application and designated starter codes. I use a complex wrapped procedure to do the password calculation. So where is the password stored? It really isn't. Someone accessing the data or the Oracle server will not find password records in the database tables, nor in files on the server. It would require much more effort.</div><div><br /></div><div><span class="Apple-style-span"><b>PUBLIC and the SYS Data Dictionary Views</b></span></div><div>For the most part, those views in the data dictionary that are granted to PUBLIC are helpful and probably even necessary for use of the database. However, it would be nice to be able to create an Oracle user/schema and not have them acquire ANYTHING. Perhaps I handle authentication through a database (as I do in the book), so I have to let users connect, but I don't want to expose some of the PUBLIC data dictionary views to the user until they have proven themselves. I solve this by turning off PUBLIC access to views like SYS.ALL_USERS.</div><div><br /></div><div>What I would prefer is for PUBLIC to be a regular role, with one addition. PUBLIC never disappears, even when you set role -- that is a nice feature. I would like to be able to revoke PUBLIC from users, or to have the requirement to specifically grant PUBLIC before it became active. Perhaps there could be a PUBLIC_REQUIRED like the current PUBLIC, and a PUBLIC_OPTIONAL that is more like an ordinary role, that can be granted and revoked, with the additional feature of never disappearing.</div><div><br /></div><div>That is all the controversies I'd like to address at this moment. I hope this discussion has led to more insight, not just more argument.</div><div><br /></div><div><span class="Apple-style-span" ><b>Synonyms Are Not Good</b></span></div><div>This is something I spend time discussing in the book, and I wanted to mention it as a controversy... Perhaps you and your application programmers depend on synonyms to find things scattered around many different schemas. This is a bad dependency - just say "No".</div><div><br /></div><div>Basically, there are security, code-sharing and maintenance issues, as well as potential production issues with code promoted from a lower environment. All this for a shortcut syntax!?! Just say "No", and make everyone refer to your Oracle structures with the schema prefix. This goes for public synonyms as well as private.</div><div><br /></div><div>I admit that one instance of a synonym may be beneficial - a synonym for a structure reference across a database link. The benefits in this case are (1) removing the complex reference from the application code and (2) giving the Oracle DBAs an extra layer of flexibility to use in moving databases and structures around. Yes, these may be the same arguments (flexibility) that you use for regular synonyms; but if you are using views, you already have sufficient flexibility for local structures. In truth, you can point a database link at the new location and get flexibility with just the link, but you may want to maintain link names that correlate to the database instance names, so you need another layer of flexibility.</div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-19161531818272639082011-10-07T08:41:00.002-04:002011-10-07T08:47:23.370-04:00Book Code CorrectionsFor the VPD functions defined in Chapter 12, the return clause lengths that I defined are insufficient. The return clause for appsec.apps_for_admin is almost 400 characters, so it is fine; but I would increase the definition of rtrn_clause to VARCHAR2(600). In appsec.apps_for_user, the return clause is over 600 characters already, so I would increase the definition of rtrn_clause in that function to VARCHAR2(1000). I like to have room to breath, even if the actual lengths of these return clauses never change.<div><br /></div><div>I will make this correction in the source code in the next update.</div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-9237976105539239812011-10-02T21:03:00.000-04:002011-10-02T21:07:54.546-04:00Updates to Supplement<div>This is an update to the section entitled: Using Structures without Two-Factor Authentication</div><div><br /></div><div>I'm going to give you the quickest path to disabling the 2-factor authentication. This will not remove references to 2-factor authentication from the code, nor will it remove the exchange of authentication codes between the client and server; it's just that, the blank codes will be exchanged and accepted. No codes will be required, and no codes will be sent to mobile devices or e-mail.</div><div><br /></div><div>Modify the appsec.appsec_public_pkg.p_get_app_conns procedure, commenting the 2-factor authentication code test and distribute lines, as shown below:</div><div><br /></div><div> --IF( m_two_factor_cd IS NULL )</div><div> --THEN</div><div> -- m_err_txt := appsec_only_pkg.f_send_2_factor( return_user, m_application_id );</div><div> --ELSIF( appsec_only_pkg.f_is_cur_cached_cd(</div><div> -- return_user, m_application_id, m_two_factor_cd ) = 'Y' )</div><div> --THEN</div><div> secret_pass_salt :=</div><div> app_sec_pkg.f_get_crypt_secret_salt( ext_modulus, ext_exponent );</div><div> secret_pass_count :=</div><div> app_sec_pkg.f_get_crypt_secret_count( ext_modulus, ext_exponent );</div><div> secret_pass :=</div><div> app_sec_pkg.f_get_crypt_secret_pass( ext_modulus, ext_exponent );</div><div> secret_pass_algorithm :=</div><div> app_sec_pkg.f_get_crypt_secret_algorithm(ext_modulus, ext_exponent);</div><div> m_crypt_connections := appsec_only_pkg.f_get_crypt_conns( m_class_instance );</div><div> --ELSE</div><div> -- -- Wrong 2-Factor code entered</div><div> -- RAISE NO_DATA_FOUND;</div><div> --END IF;</div><div><br /></div><div>Make that same change to the appsec.appsec_admin_pkg.p_copy_app_conns procedure.</div><div><br /></div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-89395862886075090232011-09-25T05:53:00.000-04:002011-09-25T21:25:33.219-04:00What was I thinking?<div>This morning I realized that I have exaggerated in my author biography. While it is true that I have over 30 years' experience programming computers, I would not categorize my responsibility as "multi-platform network integration and systems programming" until starting in about 1985. That would make it more like 26 years.</div><div><div><br /></div><div>I apologize for the exaggeration in my author biography. I really should have said "over 25 years".</div><div><br /></div></div><div>In 1985, my multi-platform network and system programming consisted of serial ports and modems, exporting mainframe database records for import to a personal computer project management system. From those simple beginnings, it wasn't until 1989 that I installed and managed my first packet-switching (more like modern) network for my workgroup. Then in 1991, I managed the most complex network of my career. Since then, multi-platform networking has become pretty much simpler.</div><div><br /></div><div>In 1991, we had to install Ethernet cards in our computers and set a non-conflicting IRQ. And we had to add software to the Windows 3.1 operating system in order to do networking. We used either Trumpet winsock or what became our standard, the Netware client software. Each computer had to have a unique TCP/IP address manually set, and had to also speak IPX/SPX for Netware. </div><div><br /></div><div>We also had a whole other side of the house in 1991: Apple. Those folks networked with Appletalk at the time (not even Ethertalk) and I connected both sides together using a Gaterbox. I can still remember the feeling of success I had when I printed a screen capture of my Windows 3.1 desktop on a color Apple printer through a Netware print queue (using the Netware NLM for Appletalk and the Gatorbox). I still have that printout.</div><div><br /></div><div>From where I worked, we could share files and information world-wide, but the world-wide-web was just a rumor. I didn't know I needed it, because I had Telnet and FTP.</div><div><br /></div><div>What was computing like for me, 30 years ago? I learned BASIC on a terminal to the mainframe in class, and had a SHARP programmable calculator that ran a simplified version of BASIC. In my last year of undergraduate college, my dad bought a Radio Shack TRS-80, Model 2 with a cassette deck for storage. I knew enough BASIC to use the TRS-80 to communicate through the serial port with a plotter and have it render my design class CAD drawings in color, from multiple perspectives (of course I calculated and entered all the points manually.)</div><div><br /></div><div>When I got my first real job, the computing resources at work were limited to dedicated word processors (a cross between a typewriter and a computer) and punch cards which I transported to the local university to have run and have reports printed. When I got my second real job, I got access to an original IBM PC. I started doing all my work in Lotus 123. This was in 1984. Big Brother became my friend, or was that Compuserve (I spent hours using TAPCIS over a modem). I bought a Compaq portable (definitely not a laptop computer) with DOS 1 something and an AST 6-pack board, an external modem and a plus (+) drive, 10 megabytes! My software was all from a company named Ashton-Tate. I communicated with friends and played long games on Bulletin Board Systems.</div><div><br /></div><div>If you recognize what I said in that last paragraph, then you are old!</div><div><br /></div><div></div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0tag:blogger.com,1999:blog-7183773701017655963.post-75467021034601231322011-09-20T22:05:00.001-04:002011-11-10T20:23:54.686-05:00Why I Wrote the Book<div>Beyond what I said in the front-matter of the book, Expert Oracle and Java, Programming Secure Oracle Applications in Java, I have other agendas. Perhaps one being that desire to have my skills and accomplishments recognized... it would be an illusion if I pretended that vanity didn't enter my psyche. I have a bit more altruistic goals as well. For one, I wanted to provide tools that you, my peer programmers can use, collected in one volume. Unfortunately, you will not find the book to be organized as a handy reference guide, because of my other goal. My primary goal is to teach, to have you delve down deep into application security issues and to apply some practical coding practices to address the issues. A final goal that I have is definitely selfish -- I want to learn. I am a lifelong student, and this book provided a focus not just for pulling together what I knew, but also for exploring and learning what I had not previously known.</div>David Coffinhttp://www.blogger.com/profile/01700372566377095903noreply@blogger.com0