<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-29442405</id><updated>2011-07-29T01:47:11.971-05:00</updated><title type='text'>Roman Kuzmik</title><subtitle type='html'>I am Java Developer. Thus, this blog is mostly about my Java experience.
Sometimes I feel opened to share my day to day adventures in Java world, so here it is.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rkuzmik.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://rkuzmik.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Roman Kuzmik</name><uri>http://www.blogger.com/profile/04528252195754670406</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_s0Y5q7RFdqk/SrEBLshn8kI/AAAAAAAAAuU/YJTWd-sOEFE/S220/rsk_avator_2008.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-29442405.post-3667411916514854541</id><published>2007-04-12T10:42:00.001-05:00</published><updated>2007-04-12T10:42:52.963-05:00</updated><title type='text'>Cannot agree with Monson-Haefel about J2EE future</title><content type='html'>&lt;span style="font-family:arial;"&gt;This is reply to original article &lt;a href="http://searchwebservices.techtarget.com/originalContent/0,289142,sid26_gci1198211,00.html"&gt;Analysts see Java EE dying in an SOA world&lt;/a&gt;.

Monson-Haefel is his article compares J2EE with Ruby-on-Rails. Ruby-on-Rails is a Web application framework thus this comparison is just like between a bike and a luxury car. It is wrong by definition. While more and more specs, JSRs and technologies (also come from J2EE) move to J2SE (just take a look at J2SE 6.0) are we going to expect the death to Java?! As Monson-Haefel sad, 'No', so why he is contradicts to himself? Btw, why CORBA is dead? We still use it in our mainframe integration :-) . Does the CORBA look complicated for you? As for me CORBA is most simplest technology ever exists in IT. If CORBA is die-hard for Monson-Haefel then despite of the honor to all his books I've no comments to the rest of the article at all :-)&lt;/span&gt;

&lt;span style="font-family:arial;"&gt; Are all those analysts talking about complexity of the J2EE from the application server implementation point of view? At this point I ready to agree with them. It is pretty hard to build J2EE5 server from scratch. But at the moment we have at least two even OpenSource implementations which work just fine (Glass Fish and JBoss). As for developers it is all about the way of use. Just take those parts form J2EE which are required for you project, then in most cases it will be 10% of all J2SE/J2EE stack. Is it hard to lean how-to use 10% of the complicated thing? It is just enough to read introduction to J2EE and define the needed parts and then follow the table of content to refer to actual information you need.&lt;/span&gt;

&lt;span style="font-family:arial;"&gt; Yep, J2SE/J2EE is a huge stack of technologies, but please look at it as a set of ready to plug and use patterns and then it won't be more complicated then GOF for ya!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29442405-3667411916514854541?l=rkuzmik.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rkuzmik.blogspot.com/feeds/3667411916514854541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29442405&amp;postID=3667411916514854541' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default/3667411916514854541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default/3667411916514854541'/><link rel='alternate' type='text/html' href='http://rkuzmik.blogspot.com/2007/04/cannot-agree-with-monson-haefel-about.html' title='Cannot agree with Monson-Haefel about J2EE future'/><author><name>Roman Kuzmik</name><uri>http://www.blogger.com/profile/04528252195754670406</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_s0Y5q7RFdqk/SrEBLshn8kI/AAAAAAAAAuU/YJTWd-sOEFE/S220/rsk_avator_2008.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29442405.post-115560646395443133</id><published>2006-08-14T20:42:00.003-05:00</published><updated>2009-09-16T11:30:04.826-05:00</updated><title type='text'>SAML Relying Party Implementation</title><content type='html'>&lt;span style=";font-family:arial;font-size:85%;"  &gt;&lt;span style="font-style: italic;"&gt;How to implement SAML based SSO Relying Party.&lt;/span&gt;

&lt;br/&gt;&lt;br/&gt;
&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Glossary.&lt;/span&gt;&lt;/span&gt;

&lt;span style="font-weight: bold; color: rgb(153, 0, 0);"&gt;SAML - &lt;/span&gt;Security Assertion Markup Language is an XML standard for exchanging authentication and authorization data between security domains, that is, between an identity provider and a service provider.
&lt;span style="font-weight: bold; color: rgb(153, 0, 0);"&gt;SSO -&lt;/span&gt; Single sign-on (SSO) is a specialized form of software authentication that enables a user to authenticate once and gain access to the resources of multiple software systems.

&lt;br/&gt;&lt;br/&gt;
&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Introduction.&lt;/span&gt;&lt;/span&gt;

