Skip to content

Instantly share code, notes, and snippets.

@ichengchao
Last active December 1, 2020 11:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ichengchao/56c8314b83497ec4d86e6cff01b42c0f to your computer and use it in GitHub Desktop.
Save ichengchao/56c8314b83497ec4d86e6cff01b42c0f to your computer and use it in GitHub Desktop.
账号生成逻辑. web: tools.html controller:AliyunToolsController.java service: ResourceDirectoryAccountFactory.java
package name.chengchao.springrun.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import name.chengchao.springrun.model.WebResult;
import name.chengchao.springrun.sso.tools.ResourceDirectoryAccountFactory;
import name.chengchao.springrun.util.UUIDUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/aliyunTools")
public class AliyunToolsController extends BaseController {
@RequestMapping("/createAccount")
public void createAccount(HttpServletRequest request, HttpServletResponse response) {
WebResult result = new WebResult();
try {
final String accessKeyId = request.getParameter("accessKeyId");
final String accessKeySecret = request.getParameter("accessKeySecret");
final String email = request.getParameter("email");
final String id = UUIDUtils.generateUUID();
ResourceDirectoryAccountFactory.logMap.put(id, new StringBuilder());
new Thread(new Runnable() {
@Override
public void run() {
try {
ResourceDirectoryAccountFactory.buildNewRD(accessKeyId, accessKeySecret, email, id);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}).start();
result.setData(id);
} catch (Exception e) {
logger.error(e.getMessage(), e);
result.setSuccess(false);
result.setErrorMsg(e.getMessage());
}
outputToJSON(response, result);
}
@RequestMapping("/getProcessById")
public void getProcessById(HttpServletRequest request, HttpServletResponse response) {
WebResult result = new WebResult();
try {
String id = request.getParameter("id");
if (null == ResourceDirectoryAccountFactory.logMap.get(id)) {
result.setData("can not find log,id:" + id);
} else {
String log = ResourceDirectoryAccountFactory.logMap.get(id).toString();
result.setData(log);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
result.setSuccess(false);
result.setErrorMsg(e.getMessage());
}
outputToJSON(response, result);
}
}
package name.chengchao.springrun.sso.tools;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.BasicCredentials;
import com.aliyuncs.auth.STSAssumeRoleSessionCredentialsProvider;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import name.chengchao.springrun.util.UUIDUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 利用已认证主体的账号生成新账号,并且开通RD,成为新RD的Master,并把原来账号邀请进来
*/
public class ResourceDirectoryAccountFactory {
public static final Map<String, StringBuilder> logMap = new HashMap<>();
public static final ThreadLocal<String> ctx = new ThreadLocal<>();
public static final Logger logger = LoggerFactory.getLogger(ResourceDirectoryAccountFactory.class);
public static void main(String[] args) {
}
public static void loggerInfo(String msg) {
logger.info(msg);
String traceId = ctx.get();
StringBuilder sb = logMap.get(traceId);
sb.append("<br/>");
sb.append(msg);
}
public static void buildNewRD(String masterAccountAccessKeyId, String masterAccountAccessKeySecret, String email, String traceId) throws Exception {
ctx.set(traceId);
DefaultProfile AliyunProfile = DefaultProfile.getProfile("cn-hangzhou");
IAcsClient masterClient = new DefaultAcsClient(AliyunProfile, new BasicCredentials(masterAccountAccessKeyId, masterAccountAccessKeySecret));
//1. 初始化RD
String rdInfo = GetResourceDirectory(masterClient);
if (null != rdInfo) {
int count = ListAccounts(masterClient);
if (count > 0) {
loggerInfo("this account has sub account,rdinfo:" + rdInfo);
return;
}
} else {
//如果rdInfo为null,则表示该账号没有开通过RD
initResourceDirectory(masterClient);
}
//2. 创建成员账号,继承主体认证
rdInfo = GetResourceDirectory(masterClient);
String rootFolderId = JSON.parseObject(rdInfo).getJSONObject("ResourceDirectory").getString("RootFolderId");
String createResult = CreateResourceAccount(masterClient, "langingzone_" + UUIDUtils.generateUUID(), rootFolderId);
String accountId = JSON.parseObject(createResult).getJSONObject("Account").getString("AccountId");
PromoteResourceAccount(masterClient, accountId, email);
boolean confirmEmail = false;
//3. 等待用户点击"立即确认"按钮
for (int i = 0; i < 60; i++) {
Thread.sleep(10000);
String accountInfo = GetAccount(masterClient, accountId);
String accountType = JSON.parseObject(accountInfo).getJSONObject("Account").getString("Type");
if ("CloudAccount".equals(accountType)) {
confirmEmail = true;
break;
}
loggerInfo("waiting confirm email,accountId:" + accountId);
}
if (!confirmEmail) {
loggerInfo("reach max waiting count,exit!");
return;
}
//4. 获取新账号的ram user的AK
//4.1 先换出master账号的ram user 的AK
String callerIdentity = GetCallerIdentity(masterClient);
String masterAccountId = JSON.parseObject(callerIdentity).getString("AccountId");
String masterRamUserName = "landingzone_master_" + UUIDUtils.generateUUID();
Map<String, String> masterRamUserAKMap = CreateRamUserAccessKey(masterClient, masterAccountId, masterRamUserName);
STSAssumeRoleSessionCredentialsProvider provider = new STSAssumeRoleSessionCredentialsProvider(new BasicCredentials(masterRamUserAKMap.get("AccessKeyId"), masterRamUserAKMap.get("AccessKeySecret")), "acs:ram::" + accountId + ":role/resourcedirectoryaccountaccessrole", AliyunProfile);
DefaultAcsClient assumeRoleClient = new DefaultAcsClient(AliyunProfile, provider);
//4.2 换取目标账户ram user的AK
String subRamUserName = "masteradmin";
Map<String, String> subRamUserAKMap = CreateRamUserAccessKey(assumeRoleClient, accountId, subRamUserName);
String subRamUserPassword = RandomStringUtils.randomAlphanumeric(10);
CreateLoginProfile(assumeRoleClient, subRamUserName, subRamUserPassword);
IAcsClient newAccountRamUserClient = new DefaultAcsClient(AliyunProfile, new BasicCredentials(subRamUserAKMap.get("AccessKeyId"), subRamUserAKMap.get("AccessKeySecret")));
//4.3 清理主账号的ram user
DeleteUser(masterClient, masterRamUserName, masterRamUserAKMap.get("AccessKeyId"), true);
//5. 解绑账号
RemoveCloudAccount(masterClient, accountId);
//6. 开通RD
initResourceDirectory(newAccountRamUserClient);
//7. 关闭原来的账号RD
DestroyResourceDirectory(masterClient);
//8. 用新账号邀请原来账号进入RD
String inviteResult = InviteAccountToResourceDirectory(newAccountRamUserClient, masterAccountId);
String handshakeId = JSON.parseObject(inviteResult).getJSONObject("Handshake").getString("HandshakeId");
Thread.sleep(3000);
AcceptHandshake(masterClient, handshakeId);
//9. 清理新账号的ram user,由于循环问题不删除user,只清理改user的policy 和 ak
DeleteUser(newAccountRamUserClient, subRamUserName, subRamUserAKMap.get("AccessKeyId"), false);
loggerInfo("*******************************************************************");
loggerInfo("master account: " + email);
loggerInfo("-------------------------------------------------------------------");
loggerInfo("ram user name: " + subRamUserName);
loggerInfo("ram user passowrd: " + subRamUserPassword);
loggerInfo("ram user login url: ");
loggerInfo("https://signin.aliyun.com/" + accountId + ".onaliyun.com/login.htm?callback=https%3A%2F%2Fhomenew.console.aliyun.com%2F#/login");
loggerInfo("*******************************************************************");
loggerInfo("__done__");
}
public static Map<String, String> CreateRamUserAccessKey(IAcsClient client, String accountId, String ramUserName) throws Exception {
CommonRequest request = new CommonRequest();
CommonResponse response;
//CreateUser
request.setSysDomain("ram.aliyuncs.com");
request.setSysVersion("2015-05-01");
request.setSysAction("CreateUser");
request.putQueryParameter("UserName", ramUserName);
request.setSysProtocol(ProtocolType.HTTPS);
response = client.getCommonResponse(request);
loggerInfo("[ram.aliyuncs.com][CreateUser]:" + response.getData());
//AttachPolicyToUser
request = new CommonRequest();
request.setSysDomain("ram.aliyuncs.com");
request.setSysVersion("2015-05-01");
request.setSysAction("AttachPolicyToUser");
request.putQueryParameter("PolicyType", "System");
request.putQueryParameter("PolicyName", "AdministratorAccess");
request.putQueryParameter("UserName", ramUserName);
request.setSysProtocol(ProtocolType.HTTPS);
response = client.getCommonResponse(request);
loggerInfo("[ram.aliyuncs.com][AttachPolicyToUser]:" + response.getData());
//CreateAccessKey
request = new CommonRequest();
request.setSysDomain("ram.aliyuncs.com");
request.setSysVersion("2015-05-01");
request.setSysAction("CreateAccessKey");
request.putQueryParameter("UserName", ramUserName);
request.setSysProtocol(ProtocolType.HTTPS);
response = client.getCommonResponse(request);
loggerInfo("[ram.aliyuncs.com][CreateAccessKey]:" + response.getData());
String AccessKeyId = JSON.parseObject(response.getData()).getJSONObject("AccessKey").getString("AccessKeyId");
String AccessKeySecret = JSON.parseObject(response.getData()).getJSONObject("AccessKey").getString("AccessKeySecret");
Map<String, String> akMap = new HashMap<>();
akMap.put("AccessKeyId", AccessKeyId);
akMap.put("AccessKeySecret", AccessKeySecret);
return akMap;
}
public static void CreateLoginProfile(IAcsClient client, String userName, String password) throws Exception {
CommonRequest request = new CommonRequest();
CommonResponse response;
//DeleteAccessKey
request.setSysDomain("ram.aliyuncs.com");
request.setSysVersion("2015-05-01");
request.setSysAction("CreateLoginProfile");
request.putQueryParameter("UserName", userName);
request.putQueryParameter("Password", password);
request.putQueryParameter("PasswordResetRequired", "true");
request.setSysProtocol(ProtocolType.HTTPS);
response = client.getCommonResponse(request);
loggerInfo("[ram.aliyuncs.com][CreateLoginProfile]:" + response.getData());
}
public static void DeleteUser(IAcsClient client, String userName, String userAccessKeyId, boolean deleteUser) throws Exception {
CommonRequest request = new CommonRequest();
CommonResponse response;
//DeleteAccessKey
request.setSysDomain("ram.aliyuncs.com");
request.setSysVersion("2015-05-01");
request.setSysAction("DeleteAccessKey");
request.putQueryParameter("UserAccessKeyId", userAccessKeyId);
request.putQueryParameter("UserName", userName);
request.setSysProtocol(ProtocolType.HTTPS);
response = client.getCommonResponse(request);
loggerInfo("[ram.aliyuncs.com][DeleteAccessKey]:" + response.getData());
if (deleteUser) {
//DetachPolicyFromUser
request.setSysDomain("ram.aliyuncs.com");
request.setSysVersion("2015-05-01");
request.setSysAction("DetachPolicyFromUser");
request.putQueryParameter("PolicyType", "System");
request.putQueryParameter("PolicyName", "AdministratorAccess");
request.putQueryParameter("UserName", userName);
request.setSysProtocol(ProtocolType.HTTPS);
response = client.getCommonResponse(request);
loggerInfo("[ram.aliyuncs.com][DetachPolicyFromUser]:" + response.getData());
//DeleteUser
request.setSysDomain("ram.aliyuncs.com");
request.setSysVersion("2015-05-01");
request.setSysAction("DeleteUser");
request.putQueryParameter("UserName", userName);
request.setSysProtocol(ProtocolType.HTTPS);
response = client.getCommonResponse(request);
loggerInfo("[ram.aliyuncs.com][DeleteUser]:" + response.getData());
}
}
public static String CreateResourceAccount(IAcsClient client, String displayName, String parentFolderId) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("CreateResourceAccount");
request.setSysProtocol(ProtocolType.HTTPS);
request.putQueryParameter("DisplayName", displayName);
request.putQueryParameter("ParentFolderId", parentFolderId);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[resourcemanager.aliyuncs.com][CreateResourceAccount]:" + result);
return result;
}
/**
* 升级成云账号,会发送邮件,需要在邮件中"立即确认"
*
* @param accountId
* @param email
* @throws Exception
*/
public static String PromoteResourceAccount(IAcsClient client, String accountId, String email) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("PromoteResourceAccount");
request.putQueryParameter("AccountId", accountId);
request.putQueryParameter("Email", email);
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[resourcemanager.aliyuncs.com][PromoteResourceAccount]:" + result);
return result;
}
/**
* 把云账号从RD中解绑
*
* @param accountId
* @throws Exception
*/
public static String RemoveCloudAccount(IAcsClient client, String accountId) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("RemoveCloudAccount");
request.putQueryParameter("AccountId", accountId);
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[resourcemanager.aliyuncs.com][RemoveCloudAccount]:" + result);
return result;
}
/**
* 开通RD
*
* @throws Exception
*/
public static void initResourceDirectory(IAcsClient client) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("InitResourceDirectory");
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
System.out.println(result);
}
public static String GetResourceDirectory(IAcsClient client) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("GetResourceDirectory");
request.setSysProtocol(ProtocolType.HTTPS);
try {
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
return result;
} catch (ClientException clientException) {
if ("ResourceDirectoryNotInUse".equals(clientException.getErrCode())) {
return null;
}
throw clientException;
}
}
public static int ListAccounts(IAcsClient client) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("ListAccounts");
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[resourcemanager.aliyuncs.com][ListAccounts]:" + result);
return JSON.parseObject(result).getInteger("TotalCount");
}
public static String GetAccount(IAcsClient client, String accountId) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("GetAccount");
request.setSysProtocol(ProtocolType.HTTPS);
request.putQueryParameter("AccountId", accountId);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[resourcemanager.aliyuncs.com][GetAccount]:" + result);
return result;
}
public static void DestroyResourceDirectory(IAcsClient client) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("DestroyResourceDirectory");
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[resourcemanager.aliyuncs.com][DestroyResourceDirectory]:" + result);
}
public static String InviteAccountToResourceDirectory(IAcsClient client, String accountId) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("InviteAccountToResourceDirectory");
request.putQueryParameter("TargetType", "Account");
request.putQueryParameter("TargetEntity", accountId);
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[resourcemanager.aliyuncs.com][InviteAccountToResourceDirectory]:" + result);
return result;
}
public static String AcceptHandshake(IAcsClient client, String handshakeId) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("resourcemanager.aliyuncs.com");
request.setSysVersion("2020-03-31");
request.setSysAction("AcceptHandshake");
request.putQueryParameter("HandshakeId", handshakeId);
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[resourcemanager.aliyuncs.com][AcceptHandshake]:" + result);
return result;
}
public static String GetCallerIdentity(IAcsClient client) throws Exception {
CommonRequest request = new CommonRequest();
request.setSysDomain("sts.aliyuncs.com");
request.setSysVersion("2015-04-01");
request.setSysAction("GetCallerIdentity");
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
String result = response.getData();
loggerInfo("[sts.aliyuncs.com][GetCallerIdentity]:" + result);
return result;
}
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Generator</title>
<link href="../../css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript" src="../../jslib/jquery.min.js"></script>
<script type="text/javascript">
let task;
$(document).ready(function () {
$("#btn_generate").on("click", function () {
let accessKeyId = $("input[name='accessKeyId']").val();
let accessKeySecret = $("input[name='accessKeySecret']").val();
let email = $('input[name="email"]').val();
$("#msgBox").show();
$("#msgBox").delay(2000).hide(1000);
$.ajax({
url: "../../aliyunTools/createAccount.htm",
data: {
accessKeyId: accessKeyId,
accessKeySecret: accessKeySecret,
email: email
},
success: function (result) {
console.log(result);
if (result.success) {
task = setInterval(function () {
$.ajax({
url: "../../aliyunTools/getProcessById.htm",
data: {
id: result.data
},
success: function (resultInfo) {
let log = resultInfo.data;
$("#consoleDiv").html(log);
if (log.endsWith('__done__')) {
clearInterval(task);
}
}
});
}, 1000);
}
}
});
});
});
</script>
</head>
<body>
<div class="container">
<h1>账号生成器</h1>
<hr>
<h3>旧账号</h3>
<br>
<div class="form-group">
<label><h4>AccessKeyId</h4></label>
<input class="form-control" name="accessKeyId" placeholder="必填">
</div>
<div class="form-group">
<label><h4>AccessKeySecret</h4></label>
<input class="form-control" name="accessKeySecret" type="password" placeholder="必填">
</div>
<br>
<h3>新账号</h3>
<br>
<div class="form-group">
<label><h4>Email</h4></label>
<input class="form-control" name="email" placeholder="必填">
</div>
<br>
<button id="btn_generate" class="btn btn-success">&nbsp;&nbsp;生成新账号&nbsp;&nbsp;</button>
<button id="btn_reset" class="btn" type="reset">重置</button>
<br>
<div id="msgBox" style="display:none" class="alert alert-success" role="alert">
已经提交,请耐心等待!
</div>
<br>
<div id="consoleDiv" style="background-color: black;color: #adb5bd;word-break: break-all;padding: 10px;">
waiting...
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment