Get Exception in thread "main" org.zaproxy.clientapi.core.ClientApiException: Does Not Exist on running form ans script authentication using zap api - owasp

public class FormAuth {
private static final String ZAP_ADDRESS = "localhost";
private static final int ZAP_PORT = 8080;
private static final String ZAP_API_KEY = null;
private static final String contextId = "1";
private static final String contextName = "Default Context";
private static final String target = "http://localhost:8090/bodgeit";
private static void setIncludeAndExcludeInContext(ClientApi clientApi) throws UnsupportedEncodingException, ClientApiException {
String includeInContext = "http://localhost:8090/bodgeit.*";
String excludeInContext = "http://localhost:8090/bodgeit/logout.jsp";
clientApi.context.includeInContext(contextName, includeInContext);
clientApi.context.excludeFromContext(contextName, excludeInContext);
}
private static void setLoggedInIndicator(ClientApi clientApi) throws UnsupportedEncodingException, ClientApiException {
// Prepare values to set, with the logged in indicator as a regex matching the logout link
String loggedInIndicator = "Logout";
// Actually set the logged in indicator
clientApi.authentication.setLoggedInIndicator(contextId, java.util.regex.Pattern.quote(loggedInIndicator));
// Check out the logged in indicator that is set
System.out.println("Configured logged in indicator regex: "
+ ((ApiResponseElement) clientApi.authentication.getLoggedInIndicator(contextId)).getValue());
}
private static void setFormBasedAuthenticationForBodgeit(ClientApi clientApi) throws ClientApiException,
UnsupportedEncodingException {
// Setup the authentication method
String loginUrl = "http://localhost:8090/bodgeit/login.jsp";
String loginRequestData = "username={%username%}&password={%password%}";
// Prepare the configuration in a format similar to how URL parameters are formed. This
// means that any value we add for the configuration values has to be URL encoded.
StringBuilder formBasedConfig = new StringBuilder();
formBasedConfig.append("loginUrl=").append(URLEncoder.encode(loginUrl, "UTF-8"));
formBasedConfig.append("&loginRequestData=").append(URLEncoder.encode(loginRequestData, "UTF-8"));
System.out.println("Setting form based authentication configuration as: "
+ formBasedConfig.toString());
clientApi.authentication.setAuthenticationMethod(contextId, "formBasedAuthentication",
formBasedConfig.toString());
// Check if everything is set up ok
System.out
.println("Authentication config: " + clientApi.authentication.getAuthenticationMethod(contextId).toString(0));
}
private static String setUserAuthConfigForBodgeit(ClientApi clientApi) throws ClientApiException, UnsupportedEncodingException {
// Prepare info
String user = "Test User";
String username = "test#example.com";
String password = "weakPassword";
// Make sure we have at least one user
String userId = extractUserId(clientApi.users.newUser(contextId, user));
// Prepare the configuration in a format similar to how URL parameters are formed. This
// means that any value we add for the configuration values has to be URL encoded.
StringBuilder userAuthConfig = new StringBuilder();
userAuthConfig.append("username=").append(URLEncoder.encode(username, "UTF-8"));
userAuthConfig.append("&password=").append(URLEncoder.encode(password, "UTF-8"));
System.out.println("Setting user authentication configuration as: " + userAuthConfig.toString());
clientApi.users.setAuthenticationCredentials(contextId, userId, userAuthConfig.toString());
clientApi.users.setUserEnabled(contextId, userId, "true");
clientApi.forcedUser.setForcedUser(contextId, userId);
clientApi.forcedUser.setForcedUserModeEnabled(true);
// Check if everything is set up ok
System.out.println("Authentication config: " + clientApi.users.getUserById(contextId, userId).toString(0));
return userId;
}
private static String extractUserId(ApiResponse response) {
return ((ApiResponseElement) response).getValue();
}
private static void scanAsUser(ClientApi clientApi, String userId) throws ClientApiException {
clientApi.spider.scanAsUser(contextId, userId, target, null, "true", null);
}
/**
* The main method.
*
* #param args the arguments
* #throws ClientApiException
* #throws UnsupportedEncodingException
*/
public static void main(String[] args) throws ClientApiException, UnsupportedEncodingException {
ClientApi clientApi = new ClientApi(ZAP_ADDRESS, ZAP_PORT, ZAP_API_KEY);
setIncludeAndExcludeInContext(clientApi);
setFormBasedAuthenticationForBodgeit(clientApi);
setLoggedInIndicator(clientApi);
String userId = setUserAuthConfigForBodgeit(clientApi);
scanAsUser(clientApi, userId);
}
}
=========================================================================================
/usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java -javaagent:/snap/intellij-idea-ultimate/319/lib/idea_rt.jar=43425:/snap/intellij-idea-ultimate/319/bin -Dfile.encoding=UTF-8 -classpath /home/arpit/IdeaProjects/maven-zap-demo/target/classes:/home/arpit/Downloads/zap-clientapi-1.9.0.jar ScriptAuth
Exception in thread "main" org.zaproxy.clientapi.core.ClientApiException: Does Not Exist
at org.zaproxy.clientapi.core.ApiResponseFactory.getResponse(ApiResponseFactory.java:50)
at org.zaproxy.clientapi.core.ClientApi.callApi(ClientApi.java:351)
at org.zaproxy.clientapi.gen.deprecated.ScriptDeprecated.load(ScriptDeprecated.java:146)
at ScriptAuth.uploadScript(ScriptAuth.java:76)
at ScriptAuth.main(ScriptAuth.java:93)