Recently I have had to implement one part of SSO. My application as a provider of the services acts like a Relying Party in the SAML terms. Relying party is the system, or administrative domain, that relies on information supplied to it by the asserting party. While Asserting party is the system, or administrative domain, that asserts information about a subject. For instance, the asserting party asserts that this user has been authenticated and has given associated attributes.
In other words I am in B2B relation with my partners. We want to use SSO all across our services. And of course we want to use modern SAML as assertion contract language.

&lt;br/&gt;&lt;br/&gt;
&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Finding solution.&lt;/span&gt;&lt;/span&gt;

In order to implement SSO with SAML you have to choose specification to which you conform. There are two of them 1.1 and 2.0.  While 2.0 is more feature rich and restrictive, old 1.1 is more wide spread and accepted across business. Specification defines not only the SAML language itself,  but also the way it can be used during assertions interchange. There are two possible ways of assertion flow for SSO purpose in 1.1 spec:

&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=";font-family:arial;font-size:85%;"  &gt;&lt;span style="font-style: italic;"&gt;Browser/Artifact Profile&lt;/span&gt; - this stand for the case when target service (the service end-user wants to access) asks another party to confirm end-user credentials. Actual assertion flow is more complicated (You can reference to actual specification part 4.1.1 for more details). &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=";font-family:arial;font-size:85%;"  &gt;&lt;span style="font-style: italic;"&gt;Browser/POST Profile&lt;/span&gt; - in this case end-user submits his passport along with the reference to the target service he wants to access.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style=";font-family:arial;font-size:85%;"  &gt;
First case with artifact interchange is not suite for us. I have to initiate outgoing connection to trusted business partner site in order to obtain actual SAML assertion. I have to create request based on  artifact  supplied me earlier. To involve this kind of dependency is not a good idea for my particular application. I do not want to have a third party system access from inside my firewall. Altough, it is plain HTTP outgoing connection.

The second case with all-sufficient SAML assertion I like more. From the top level overview it looks simple as that:

&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1524/3137/1600/SSO_topLevelSequence.0.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/1524/3137/400/SSO_topLevelSequence.png" alt="" border="0" /&gt;&lt;/a&gt;
&lt;span style=";font-family:arial;font-size:85%;"  &gt;

End-User (browser) submit  me (Relying party) ready to use passport (assertion). I trust this passport based in special trust relationship between me (Relying party) and asserting party who actually issued this passport.

The important note here is I do not mention how this trust relationship has been established. This space is for another article I expect to publish in near future.

&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Implementation&lt;/span&gt;&lt;/span&gt;.

It is a good point here to start from utilizing ready to use SAML library.  There is open source library called opensaml which can handle most of the SAML related operations. This is quite fresh library from the implementation point of view.  And some times I find very strange architectural decisions in it. However, and it is more important for us, it works!  So let's take all OpenSAML abstraction into our design and proceed with diagramming.

&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1524/3137/1600/SSO_detailedRelayingPartySequence.1.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/1524/3137/400/SSO_detailedRelayingPartySequence.0.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style=";font-family:arial;font-size:85%;"  &gt;

At the first step, according to specification, browser post "Form with Response&amp; Assertion"  to our Servlet.

&lt;span style="font-weight: bold;"&gt;Note:&lt;/span&gt;
&lt;span style="font-style: italic;"&gt;It is a little bit unusual here, why we submit response? In general it is clearer to submit requests. At least submit some kind of TransmitAssertionUnit, SAMLAssertionMessage or any other well suited for this particular satiation object name of the underlying abstraction. &lt;/span&gt;

At the second step we have to construct BrowserProfileRequest object. It encapsulates data submitted for us by Asserting party through user browser in HttpRequest.

At the third step we have to create binding profile we have chosen. In our case it is SAMLBrowserProfile. Let's use factory to create an instance and then perform response (actually, as I mentioned early it is request or just a message containing our assertion, but for some reason it is called BrowserProfileResponse) processing.

Once we have BrowserProfileResponse object we have all information necessary to perform all other operations.  It can be trust relationship validation step (As I mentioned earlier. See the next post for details). It can be some kind of authentications steps in which we create internal object represents authenticated user. And finally, we can redirect user to requested resource.

Let's step ahead to actual coding. I want to have my servlet code clear. Thus let's introduce SsoSamlHelper here. This helper takes care of all implementation details. Then actual servlet looks like template method. &lt;/span&gt;

&lt;pre class="brush:java"&gt;

package org.ots.sso;

import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opensaml.NoSuchProviderException;
import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLBrowserProfile;
import org.opensaml.SAMLBrowserProfileFactory;
import org.opensaml.SAMLException;
import org.opensaml.SAMLSignedObject;
import org.opensaml.UnsupportedProfileException;
import org.opensaml.SAMLBrowserProfile.BrowserProfileRequest;
import org.opensaml.SAMLBrowserProfile.BrowserProfileResponse;

import org.ots.ws.security.KeyStoreHolder;

/**
 * Useful static method to manipulate with SAML objects
 *
 * @version $Id$
 * @author Roman Kuzmik
 */
public class SsoSamlHelper {
    private static final Log log = LogFactory.getLog(SsoSamlHelper.class);

    /**
     * Exctract from HHTP request all SSO SAML related information
     *
     * @param httpRequest
     * @return
     * @throws SsoSamlException
     */
    public static BrowserProfileRequest createRequest(HttpServletRequest httpRequest) throws SsoSamlException{
        log.debug("");

        try {
            SAMLBrowserProfile profile = SAMLBrowserProfileFactory.getInstance();
            BrowserProfileRequest samlRequest = profile.receive(httpRequest);
            return samlRequest;
        } catch (UnsupportedProfileException e) {
            throw new SsoSamlException(e);
        } catch (NoSuchProviderException e) {
            throw new SsoSamlException(e);
        }
    }

    /**
     * Perform SAML assertion reconstruction from the BrowserProfileRequest provided
     *
     * @param samlRequest
     * @return
     * @throws SsoSamlException
     */
    public static BrowserProfileResponse processRequest(BrowserProfileRequest samlRequest) throws SsoSamlException{
        log.debug("");

        try {
            SAMLBrowserProfile profile = SAMLBrowserProfileFactory.getInstance();

            StringBuffer issuerBuffer = new StringBuffer();

            BrowserProfileResponse samlResponse = profile.receive(
                    issuerBuffer,
                    samlRequest,
                    SsoSamlConstants.SAML_SSO_RECEPIENT,
                    /*ReplayCache*/ null,
                    /*SAMLBrowserProfile.ArtifactMapper*/ null,
                    SsoSamlConstants.SAML_MINOR_VERSION
            );
                    
            log.debug("done");
            return samlResponse;
        } catch (UnsupportedProfileException e) {
            throw new SsoSamlException(e);
        } catch (NoSuchProviderException e) {
            throw new SsoSamlException(e);
        } catch (SAMLException e) {
            throw new SsoSamlException(e);
        }  
    }

    /**
     * Give me trust entity key
     *
     * @param assertion
     * @return
     */
    public static String getIssuer(SAMLAssertion assertion){
        return assertion.getIssuer().trim();
    }

    /**
     * WS-S Signature validation
     *
     * @param samlObject
     * @param issuer
     * @param keyStoreHolder
     * @throws SsoSamlException
     */
    public static void verifySignature(SAMLSignedObject samlObject, String issuer, KeyStoreHolder keyStoreHolder) throws SsoSamlException{
        log.debug("");
        try {
            samlObject.verify(keyStoreHolder.getPublicKey(issuer));
        } catch (KeyStoreException e) {
            throw new SsoSamlException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new SsoSamlException(e);
        } catch (UnrecoverableKeyException e) {
            throw new SsoSamlException(e);
        } catch (SAMLException e) {
            throw new SsoSamlException(e);
        }
        log.debug("done");
    }
}
&lt;/pre&gt;&lt;span style="font-size:85%;"&gt;


&lt;span style="font-family:arial;"&gt;Javadoc provided here should be self explanations. &lt;/span&gt;

&lt;span style="font-family:arial;"&gt;Now we can construct our servlet in three lines of code as follows:&lt;/span&gt;

&lt;pre class="brush:java"&gt;
BrowserProfileRequest samlRequest = SsoSamlHelper.createRequest(httpRequest);
BrowserProfileResponse samlResponse = SsoSamlHelper.processRequest(samlRequest);
String issuer = SsoSamlHelper.getIssuer(samlResponse.assertion);
SsoSamlHelper.verifySignature(samlResponse.response, issuer, keyStoreHolder);
String nameIdentifier = samlResponse.authnStatement.getSubject().getNameIdentifier().getName();

//auth user with username==nameIdentifier

//redirect to samlRequest.TARGET
&lt;/pre&gt;

&lt;span style="font-family:arial;"&gt;That's it!

Servlet out looks as follows:

