Search code examples
tomcatservletsprivate-keygoogle-client

Loading pk12 java.io.File for Google Client API in a Servlet Container


I have an application that gets deployed into Tomacat servlet containers. I have a background job that gets run where I make a call to Google Analytics that is authorized using a Service Account's PK12 file.

I don't have access to the container's file system, so I deploy the pk12 file in my WAR's WEB-INF/ . I don't anticipate being given access to add any authentication keys into the Servlet Container's host's system registry/keychain.

GoogleCredential's Buidler.setServiceAccountPrivateKeyFromP12File(File) only takes java.io.File, so I ended up doing something that is kludgey to authorize. I open the PK12 file using serveltContenxt.getResourceAsStream and copy it's contents to a temporary file which I pass into the Credential's builder.

When I tried to do

java.io.File p12File = new java.io.File(servletContext.getResource('...pk12.file...').getFile()) 

there was an error saying that the File doesn't exists because it tries to open a file on disk while the pk12 file is either not unbundled or the URI that comes back isn't the correct one for the file.

What's the right way to do this? I'm new to the world of PrivateKey authentication and the google client api.

Here's my currently working code:

        // create file because credential only takes a File object
        final File p12File = File.createTempFile("xxx", ".tmp"); 
        p12File.deleteOnExit();
        InputStream in = servletContext.getResourceAsStream("...pk12.file...");
        FileOutputStream out = new FileOutputStream(p12File);  
        org.apache.commons.io.IOUtils.copy(in, out);
        out.flush();
        out.close();
        in.close();

        GoogleCredential credential = new  GoogleCredential.Builder().setTransport(httpTransport)
                .setJsonFactory(JSON_FACTORY)
                .setServiceAccountId("xxxxxxx@developer.gserviceaccount.com")
            .setServiceAccountScopes(Collections.singleton(AnalyticsScopes.ANALYTICS_READONLY))
                .setServiceAccountPrivateKeyFromP12File(p12File)
                .build();

        p12File.delete();

        // Set up and return Google Analytics API client.
        this.analytics = new Analytics.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName("mybackgroundprocess/1.0").build();

thanks


Solution

  • I found the same problem was answered here: Getting a PrivateKey object from a .p12 file in Java

    I just had to create a private key from the resource

    InputStream in = servletContext.getResourceAsStream("p12.file");
    PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(), in, "notasecret", "privatekey", "notasecret");
    

    and then call

    GoogleCredential.Builder.setServiceAccountPrivateKey(PrivateKey privateKey)