2.6.1.1 Java

Authentication against the REST API, in the Java client, makes use of a few Jersey utilities. In the RestClient provided in com.oracle.ovm.mgr.ws.client, a login method has been defined:

...
public class RestClient
{
   public static final String                   URI_BASE_PATH     = "/ovm/core/wsapi/rest";
   String                                       SECURE_PROTOCOL   = "https";
   String                                       INSECURE_PROTOCOL = "http";

   private static final Map<Class, GenericType> genericTypeMap = new HashMap<Class, GenericType>();

   private boolean                              debug             = false;
   private URI                                  baseURI;
   private Client                               webClient         = null;
   private List<NewCookie>                      cookies;
   private String                               mediaType         = MediaType.APPLICATION_XML;
   private Locale                               locale            = null;
   private SSLSocketFactory                     sslSocketFactory  = null;
...

   public boolean login(final String username, final String password, final Locale locale, 
               final String path) throws WsException
   {
       try
       {
            // Make a dummy request to pass the authorization info to the server get 
            // the session id (which is returned in a cookie)
            if (getCookies() == null)
            {
                final WebResource resource = 
                getWebClient().resource(getBuilder().path(path).build());
                // Specify media type to accept
                final Builder resourceBuilder = resource.accept(getMediaType());
                // Append auth info
                resourceBuilder.header("Authorization", 
                "Basic " + new String(Base64.encode(username + ":" + password)));

                if (locale != null)
                {
                    resourceBuilder.acceptLanguage(locale);
                }

                final ClientResponse response = resourceBuilder.head();
                setCookies(response.getCookies());
            }

            return true;
        }
        catch (final UniformInterfaceException ex)
        {
            throw convertException(ex);
        }
    }
...
}

Note that an initial request is sent and an Authorization header is attached with the Base64 encoded username and password required for HTTP Basic authentication. The session information is returned as a cookie in the server response, and this cookie can be used for all subsequent requests.

The OvmWsRestClient class in com.oracle.ovm.mgr.ws.client extends the RestClient class. It provides the API function that gets called in the sample application and defines the dummy query that is performed against the API to achieve authentication:

public class OvmWsRestClient extends RestClient implements OvmWsClient
{
    public static final String URI_BASE_PATH = "/ovm/core/wsapi/rest";

    public OvmWsRestClient()
    {
        super();
    }
    @Override
    public boolean login(final String username, final String password, 
         final Locale locale) throws WsException
    {
        return super.login(username, password, locale, "Server");
    }
...
}

Now in the WsDevClient class (the sample application), all we need to do is call this method:

...

public class WsDevClient
{
...
public void run()
    {
        try
        {
         ...
         api = OvmWsClientFactory.getOvmWsClient(wsimpl);
         ...
            api.initialize(hostname, port, true);
         // Authenticate with the OvmApi Service
            api.login(username, password, Locale.getDefault());
         ...
         }
...
}

There are a few things to note about how this has been implemented in the sample client. The first point is that we refer to the OvmWsClientFactory class to determine whether we are using the REST client or the SOAP client, using the string variable 'wsimpl'. This class allows us to use the same demo code to show both APIs. It contains a switch statement that sets up the appropriate client object:

switch (implementation)
        {
            case SOAP:
                return new OvmWsSoapClient();

            case REST:
                return new OvmWsRestClient();
        }

Before the login method is called, an initialize method is used to set the hostname and port number on which the Oracle VM Manager is running. This method is ultimately defined in the RestClient class and simply takes all of the components that make up the base URI and constructs the base URI that is used thereafter.

A final thing to note, is that the call to the initialize and login methods provide some preset variables. In fact, the com.oracle.ovm.mgr.ws.sample package also includes a properties file: WsDevClient.properties. This file contains the default values for many of the variables referenced throughout this guide. For the sample code to work according to the specifics of your own environment, many of these variables must be overridden. Instructions for handling variable overriding are provided in the comments of this properties file itself.

What about Certificate-based Authentication?

Since the code in the SDK does not assume that you have set up user certificates, there are no examples showing how to authenticate using a signed SSL certificate. However, all that is required for this to happen is for you to use the certificate for all REST requests in your session. In Java, the easiest way to do this is to ensure that you have the certificate and its associated key stored in a keystore file. You can then use the keystore to load your key manager and trust manager that can be used to initialize an SSL context that is used for all connections.

The following example code, should help to get you started. It has been stripped of any error handling that may obfuscate what is required. This code expects the following variables to be initialized:

File keystoreFile;        // A file representing the location of the KeyStore
char[] keystorePassword;  // The KeyStore password
char[] keyPassword;       // The key password - if you didn't specify one when creating your
                          // key, then use the keystorePassword for this as well

The code required to use this keystore to initialize an SSL context follows:

// Load your keystore
FileInputStream stream = new FileInputStream(keystoreFile);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(stream, keystorePassword);
stream.close();
 
// Initialize the key manager from the keystore
KeyManagerFactory kmFactory = 
  KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmFactory.init(keystore, keyPassword);
KeyManager km[] = kmFactory.getKeyManagers();
 
// Initialize the trust manager from the keystore
TrustManagerFactory tmFactory = 
  TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmFactory.init(keystore);
TrustManager tm[] = tmFactory.getTrustManagers();
 
// Initialize an SSL context and make it the default for all connections
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(km, tm, null);
SSLContext.setDefault(ctx);

This code could be substituted in the WsDevClient class where the initial SSL context is set:

public void run() {
        try {
            // Configure the SSLContext with an insecure TrustManager
            // This is done to avoid the need to use valid certificates in the 
            // development environment.
            // This should not be done in a real / secure environment.
            final SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(new KeyManager[0], new TrustManager[]{
                        new InsecureTrustManager()
                    }, new SecureRandom());
            SSLContext.setDefault(ctx);
...
}