The recommended way to automate authentiation in ZAP is to configure and test it in the desktop, then export the context and import that via the API. If the authentication uses scripts then these will need to be registered with ZAP first.

Related

Keycloak - Customize "sub" format in JWT token

I'm trying to find a way to change the "sub" format in JWT Token provided by Keycloak, I know it came from Keycloak User Id but i'm not sure we can't change it.
For example for now I have something like this :
"sub": "f:39989175-b393-4fad-8f84-628b9712f93b:testldap",
I would like it smaller 😅.
I'm not sure that modifying 'sub' is a good idea, but if you sure, you can use something like that:
/**
* Class for signing JWT (when you get tokens in base64 actually they are
* signed by issuer server see https://jwt.io)
*/
public static class JwtSigner {
private final KeyPair keyPair;
private final String kid;
public JwtSigner(String privateKeyPem) {
PrivateKey privateKey = PemUtils.decodePrivateKey(privateKeyPem);
PublicKey publicKey = KeyUtils.extractPublicKey(privateKey);
keyPair = new KeyPair(publicKey, privateKey);
kid = KeyUtils.createKeyId(keyPair.getPublic());
}
public String encodeToken(AccessToken accessToken) {
return new JWSBuilder()
.type("JWT")
.kid(kid)
.jsonContent(accessToken)
.sign(Algorithm.RS256, keyPair.getPrivate());
}
}
/**
* This class allows you to update several token fields and re-encode token
*/
public static class JwtTransformer<T extends AccessToken> {
private T token;
public JwtTransformer(String tokenString, Class<T> tokenType) throws JWSInputException {
try {
token = JsonSerialization.readValue(new JWSInput(tokenString).getContent(), tokenType);
} catch (IOException e) {
throw new JWSInputException(e);
}
}
public static <T extends AccessToken> T decode(String tokenString, Class<T> tokenType) throws JWSInputException {
return new JwtTransformer<>(tokenString, tokenType).decode();
}
public static JwtTransformer<AccessToken> forAccessToken(String tokenString) throws JWSInputException {
return new JwtTransformer<>(tokenString, AccessToken.class);
}
public static JwtTransformer<RefreshToken> forRefreshToken(String tokenString) throws JWSInputException {
return new JwtTransformer<>(tokenString, RefreshToken.class);
}
public T decode() {
return token;
}
public JwtTransformer transform(Consumer<T> consumer) {
consumer.accept(token);
return this;
}
public String encode(JwtSigner jwtSigner) {
return jwtSigner.encodeToken(token);
}
}
I used this classes for tests, but you can adopt them for your needs. Take a note that private key that required for JwtSigner initializaton is stored in keycloak DB, and can not be easily extracted via Admin Console UI. Check out result of
select VALUE
from KEYCLOAK.COMPONENT
inner join KEYCLOAK.COMPONENT_CONFIG
on KEYCLOAK.COMPONENT.ID = KEYCLOAK.COMPONENT_CONFIG.COMPONENT_ID
where PARENT_ID = '%YOUR_REALM_NAME%'
and PROVIDER_ID = 'rsa-generated'
and COMPONENT_CONFIG.NAME = 'privateKey';
So finally you can do something like
String new AccessToken = JwtTransformer.forAccessToken(accessTokenString)
.transform(token -> {
token.subject(subModificationFunction(token.getSubject()))
})
.encode();

How to pass user context object to the response callback of async Jetty HTTP client?

When sending notifications to single recipients over Google Firebase Cloud Messaging, sometimes a response comes back (200 + error:MissingRegistration, 200 + error:InvalidRegistration, 200 + error:NotRegistered), which requires deleting the token of that recipient (because she for example reinstalled the Android app and the token has changed).
My question is:
How to pass that string (the FCM token) back to the response callback of the non-blocking Jetty HTTP client?
Currently my workaround is to add a custom HTTP header to my request:
X-token: APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...
and then I retrieve it in the response callback. But this is a hack, because FCM does not specify such a header and also I need to pass more custom data (the internal user id in my app) back.
Here is my current source code with the custom HTTP header, how to change it please?
private static final String FCM_URL = "https://fcm.googleapis.com/fcm/send";
private static final String FCM_KEY = "key=REPLACE_BY_YOUR_KEY";
private static final String FCM_RESULTS = "results";
private static final String FCM_ERROR = "error";
private static final String FCM_NOT_REGISTERED = "NotRegistered";
private static final String FCM_MISSING_REGISTRATION = "MissingRegistration";
private static final String FCM_INVALID_REGISTRATION = "InvalidRegistration";
private static final String FCM_X_TOKEN = "X-token";
private static final String TOKEN = "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...";
private static final Map<String, Object> REQUEST = new HashMap<>();
private static final Map<String, Object> NOTIFICATION = new HashMap<>();
private static final Map<String, Object> DATA = new HashMap<>();
static {
REQUEST.put("to", TOKEN);
REQUEST.put("notification", NOTIFICATION);
REQUEST.put("data", DATA);
NOTIFICATION.put("body", "great match!");
NOTIFICATION.put("title", "Portugal vs. Denmark");
NOTIFICATION.put("icon", "myicon");
DATA.put("Nick", "Mario");
DATA.put("Room", "PortugalVSDenmark");
}
private static final SslContextFactory sFactory = new SslContextFactory();
private static final HttpClient sHttpClient = new HttpClient(sFactory);
private static final BufferingResponseListener sFcmListener = new BufferingResponseListener() {
#Override
public void onComplete(Result result) {
if (!result.isSucceeded()) {
System.err.println(result.getFailure());
return;
}
String body = getContentAsString(StandardCharsets.UTF_8);
try {
Map<String, Object> resp = (Map<String, Object>) JSON.parse(body);
Object[] results = (Object[]) resp.get(FCM_RESULTS);
Map map = (Map) results[0];
String error = (String) map.get(FCM_ERROR);
System.out.printf("error: %s\n", error);
if (FCM_NOT_REGISTERED.equals(error) ||
FCM_MISSING_REGISTRATION.equals(error) ||
FCM_INVALID_REGISTRATION.equals(error)) {
String token = result.getRequest().getHeaders().get(FCM_X_TOKEN);
System.out.printf("TODO delete invalid FCM token from the database: %s\n", token);
}
} catch (Exception ex) {
System.err.println(ex);
}
}
};
public static void main(String[] args) throws Exception {
sHttpClient.start();
sHttpClient.POST(FCM_URL)
.header(HttpHeader.AUTHORIZATION, FCM_KEY)
.header(HttpHeader.CONTENT_TYPE, "application/json")
.header(FCM_X_TOKEN, TOKEN) // Workaround, how to improve?
.content(new StringContentProvider(JSON.toString(REQUEST)))
.send(sFcmListener);
}
You want to set the token as a request attribute and the retrieve it back:
httpClient.POST(url)
.attribute(key, token)
...
.send(new BufferingResponseListener() {
#Override
public void onComplete(Result result) {
Object token = result.getRequest().getAttribute(key);
...
}
});

netty SimpleChannelInboundHandler<String> channelRead0 only occasionally invoked

I know that there are several similar questions that have either been answered or still outstanding, however, for the life of me...
Later Edit 2016-08-25 10:05 CST - Actually, I asked the wrong question.
The question is the following: given that I have both a netty server (taken from DiscardServer example) and a netty client - (see above) what must I do to force the DiscardServer to immediately send the client a request?
I have added an OutboundHandler to the server and to the client.
After looking at both the DiscardServer and PingPongServer examples, there is an external event occurring to kick off all the action. In the case of Discard server, it is originally waiting for a telnet connection, then will transmit whatever was in the telnet msg to the client.
In the case of PingPongServer, the SERVER is waiting on the client to initiate action.
What I want is for the Server to immediately start transmitting after connection with the client. None of the examples from netty seem to do this.
If I have missed something, and someone can point it out, much good karma.
My client:
public final class P4Listener {
static final Logger LOG;
static final String HOST;
static final int PORT;
static final Boolean SSL = Boolean.FALSE;
public static Dto DTO;
static {
LOG = LoggerFactory.getLogger(P4Listener.class);
HOST = P4ListenerProperties.getP4ServerAddress();
PORT = Integer.valueOf(P4ListenerProperties.getListenerPort());
DTO = new Dto();
}
public static String getId() { return DTO.getId(); }
public static void main(String[] args) throws Exception {
final SslContext sslCtx;
if (SSL) {
LOG.info("{} creating SslContext", getId());
sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} else {
sslCtx = null;
}
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.handler(new P4ListenerInitializer(sslCtx));
// Start the connection attempt.
LOG.debug(" {} starting connection attempt...", getId());
Channel ch = b.connect(HOST, PORT).sync().channel();
// ChannelFuture localWriteFuture = ch.writeAndFlush("ready\n");
// localWriteFuture.sync();
} finally {
group.shutdownGracefully();
}
}
}
public class P4ListenerHandler extends SimpleChannelInboundHandler<String> {
static final Logger LOG = LoggerFactory.getLogger(P4ListenerHandler.class);
static final DateTimeFormatter DTFormatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHMMss.SSS");
static final String EndSOT;
static final String StartSOT;
static final String EOL = "\n";
static final ClassPathXmlApplicationContext AppContext;
static {
EndSOT = P4ListenerProperties.getEndSOT();
StartSOT = P4ListenerProperties.getStartSOT();
AppContext = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
}
private final RequestValidator rv = new RequestValidator();
private JAXBContext jaxbContext = null;
private Unmarshaller jaxbUnmarshaller = null;
private boolean initialized = false;
private Dto dto;
public P4ListenerHandler() {
dto = new Dto();
}
public Dto getDto() { return dto; }
public String getId() { return getDto().getId(); }
Message convertXmlToMessage(String xml) {
if (xml == null)
throw new IllegalArgumentException("xml message is null!");
try {
jaxbContext = JAXBContext.newInstance(p4.model.xml.request.Message.class, p4.model.xml.request.Header.class,
p4.model.xml.request.Claims.class, p4.model.xml.request.Insurance.class,
p4.model.xml.request.Body.class, p4.model.xml.request.Prescriber.class,
p4.model.xml.request.PriorAuthorization.class,
p4.model.xml.request.PriorAuthorizationSupportingDocumentation.class);
jaxbUnmarshaller = jaxbContext.createUnmarshaller();
StringReader strReader = new StringReader(xml);
Message m = (Message) jaxbUnmarshaller.unmarshal(strReader);
return m;
} catch (JAXBException jaxbe) {
String error = StacktraceUtil.getCustomStackTrace(jaxbe);
LOG.error(error);
throw new P4XMLUnmarshalException("Problems when attempting to unmarshal transmission string: \n" + xml,
jaxbe);
}
}
#Override
public void channelActive(ChannelHandlerContext ctx) {
LOG.debug("{} let server know we are ready", getId());
ctx.writeAndFlush("Ready...\n");
}
/**
* Important - this method will be renamed to
* <code><b>messageReceived(ChannelHandlerContext, I)</b></code> in netty 5.0
*
* #param ctx
* #param msg
*/
#Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
ChannelFuture lastWriteFuture = null;
LOG.debug("{} -- received message: {}", getId(), msg);
Channel channel = ctx.channel();
Message m = null;
try {
if (msg instanceof String && msg.length() > 0) {
m = convertXmlToMessage(msg);
m.setMessageStr(msg);
dto.setRequestMsg(m);
LOG.info("{}: received TIMESTAMP: {}", dto.getId(), LocalDateTime.now().format(DTFormatter));
LOG.debug("{}: received from server: {}", dto.getId(), msg);
/*
* theoretically we have a complete P4(XML) request
*/
final List<RequestFieldError> errorList = rv.validateMessage(m);
if (!errorList.isEmpty()) {
for (RequestFieldError fe : errorList) {
lastWriteFuture = channel.writeAndFlush(fe.toString().concat(EOL));
}
}
/*
* Create DBHandler with message, messageStr, clientIp to get
* dbResponse
*/
InetSocketAddress socketAddress = (InetSocketAddress) channel.remoteAddress();
InetAddress inetaddress = socketAddress.getAddress();
String clientIp = inetaddress.getHostAddress();
/*
* I know - bad form to ask the ApplicationContext for the
* bean... BUT ...lack of time turns angels into demons
*/
final P4DbRequestHandler dbHandler = (P4DbRequestHandler) AppContext.getBean("dbRequestHandler");
// must set the requestDTO for the dbHandler!
dbHandler.setClientIp(clientIp);
dbHandler.setRequestDTO(dto);
//
// build database request and receive response (string)
String dbResponse = dbHandler.submitDbRequest();
/*
* create ResponseHandler and get back response string
*/
P4ResponseHandler responseHandler = new P4ResponseHandler(dto, dbHandler);
String responseStr = responseHandler.decodeDbServiceResponse(dbResponse);
/*
* write response string to output and repeat exercise
*/
LOG.debug("{} -- response to be written back to server:\n {}", dto.getId(), responseStr);
lastWriteFuture = channel.writeAndFlush(responseStr.concat(EOL));
//
LOG.info("{}: response sent TIMESTAMP: {}", dto.getId(), LocalDateTime.now().format(DTFormatter));
} else {
throw new P4EventException(dto.getId() + " -- Message received is not a String");
}
processWriteFutures(lastWriteFuture);
} catch (Throwable t) {
String tError = StacktraceUtil.getCustomStackTrace(t);
LOG.error(tError);
} finally {
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
}
}
private void processWriteFutures(ChannelFuture writeFuture) throws InterruptedException {
// Wait until all messages are flushed before closing the channel.
if (writeFuture != null) {
writeFuture.sync();
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
/**
* Creates a newly configured {#link ChannelPipeline} for a new channel.
*/
public class P4ListenerInitializer extends ChannelInitializer<SocketChannel> {
private static final StringDecoder DECODER = new StringDecoder();
private static final StringEncoder ENCODER = new StringEncoder();
private final SslContext sslCtx;
public P4ListenerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
#Override
public void initChannel(SocketChannel ch) {
P4ListenerHandler lh = null;
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
P4Listener.LOG.info("{} -- constructing SslContext new handler ", P4Listener.getId());
pipeline.addLast(sslCtx.newHandler(ch.alloc(), P4Listener.HOST, P4Listener.PORT));
} else {
P4Listener.LOG.info("{} -- SslContext null; bypassing adding sslCtx.newHandler(ch.alloc(), P4Listener.HOST, P4Listener.PORT) ", P4Listener.getId());
}
// Add the text line codec combination first,
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(DECODER);
P4Listener.LOG.debug("{} -- added Decoder ", P4Listener.getId());
pipeline.addLast(ENCODER);
P4Listener.LOG.debug("{} -- added Encoder ", P4Listener.getId());
// and then business logic.
pipeline.addLast(lh = new P4ListenerHandler());
P4Listener.LOG.debug("{} -- added P4ListenerHandler: {} ", P4Listener.getId(), lh.getClass().getSimpleName());
}
}
#Sharable
public class P4ListenerOutboundHandler extends ChannelOutboundHandlerAdapter {
static final Logger LOG = LoggerFactory.getLogger(P4ListenerOutboundHandler.class);
private Dto outBoundDTO = new Dto();
public String getId() {return this.outBoundDTO.getId(); }
#Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
try {
ChannelFuture lastWrite = ctx.write(Unpooled.copiedBuffer((String) msg, CharsetUtil.UTF_8));
try {
if (lastWrite != null) {
lastWrite.sync();
promise.setSuccess();
}
} catch (InterruptedException e) {
promise.setFailure(e);
e.printStackTrace();
}
} finally {
ReferenceCountUtil.release(msg);
}
}
}
output from client
Just override channelActive(...) on the handler of the server and trigger a write there.

Google Cloud Storage - JAVA REST API - Getting SignatureDoesNotMatch

I am using jersey-client to make REST Call . I am getting SignatureDoesNotMatch error in response.
I was trying to List down Bucket names using GET Service , also tried to list Bucket object using GET Bucket method.
here is my sample code.
Any hint or solution ?
public class restSample {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private static final String PROJECT_ID = "10XXXXXXXX478";
public static String Base64Encoding()
throws java.security.SignatureException, UnsupportedEncodingException {
String access_id = "GOOGBAXXXXXXXXXXBI";
String secret_key = URLEncoder.encode("pWTXXXXXXXXXXXXXXXRo85T+XXXXXXXXX3O","UTF-8");
String bucket = "bucket_name";
String version_header = "x-goog-api-version:1";
String project_header = "x-goog-project-id:"+PROJECT_ID;
String canonicalizedResources = "/"+bucket+"/";
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 30);
long expiration = calendar.getTimeInMillis();
String stringToSign = URLEncoder.encode("GET\n\n\n"+expiration+"\n"+version_header+"\n"+project_header+"\n"+canonicalizedResources,"UTF-8");
//String stringToSign = URLEncoder.encode("GET\n\n\n"+getdate()+"\n"+version_header+"\n"+project_header+"\n"+canonicalizedResources,"UTF-8");
String authSignature="";
try {
SecretKeySpec signingKey = new SecretKeySpec(secret_key.getBytes(),HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(stringToSign.getBytes("UTF-8"));
// base64-encode the hmac
authSignature = new String(Base64.encode(rawHmac));
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
authSignature = (access_id +":"+ authSignature);
return authSignature;
}
public static void main(String[] args) {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
String authSignature = null;
try {
authSignature = "GOOG1 "+ Base64Encoding();
} catch (SignatureException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
WebResource service = client.resource(getBaseURI());
ClientResponse response = service.accept(MediaType.APPLICATION_XML)
.header("Authorization",authSignature)
.header("Date", getdate())
.header("Content-Length", "0")
.header("x-goog-api-version", "1")
.header("x-goog-project-id", PROJECT_ID)
.get(ClientResponse.class);
System.out.println(response.getClientResponseStatus().getFamily());
System.out.println("response1 :: " + response.getEntity(String.class));
}
private static URI getBaseURI() {
String url = "https://bucket_name.storage.googleapis.com";
return UriBuilder.fromUri(url).build();
}
private static String getdate(){
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z ", new Locale("US"));
Calendar cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));
format.setCalendar(cal);
return format.format(new Date());
}
}
Thanks!
Make sure the string you are signing matches the expected string to sign. Google cloud storage returns the expected string to sign in the HTTP response if authentication fails.
In your particular example it looks like you are adding both the version_header and project_header into the string to sign. These are not in the list of CanonicalHeaders nor CanonicalExtensionHeaders, so you are signing a different string than the server.
You can review the list here: https://developers.google.com/storage/docs/reference/v1/developer-guidev1#authentication

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.