&lt;pre class="brush:text"&gt;
10:10:27(DEBUG)[ws.security.KeyStoreHolder.initKeyStore():74] 
10:10:27(DEBUG)[ws.security.KeyStoreHolder.initTrustStore():84] 
10:10:27(DEBUG)[sso.SsoSamlServlet.service():42] [START] 
10:10:27(DEBUG)[sso.SsoSamlServlet.service():45] read HTTP request into BrowserProfileRequest 
10:10:27(DEBUG)[sso.SsoSamlHelper.createRequest():40] 
10:10:27(DEBUG)[sso.SsoSamlServlet.service():47] samlRequest.SAMLResponse: base 64 code here 
10:10:27(DEBUG)[sso.SsoSamlServlet.service():48] samlRequest.TARGET:target URL here
10:10:27(DEBUG)[sso.SsoSamlServlet.service():50] process BrowserProfileRequest into BrowserProfileResponse 
10:10:27(DEBUG)[sso.SsoSamlHelper.processRequest():54] 
10:10:28(DEBUG)[sso.SsoSamlHelper.processRequest():70] done 
10:10:28(DEBUG)[sso.SsoSamlServlet.service():54] issuer: 'My partner #1' 
10:10:28(DEBUG)[sso.SsoSamlServlet.service():56] verify response signature 10:10:28(DEBUG)[sso.SsoSamlHelper.verifySignature():86] 
10:10:28(INFO) [security.signature.Reference.verify():742] Verification successful for URI "#cMnRtaOAdFkQmoCoQUdn" 
10:10:28(DEBUG)[sso.SsoSamlHelper.verifySignature():98] done 
10:10:28(DEBUG)[sso.SsoSamlServlet.service():59] perform authentication 10:10:28(DEBUG)[sso.SsoSamlServlet.service():61] nameIdentifier: hemaTest 
10:10:28(DEBUG)[service.handler.SecurityManager.getUserPasswordFromSamlAssertion():39] retrieve runtime properties 
10:10:28(DEBUG)[service.handler.SecurityManager.getUserPasswordFromSamlAssertion():43] companyName:My partner #1 
10:10:28(DEBUG)[service.handler.SecurityManager.getUserPasswordFromSamlAssertion():44] loginId:partnerUser_1 
10:10:28(DEBUG)[sso.SsoSamlServlet.service():69]
&lt;/pre&gt;

&lt;br/&gt;&lt;br/&gt;
&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;font-family:arial;" &gt;Test: SAML Asserting party Implementation.&lt;/span&gt;&lt;/span&gt;

&lt;span style="font-family:arial;"&gt;At this point we have to test our code. In order to do it we have to implement Asserting party. This includes "Inter-Site Transfer Service" implementation and all necessary parts for the browser functionality. This is definitely quite enough for the next article. &lt;/span&gt;

&lt;br/&gt;&lt;br/&gt;
&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;font-family:arial;" &gt;References.&lt;/span&gt;&lt;/span&gt;

&lt;span style="font-family:arial;"&gt;&lt;a href="http://www.opersaml.com"&gt;www.opersaml.com&lt;/a&gt; - SAML 1.1 and 2.0 implementation &lt;/span&gt;
&lt;span style="font-family:arial;"&gt;&lt;a href="http://www.oasis-open.org/committees/documents.php?wg_abbrev=security"&gt;SAML 1.1 specifications&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29442405-115560646395443133?l=rkuzmik.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rkuzmik.blogspot.com/feeds/115560646395443133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29442405&amp;postID=115560646395443133' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default/115560646395443133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default/115560646395443133'/><link rel='alternate' type='text/html' href='http://rkuzmik.blogspot.com/2006/08/saml-relying-party-implementation.html' title='SAML Relying Party Implementation'/><author><name>Roman Kuzmik</name><uri>http://www.blogger.com/profile/04528252195754670406</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_s0Y5q7RFdqk/SrEBLshn8kI/AAAAAAAAAuU/YJTWd-sOEFE/S220/rsk_avator_2008.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29442405.post-115534238445028129</id><published>2006-08-11T19:26:00.004-05:00</published><updated>2009-09-16T11:20:19.108-05:00</updated><title type='text'>Local Managed DNS (Java)</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Introduction.&lt;/span&gt;&lt;/span&gt;

&lt;/span&gt;&lt;span style="font-family:arial;"&gt;   As you probably know it is quite often when Web developer goes to change default DNS behavior on his workstation. I mean sometimes it is important to change host name resolution locally and point specific host name to localhost ip address. Suppose you work under 'blahblah.com' web site on your workstation and you have to test this site locally, for example by starting you browser and point it to &lt;span style="font-style: italic;"&gt;http://blahblah.com&lt;/span&gt;. While this site is already on production you browser resolves 'blahblah.com' to real IP address instead of local one. Of course the simplest way here (and I am sure it is quite wide spread) is to change you local hosts file (&lt;span style="font-style: italic;"&gt;/etc/hosts&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;%SystemRoot%\system32\drivers\etc\hosts&lt;/span&gt;) by adding the following entry:&lt;/span&gt;
&lt;/span&gt;
&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;127.0.0.1 blahblah.com&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;

&lt;span style="font-family:arial;"&gt;  It is ok and works quite well not only for browser but also for all IP applications running on you workstation. Today I have a deal with system which has at least three stages: development, staging and production. Thus, sometimes I have to change my hosts file and switch host name-IP mapping for all those configurations. My host now looks like:&lt;/span&gt;

&lt;/span&gt;
&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;#this is for dev &lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;12.12.12.10 blahblah.com  &lt;/span&gt;

&lt;span style="font-family:courier new;"&gt;#this is for staging &lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;#12.12.12.11 blahblah.com &lt;/span&gt;

&lt;span style="font-family:courier new;"&gt;#this is for production &lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;#12.12.12.12 blahblah.com&lt;/span&gt;&lt;/span&gt;
&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;
&lt;/span&gt;

&lt;br/&gt;&lt;br/&gt;
&lt;span style="font-family:arial;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Problem area.&lt;/span&gt;&lt;/span&gt;

&lt;/span&gt;&lt;span style="font-family:arial;"&gt;  My real hosts file looks much more complicated, because we have more than one server on each stage. Every time when you want to switch environment you go to hosts and comment/uncomment certain lines. Everything works fine until you have to write automated stand alone tool in Java which has to manage this hostname-ip mapping itself. There are a lot of possible targets for such tools. It can be some kind of testing tool, which has to execute several tests on each environment at ones (dev, stage, prod). Or it can be quite complicated tool which has to monitor cluster of web sites (i.e. by execute functional tests against it) where each host has its unique IP address but they all belongs to one host name. It is not very good idea to install this monitoring tool on each node in the cluster. It is better to have dedicated monitoring node which will run its tests in sequence or in parallel, and perform its operations under all nodes in the cluster. There are no any problems in implementing such a tool along if you know all IP addresses of all nodes in the cluster and you tests relay only on this IP addresses. However, in web development host name it is very important. It helps web server which listens on specific IP_address:port to determine certain application requested by particular URL request. And sometimes this web application performs HTTP redirects in order to perform several business operations, which also relay on host name. &lt;/span&gt;
&lt;span style="font-family:arial;"&gt;  So at this point we have to implement something like:&lt;/span&gt;

&lt;/span&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1524/3137/1600/DnsRequestSequence.0.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/1524/3137/400/DnsRequestSequence.gif" alt="" border="0" /&gt;&lt;/a&gt;
&lt;/div&gt;&lt;span style="font-size:85%;"&gt;


&lt;span style="font-family:arial;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Implementation.&lt;/span&gt;&lt;/span&gt;

&lt;/span&gt;&lt;span style="font-family:arial;"&gt; Do you have any ideas how to implement it? My first idea was to manage hosts file content from my monitoring java application? He-he. Yes, it was not very good idea. There are a lot of other applications can be run on monitoring node and I should not affect them at all. Thus I have to do something inside my JVM to perform host name resolution management. This is a good point let's dig inside it.&lt;/span&gt;

&lt;span style="font-family:arial;"&gt;   I have my monitor tool ready, and it uses a lot of network libraries (apache http client, http Unit, CORBA nameservers and so forth). All those libraries use java.net package to perform all network operations. By default this package internally relies on Sun implementation of the IP stack. It means that I have to do something to alter default host name resolution behavior inside java.net package. Let's start. Definitely the entry point is InetAddress class and its

&lt;/span&gt;&lt;/span&gt;&lt;div style="text-align: center;"&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;font-size:85%;"  &gt;byte[][] lookupAllHostAddr(String name)&lt;/span&gt;
&lt;/div&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;
&lt;/span&gt;&lt;span style="font-family:arial;"&gt;method which performs lookup by given hostname, and returns array of IP addresses belong to this hostname.  You probably cannot find this method using your javadoc, he-he, and you are right this method is a part of java.net.InetAddressImpl interface which is package level and InetAddress itself doesn't implement it. But internally it uses Inet4AddressImpl class to perform several operation, and this Inet4AddressImpl implements InetAddressImpl interface. lookupAllHostAddr is the native method inside Inet4AddressImpl. Good investigation, but it still won't help us because we still have no idea how to alter name resolution behavior.&lt;/span&gt;
&lt;span style="font-family:arial;"&gt;  It is good practice and common way to override default implementation using standard discovery mechanism. You have to place in your &lt;span style="font-style: italic;"&gt;META-INF/services/facroty_name_here&lt;/span&gt; text file with one line as content with full qualified class name of the factory. This file is used by resource factory configuration.which instantiates this factory class mentioned in file and uses it to produce concrete objects. Common example is XML related libs which uses the following descriptors in META-INF/services:
&lt;/span&gt;&lt;/span&gt;
&lt;ul  style="font-family:courier new;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;javax.xml.parsers.DocumentBuilderFactory&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;javax.xml.parsers.SAXParserFactory&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;javax.xml.validation.SchemaFactory&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;org.w3c.dom.DOMImplementationSourceList&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;org.xml.sax.driver&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;com.sun.org.apache.xml.internal.dtm.DTMManager&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;javax.xml.transform.TransformerFactory&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;Preliminary the same situation we have here in Sun's InetAddress. InetAddress looks at the sun.net.spi.nameservice.provider.X system property in order to decide which name service implementation to use. By default it uses Inet4AddressImpl to create anonymous sun.net.spi.nameservice.NameService object. You have two options here:&lt;/span&gt;

&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;specify &lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;sun.net.spi.nameservice.provider.1=default|dns,sun&lt;/span&gt; system property. This will use Sun's DNS name service provider through JNDI.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;create your own name service and specify sun.net.spi.nameservice.provider.1 system property with you custom value.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:85%;"&gt;
&lt;span style="font-family:arial;"&gt;Hey! It seems we are about to bring an issue to a close very fast! Let's create our own &lt;span style="font-style: italic;"&gt;sun.net.spi.nameservice.NameService&lt;/span&gt;, god bless Sun, there are only two methods to override. And then we will be ready to plug it into sun.net.spi.nameservice.provider.X infrastructure. This falls into several steps.&lt;/span&gt;

&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;create descriptor in META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor and mention our new descriptor class there: org.ots.dns.LocalManagedDnsDescriptor&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;create LocalManagedDnsDescriptor itselfs, it should implements sun.net.spi.nameservice.NameServiceDescriptor and return NameService in createNameService() method&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;create our custom NameService itself:  &lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:arial;" &gt;public class LocalManagedDns implements NameService&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:85%;"&gt;
&lt;span style="font-family:arial;"&gt;Now we are going to implement only lookupAllHostAddr which can look as follows:&lt;/span&gt;

&lt;pre class="brush: java;"&gt;
        if ("blahblah.com".equalsIgnoreCase(hostname)) {
            byte[] ip = Util.textToNumericFormat("12.12.12.10");
            return new byte[][] { ip };
        } else {
            throw new UnknownHostException();
        }
&lt;/pre&gt;


&lt;span style="font-family:arial;"&gt;  This is quite enough for the first test. If you run this code you will find that it works! However it works only for 'blahblah.com', every other host name lookup will throw UnknownHostException. It is good that we substitute our host name with desired IP address, but we also have to do something with other hostname lookups which are not involved into manipulations.&lt;/span&gt;
&lt;span style="font-family:arial;"&gt;  The first idea here is to create sun.net.spi.nameservice.providerS tree, in the way if one provider cannot lookup host then another try to do the lookup itself:

&lt;/span&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;sun.net.spi.nameservice.provider.1=dns, LocalManagedDns&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;sun.net.spi.nameservice.provider.2=default&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;sun.net.spi.nameservice.provider.3=dns, sun&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;

&lt;span style="font-family:arial;"&gt;  However, these or any other combination of the properties won't help us, because InetAddress creates only one NameService for its own needs. As I understand this is the first one which is successfully created. For us it means that we have to deal with all host name lookup in our LocalManagedDns. Eh-h-h, it is not very good news.&lt;/span&gt;
&lt;span style="font-family:arial;"&gt;  So, let's try to use Sun name service implementation inside our LocalManagedDns. Go to java.net and let's grab something from it. But all interesting classes there are final and package level. Thus, we cannot use them at all. Of course we can try to write our own class in java.net package and extends it from Inet4AddressImpl. But we will get "&lt;span style="color: rgb(102, 51, 102);font-family:courier new;" &gt;java.lang.SecurityException: Prohibited package name&lt;/span&gt;" at runtime in this case. And as I know there is no way around it, neither java.policy will help us.  I could not find any way to use native JVM name service functions from user code. Thanks god, there is java libraries that can take care about DNS functions. It is DnsJava project. It has full DNS server/client functionality, but in our case all we need is to lookup host by name. With DnsJava it can be done in one line of code.&lt;/span&gt;
&lt;span style="font-family:arial;"&gt;  Let's create DNSJavaNameService instance inside our LocalManagedDns and delegate all unmatched call to it. Also let's introduce NameStore, it is singleton which will store custom hostname/IP mapping and provide API to manage such a mappings. &lt;/span&gt;

