管理认证请求
Amazon 的 S3 服务使用访问密钥以及请求头和密钥的散列来认证请求。 它具有提供经过身份验证的请求的优势,尤其适用于大型上传,且无需 SSL 开销。
S3 API 的大多数用例都涉及使用开放式源代码 S3 客户机,例如 Amazon SDK for Java 或 Python Boto 中的 AmazonS3Client 。 这些库不支持 Ceph Object Gateway 管理 API。 您可以对这些库进行子类和扩展,以支持 Ceph 管理 API。 或者,您可以创建唯一的网关客户机。
创建 execute() 方法
execute() 方法。CephAdminAPI 类示例,也不打算用于商业用途。 它仅用于说明目的。调用 Ceph Object Gateway
客户机代码 包含对 Ceph Object Gateway 的五个调用,用于演示 CRUD 操作:
创建用户
获取用户
修改用户
创建子用户
删除用户
以这个例子为例,获取 httpcomponents-client-4.5.3 HTTP 组件。 例如,您可以在这里下载: http://hc.apache.org/downloads.cgi. 然后解压缩 tar 文件,浏览至其 lib 目录,并将内容复制到 JAVA_HOME 目录的 /jre/lib/ext 目录或定制类路径。
在查看 CephAdminAPI示例时,请注意 execute() 方法接受 HTTP、请求路径、可选子资源(如果未指定则为 null )和参数映射。 要与子资源 (例如, subuser和 key) 一起运行,您将需要在 execute() 方法中指定子资源作为自变量。
示例方法:
构建 URI。
生成HTTP 标头字符串。
例如,
PUT、POST、GET、DELETE等,都是 HTTP的实例。将
Date头添加到 HTTP和请求头中。HTTP添加
Authorization头。实例化HTTP ,并向其传递已实例化的 HTTP。
发出请求。
返回响应。
构建头字符串
构建头字符串是过程中涉及 Amazon 的 S3 认证过程的部分。 具体来说,示例方法执行以下操作:
添加请求类型,例如,
PUT,POST,GET和DELETE。添加日期。
添加 requestPath。
请求类型应该为大写,没有前导空格或尾部空格。 如果不删除空格,那么认证将失败。 日期必须以 GMT 表示,否则认证将失败。
示例性方法没有任何其他头。 Amazon S3 认证过程按字典顺序对 x-amz 头进行排序。 因此,如果要添加 x-amz 头,请确保按字典顺序添加这些头。
一旦创建了标题字符串,下一步就是实例化HTTP ,并将URI传递给它。 示例性方法使用 PUT 来创建用户和子用户,使用 GET 来获取用户,使用 POST 来修改用户以及使用 DELETE 来删除用户。
在实例化请求后,添加后跟 Authorization 头的 Date 头。 Amazon 的 S3 认证使用标准 Authorization 头,并且具有以下结构:
Authorization: AWS _ACCESS_KEY_:_HASH_OF_HEADER_AND_SECRET_
CephAdminAPI 示例类中有一个 base64Sha1Hmac() 方法,该方法接收头字符串和管理员用户的秘钥,并以 SHA1 HMAC 作为 base-64 编码字符串返回。 每个 execute() 调用都将调用同一代码行来构建 Authorization 头:
httpRequest.addHeader("Authorization", "AWS " + this.getAccessKey() + ":" + base64Sha1Hmac(headerString.toString(), this.getSecretKey()));
以下 CephAdminAPI 示例类要求您将访问密钥,密钥和端点传递给构造函数。 该类提供存取器方法以在运行时对其进行更改。
示例
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.ZoneId;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.Header;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.utils.URIBuilder;
import java.util.Base64;
import java.util.Base64.Encoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Mac;
import java.util.Map;
import java.util.Iterator;
import java.util.Set;
import java.util.Map.Entry;
public class CephAdminAPI {
/*
* Each call must specify an access key, secret key, endpoint and format.
*/
String accessKey;
String secretKey;
String endpoint;
String scheme = "http"; //http only.
int port = 80;
/*
* A constructor that takes an access key, secret key, endpoint and format.
*/
public CephAdminAPI(String accessKey, String secretKey, String endpoint){
this.accessKey = accessKey;
this.secretKey = secretKey;
this.endpoint = endpoint;
}
/*
* Accessor methods for access key, secret key, endpoint and format.
*/
public String getEndpoint(){
return this.endpoint;
}
public void setEndpoint(String endpoint){
this.endpoint = endpoint;
}
public String getAccessKey(){
return this.accessKey;
}
public void setAccessKey(String accessKey){
this.accessKey = accessKey;
}
public String getSecretKey(){
return this.secretKey;
}
public void setSecretKey(String secretKey){
this.secretKey = secretKey;
}
/*
* Takes an HTTP Method, a resource and a map of arguments and
* returns a CloseableHTTPResponse.
*/
public CloseableHttpResponse execute(String HTTPMethod, String resource,
String subresource, Map arguments) {
String httpMethod = HTTPMethod;
String requestPath = resource;
StringBuffer request = new StringBuffer();
StringBuffer headerString = new StringBuffer();
HttpRequestBase httpRequest;
CloseableHttpClient httpclient;
URI uri;
CloseableHttpResponse httpResponse = null;
try {
uri = new URIBuilder()
.setScheme(this.scheme)
.setHost(this.getEndpoint())
.setPath(requestPath)
.setPort(this.port)
.build();
if (subresource != null){
uri = new URIBuilder(uri)
.setCustomQuery(subresource)
.build();
}
for (Iterator iter = arguments.entrySet().iterator();
iter.hasNext();) {
Entry entry = (Entry)iter.next();
uri = new URIBuilder(uri)
.setParameter(entry.getKey().toString(),
entry.getValue().toString())
.build();
}
request.append(uri);
headerString.append(HTTPMethod.toUpperCase().trim() + "\n\n\n");
OffsetDateTime dateTime = OffsetDateTime.now(ZoneId.of("GMT"));
DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
String date = dateTime.format(formatter);
headerString.append(date + "\n");
headerString.append(requestPath);
if (HTTPMethod.equalsIgnoreCase("PUT")){
httpRequest = new HttpPut(uri);
} else if (HTTPMethod.equalsIgnoreCase("POST")){
httpRequest = new HttpPost(uri);
} else if (HTTPMethod.equalsIgnoreCase("GET")){
httpRequest = new HttpGet(uri);
} else if (HTTPMethod.equalsIgnoreCase("DELETE")){
httpRequest = new HttpDelete(uri);
} else {
System.err.println("The HTTP Method must be PUT,
POST, GET or DELETE.");
throw new IOException();
}
httpRequest.addHeader("Date", date);
httpRequest.addHeader("Authorization", "AWS " + this.getAccessKey()
+ ":" + base64Sha1Hmac(headerString.toString(),
this.getSecretKey()));
httpclient = HttpClients.createDefault();
httpResponse = httpclient.execute(httpRequest);
} catch (URISyntaxException e){
System.err.println("The URI is not formatted properly.");
e.printStackTrace();
} catch (IOException e){
System.err.println("There was an error making the request.");
e.printStackTrace();
}
return httpResponse;
}
/*
* Takes a uri and a secret key and returns a base64-encoded
* SHA-1 HMAC.
*/
public String base64Sha1Hmac(String uri, String secretKey) {
try {
byte[] keyBytes = secretKey.getBytes("UTF-8");
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(uri.getBytes("UTF-8"));
Encoder base64 = Base64.getEncoder();
return base64.encodeToString(rawHmac);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
后续 CephAdminAPIClient 示例说明了如何实例化 CephAdminAPI 类,构建请求参数映射以及使用 execute() 方法来创建,获取,更新和删除用户。
示例
import java.io.IOException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import java.util.*;
public class CephAdminAPIClient {
public static void main (String[] args){
CephAdminAPI adminApi = new CephAdminAPI ("FFC6ZQ6EMIF64194158N",
"Xac39eCAhlTGcCAUreuwe1ZuH5oVQFa51lbEMVoT",
"ceph-client");
/*
* Create a user
*/
Map requestArgs = new HashMap();
requestArgs.put("access", "usage=read, write; users=read, write");
requestArgs.put("display-name", "New User");
requestArgs.put("email", "new-user@email.com");
requestArgs.put("format", "json");
requestArgs.put("uid", "new-user");
CloseableHttpResponse response =
adminApi.execute("PUT", "/admin/user", null, requestArgs);
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
try {
System.out.println("\nResponse Content is: "
+ EntityUtils.toString(entity, "UTF-8") + "\n");
response.close();
} catch (IOException e){
System.err.println ("Encountered an I/O exception.");
e.printStackTrace();
}
/*
* Get a user
*/
requestArgs = new HashMap();
requestArgs.put("format", "json");
requestArgs.put("uid", "new-user");
response = adminApi.execute("GET", "/admin/user", null, requestArgs);
System.out.println(response.getStatusLine());
entity = response.getEntity();
try {
System.out.println("\nResponse Content is: "
+ EntityUtils.toString(entity, "UTF-8") + "\n");
response.close();
} catch (IOException e){
System.err.println ("Encountered an I/O exception.");
e.printStackTrace();
}
/*
* Modify a user
*/
requestArgs = new HashMap();
requestArgs.put("display-name", "John Doe");
requestArgs.put("email", "johndoe@email.com");
requestArgs.put("format", "json");
requestArgs.put("uid", "new-user");
requestArgs.put("max-buckets", "100");
response = adminApi.execute("POST", "/admin/user", null, requestArgs);
System.out.println(response.getStatusLine());
entity = response.getEntity();
try {
System.out.println("\nResponse Content is: "
+ EntityUtils.toString(entity, "UTF-8") + "\n");
response.close();
} catch (IOException e){
System.err.println ("Encountered an I/O exception.");
e.printStackTrace();
}
/*
* Create a subuser
*/
requestArgs = new HashMap();
requestArgs.put("format", "json");
requestArgs.put("uid", "new-user");
requestArgs.put("subuser", "foobar");
response = adminApi.execute("PUT", "/admin/user", "subuser", requestArgs);
System.out.println(response.getStatusLine());
entity = response.getEntity();
try {
System.out.println("\nResponse Content is: "
+ EntityUtils.toString(entity, "UTF-8") + "\n");
response.close();
} catch (IOException e){
System.err.println ("Encountered an I/O exception.");
e.printStackTrace();
}
/*
* Delete a user
*/
requestArgs = new HashMap();
requestArgs.put("format", "json");
requestArgs.put("uid", "new-user");
response = adminApi.execute("DELETE", "/admin/user", null, requestArgs);
System.out.println(response.getStatusLine());
entity = response.getEntity();
try {
System.out.println("\nResponse Content is: "
+ EntityUtils.toString(entity, "UTF-8") + "\n");
response.close();
} catch (IOException e){
System.err.println ("Encountered an I/O exception.");
e.printStackTrace();
}
}
}
参考
有关 Amazon S3 身份验证程序的详细说明,请查阅 Amazon Simple Storage Service 文档中的 " REST 请求的签名和身份验证 "部分。
有关更多信息,请参阅 S3 认证。