how can I key rotate for google cloud storage service account? - google-cloud-storage

I have written code for accessing GCS bucket to store files thru API in java which takes JSON credential file. I have created that JSON file from google console. I need to automate the JSON file or key rotation for every 90 days. How to regenerate/rotate that JSON file? I am a newbie to GCS.
import java.io.IOException;
import java.security.GeneralSecurityException;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpMethods;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.iam.v1.Iam;
import com.google.api.services.iam.v1.IamRequest;
import com.google.api.services.iam.v1.IamRequestInitializer;
import com.google.api.services.iam.v1.model.CreateServiceAccountKeyRequest;
public class TestServiceAccount {
public static void main(String[] args) {
// TODO Auto-generated method stub
//ServiceAccountKey key = new ServiceAccountKey();
try {
System.out.println("created");
String KEY = "AIzaSyDjHg2u4bwfvncb_YwdjJC_vUPRYLW5Sh8";
IamRequestInitializer req = new IamRequestInitializer(KEY);
HttpTransport transport;
transport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
Iam iam = new Iam(transport,jsonFactory,new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
httpRequest.setConnectTimeout(0);
httpRequest.setReadTimeout(0);
}
});
//https://iam.googleapis.com/v1/projects/newsampleproject/serviceAccounts/NewServiceAccount/keys
MyIamRequest<String> request = new MyIamRequest<String>(
iam, HttpMethods.POST, "/v1/projects/newsampleproject/serviceAccounts/NewServiceAccount/keys", String.class, String.class);
req.initialize(request);
System.out.println(req.getKey());
req.initializeJsonRequest(request);
System.out.println(req.getUserIp());
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
//req.initializeJsonRequest(request);
}
public static HttpRequestFactory createRequestFactory(HttpTransport transport) {
return transport.createRequestFactory(new HttpRequestInitializer() {
public void initialize(HttpRequest request) throws IOException {
}
});
}
}
This what I have written to call the API But i am not sure if this is the way to call it.

try this solution, it worked for me
private static void createNewKey(IamRequestInitializer req) throws IOException, GeneralSecurityException {
Iam iam = jsonAuthentication();
CreateServiceAccountKeyRequest keyRequest = new CreateServiceAccountKeyRequest();
keyRequest.setKeyAlgorithm(KEY_ALGO);
String account = SERVICE_ACCOUNT_URL + SERVICE_ACCOUNT_EMAIL;
iam.projects().serviceAccounts().keys().create(account, keyRequest);
String requestString = BASE_URL + SERVICE_ACCOUNT_EMAIL + KEY;
ServiceAccountKey result = getServiceAccountKey(req, iam, requestString);
String jsonKey = new String(result.decodePrivateKeyData());
System.out.println(jsonKey);
JsonFileUtil.createFile(JSON_KEY_FILE_NAME, jsonKey);
}
private static <T> T getServiceAccountKey(IamRequestInitializer req, Iam iam, String requestString)
throws IOException {
MyIamRequest<String> request = new MyIamRequest<String>(iam, HttpMethods.POST, requestString, String.class,
ServiceAccountKey.class);
request.setKey(API_KEY);
request.setFields(
"keyAlgorithm,name,privateKeyData,privateKeyType,publicKeyData,validAfterTime,validBeforeTime");
req.initializeJsonRequest(request);
System.out.println(request.getRequestHeaders());
return (T) request.execute();
}

If you're using a JSON credential file, you are acting as some particular service account which is a member of your project and has access to the files.
Service accounts can be programmatically controlled for exactly this sort of use case. The IAM Service Account API controls service accounts, and the two methods you want for key rotation are serviceAccount.keys.create() and serviceAccount.keys.delete().
The result of the create() call (if you pass in the private key type TYPE_GOOGLE_CREDENTIALS_FILE), will be a new, valid JSON credential file for your service account.

#user7049946
ServiceAccountKey response = getServiceAccountKey(req, iam, requestString);
CreateNewJson.createFile("NEW_JSON_KEY_FILE_NAME", new String(response.decodePrivateKeyData()));
create new class to convert that conent into new file.
public class CreateNewJson {
public static void createFile(String filename, String content) throws IOException {
FileOutputStream fileOutputStream = null;
File file;
file = new File(filename);
fileOutputStream = new FileOutputStream(file);
if (!file.exists()) {
file.createNewFile();
}else{
file.delete();
file.createNewFile();
}
byte[] contentInBytes = content.getBytes();
fileOutputStream.write(contentInBytes);
fileOutputStream.flush();
fileOutputStream.close();
System.out.println("File Created");
}
}

Related

How to choose the encode of a file created by SmbFileOutputStream?

I am using a method to create a file in a specific path in a shared folder inside my local net.
public static void stringToArquivoTextoRemoto(String path, String fileName, String content, NtlmPasswordAuthentication auth) {
String absolutePath = path + File.separator + fileName;
try {
jcifs.Config.setProperty("jcifs.smb.client.disablePlainTextPasswords", "false");
SmbFile smbFile = new SmbFile(absolutePath, auth);
SmbFileOutputStream smbFileOutputStream = new SmbFileOutputStream(smbFile);
smbFileOutputStream.write(content.getBytes());
smbFileOutputStream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (SmbException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Now, I am trying to change the encode from "UTF-8" to "ISO-8859-1".
I already tried to put:
jcifs.Config.setProperty( "jcifs.encoding", "ISO-8859-1" );
But it didn't work.
I found a lot of information about how to change the encode using the FileOutputStream, but I found nothing about this using SmbFileOutputStream.
What do I need to do to choose the encode of a file created by SmbFileOutputStream?
This will solve the issue:
package fileWriting;
import java.io.IOException;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileOutputStream;
public class testWriting {
public static void main(String[] args) throws IOException {
String user = "domain;username:password";
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(user);
String path = "smb://shared/Projects/test.txt";
SmbFile sFile = new SmbFile(path, auth);
try (SmbFileOutputStream sfos = new SmbFileOutputStream(sFile)) {
String v = "Test for file writing!";
byte[] utf = v.getBytes("UTF-8");
byte[] latin1 = new String(utf, "UTF-8").getBytes("ISO-8859-1");
sfos.write(latin1,0,latin1.length );
}
}
}

CAS consumer not working as expected

I have a CAS consumer AE which is expected to iterates over CAS objects in a pipeline, serialize them and add the serialized CASs to an xml file.
public class DataWriter extends JCasConsumer_ImplBase {
private File outputDirectory;
public static final String PARAM_OUTPUT_DIRECTORY = "outputDir";
#ConfigurationParameter(name=PARAM_OUTPUT_DIRECTORY, defaultValue=".")
private String outputDir;
CasToInlineXml cas2xml;
public void initialize(UimaContext context) throws ResourceInitializationException {
super.initialize(context);
ConfigurationParameterInitializer.initialize(this, context);
outputDirectory = new File(outputDir);
if (!outputDirectory.exists()) {
outputDirectory.mkdirs();
}
}
#Override
public void process(JCas jCas) throws AnalysisEngineProcessException {
String file = fileCollectionReader.fileName;
File outFile = new File(outputDirectory, file + ".xmi");
FileOutputStream out = null;
try {
out = new FileOutputStream(outFile);
String xmlAnnotations = cas2xml.generateXML(jCas.getCas());
out.write(xmlAnnotations.getBytes("UTF-8"));
/* XmiCasSerializer ser = new XmiCasSerializer(jCas.getCas().getTypeSystem());
XMLSerializer xmlSer = new XMLSerializer(out, false);
ser.serialize(jCas.getCas(), xmlSer.getContentHandler());*/
if (out != null) {
out.close();
}
}
catch (IOException e) {
throw new AnalysisEngineProcessException(e);
}
catch (CASException e) {
throw new AnalysisEngineProcessException(e);
}
}
I am using it inside a pipeline after all my annotators, but it couldn't read CAS objects (I am getting NullPointerException at jCas.getCas()). It looks like I don't seem to understand the proper usage of CAS consumer. I appreciate any suggestions.

SSL "Peer not Authenticated" error with HttpClient 4 - works in some case but not others

I have a wildcard cert for *.mydomain.com (the names have been changed to protect the innocent...that is NOT the real domain :) )
When using a correctly implemented Java HttpClient 4 (the issue is not seen in FF), Service calls made via HTTPS to api.mydomain.com are successful where as identical service calls made to non-production subdomains of mydomain.com (developer.mydomain.com, api-beta.mydomain.com, api-uat.mydomain.com) generate this Exception with the Test harness code below:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.mydomain.httpclientexample.HttpClientTestv2.main(HttpClientTestv2.java:54)
While the SLL cert on developer.mydomain.com, api-beta.mydomain.com & api-uat.mydomain.com appears to be the same WC cert as api.mydomain.com, the exception is not seen on api.mydomain.com but it is on the other sub-domains. The code works on api-na.mydomain.com and should work on the non-production subdomains.
Any ideas?
Client code: As you can see, I can easily change the ADDRESS_VALIDATION_SERVICE_URI I want to call. The api.mydomain.com one works without the SSLPeerUnverifiedException; the other three URIs throw the exception...
package com.mydomain.httpclientexample;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class HttpClientTestv2 {
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://developer.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api-beta.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api-uat.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
public final static String APIKEY_ATTRIBUTE_NAME = "apikey";
public final static String APIKEY_ATTRIBUTE_VALUE = "2c90bc83e821364ffa557486c3e2a44e";
/**
* #param args
*/
public static void main(String[] args) {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(ADDRESS_VALIDATION_SERVICE_URI);
System.out.println("executing request" + httpPost.getRequestLine());
//set a request header
httpPost.setHeader(APIKEY_ATTRIBUTE_NAME , APIKEY_ATTRIBUTE_VALUE);
//add the xml body
StringEntity postBody = null;
try {
postBody = new StringEntity(getXMLDoc(),"UTF-8");
} catch (UnsupportedEncodingException uee) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in UnsupportedEncodingException catch block");
System.out.println("----------------------------------------");
uee.printStackTrace();
}
httpPost.setEntity(postBody);
HttpResponse response;
try {
response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
System.out.println("Content:" + EntityUtils.toString(entity));
EntityUtils.consume(entity);
// entity.consumeContent();
}
} catch (ClientProtocolException e) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in ClientProtocolException catch block");
System.out.println("----------------------------------------");
e.printStackTrace();
} catch (IOException e) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in ClientProtocolException catch block");
System.out.println("----------------------------------------");
e.printStackTrace();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
private static String getXMLDoc() {
StringBuffer XMLDoc = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?><AddressValidationRequest xmlns=\"http://api.mydomain.com/schema/checkout/1.0\">")
.append("<Header><MaxAddressSuggestions>5</MaxAddressSuggestions></Header>")
.append("<Address><Line1>17243 S. Mill Ln</Line1><Line2/><City>Ocean View</City><MainDivision>DE</MainDivision><CountryCode>US</CountryCode><PostalCode>19970</PostalCode></Address>")
.append("</AddressValidationRequest>");
return XMLDoc.toString();
}
}

