管理认证请求
Amazon 的 S3 服务使用访问密钥以及请求头和密钥的散列来认证请求。 它具有在没有 SSL 开销的情况下提供已认证的请求 (尤其是大型上载) 的优点。
S3 API 的大多数用例都涉及使用开放式源代码 S3 客户机,例如 Amazon SDK for Java 或 Python Boto 中的 AmazonS3Client 。 这些库不支持 Ceph Object Gateway 管理 API。 您可以对这些库进行子类和扩展,以支持 Ceph 管理 API。 或者,您可以创建唯一的网关客户机。
创建 execute() 方法
本节中的示例类演示了如何创建一个xml-ph-0000@deepl.internal方法,该 CephAdminAPI 本节中的示例类演示了如何创建一个 execute() 方法,该方法可以接收请求参数、验证请求、调用Ceph Admin API并接收响应。
注: CephAdminAPI 类示例不受支持或不打算用于商业用途。 它仅用于说明目的。* *
调用 Ceph Object Gateway
客户机代码 包含对 Ceph Object Gateway 的五个调用,用于演示 CRUD 操作:
创建用户
获取用户
修改用户
创建子用户
删除用户
以这个例子为例,获取 httpcomponents-client-4.5.3 Apache HTTP 组件。 你可以在这里下载: http://hc.apache.org/downloads.cgi。 然后解压缩 tar 文件,浏览至其 lib 目录,并将内容复制到 JAVA_HOME 目录的 /jre/lib/ext 目录或定制类路径。
当您查看 CephAdminAPI 类示例时,请注意, execute() 方法接受一个 HTTP 方法、一个请求路径、一个可选的子资源(如果未指定,则为 null )和一个参数映射。 要使用子资源 (例如, subuser和 key) 执行,您将需要在 execute() 方法中指定子资源作为自变量。
示例方法:
构建 URI。
生成一个 HTTP 报头字符串。
例如, HTTP 请求的实例化,
PUT、POST、GET、DELETE。将
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_示例类有一个xml-ph-0000@deepl.internal方法,该方法接受标题字符串和管理员用户的密钥,并返回一个xml-ph-0001@deepl.internal H 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 认证 以获取更多详细信息。