&lt;pre class="brush: java;"&gt;
package org.ots.dns;

import java.net.UnknownHostException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import sun.net.spi.nameservice.NameService;

/**
 *
 * @version $Id$
 * @author Roman Kuzmik
 */
public class LocalManagedDns implements NameService {
    private static final Log log = LogFactory.getLog(LocalManagedDns.class);

    NameService defaultDnsImpl = new DNSJavaNameService();

    /**
     * @see sun.net.spi.nameservice.NameService#getHostByAddr(byte[])
     */
    public String getHostByAddr(byte[] ip) throws UnknownHostException {
        log.debug("");

        return defaultDnsImpl.getHostByAddr(ip);
    }

    /**
     * @see sun.net.spi.nameservice.NameService#lookupAllHostAddr(java.lang.String)
     */
    public byte[][] lookupAllHostAddr(String name) throws UnknownHostException {
        log.debug("");

        String ipAddress = NameStore.getInstance().get(name);
        if (!StringUtils.isEmpty(ipAddress)){
            log.debug("\tmatch");
            byte[] ip = Util.textToNumericFormat(ipAddress);
            return new byte[][]{ip};
        } else {
            log.debug("\tmiss");
            return defaultDnsImpl.lookupAllHostAddr(name);
        }
    }

}
&lt;/pre&gt;


&lt;span style="font-family:arial;"&gt;Let's design NameStore in way it can handle singleton scope mapping as well as local thread level mapping. In my monitoring tool I have thread pool which executes task in parallel and every task thread has to have its own hostname/IP mapping.&lt;/span&gt;

&lt;pre class="brush: java;"&gt;
package org.ots.dns;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

/**
 *
 * @version $Id$
 * @author Roman Kuzmik
 */
public class NameStore {

    protected static NameStore singleton;

    protected Map globalNames;
    protected ThreadLocal localThread;

    protected NameStore(){
        globalNames = Collections.synchronizedMap(new HashMap());
        localThread = new ThreadLocal();
    }

    public static NameStore getInstance(){
        if (singleton == null) {
            synchronized (NameStore.class) {
                if (singleton == null) {
                    singleton = new NameStore();
                }
            }
        }
        return singleton;
    }

    public void put(String hostName, String ipAddress){
        globalNames.put(hostName, ipAddress);
    }
    public void remove(String hostName){
        globalNames.remove(hostName);
    }

    public synchronized void putLocal(String hostName, String ipAddress){
        Map localThreadNames = (Map) localThread.get();
        if (localThreadNames == null){
            localThreadNames = Collections.synchronizedMap(new HashMap());
            localThread.set(localThreadNames);
        }
        localThreadNames.put(hostName, ipAddress);
    }
    public void removeLocal(String hostName){
        Map localThreadNames = (Map) localThread.get();
        if (localThreadNames != null){
            localThreadNames.remove(hostName); 
        }
    }

    public String get(String hostName){
        String ipAddress = null;
        Map localThreadNames = (Map) localThread.get();
        if (localThreadNames != null){
            ipAddress = (String)localThreadNames.get(hostName); 
        }
        if (StringUtils.isEmpty(ipAddress)) {
            return (String)globalNames.get(hostName);
        }
        return ipAddress;
    }

}
&lt;/pre&gt;


&lt;span style="font-family:arial;"&gt;At this point we are ready to write simple test:&lt;/span&gt;
&lt;pre class="brush: java;"&gt;
        hostName = "google.com";
        ipAddress = "127.0.0.1";
        NameStore.getInstance().put(hostName, ipAddress);
        performLookup(hostName);

        hostName = "google.com";
        NameStore.getInstance().remove(hostName);
        performLookup(hostName);
&lt;/pre&gt;

&lt;span style="font-family:arial;"&gt;This code should lookup google.com to 127.0.0.1 at a first stage and then lookup the same host to its real IP addresses. First stage works fine, but second fails. It is not because we done something wrong in stage two, it is because InetAddress maintains addressCache. And during second lookup request it simply return cached value. Ups-s-s. We've created our own NameServiceProvider, plugged it into JVM, incorporated JavaDns and all these things do not work because of InetAddress.addressCache ?! Nice:. &lt;/span&gt;
&lt;span style="font-family:arial;"&gt;Let's go back to Java sources again:. searching: found: there is property which can help us!&lt;/span&gt;

&lt;span style="color: rgb(153, 153, 153);font-family:arial;" &gt;        //disable DNS cashe&lt;/span&gt;
&lt;span style="font-family:arial;"&gt;        Security.setProperty("&lt;span style="color: rgb(153, 0, 0);"&gt;networkaddress.cache.ttl&lt;/span&gt;", "0");&lt;/span&gt;

&lt;span style="font-family:arial;"&gt;Now our test code works fine:&lt;/span&gt;

&lt;pre class="brush: java;"&gt;
        hostName = "google.com";
        ipAddress = "127.0.0.2";
        NameStore.getInstance().put(hostName, ipAddress);
        performLookup(hostName);
      
        hostName = "google.com";
        ipAddress = "127.0.0.3";
        NameStore.getInstance().putLocal(hostName, ipAddress);
        performLookup(hostName);

        new Thread(){

            public void run() {
                String hostName = "google.com";
                try {
                    performLookup(hostName);
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
 
        }.start();
&lt;/pre&gt;&lt;span style="font-family:arial;"&gt;Output:

&lt;pre class="brush: text;"&gt;
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsDescriptor.getType():33]
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsDescriptor.getProviderName():41]
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsDescriptor.createNameService():53]
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():34]
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():38]     match
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsTest.performLookup():74] google.com/127.0.0.1
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():34]
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():42]     miss
[java] 19:52:05(DEBUG)[vzb.dns.DNSJavaNameService.lookupAllHostAddr():32] google.com
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsTest.performLookup():74] google.com/64.233.187.99
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsTest.performLookup():74] google.com/72.14.207.99
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsTest.performLookup():74] google.com/64.233.167.99
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():34]
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():38]     match
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsTest.performLookup():74] google.com/127.0.0.2
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():34]
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():38]     match
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsTest.performLookup():74] google.com/127.0.0.3
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():34]
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDns.lookupAllHostAddr():38]     match
[java] 19:52:05(DEBUG)[vzb.dns.LocalManagedDnsTest.performLookup():74] google.com/127.0.0.2
&lt;/pre&gt;
&lt;/span&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;span style="font-family:arial;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Conclusion.&lt;/span&gt;&lt;/span&gt;

&lt;/span&gt;&lt;span style="font-family:arial;"&gt;In this article we wrote our custom NameServiceProvider which able to manage its name resolution behavior through it's simple API. It looks like we have our own hosts file inside JVM. See attached &lt;a href="http://kuzmik.info/examples/LocalManagedDns.zip"&gt;LocalManagedDns.zip&lt;/a&gt; for the full source code provided along with this article. This is an example code so there is no license required. Please see corresponding license for libraries included into this package. &lt;/span&gt;

&lt;br/&gt;&lt;br/&gt;
&lt;span style="font-weight: bold;font-family:arial;font-size:100%;"  &gt;References.&lt;/span&gt;

&lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html"&gt;&lt;span style="font-family:arial;"&gt;http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html&lt;/span&gt;&lt;/a&gt;
&lt;a href="http://www.xbill.org/dnsjava/"&gt;&lt;span style="font-family:arial;"&gt;http://www.xbill.org/dnsjava/&lt;/span&gt;&lt;/a&gt;

&lt;span style="font-family:arial;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29442405-115534238445028129?l=rkuzmik.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rkuzmik.blogspot.com/feeds/115534238445028129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29442405&amp;postID=115534238445028129' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default/115534238445028129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default/115534238445028129'/><link rel='alternate' type='text/html' href='http://rkuzmik.blogspot.com/2006/08/local-managed-dns-java_11.html' title='Local Managed DNS (Java)'/><author><name>Roman Kuzmik</name><uri>http://www.blogger.com/profile/04528252195754670406</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_s0Y5q7RFdqk/SrEBLshn8kI/AAAAAAAAAuU/YJTWd-sOEFE/S220/rsk_avator_2008.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29442405.post-114978046057751341</id><published>2006-06-08T10:27:00.000-05:00</published><updated>2006-06-08T11:06:56.820-05:00</updated><title type='text'>Welcome</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1524/3137/1600/Avator-100x100.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/1524/3137/320/Avator-100x100.jpg" alt="" border="0" /&gt;&lt;/a&gt;
Welcome to Roman Kuzmik personal blog.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29442405-114978046057751341?l=rkuzmik.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rkuzmik.blogspot.com/feeds/114978046057751341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29442405&amp;postID=114978046057751341' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default/114978046057751341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29442405/posts/default/114978046057751341'/><link rel='alternate' type='text/html' href='http://rkuzmik.blogspot.com/2006/06/welcome.html' title='Welcome'/><author><name>Roman Kuzmik</name><uri>http://www.blogger.com/profile/04528252195754670406</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_s0Y5q7RFdqk/SrEBLshn8kI/AAAAAAAAAuU/YJTWd-sOEFE/S220/rsk_avator_2008.jpg'/></author><thr:total>2</thr:total></entry></feed>