How to upload file to google cloud storage using java?

I use org.apache.commons.fileupload to upload file
class StorageService is a service that use cloud storage APIs to store file
This is my code
public class UploadFileAction extends org.apache.struts.action.Action {
private static final String SUCCESS = "success";
private StorageService storage = new StorageService();
private static final int BUFFER_SIZE = 1024 * 1024;
#Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String fileName = item.getName();
String mime = item.getContentType();
storage.init(fileName, mime);
InputStream is = item.openStream();
byte[] b = new byte[BUFFER_SIZE];
int readBytes = is.read(b, 0, BUFFER_SIZE);
while (readBytes != -1) {
storage.storeFile(b, BUFFER_SIZE);
readBytes = is.read(b, 0, readBytes);
}
is.close();
storage.destroy();
}
return mapping.findForward(SUCCESS);
}
}
package storageservice;
import com.google.appengine.api.files.*;
import com.google.appengine.api.files.GSFileOptions.GSFileOptionsBuilder;
import java.io.*;
import java.nio.channels.Channels;
public class StorageService {
private static final String BUCKET_NAME = "thoitbk";
private FileWriteChannel writeChannel = null;
private OutputStream os = null;
public void init(String fileName, String mime) throws Exception {
FileService fileService = FileServiceFactory.getFileService();
GSFileOptionsBuilder builder = new GSFileOptionsBuilder()
.setAcl("public_read")
.setBucket(BUCKET_NAME)
.setKey(fileName)
.setMimeType(mime);
AppEngineFile writableFile = fileService.createNewGSFile(builder.build());
boolean lock = true;
writeChannel = fileService.openWriteChannel(writableFile, lock);
os = Channels.newOutputStream(writeChannel);
}
public void storeFile(byte[] b, int readSize) throws Exception {
os.write(b, 0, readSize);
os.flush();
}
public void destroy() throws Exception {
os.close();
writeChannel.closeFinally();
}
}
In local this works fine but error when I deploy my app
Please help me!
Make sure your app's service account has WRITE access to the bucket in question, either by adding the service account to the team with can edit rights or else update the bucket acl to explicitly grant the service account WRITE access. See this question for more details.

Send byte array from web service to client

I want to send a byte array from a web service to a client that requests an operation exposed via the service. In my method, I read an image into a byte array. I think place this byte array into a wrapper POJO. This is the return type for the operation.
#Override
public ImageWrapper getImage() {
File imageFile = new File("C:\\images\\car.jpg");
ImageWrapper wrapper = null;
try {
BufferedImage img = ImageIO.read(imageFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
ImageIO.write(img, "jpg", baos);
baos.flush();
byte[] result = baos.toByteArray();
baos.close();
wrapper = new ImageWrapper();
wrapper.setContent(result);
System.out.println("Service image wrapper: " + wrapper);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return wrapper;
}
I can receive the ImageWrapper object in the client ok. It has a different id to the ImageWrapper instance that is created by the web service on the server, as I would expect. But, the problem is that when I try to get the byte[] array from the ImageWrapper, it is null... Any ideas why? The wrapper class looks like:
package soap.service.model;
public class ImageWrapper {
private byte[] content;
public void setContent(byte[] content) {
this.content = content;
}
public byte[] getImg() {
return this.content;
}
}
and the client looks like:
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import soap.service.model.ImageWrapper;
import soap.service.sei.ImageSei;
public class ImageClient {
public static void main(String... args) throws MalformedURLException {
URL url = new URL("http://localhost:8080/image?wsdl");
QName qname = new QName("http://impl.service.soap/", "ImageImplService");
Service service = Service.create(url, qname);
ImageSei sei = service.getPort(ImageSei.class);
ImageWrapper iw = sei.getImage();// This is ok
System.out.println(iw.getImg()); // * This is null
}
}
========================================================================
Update Even if I change the byte array in ImageWrapper to a String, it
still comes back as 'null' in the client. I have my web service set to use
'Document' style also.
Your interface object (the one getting serialized and being transfered) does not contain public data (only a method to get private data). Your byte[] should be a public field or property to be included in the serialized data