2016-03-14 14 views
5

Quando richiamo gli endpoint API dal client REST, ho riscontrato un errore relativo alla firma.Come generare la firma in AWS da Java

Richiesta:

Host: https://xxx.execute-api.ap-southeast-1.amazonaws.com/latest/api/name

Autorizzazione: AWS4-HMAC-SHA256 Credential = {AWSKEY}/20.160.314/ap-sud-est-1/execute-api/aws4_request, SignedHeaders = host; intervallo; x-amz-date, Firma = {signature}

X-Amz-Date: 20160314 T102915Z

Risposta:

{ 
"message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. The Canonical String for this request should have been 'xxx' " 
} 

da codice Java, ho seguito AWS di riferimento di come generare Signature.

String secretKey = "{mysecretkey}"; 
    String dateStamp = "20160314"; 
    String regionName = "ap-southeast-1"; 
    String serviceName = "execute-api"; 

    byte[] signature = getSignatureKey(secretKey, dateStamp, regionName, serviceName); 
    System.out.println("Signature : " + Hex.encodeHexString(signature)); 

    static byte[] HmacSHA256(String data, byte[] key) throws Exception { 
     String algorithm="HmacSHA256"; 
     Mac mac = Mac.getInstance(algorithm); 
     mac.init(new SecretKeySpec(key, algorithm)); 
     return mac.doFinal(data.getBytes("UTF8")); 
    } 

    static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception { 
     byte[] kSecret = ("AWS4" + key).getBytes("UTF8"); 
     byte[] kDate = HmacSHA256(dateStamp, kSecret); 
     byte[] kRegion = HmacSHA256(regionName, kDate); 
     byte[] kService = HmacSHA256(serviceName, kRegion); 
     byte[] kSigning = HmacSHA256("aws4_request", kService); 
     return kSigning; 
    } 

Posso sapere cosa ho sbagliato durante la creazione della firma?

riferimento come generare Firma: http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java

+0

Hai trovato una soluzione? –

risposta

1

Dall'esempio codice di cui sopra sembra che non si sta creando una richiesta canonica e della sua integrazione nella stringa che viene firmato come da http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html

Invece di applicazione del presente tu stesso hai guardato usando una libreria di terze parti.

aws-v4-signer-java è una libreria leggera, a dipendenza zero che semplifica la generazione di firme AWS V4.

String contentSha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; 
HttpRequest request = new HttpRequest("GET", new URI("https://examplebucket.s3.amazonaws.com?max-keys=2&prefix=J")); 
String signature = Signer.builder() 
     .awsCredentials(new AwsCredentials(ACCESS_KEY, SECRET_KEY)) 
     .header("Host", "examplebucket.s3.amazonaws.com") 
     .header("x-amz-date", "20130524T000000Z") 
     .header("x-amz-content-sha256", contentSha256) 
     .buildS3(request, contentSha256) 
     .getSignature(); 

Disclaimer: Sono l'autore delle biblioteche.

+0

Hiya Lucas, sono curioso di sapere se questa libreria è stata testata per un server back-end che fornisce le firme a un client front-end per il caricamento diretto su S3. È necessario calcolare lo sha256 del contenuto lato client e quindi inviarlo al server come parte del calcolo della firma? – charneykaye

3

È possibile utilizzare le classi da AWS-java-sdk-core: https://github.com/aws/aws-sdk-java/tree/master/aws-java-sdk-core

Più in particolare, Request, Aws4Signer e pochi altri quelli:

//Instantiate the request 
Request<Void> request = new DefaultRequest<Void>("es"); //Request to ElasticSearch 
request.setHttpMethod(HttpMethodName.GET); 
request.setEndpoint(URI.create("http://...")); 

//Sign it... 
AWS4Signer signer = new AWS4Signer(); 
signer.setRegionName("..."); 
signer.setServiceName(request.getServiceName()); 
signer.sign(request, new AwsCredentialsFromSystem()); 

//Execute it and get the response... 
Response<String> rsp = new AmazonHttpClient(new ClientConfiguration()) 
    .requestExecutionBuilder() 
    .executionContext(new ExecutionContext(true)) 
    .request(request) 
    .errorResponseHandler(new SimpleAwsErrorHandler()) 
    .execute(new SimpleResponseHandler<String>()); 

Se si desidera un design più pulito, è possibile usa il pattern Decorator per comporre alcune classi eleganti e nascondere il pasticcio di cui sopra. Un esempio per questo qui: http://www.amihaiemil.com/2017/02/18/decorators-with-tunnels.html

Problemi correlati