// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package com.google.crypto.tink.integration.awskms;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.auth.PropertiesFileCredentialsProvider;
import com.amazonaws.services.kms.AWSKMS;
import com.amazonaws.services.kms.AWSKMSClientBuilder;
import com.google.auto.service.AutoService;
import com.google.crypto.tink.Aead;
import com.google.crypto.tink.KmsClient;
import com.google.crypto.tink.subtle.Validators;
import java.security.GeneralSecurityException;
import org.apache.commons.lang3.StringUtils;

/**
 * An implementation of {@link KmsClient} for <a href="https://aws.amazon.com/kms/">AWS KMS</a>.
 *
 * @since 1.0.0
 */
@AutoService(KmsClient.class)
public final class AwsKmsClient implements KmsClient {
  /** The prefix of all keys stored in AWS KMS. */
  public static final String PREFIX = "aws-kms://";

  private AWSKMS client;
  private String keyUri;

  /** Constructs a generic AwsKmsClient that is not bound to any specific key. */
  public AwsKmsClient() {}

  /** Constructs a specific AwsKmsClient that is bound to a single key identified by {@code uri}. */
  public AwsKmsClient(String uri) {
    if (!uri.toLowerCase().startsWith(PREFIX)) {
      throw new IllegalArgumentException("key URI must starts with " + PREFIX);
    }
    this.keyUri = uri;
  }

  /**
   * @return @return true either if this client is a generic one and uri starts with {@link
   *     AwsKmsClient#PREFIX}, or the client is a specific one that is bound to the key identified
   *     by {@code uri}.
   */
  @Override
  public boolean doesSupport(String uri) {
    if (this.keyUri != null && this.keyUri.equals(uri)) {
      return true;
    }
    return this.keyUri == null && uri.toLowerCase().startsWith(PREFIX);
  }

  /**
   * Loads AWS credentials from a properties file.
   *
   * <p>The AWS access key ID is expected to be in the <code>accessKey</code> property and the AWS
   * secret key is expected to be in the <code>secretKey</code> property.
   *
   * @throws GeneralSecurityException if the client initialization fails
   */
  @Override
  public KmsClient withCredentials(String credentialPath) throws GeneralSecurityException {
    try {
      if (credentialPath == null) {
        return withDefaultCredentials();
      }
      return withCredentialsProvider(new PropertiesFileCredentialsProvider(credentialPath));
    } catch (AmazonServiceException e) {
      throw new GeneralSecurityException("cannot load credentials", e);
    }
  }

  /**
   * Loads default AWS credentials.
   *
   * <p>AWS credentials provider chain that looks for credentials in this order:
   *
   * <ul>
   *   <li>Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_KEY
   *   <li>Java System Properties - aws.accessKeyId and aws.secretKey
   *   <li>Credential profiles file at the default location (~/.aws/credentials)
   *   <li>Instance profile credentials delivered through the Amazon EC2 metadata service
   * </ul>
   *
   * @throws GeneralSecurityException if the client initialization fails
   */
  @Override
  public KmsClient withDefaultCredentials() throws GeneralSecurityException {
    try {
      return withCredentialsProvider(new DefaultAWSCredentialsProviderChain());
    } catch (AmazonServiceException e) {
      throw new GeneralSecurityException("cannot load default credentials", e);
    }
  }

  /** Loads AWS credentials from a provider. */
  public KmsClient withCredentialsProvider(AWSCredentialsProvider provider)
      throws GeneralSecurityException {
    try {
      String[] tokens = StringUtils.split(this.keyUri, ":");
      this.client = AWSKMSClientBuilder.standard()
                    .withCredentials(provider)
                        .withRegion(Regions.fromName(tokens[3])).build();
      return this;
    } catch (AmazonServiceException e) {
      throw new GeneralSecurityException("cannot load credentials from provider", e);
    }
  }

  @Override
  public Aead getAead(String uri) throws GeneralSecurityException {
    if (this.keyUri != null && !this.keyUri.equals(uri)) {
      throw new GeneralSecurityException(
          String.format("this client is bound to %s, cannot load keys bound to %s",
              this.keyUri, uri));
    }
    return new AwsKmsAead(client, Validators.validateKmsKeyUriAndRemovePrefix(PREFIX, uri));
  }
}

@@ -929,32 +929,70 @@
 ntialsProvider;%0A
+import com.amazonaws.regions.Regions;%0A
 import com.amazo
@@ -1292,53 +1292,8 @@
 ion;
-%0Aimport org.apache.commons.lang3.StringUtils;
 %0A%0A/*
@@ -4307,26 +4307,8 @@
 s = 
-StringUtils.split(
 this
@@ -4314,18 +4314,23 @@
 s.keyUri
-, 
+.split(
 %22:%22);%0A  
@@ -4346,16 +4346,26 @@
 client =
+%0A         
  AWSKMSC
@@ -4398,30 +4398,24 @@
             
-      
 .withCredent
@@ -4439,34 +4439,24 @@
             
-        
-  
 .withRegion(
@@ -4483,16 +4483,31 @@
 ens%5B3%5D))
+%0A              
 .build()
@@ -4870,16 +4870,31 @@
 .format(
+%0A              
 %22this cl
@@ -4944,30 +4944,16 @@
  to %25s%22,
-%0A             
  this.ke

Fix breakage due to missing org.apache.commons.lang3 package.